I have implemented a simple state machine for an embedded system using C’s switch statement. I know it would be better if I used function pointers with a look up table but I’m saving that as a next step.
My state machine has the following states:
- Startup (the initial state)
- Startup Error.
- Idle (the system only checks for input in this state. It does not update the display or anything else. It’s just ‘idle’).
- Check (this is the actual application)
- Program
- Copy to Internal Memory
When the system starts up, it enter the startup state which configures the ports, initializes the display and does a hand-shake with the ICs connected on the SPI bus to ensure everything is A-OK. If so, the system enters the Idle state. If not, it enters the Startup Error state, displays an error on the LCD, flags a variable and then enters the Idle state.
In the Idle state, the program polls 3 pins on the microcontroller to check if one of the 3 buttons (Check, Program, Copy to Mem.) is pressed. Depending on which button is pressed, it enters the appropriate state, executes some code, updates the LCD and then returns back to the Idle state. NOTE: The system does NOT care if a button is pressed if there was a hardware fault in the system. The Startup Error state flags a variable called hardware_fault which, if set, ensures that the Idle state does not bother polling any of the input buttons.
This is the first time I’m implementing a state machine and I was just unsure if this was a good design. I haven’t really seen any examples of FSMs where they poll for input in an Idle state. Instead, it seems, most examples are rather sequential in nature (like a counter, for instance). So, my question is, is my design reasonable? It DOES work but as everyone here knows, there is bad design and then there is good design.
You should refactor your code away from a switch statement and use a transition table as you mention. Code around a switch doesn’t scale, is messy and quickly becomes difficult to read and update.
To answer your question, I would say that most state machines are actually like yours: they react to events (in your case, the poll). If they are purely sequential, without events at all, they are for specialized usages, like implementing a regex…
As a note, the
Idlestate is equivalent to the runtime core of a state machine library: it intercepts events and posts them to the state machine. With a state machine library, it would be “hidden” from the client code, while a bare bones implementation like yours has to do event polling explicitly.And now a design critique: one should avoid global variables in general, and especially so in a state machine. State
Idleshould not know about ahardware_faultglobal variable. With state machines, one should strive to “embed” global variables in the state machine itself, by adding states (when it makes sense!). A very good introduction to (hierarchical) state machines and explanation of the rationale is here.Using the UML notation (see here for a tutorial), your state machine is:

An easy refactoring to remove the

hardware_faultdependency all together is:That is, we just stay forever in the
StartupErrorstate, without transitioning toIdle.The ε (epsilon) represents an empty transition, that is, a transition that is taken as soon as the activity associated with the source node is over, without any event. This is what you mean by “sequential” state machines.
I am also including the sources to the first diagram (the second one is very similar), generated with the very easy and powerful PlantUML.