Who Am I?
- Mikael Rosbacke
- Independent SW developer, active in Stockholm/Sweden.
- Focus on microcontrollers, embedded Linux, C, C++.
e-mail: mikael.rosbacke@gmail.com
github: http://www.github.com/rosbacke
http://www.akaza.se
Yet another state machine tool
One more stab at getting a decent framework for state machines
Want to do this with switch/case?

Scope
- A C++ helper to make it easy to write a hierarchical state machine directly in C++.
- No code generation.
- Support for entry/exit actions, hierarchy and queueing of events.
- Microcontroller / real-time friendly. No heap allocation after construction.
- Intended for modelling high level state in embedded devices.
Out of scope
- Thread safety.
- Continuous processing. Use repeated events for that.
- Time handling. Use external timers to deliver events.
- 'And' states. Use 2 parallel state machines.
- Unsuitable for low level tasks such as protocol decoding, parsing etc.
Use class/object as a state
- Constructor/destructor is entry/exit event.
- State hierarchy is not inheritance. It is realised with a stack of active states.
- Events are objects of any value based type. Primitive types are ok.
- Incoming events are queued. Guarantee run-to-completion semantics. (transitions postponed.)
- Event delivery to active state via an 'event' function.
Typical use
#include "MyFsm.h"
int main()
{
// The state machine is an ordinary object.
MyFsm fsm;
// Perform initial jump to start state. entry events called.
fsm.setStartState<state1>();
MyEvent ev1;
fsm.postEvent(ev1);
// ...
fsm.postEvent(ev1);
}
// Upon destruction, relevant exit events are called.
Typical fsm class
#include <StateChart.h>
// Ordinary class, needs to inherit from FsmBase.
// MyFsmDesc contain configuration information about the fsm.
class MyFsm : public FsmBase<MyFsmDesc> {
public:
// No special requirements on constructors.
MyFsm() {}
// Additional user defined data.
// Can be accessed from state classes.
int myFsmData = 0;
// FsmBase contain the 'postEvent' function.
};
Typical state class
// State classes inherits StateBase with needed template arguments.
class MyState1 : public StateBase<MyFsmDesc, States::state1> {
public:
// Required constructor. Use body for entry event code.
MyState1(StateArgs& args) : StateBase(args), stateData(0)
{ /* entry event code */ }
// Optional destructor. default is fine.
~MyState1() { /* exit event code */ }
// Handle all incoming events.
bool event(const MyEvent& ev) {
if (ev.foo()) {
transition<MyState2>();
return true; // We want to stop processing this event.
}
return false; // We want parent state to see the event.
}
int stateData; // Additional data possible as normal.
};
Fsm description class
// States represented both with a type and an enum value.
enum class States { myState1, myState2, /* ... */ };
class MyEvent;
class MyFsm;
class MyFsmDesc {
public:
using Event = MyEvent; // Event class. Can be primitive.
using Fsm = MyFsm; // State machine class.
// Called during setup. Will build up the state hierarchy.
// Forward declared here.
static void setupStates(FsmSetup<MyFsmDesc>& sc);
};
State setup function
void MyFsmDesc::setupStates(FsmSetup<UserFsmDesc>& sc)
{
// Add a root state. (level 0)
sc.addState<State1>();
// Another root state.
sc.addState<State2>();
// sub state to state 1. (level 1)
sc.addState<State3, State1>();
// sub state to state 2. (level 1)
sc.addState<State4, State2>();
}
State features
// Typical support functions inherited from statebase
template </* ... */ > class StateBase
{
// All copy/move/assign deleted.
// Transition to new state once eventprocessing is done.
template <typename TargetState>
void transition();
void transition(StateId id);
/// Reference to our state machine object. (MyFsm in our case)
Fsm& fsm();
// Return a reference to the parent state.
template <class ParentState>
ParentState& parent();
};
Fsm features
// Typical support functions inherited from FsmBase
template </* ... */ > class FsmBase {
// Currently active state id.
StateId currentStateId() const;
// Get current active state object. nullptr if type mismatch.
template <class State>
const State* currentState() const;
// Get any of the currently active state object.
template <class State>
const State* activeState() const;
// (Planned): Set a callback to be called upon state change.
using StateCB = std::function<void(Fsm&, StateId)>;
void setStatechangedCB(StateCB cb);
};
Mechanisms
- Uses placement new/delete for state entry/exit.
- Function setStartState will allocate enough memory at each state level to contain the largest state.
- State tree is set up using function static objects. Done at first use, then reused.
- State classes are not polymorphic. Event calls are done using Sean Parents methods for virtual calls at call site.
Current status
- Code is available at github. Licence TBD, but MIT or BSD are likely.
- Still prototype quality. I've used it in internal projects. Some unit tests are available. But the interface is still settling in. Use it, but be prepared for changes if you want to upgrade later.
- I've used an earlier version based on static function pointers in a commercial setting. Had good experience with that. (Inspired by Miro Sameks work)
Thank you for your attention
Code available at github:
http://www.github.com/rosbacke/MCU-tools
To get in touch:
email: mikael.rosbacke@gmail.com
web: http://www.akaza.se
Yet another state machine
By mikael rosbacke
Yet another state machine
Presents a class based state machine framework for C++.
- 408