Boost MSM: No transition from submachine to external state

Using the following example as a template: http://svn.boost.org/svn/boost/trunk/libs/msm/doc/HTML/examples/CompositeTut... http://svn.boost.org/svn/boost/trunk/libs/msm/doc/HTML/examples/CompositeTut... I am trying to create a state machine that consists of an alarm state and a composite state (submachine). When an alarm event is posted while in the composite state, the state machine is supposed to transition to the Alarm state; however, the machine complains that no transition from the composite state on the alarm event exists. This is similar to the example where the player is in playing and a stop event is received. Below is a dumbed-down version of my state machine: http://boost.2283326.n4.nabble.com/file/n4300991/StateMachine.gif Here is the implementation: Here is the output: See anything that could be causing my problem? -- View this message in context: http://boost.2283326.n4.nabble.com/Boost-MSM-No-transition-from-submachine-t... Sent from the Boost - Users mailing list archive at Nabble.com.

----- Original Message ----- From: stetkas Newsgroups: gmane.comp.lib.boost.user To: boost-users@lists.boost.org Sent: Monday, January 16, 2012 7:37 PM Subject: Boost MSM: No transition from submachine to externalstate Using the following example as a template: http://svn.boost.org/svn/boost/trunk/libs/msm/doc/HTML/examples/CompositeTut... I am trying to create a state machine that consists of an alarm state and a composite state (submachine). When an alarm event is posted while in the composite state, the state machine is supposed to transition to the Alarm state; however, the machine complains that no transition from the composite state on the alarm event exists. This is similar to the example where the player is in playing and a stop event is received. Below is a dumbed-down version of my state machine: Here is the implementation: // File: StateMachine.cpp #include <iostream> // back-end #include <boost/msm/back/state_machine.hpp> //front-end #include <boost/msm/front/state_machine_def.hpp> #include <boost/msm/front/euml/euml.hpp> namespace msm = boost::msm; namespace mpl = boost::mpl; using namespace std; namespace { static bool s_deviceInited = false; struct setDeviceInited { template<class Fsm, class Evt, class SourceState, class TargetState> void operator()(Evt const& evt, Fsm& fsm, SourceState& ss, TargetState& ts) { s_deviceInited = true; std::cout << "s_deviceInited=" << s_deviceInited << std::endl; } }; struct resetDeviceInited { template<class Fsm, class Evt, class SourceState, class TargetState> void operator()(Evt const& evt, Fsm& fsm, SourceState& ss, TargetState& ts) { s_deviceInited = true; std::cout << "s_deviceInited=" << s_deviceInited << std::endl; } }; struct deviceInited { template<class Fsm, class Evt, class SourceState, class TargetState> bool operator()(Evt const& evt, Fsm& fsm, SourceState& ss, TargetState& ts) { std::cout << "s_deviceInited=" << s_deviceInited << std::endl; return s_deviceInited; } }; // events struct EvDeviceInited : msm::front::euml::euml_event<EvDeviceInited>{}; struct EvAlarm : msm::front::euml::euml_event<EvAlarm>{}; struct EvAlarmCleared : msm::front::euml::euml_event<EvAlarmCleared>{}; // define some dummy instances for use in the transition table EvDeviceInited evDeviceInited; EvAlarm evAlarm; EvAlarmCleared evAlarmCleared; // The list of FSM states struct Alarm_TImpl : public msm::front::state<> , public msm::front::euml::euml_state<Alarm_TImpl> { // every (optional) entry/exit methods get the event passed. template <class Event,class FSM> void on_entry(Event const&,FSM& ) {std::cout << "entering: Alarm" << std::endl;} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {std::cout << "leaving: Alarm" << std::endl;} }; struct Operate_TImpl : public msm::front::state<> , public msm::front::euml::euml_state<Operate_TImpl> { template <class Event,class FSM> void on_entry(Event const& ,FSM&) {std::cout << "entering: Operate" << std::endl;} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {std::cout << "leaving: Operate" << std::endl;} }; struct Initialize_TImpl : public msm::front::state<> , public msm::front::euml::euml_state<Initialize_TImpl> { template <class Event,class FSM> void on_entry(Event const& ,FSM&) {std::cout << "entering: Initialize" << std::endl;} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {std::cout << "leaving: Initialize" << std::endl;} }; Initialize_TImpl initialize; Operate_TImpl operate; // Normal Submachine front-end struct Normal_T : public msm::front::state_machine_def<Normal_T> { template <class Event,class FSM> void on_entry(Event const& ,FSM&) {std::cout << "entering: Normal" << std::endl;} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {std::cout << "leaving: Normal" << std::endl;} typedef Initialize_TImpl initial_state; // Playing has a transition table BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE(( // +------------------------------------------------------------------------------+ operate == initialize [deviceInited()], initialize == initialize + evDeviceInited / setDeviceInited() // +------------------------------------------------------------------------------+ ),transition_table ) }; // Normal Submachine back-end typedef boost::msm::back::state_machine<Normal_T> Normal_THelper; struct Normal_TImpl : public Normal_THelper, public msm::front::euml::euml_state<Normal_THelper> { }; //to make the transition table more readable Alarm_TImpl alarm; Normal_TImpl normal; // front-end: define the FSM structure struct StateMachine_T : public msm::front::state_machine_def<StateMachine_T> { template <class Event,class FSM> void on_entry(Event const& ,FSM&) {std::cout << "entering: StateMachine" << std::endl;} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {std::cout << "leaving: StateMachine" << std::endl;} // the initial state of the player SM. Must be defined typedef Normal_TImpl initial_state; BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE(( normal + evAlarm / resetDeviceInited() == alarm, alarm + evAlarmCleared == normal ),transition_table) // Replaces the default no-transition response. template <class FSM,class Event> void no_transition(Event const& e, FSM&,int state) { std::cout << "no transition from state " << state << " on event " << typeid(e).name() << std::endl; } }; // Link the back-end typedef msm::back::state_machine<StateMachine_T> StateMachine; void test() { StateMachine p; p.start(); p.process_event(evAlarm); p.process_event(evAlarmCleared); p.process_event(evDeviceInited); p.process_event(evAlarm); p.process_event(evAlarmCleared); p.process_event(evDeviceInited); p.process_event(evAlarm); p.process_event(evAlarmCleared); p.process_event(evDeviceInited); p.process_event(evAlarm); p.process_event(evAlarmCleared); p.stop(); } } int gpp_main() { test(); return 0; } Here is the output: StateMachine entering: Normal entering: Initialize s_deviceInited=0 no transition from state 2 on event N12_GLOBAL__N_17EvAlarmE no transition from state 2 on event N12_GLOBAL__N_114EvAlarmClearedE leaving: Initialize s_deviceInited=1 entering: Initialize s_deviceInited=1 leaving: Initialize entering: Operate no transition from state 2 on event N12_GLOBAL__N_17EvAlarmE no transition from state 2 on event N12_GLOBAL__N_114EvAlarmClearedE no transition from state 2 on event N12_GLOBAL__N_114EvDeviceInitedE no transition from state 2 on event N12_GLOBAL__N_17EvAlarmE no transition from state 2 on event N12_GLOBAL__N_114EvAlarmClearedE no transition from state 2 on event N12_GLOBAL__N_114EvDeviceInitedE no transition from state 2 on event N12_GLOBAL__N_17EvAlarmE no transition from state 2 on event N12_GLOBAL__N_114EvAlarmClearedE leaving: Operate leaving: Normal leaving: StateMachine See anything that could be causing my problem? Hi, this looks like an old problem (definition of composites in eUML) which I thought was long solved, but well, seems like no :( I'll need to have a look at it. In the meantime, please use the functor front-end, which is safer. I attach a working version with this front-end to get you going until I solve this. Cheers, Christophe

