Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork6
Overview Extended Tutorial
Andrew Gresyk edited this pageApr 1, 2022 ·2 revisions
Configure optional FFSM2 functionality using #defines(in this case we're usingplans to maketransition cycle more straightforward):
#defineFFSM2_ENABLE_PLANS
Include FFSM2 header:
#include<ffsm2/machine_dev.hpp>
Defineinterface class between the state machine and its host(also ok to use the host object itself):
structContext {bool powerOn;};
Definetype configuration:
using Config = ffsm2::Config::ContextT<Context>;Define
ffsm2::MachineT<>alias for convenience:using M = ffsm2::MachineT<Config>;Declare state machine structure. States need to be forward declared, e.g. with a magic macro:
#defineS(s)structsusing FSM = M::Root<S(On),S(Off),// initial state S(Red), S(Yellow), S(Green), S(Done) >;#undef S
While FFSM2transitions aren't event-based, events can be used to have FSM react to external stimuli:
structEvent {};
Define states and override requiredstate methods:
structOff : FSM::State{// called before state activation, use to re-route transitionsvoidentryGuard(FullControl& control) {// access shared dataif (control.context().powerOn)// initiate a transition into 'On' region control.changeTo<Red>(); }// called on state deactivationvoidexit(PlanControl&/*control*/) {}};structOn : FSM::State{// called on state activationvoidenter(PlanControl& control) {// access the plan for the regionauto plan = control.plan();// sequence plan steps, executed when the previous state succeeds plan.change<Red, Yellow>(); plan.change<Yellow, Green>(); plan.change<Green, Yellow>(); plan.change<Yellow, Red>(); }// called on state deactivationvoidexit(PlanControl&/*control*/) {}// called on the successful completion of all plan stepsvoidplanSucceeded(FullControl& control) { control.changeTo<Done>(); }// called if any of the plan steps failsvoidplanFailed(FullControl&/*control*/) {}};structRed : FSM::State{// called on periodic state machine updatesvoidupdate(FullControl& control) {// notify successful completion of the plan step control.succeed();// plan will advance to the 'Yellow' state }};structYellow : FSM::State{voidupdate(FullControl& control) {// plan will advance to the 'Green' state on the first entry// and 'Red' state on the second one control.succeed(); }};structGreen : FSM::State{// called on external eventsvoidreact(const Event&, FullControl& control) {// advance to the next plan step control.succeed(); }};structDone : FSM::State{};
Write the client code to use your new state machine:
TEST_CASE("Wiki.Tutorial") {// Create context and state machine instances: Context context; context.powerOn =true; FSM::Instance fsm{context};REQUIRE(fsm.isActive<Red>());// On's initial sub-state fsm.update();REQUIRE(fsm.isActive<Yellow>());// 1st setp of On's plan fsm.update();REQUIRE(fsm.isActive<Green>());// 2nd setp of On's plan fsm.react(Event{});REQUIRE(fsm.isActive<Yellow>());// 3rd setp of On's plan fsm.update();REQUIRE(fsm.isActive<Red>());// 4th setp of On's plan fsm.update();REQUIRE(fsm.isActive<Done>());// activated by On::planSucceeded()}