/* * First draft of a Timer implementation to be used in any MSM * * by Albert Gil */ #include #include #include // to use the Row functor #include // for And_, Or_, Not_ operators #include namespace msm = boost::msm; namespace mpl = boost::mpl; namespace front = boost::msm::front; using namespace boost::msm::front; using namespace msm::front::euml; // for And_, Or_, Not_ operators using namespace std; /* * Helper classes just for a better debugging/log */ struct NameVisitor : public std::vector{}; struct BaseBaseState //: public boost::msm::front::state<> { // signature of the accept function typedef boost::msm::back::args accept_sig; // a reference do no work for substates // we also want polymorphic states virtual ~BaseBaseState() {} // default implementation for states who do not need to be visited //virtual std::string get_name() const { return "UndefinedStateName"; } void accept(NameVisitor* v) const { v->push_back("UndefinedStateName"); } }; struct BaseState : public boost::msm::front::state { BaseState( const std::string& name = "AState" ) : name(name) {} std::string name; template void on_entry(Event const& ,FSM& fsm) { std::cout << "--> " << name << " in state machine " << fsm.name << std::endl; } template void on_exit(Event const&,FSM& fsm) { std::cout << "<-- " << name << " in state machine " << fsm.name << std::endl; } void accept(NameVisitor* v) const { v->push_back(name); } //std::string get_name() const{ return name; } }; template struct BaseStateMachine : public boost::msm::front::state_machine_def { BaseStateMachine( const std::string& name = "AStateMachine" ) : name(name) {} std::string name; void accept(NameVisitor* v) const { v->push_back(name); } //std::string get_name() const{ return name; } /* * To activate deferred events */ typedef int activate_deferred_events; template void on_entry(Event const& ,FSM& fsm) { std::cout << "--> " << name << " in state machine " << fsm.name << std::endl; } template void on_exit(Event const&,FSM& fsm ) { std::cout << "<-- " << name << " in state machine " << fsm.name << std::endl; } template void no_transition(Event const& e, FSM& fsm, int state) { NameVisitor names; fsm.visit_current_states( &names ); std::cout << "Ignoring event " << e.name(); std::cout << " in state(s)"; for(std::size_t ii=0; ii struct Reset { static std::string name() { return "Reset"; } template void operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt) { std::cout << "Action Timer::Reset in state " << src.name << " in state machine " << fsm.name << std::endl; if( using_ugly_ptr ) global_timer_start( Seconds ); // it works!! else fsm.process_event(Timer::Start(Seconds)); // it is not upper-forwarded... } }; struct Start { Start( int time = 5 ) : time(time) {} int time; static std::string name() { return "Start"; } template void operator()(EVT const& evt,FSM& fsm,/*SourceState&*/ Timer& src,TargetState& tgt) { src.timer = evt.time; src.paused = false; std::cout << "Action Timer::Start: " << src.timer << " in state machine " << fsm.name << std::endl; } }; struct Clock { static std::string name() { return "Clock"; } template void operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt) { if(!src.paused) { --src.timer; std::cout << "Action Timer::Clock: " << src.timer << " in state machine " << fsm.name << std::endl; if( src.timer == 0) { src.paused = true; fsm.process_event(TimeOut()); } } else { std::cout << "Action Timer::Clock is paused" << std::endl; } } }; struct TimeOut { static std::string name() { return "TimeOut"; } }; }; /* * Events */ struct Event { static std::string name() { return "Event"; } }; struct SubEvent { static std::string name() { return "SubEvent"; } }; /* * Class to implement the front-end of the state machine */ struct MyStateMachine_ : public BaseStateMachine { MyStateMachine_() : BaseStateMachine( "MyStateMachine" ) {} /* * States */ struct State1 : public BaseState{ State1 () : BaseState("State1") {} }; struct State2 : public BaseState{ State2 () : BaseState("State2") {} }; /* * SubMachineSatates */ struct State3_ : public BaseStateMachine { State3_() : BaseStateMachine( "State3" ) {} /* * States */ struct SubState1 : public BaseState{ SubState1 () : BaseState("SubState1") {} }; struct SubState2 : public BaseState{ SubState2 () : BaseState("SubState2") {} }; /* * The initial state (must be defined) */ typedef mpl::vector initial_state; struct transition_table : mpl::vector< // SourceState Event TargetSate Action Guard // +-----------+-------------+------------+---------------------+----------------------+ Row < SubState1 , SubEvent , SubState2 , Timer::Reset<> >, Row < SubState2 , SubEvent , SubState1 , Timer::Reset<> > // +-----------+-------------+------------+---------------------+----------------------+ > {}; }; /* * Defining the back-end (the real) of the MenuMode state machine */ typedef msm::back::state_machine State3; /* * The initial state (must be defined) */ typedef boost::mpl::vector initial_state; struct transition_table : mpl::vector< // SourceState Event TargetSate Action Guard // +--------------+----------------+--------------+---------------------+----------------------+ Row < State1 , Event , State2 , Timer::Reset<> >, Row < State2 , Event , State3 , Timer::Reset<> >, Row < State2 , Timer::TimeOut , State1 >, Row < State3 , Timer::TimeOut , State1 >, // +--------------+----------------+------------------------------------+----------------------+ Row < Timer , Timer::Start , none , Timer::Start >, Row < Timer , Timer::Clock , none , Timer::Clock > > {}; }; /* * Defining the back-end (the real) of the MenuMode state machine */ typedef msm::back::state_machine MyStateMachine; MyStateMachine* gfsm; void Timer::global_timer_start( int time ) { gfsm->process_event(Timer::Start(time)); } void test() { MyStateMachine sm; //using_ugly_ptr = true; // uncommenting this line makes the Timer work gfsm = &sm; // initializing the "ugly" pointer sm.start(); sm.process_event(Event()); // tr. to State2 (Timer 5) // lets imagine there's no event for a while... sm.process_event(Timer::Clock()); // tr. to State2 (Timer 4) sm.process_event(Timer::Clock()); // tr. to State2 (Timer 3) sm.process_event(Timer::Clock()); // tr. to State2 (Timer 2) sm.process_event(Timer::Clock()); // tr. to State2 (Timer 1) sm.process_event(Timer::Clock()); // tr. to State1 (Timer Paused) sm.process_event(Timer::Clock()); // (Timer Paused) // and now events normally... sm.process_event(Event()); // tr. to State2 (Timer 5) sm.process_event(Timer::Clock()); // tr. to State2 (Timer 4) sm.process_event(Event()); // to State3 / SubState1 (Timer 5) sm.process_event(Timer::Clock()); // to State3 / SubState1 (Timer 4) sm.process_event(SubEvent()); // to State3 / SubState2 (Timer is not reset!!) sm.process_event(Timer::Clock()); // to State3 / SubState2 (Timer 3!!) sm.process_event(SubEvent()); // to State3 / SubState1 (Timer is not reset!!) sm.process_event(Timer::Clock()); // to State3 / SubState2 (Timer 2!!) sm.process_event(Timer::Clock()); // to State3 / SubState2 (Timer 1!!) sm.process_event(Timer::Clock()); // to State1 (Timer Paused!!) sm.process_event(Timer::Clock()); // (Timer Paused!!) } int main() { test(); return 0; }