1

I want to gain from recent advice from this forum by re-doing my project using 'state machine' logic if possible, in an effort to reduce wasted processor time and variables usage.

I'm starting from Nick Gammons 'state machine to process input from the serial port' example http://www.gammon.com.au/statemachine, which shows all the different possible combinations for all the special control character 'events' against all the possible machine states - essentially a 2-dimensional grid.

I've refined my goal to the processing of serial input in a format of "command [parameters] [options]", similar to a DOS command-line format, eg: DIR "c:\program files" /w /s. This would free me from needing large Buffer[] and Header[] string, and avoides any parsing,

Therefore my event control characters are space, comma, single-quote, double-quote, forward-slash, Carraige Return, and my 'states' are NULL, COMMAND, PARAMETER, OPTIONS

The OPTIONS state adds characters to a temporary option[] string until a comma or space delimiter or Carraige Return causes that option to be processed as appropriate, perhaps saving its value to a recognised variable.

The COMMAND and PARAMETER 'states' add characters to their corresponding command[] and parameters[] strings, including the special control characters if they are contained within either single or double quotes (thereby allowing quotes as part of a string if used within a pair of the other type).

So there appears to be a second state machine needed for NoQuotes, SingleQuotes and DoubleQuotes to modify the operation of the COMMAND, PARAMETER and OPTIONS states.

This is where I run out of neurons, because all I see is an impossibly complex 2-machine-state 3-dimensional grid with too many possible permutations.

But I suspect there must be a very practical way to implement this, because it lies at the heart of almost all command-line utilities dating back to a time when processor power and memory availability were scarcer than hens teeth, and those old DOS command-line utilities needed to be as mimimal as was possible, including their command-line parsing.

So can anybody suggest a feasible model (machine-state or otherwise) for getting command-line type format from input?

UPDATE

Oh dear... I've just seen another complication I hadn't spotted before, which is that '/' options are not necessarily always at the end, which means that except if the options state changes by carraige-return, options state change by delimiter have to return to the state prior to the options state change (phew, I hope that makes some sense). Anyway, I think it's back to drawing board because this approach seems likely to be too complicated, as the 2 answers already suggest.

6
  • The common way of handing interacting states is to expand the interactions into their own state. i.e. PARAMETER vs SingleQuotes_PARAMETER DoubleQuotes_PARAMETER, where their processing could share much the same code. See github.com/Traumflug/Teacup_Firmware/blob/master/gcode_parse.c for an big example. Also, this is too broad (you don't have a syntax for us to use) and is really off topic for an Arduino-focused forum.
    – Dave X
    Mar 10, 2016 at 14:03
  • Another way to think of it as a state machine is that your state space is a many-dimensional vector of state variables, with a {COMMAND, PARAMETER[],OPTIONS[],etc...)
    – Dave X
    Mar 10, 2016 at 14:22
  • The question is very much Arduino because I wish to read incoming serial and 'sort' it into command plus optional parameter plus optional control-options, therefore mention of DOS command-line was merely giving a syntax example of the required serial format. Mar 10, 2016 at 14:37
  • Some sort of general DOS syntax, or the much more limited syntax for a particular command? With a particular command, there are only a limited number of parameters and options, and your /parser/ state machine can sort them out into their /process/ state variables somewhat like Teacup does.
    – Dave X
    Mar 10, 2016 at 14:55
  • It's for whatever local 'commands' and 'parameters the arduino is programmed tolook for in incoming serial, eg: 'LED1 ON', or 'IRSEND "NEC 0xFFEE9123 32". The options are for optional arduino-to-arduino sending of control info, such as /c(hecksum)=nnn, /l(ength)=nnn, /s(ource)=nnn etc. The idea is to read incoming serial a byte at a time and send to command or params or options on the fly, rather than needing to parse an additional large buffer string after. Mar 10, 2016 at 15:21

2 Answers 2

2

Suggestion: - don't try to "moosh" (that's a technical-term!) the state-machine heirarchy down into one large, flat state-machine. That way lies madness. Keep your { NULL, COMMAND, PARAMETER, OPTIONS } state machine, for instance, and, wherever you need something more than simple string collection in one of those states, call a parser SM appropriate to the kind(s) of input you expect at that point - a number, a quoted string, an option specifier, etc.

2
  • I think I understand (probably too late to avoid madness though cos I think the state machine may have already 'mooshed' my head). As you say, use NULL, COMMAND, PARAMETER as the states to change through. And even though NoQuotes, SingleQuotes, Double-Quotes and possibly Options might justify a state machine themselves, best just to treat them as separate processes within the main state machine. Mar 10, 2016 at 15:57
  • You might also consider as a mid-point, a universal parser that can handle various input types, but separate from the main SM. You'll know best, once you quick sketch up a couple of SM hierarchies (that's 'sketch' as in 'circles and arrows', not as in 'coding').
    – JRobert
    Mar 10, 2016 at 17:32
2

Personally I don't think Nick advised to do command line pattern parsing with a state machine. His example is about changing a state machine based on command line input.
I have written some command line parsers and I never used a state machine to do so. I would not advice to use a state machine to do so.
Simple string parsing is far easier.

Edit To answer the remark below:
I would not advice to go byte by byte. I'd advice to go the line by line way. I have written a library to do read line by line and an article on how that one works. http://blog.baeyens.it/#post16
Here a link to the lib https://github.com/jantje/libraries/tree/master/SerialCommunicator.
Here is a parcing code example. It is not so interesting for you as I have it done in a stage by stage way in a very high level way of coding. https://github.com/jantje/libraries/blob/master/SerialBridgeCommunicator/SerialBridgeCommunicator.cpp#L21

Basically the algorithm is=
1 Take the first word;
2 identify the word.
3 If the command is complete ->do it
else Send the rest of the string to a specialized piece of code. (which has the same algorithm)

2
  • I thought my needs were the same as Nicks example - to read incoming serial a byte at a time and send to command or params or options on the fly then action them as appropriate after reading a carraige-return, rather than then needing to parse an additional large buffer string after. But no point me shooting for the moon - you mentioned doing command line parser previously... would you happen to have a suitable flowchart or algorithm? Mar 10, 2016 at 15:35
  • I would not advice to go byte by byte. I'd advice to go the line by line way.
    – jantje
    Mar 10, 2016 at 16:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.