Skip to content

Tutorial

Andrew Gresyk edited this page May 12, 2019 · 2 revisions
  1. Include HFSM2 header:
#include <hfsm2/machine.hpp>
  1. Define interface class between the state machine and its host (also ok to use the host object itself):
struct Context {
    bool powerOn;
};
  1. (Optional, recommended) Typedef hfsm2::Machine for convenience:
using M = hfsm2::MachineT<Context>;
  1. Declare state machine structure:

States need to be forward declared, e.g. with a magic macro:

#define S(s) struct s

using FSM = M::PeerRoot<
                S(Off),                                // initial top-level state
                M::Composite<S(On),                    // sub-machine region with a head state (On) and and 3 sub-states
                    S(Red),                            // initial sub-state of the region
                    S(Yellow),
                    S(Green)
                >,
                S(Done)
            >;

#undef S
  1. (Optional) Define events:
struct Event {};
  1. Define states and override any state methods:
struct Off
    : FSM::State
{
    void entryGuard(FullControl& control) {            // called before state activation, use to re-route transitions
        if (control.context().powerOn)                 // access shared data
            control.changeTo<On>();                    // initiate a transition into 'On' region
    }
};

struct On
    : FSM::State
{
    void enter(PlanControl& control) {                 // called on state activation
        auto plan = control.plan();                    // access the plan for the region

        plan.append<Red, Yellow>();                    // sequence plan steps, executed when the previous state succeeds
        plan.append<Yellow, Green>();
        plan.append<Green, Yellow>();
        plan.append<Yellow, Red>();
    }

    void exit(PlanControl& /*control*/) {}             // called on state deactivation

    void planSucceeded(FullControl& control) {         // called on the successful completion of all plan steps
        control.changeTo<Done>();
    }

    void planFailed(FullControl& /*control*/) {}       // called if any of the plan steps fails
};

struct Red
    : FSM::State
{
    void update(FullControl& control) {                // called on periodic state machine updates
        control.succeed();                             // notify successful completion of the plan step
    }                                                  // plan will advance to the 'Yellow' state
};

struct Yellow
    : FSM::State
{
    void update(FullControl& control) {
        control.succeed();                             // plan will advance to the 'Green' state on the first entry
                                                       // and 'Red' state on the second one
    }
};

struct Green
    : FSM::State
{
    void react(const Event&, FullControl& control) {   // called on external events
        control.succeed();                             // advance to the next plan step
    }
};

struct Done
    : FSM::State
{};
  1. Write the client code to use your new state machine:
int main() {
  1. Create context and state machine instances:
    Context context;
    context.powerOn = true;

    FSM fsm{context};
    assert(fsm.isActive<On>());                        // activated by Off::entryGuard()
    assert(fsm.isActive<Red>());                       // On's initial sub-state
  1. Call FSM::update() for fsm to process transitions:
    fsm.update();
    assert(fsm.isActive<Yellow>());                    // 1st setp of On's plan

    fsm.update();
    assert(fsm.isActive<Green>());                     // 2nd setp of On's plan
  1. (Optional) Event reactions also causes transitions getting processed:
    fsm.react(Event{});
    assert(fsm.isActive<Yellow>());                    // 3rd setp of On's plan
  1. Keep updating the FSM until it's done:
    fsm.update();
    assert(fsm.isActive<Red>());                       // 4th setp of On's plan

    fsm.update();
    assert(fsm.isActive<Done>());                      // activated by On::planSucceeded()

    return 0;
}

Documentation

Basic features

Clone this wiki locally
You can’t perform that action at this time.