FSM library

I did a little embedded project recently.  Years ago I bought a binary coded decimal clock which no longer works, and I thought I could replace it with one I built myself.  (In reality this was simply an excuse to play with programming a Raspberry Pi Pico.)

Broken BCD clock (left) and home grown replacement (right).  The LEDs are in 6 columns and represent time in hh:mm:ss format, with each decimal digit represented in binary.

During the project I realised I needed to create a little Finite State Machine to enable setting of the time using the bootsel button.  So I searched around on the internet and found tens of different libraries, but each with its own drawbacks.

Some required a wizard executable to auto-generate code which you then edit, which has the drawback that if you change the input to the wizard you then need to manually merge new auto-generated code with your changes.  Other libraries, had this strange thing where each state had its own "enter" and "exit" methods even though transitions between some pairs of states do not require everything to be torn down and restarted.  (The most generic pattern is a lookup which matches initial state and event to action and new state.)  Many libraries included code which used the heap which, while not a problem for my project, means it is not suitable for a lot of embedded systems.  Finally I wanted something where I could easily autogenerate graphviz output, directly from the code, like this:

Finite State Machine for BCD clock home project

This meant I needed to write my own library.  And here it is: a single-file, header-only, FSM library free to use with no license


The first step is to create a header file that defines the state transition table, e.g. example/ExampleFsmTable.h.  This contains a class which contains enumerations for the states, the events, and the actions.  It also contains a transition table.  This header can be processed directly by tools/gen_graph to generate an image like the one above.  The next step is to create another header, e.g. example/ExampleFsm.h,  containing the definition of the FSM itself, and this is what needs to include the single header file "Fsm.h" from the library.  Finally, the application can create an instance of this and inject events causing actions in the FSM to get called automatically, for example (from example/main.cpp)

#include "ExampleFsm.h"

int main()
{
    ExampleFsm fsm{};

    // Change from open -> closed
    fsm.inject_event(ExampleFsm::EV_BUTTON_PRESS);

    // Change from closed -> open
    fsm.inject_event(ExampleFsm::EV_BUTTON_PRESS);

    // Change from open -> closed
    fsm.inject_event(ExampleFsm::EV_BUTTON_PRESS);

    // Change from closed -> open
    fsm.inject_event(ExampleFsm::EV_TIMEOUT);

    return 0;
}

This FSM library should be suitable for any C++ project, is extremely low overhead, and hopefully quick to grasp.

Comments

Popular posts from this blog

The GHZ experiment cartoon

How To Make ASCII Diagrams Beautifuller

Tides