TinyFSM – Finite State Machine Library

TinyFSM is a simple finite state machine library for C++, designed for optimal performance and low memory footprints.

This is a simple header including library allowing developers to easily understand what is actually happening behind the curtains. TinyFSM basically wraps event dispatching into function calls, making event dispatching equally fast to calling (or even inlining) a function. Even in the worst case, dispatching leads to nothing more than a single vtable lookup and function call!

Pre-requite: Requires C++11 language standard

Key Features:

  • Entry/exit actions
  • Event actions
  • Transition functions
  • Transition conditions
  • Event payload (classes)
  • Inheritance of states and action functions

It is as easy as adding the source code in your project and just point your compiler to:

#include <tinyfsm.hpp>

Example:

We’ll be taking an elevator example, where the elevator has call button to every floor, it has sensors reporting the current position and an alarm button for emergency. 

Key Terminologies/Steps:

  1. State definition: States are derived classes from a base FSM state, providing react() functions for every event, as well as entry() and exit() functions
  2. Event Dispatching: TinyFSM does not hold state/event function tables like most other state machine processors do. Instead, it keeps a pointer to the current state (having the type of the state machine base class). Dispatching an event simply calls the react() function of the current state, with the event class as argument. This results in a single vtable lookup and a function call, which is very efficient!

Usage:

  • Declare Events: The very first step is to declare the events that our state machine will listen to. These events are nothing but the classes that derived from tinyfsm::Event class. Here we’ll declare 3 events, “Call“, “Floor” and “Alarm“. Member variable “floor” will be used to indicate the floor number on “Call” and “Floor Sensor” events
struct FloorEvent : tinyfsm::Event
{
 int floor;
};

struct Call        : FloorEvent { };
struct FloorSensor : FloorEvent { };
struct Alarm       : tinyfsm::Event { };
  • Declare your state machine class: State machines are classes derived from tiny::fsm<> template class. We also need to declare some public members like react() : for each event, entry() and exit()
class Elevator : public tinyfsm::Fsm<Elevator>
{
public:
 /* default reaction for unhandled events */
 void react(tinyfsm::Event const &) { };

 virtual void react(Call        const &);
 virtual void react(FloorSensor const &);
 void         react(Alarm       const &);

 virtual void entry(void) { };  /* entry actions in some states */
 void         exit(void)  { };  /* no exit actions */
};

NOTE:Below you can see a react() has been defined for all the events that we declared above.

  • Declaring states of your state machine: States are classes that derived from the state machine class that we just introduced above. State classes are implicitly instantiated
class Panic : public Elevator
{
 void entry() override;
};

class Moving : public Elevator
{
 void react(FloorSensor const&) override;
};

class Idle : public Elevator
{
 void entry() override;
 void react(Call const& e) override;
};
  • Implementing Action and Event reactions: Generally, the event reaction includes:
    • Processing of data
    • send events to other state machines
    • Transition to other states (It should be the last call, and shall not be used in entry() or exit() functions)
void Idle::entry() {
 send_event(MotorStop());
}

void Idle::react(Call const & e) {
 dest_floor = e.floor;

 if(dest_floor == current_floor)
   return;

 /* lambda function used for transition action */
 auto action = [] {  
   if(dest_floor > current_floor)
     send_event(MotorUp());
   else if(dest_floor < current_floor)
     send_event(MotorDown());
 };

 transit<Moving>(action);
};

transit<> will do the following:

  1. call exit() of the current state
  2. call transition action if provided
  3. change the current state to new state
  4. call entry of the new state
  • Defining the initial state of the state machine: Initial state can be defined as  FSM_INITIAL_STATE(fsm, state). For Example:
FSM_INITIAL_STATE(Elevator, Idle)
  • Event Dispatching: As shown in the example above (the one where implementation of actions and reaction is given), we can see we have used send_event()  function for event dispatching. This is not a function which is provided by tinyfsm. Such a function can be defined as:
typedef tinyfsm::FsmList<Motor, Elevator> fsm_list;

template<typename E>
void send_event(E const & event)
{
 fsm_list::template dispatch<E>(event);
}

Here, send_event() dispatches events to all state machines in the list.

Source: https://digint.ch/tinyfsm/index.html

Leave a comment

Create a free website or blog at WordPress.com.

Up ↑