thank you for this detailed explanation and the examples.
I would like to implement a FSM on a microprocessor but I have identified what I expect to be different events and would need to enter states based on multiple events.
For example, I have state "Running" which receives updates from an ADC (Event?), but can also be entered from "Sleeping" (if the supply voltage got too low previously) and from "Idle" (if a button is pressed).
Can I achieve this using this design? I thought about writing a generic event but feel like I would work around the framework that handles CANNOT_HAPPEN and EVENT_IGNORED and around the state functions.
Thank you for this State machine implementation, it is very interesting.
I'm trying to implement it on an embedded system based on a PIC18F15256. However, the event data is not always sent correctly to the state functions. The compiler also complains about possible Hardware stack overflow. In order to make the code more lightweight for the PIC I wanted to remove the assert functions and the fixed block memory allocator. For this I tried to use a static event_data variable and use its address when calling events. The call tree got much flater. However, the event_data is always passed completely wrong to the event functions. I expect something happens when the event data is given as a void pointer to the _SM_StateEngine function, but I cannot figure out what.
So my question is: Why is the event data dynamically allocated and freed? Can it be replaced by a static variable instead? I'm using only a single instance of the state machine in my code.
I vaguely recall reading the original article many years ago, and I think it's great to see people calling out C for such things as implementing a robust FSM, which begs for the lean, mean implementation afforded by the code generated by a good optimizing C compiler.
thank you for your effort to present your state machine. Why do you define separate event functions instead of one state event map? For example you could add the content to the external event function.
Thanks for another great article! If possible I try not to make too many states in my code. Consider a machine that needed to be reset to a "home" position when powered up. This is often done with one thing moving at a time to avoid mechanical damage. In a resetting state the sudo code might look like this:
Turn on motor A
Wait for motor A home switch
Turn on valve X
Wait for valve X home switch. And so forth.
I'm inclined to make one resetting state and walk down these commands using a switch statement. Incrementing a index to jump to each time the reset state is run and a series of operations completed. While this works, I feel like there must be something more elegant than a switch statement to control this long sequential process within a state.
Do have something more elegant in C that I might consider? Single thread.
Thanks and any feedback is much appreciated,
I want to incorporate a FSM into a C# project so that it governs the appearance (showing or hiding, enabling or disabling) of various UI controls, depending on what actions the user performs. But I don't know in advance the complete set of behaviors that it should implement. So I don't want to have to hard-code the various states, events, and transitions. Would it possible to have that data stored in a config file, or a resource file in the project, so that it would be simple to modify, add, and delete those directives, and have the program read in that information and build the FSM dynamically?
Thanks very much David for this well-organized and clearly-explained article. I'm chagrined to say that despite 30+ years of coding I've never learned about FSMs -- the hazards of self-education, perhaps. I can think of many occassions when this formalism would have aided my work! Better late than never, I hope...
My question is perhaps a bit pedantic, but since this is my first encounter with FSM I'd like to make sure I have the hang of it: it seems to me that "ChangeSpeed" isn't really a state, or at least not the best *name* for the state. Wouldn't it be better to think of the state as "Running", or maybe "RunningAtSpeed"?
Can you point me to any guidelines for naming states and events that you find useful?
Regarding the naming, there are certainly rules others have proposed for naming events and states. The names might be better, but its a simple example to just show functionality. I don't have a link or any guidance offhand. There are articles I've used in the past but didn't keep them.
I kept the state names since (a) I wrote the original C++ article like 20 years ago and (b) I already had the state machine image and was too lazy to recreate it.
Hey, nice article, I appreciate the detailed write up and explanation.
I was messing around with your motor state machine example, trying to implement a function that returns the currentspeed of the motor. I don't have that much experience programming, so I wasn't able to figure out a way to implement a function like this yet. I was hoping you could think of a nice solution, where you could request the current speed regardless of the state the motor is in.
I also thought of another feature I'd like to try and implement: a lock/unlock parameter. When the motor is locked it will stay in ST_IDLE and if it is unlocked it will work like it normally does. I'm guessing the best way to implement this would be with an external event. In the ST_IDLE transition map you'd have to check the "locked/unlocked" parameter upon receiving a setSpeed event.
// Public accessor
In Motor.c add:
// Get current speed
Motor* pInstance = SM_GetInstance(Motor);
In main.c add:
// Get current speed from Motor1SM
INT currentSpeed = SM_Get(Motor1SM, MTR_GetSpeed);
Second question: Lock or unlock the state machine. External events would be reasonable solution (e.g. MTR_Lock() and MTR_Unlock(). You add a lock state to the state machine (e.g. ST_LOCK) and the state machine stays in the locked state until MTR_Unlock() external event moves it back to ST_IDLE for instance.
If I find time I'll update the article and attached code. Let me know if you have any problems.
I have downloaded the code and tried to plug it in as is, with some minor changes according to the compiler and run it on TI compiler. I've been running into this error in on the end of transition map.
I'm running it on TI version 8.3.5 C compiler. I removed the usage of mem allocation, and the extra files used only statemachine.c/h, Centrifuge_Test.c/h and called SM_EVENT in my own main code.
I would like to know if I could translate this article to portuguese and use it in my classes of
Microcontrollers PIC and Robotics in a specialization course and in a technician course of Industrial Automation.
If yes, what I must to do?