----- Original Message ----- From: stetkas Newsgroups: gmane.comp.lib.boost.user To: boost-users@lists.boost.org Sent: Monday, January 16, 2012 7:37 PM Subject: Boost MSM: No transition from submachine to externalstate Using the following example as a template: http://svn.boost.org/svn/boost/trunk/libs/msm/doc/HTML/examples/CompositeTut... I am trying to create a state machine that consists of an alarm state and a composite state (submachine). When an alarm event is posted while in the composite state, the state machine is supposed to transition to the Alarm state; however, the machine complains that no transition from the composite state on the alarm event exists. This is similar to the example where the player is in playing and a stop event is received. Below is a dumbed-down version of my state machine: Hi again, ah I remember now. I changed the example last june because of a problem with exit points. If you write: typedef boost::msm::back::state_machine<Normal_T> Normal_THelper; struct Normal_TImpl : public Normal_THelper, public msm::front::euml::euml_state<Normal_TImpl > { }; Then it will work in your case but likely fail if faced with exit points. If you have none, you can use this trick temporarily while I have a look at this. Otherwise you'll need to use the example I just posted, eUML is still in development and an experimental front-end. Christophe

Thanks Christophe. I will make the change to see it work; but based on your comments, I'll probably switch to one of the other front-ends. Thanks, Steve -- View this message in context: http://boost.2283326.n4.nabble.com/Boost-MSM-No-transition-from-submachine-t... Sent from the Boost - Users mailing list archive at Nabble.com.

Thanks Christophe. I will make the change to see it work; but based on your comments, I'll probably switch to one of the other front-ends.
Thanks,
Steve
What I mean is that eUML is not used as long as other front-ends and therefore less tested. But there has been so far no bug I haven't been able to fix within a few days. In the case you reported, I have a fix which seems to be working (and reduces the syntax needed), I just need to play with it a bit more before committing it. Christophe

Oh I know; but I just cannot put something listed as experimental in production code that's all. Thanks for your help! Steve -- View this message in context: http://boost.2283326.n4.nabble.com/Boost-MSM-No-transition-from-submachine-t... Sent from the Boost - Users mailing list archive at Nabble.com.

Thanks Christophe. I will make the change to see it work; but based on your comments, I'll probably switch to one of the other front-ends.
Thanks,
Steve
What I mean is that eUML is not used as long as other front-ends and therefore less tested. But there has been so far no bug I haven't been able to fix within a few days. In the case you reported, I have a fix which seems to be working (and reduces the syntax needed), I just need to play with it a bit more before committing it.
Hi, as promised, I fixed this problem (trunk rev. 76655). It even requires less typing. You define a submachine with front-end like always and use it in another state machine. In your case, you'd have: typedef boost::msm::back::state_machine<Normal_T> Normal_TImpl; The remaining code is unchanged: Alarm_TImpl alarm; BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE(( normal + evAlarm / resetDeviceInited() == alarm, alarm + evAlarmCleared == normal ),transition_table) You probably moved to another front-end, but in case you want to try eUML, this problem is fixed. Cheers, Christophe
participants (2)
-
Christophe Henry
-
stetkas