Example implementation of a simplified elevator logic, using TinyFSM.
Imagine a elevator having:
- "Call" button on each floor,
- "Floor Sensor" on each floor, triggering an event as soon as the elevator arrives there,
- "Alarm" button.
The elevator example implements two state machines interacting with each other:
-
Elevator
- State: Idle
- State: Moving
- State: Panic
-
Motor
- State: Stopped
- State: Up
- State: Down
A good state machine design avoids circular dependencies at all cost: While the elevator sends events to the motor, the motor NEVER sends events to the elevator (top-down only).
Did you notice the motor starting twice? This is by design, let's have a look at the call stack of fsm_list::start() in main.cpp:
FsmList<Motor, Elevator>::start()
Motor::set_initial_state()
Motor::current_state = Stopped
Elevator::set_initial_state()
Elevator::current_state = Idle
Motor::enter()
Motor:Stopped->entry()
cout << "Motor: stopped" <-- HERE
Motor::direction = 0
Elevator::enter()
Elevator:Idle->entry()
send_event(MotorStop)
Motor::react(MotorStop)
Motor:Stopped->transit<Stopped>
Motor:Stopped->exit()
Motor::current_state = Stopped
Motor:Stopped->entry()
cout << "Motor: stopped" <-- HERE
Motor::direction = 0
Elevator::react(MotorStop)
If we really had to work around this, we could either:
-
Change the initialization (bad design practice!) in main.cpp:
- fsm_list::start(); + fsm_list::set_initial_state(); + Elevator::enter();
-
Modify the Motor:Stopped->entry() function in motor.cpp:
class Stopped : public Motor { void entry() override { + if(direction == 0) + return; cout << "Motor: stopped" << endl; direction = 0; };