HFSM2
Search…
Quick Tutorial
1. Include the C/C++ headers
1
#include <assert.h>
Copied!
2. Configure optional HFSM2 functionality using #defines (in this case we're using Plans to make transition cycle more straightforward):
1
#define HFSM2_ENABLE_PLANS
Copied!
3. Include HFSM2 header:
1
#include <hfsm2/machine.hpp>
Copied!
4. Define interface class between the state machine and its host (also ok to use the host object itself):
1
struct Context {
2
bool powerOn;
3
};
Copied!
5. (Optional) Define type config:
1
using Config = hfsm2::Config::ContextT<Context>;
Copied!
6. (Optional, recommended) Definehfsm2::Machine for convenience:
1
using M = hfsm2::MachineT<Config>;
Copied!
7. Declare state machine structure. States need to be forward declared, e.g. with a magic macro:
1
#define S(s) struct s
2
3
using FSM = M::PeerRoot<
4
S(Off), // initial top-level state
5
M::Composite<S(On), // sub-machine region with a head state (On) and and 3 sub-states
6
S(Red), // initial sub-state of the region
7
S(Yellow),
8
S(Green)
9
>,
10
S(Done)
11
>;
12
13
#undef S
Copied!
8. (Optional) While HFSM2 transitions aren't event-based, events can be used to have FSM react to external stimuli:
1
struct Event {};
Copied!
9. Define states and override required state methods:
1
struct Off
2
: FSM::State
3
{
4
void entryGuard(FullControl& control) { // called before state activation, use to re-route transitions
5
if (control.context().powerOn) // access shared data
6
control.changeTo<On>(); // initiate a transition into 'On' region
7
}
8
};
Copied!
1
struct On
2
: FSM::State
3
{
4
void enter(PlanControl& control) { // called on state activation
5
auto plan = control.plan(); // access the plan for the region
6
7
plan.change<Red, Yellow>(); // sequence plan steps, executed when the previous state succeeds
8
plan.change<Yellow, Green>();
9
plan.change<Green, Yellow>();
10
plan.change<Yellow, Red>();
11
}
12
13
void exit(PlanControl& /*control*/) {} // called on state deactivation
14
15
void planSucceeded(FullControl& control) { // called on the successful completion of all plan steps
16
control.changeTo<Done>();
17
}
18
19
void planFailed(FullControl& /*control*/) {} // called if any of the plan steps fails
20
};
Copied!
1
struct Red
2
: FSM::State
3
{
4
void update(FullControl& control) { // called on periodic state machine updates
5
control.succeed(); // notify successful completion of the plan step
6
} // plan will advance to the 'Yellow' state
7
};
Copied!
1
struct Yellow
2
: FSM::State
3
{
4
void update(FullControl& control) {
5
control.succeed(); // plan will advance to the 'Green' state on the first entry
6
// and 'Red' state on the second one
7
}
8
};
Copied!
1
struct Green
2
: FSM::State
3
{
4
void react(const Event&, FullControl& control) { // called on external events
5
control.succeed(); // advance to the next plan step
6
}
7
};
Copied!
1
struct Done
2
: FSM::State
3
{};
Copied!
10. Write the client code to use your new state machine:
1
int main() {
Copied!
11. Create context and state machine instances:
1
Context context;
2
context.powerOn = true;
3
4
FSM::Instance fsm{context};
5
assert(fsm.isActive<On>()); // activated by Off::entryGuard()
6
assert(fsm.isActive<Red>()); // On's initial sub-state
Copied!
12. Call FSM::update() for the FSM to process transitions:
1
fsm.update();
2
assert(fsm.isActive<Yellow>()); // 1st setp of On's plan
3
4
fsm.update();
5
assert(fsm.isActive<Green>()); // 2nd setp of On's plan
Copied!
13. (Optional) Event reactions also cause transitions to be processed:
1
fsm.react(Event{});
2
assert(fsm.isActive<Yellow>()); // 3rd setp of On's plan
Copied!
14. Keep updating the FSM for as long as necessary:
1
fsm.update();
2
assert(fsm.isActive<Red>()); // 4th setp of On's plan
3
4
fsm.update();
5
assert(fsm.isActive<Done>()); // activated by On::planSucceeded()
6
7
return 0;
8
}
Copied!

See Also

Last modified 1yr ago
Copy link
Contents
See Also