EumlInternalDistributed.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Copyright 2010 Christophe Henry
  2. // henry UNDERSCORE christophe AT hotmail DOT com
  3. // This is an extended version of the state machine available in the boost::mpl library
  4. // Distributed under the same license as the original.
  5. // Copyright for the original version:
  6. // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
  7. // under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #include <vector>
  11. #include <iostream>
  12. #include <boost/msm/back/state_machine.hpp>
  13. #include <boost/msm/front/euml/euml.hpp>
  14. using namespace std;
  15. using namespace boost::msm::front::euml;
  16. using namespace boost::msm::front;
  17. namespace msm = boost::msm;
  18. // entry/exit/action/guard logging functors
  19. #include "logging_functors.h"
  20. namespace // Concrete FSM implementation
  21. {
  22. // events
  23. // note that unlike the SimpleTutorial, events must derive from euml_event.
  24. BOOST_MSM_EUML_EVENT(play)
  25. BOOST_MSM_EUML_EVENT(end_pause)
  26. BOOST_MSM_EUML_EVENT(stop)
  27. BOOST_MSM_EUML_EVENT(pause)
  28. BOOST_MSM_EUML_EVENT(open_close)
  29. BOOST_MSM_EUML_EVENT(internal_event)
  30. BOOST_MSM_EUML_EVENT(next_song)
  31. BOOST_MSM_EUML_EVENT(previous_song)
  32. // A "complicated" event type that carries some data.
  33. BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
  34. BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
  35. BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
  36. BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
  37. // Concrete FSM implementation
  38. // The list of FSM states
  39. BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
  40. // we just declare a state type but do not create any instance as we want to inherit from this type
  41. BOOST_MSM_EUML_DECLARE_STATE((Open_Entry,Open_Exit),Open_def)
  42. // derive to be able to add an internal transition table
  43. struct Open_impl : public Open_def
  44. {
  45. BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
  46. open_close [internal_guard1] / internal_action1 ,
  47. open_close [internal_guard2] / internal_action2 ,
  48. internal_event / internal_action
  49. ))
  50. };
  51. // declare an instance for the stt as we are manually declaring a state
  52. Open_impl const Open;
  53. BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
  54. // Playing is a state machine itself.
  55. // It has 3 substates
  56. BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
  57. BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
  58. BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
  59. // Playing has a transition table
  60. BOOST_MSM_EUML_TRANSITION_TABLE((
  61. // +------------------------------------------------------------------------------+
  62. Song2 == Song1 + next_song / start_next_song,
  63. Song1 == Song2 + previous_song / start_prev_song,
  64. Song3 == Song2 + next_song / start_next_song,
  65. Song2 == Song3 + previous_song / start_prev_song
  66. // +------------------------------------------------------------------------------+
  67. ),playing_transition_table )
  68. BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
  69. init_ << Song1 // Init State
  70. ),Playing_def)
  71. // some action for the internal transition
  72. BOOST_MSM_EUML_ACTION(playing_internal_action)
  73. {
  74. template <class FSM,class EVT,class SourceState,class TargetState>
  75. void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
  76. {
  77. cout << "Playing::internal action" << endl;
  78. }
  79. };
  80. // derive to be able to add an internal transition table
  81. struct Playing_ : public Playing_def
  82. {
  83. BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
  84. internal_event / playing_internal_action
  85. ))
  86. };
  87. // choice of back-end
  88. typedef msm::back::state_machine<Playing_> Playing_type;
  89. Playing_type const Playing;
  90. // state not needing any entry or exit
  91. BOOST_MSM_EUML_STATE((),Paused)
  92. // guard conditions
  93. BOOST_MSM_EUML_ACTION(good_disk_format)
  94. {
  95. template <class FSM,class EVT,class SourceState,class TargetState>
  96. bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
  97. {
  98. // to test a guard condition, let's say we understand only CDs, not DVD
  99. if (evt.get_attribute(cd_type)!=DISK_CD)
  100. {
  101. std::cout << "wrong disk, sorry" << std::endl;
  102. // just for logging, does not block any transition
  103. return true;
  104. }
  105. std::cout << "good disk" << std::endl;
  106. return true;
  107. }
  108. };
  109. // replaces the old transition table
  110. BOOST_MSM_EUML_TRANSITION_TABLE((
  111. Stopped + play / start_playback == Playing ,
  112. Stopped + open_close / open_drawer == Open ,
  113. Stopped + stop == Stopped ,
  114. // +------------------------------------------------------------------------------+
  115. Open + open_close / close_drawer == Empty ,
  116. // +------------------------------------------------------------------------------+
  117. Empty + open_close / open_drawer == Open ,
  118. Empty + cd_detected
  119. [good_disk_format&&(event_(cd_type)==Int_<DISK_CD>())]
  120. / (store_cd_info,process_(play))
  121. == Stopped ,
  122. // +------------------------------------------------------------------------------+
  123. Playing + stop / stop_playback == Stopped ,
  124. Playing + pause / pause_playback == Paused ,
  125. Playing + open_close / stop_and_open == Open ,
  126. // +------------------------------------------------------------------------------+
  127. Paused + end_pause / resume_playback == Playing ,
  128. Paused + stop / stop_playback == Stopped ,
  129. Paused + open_close / stop_and_open == Open
  130. // +------------------------------------------------------------------------------+
  131. ),transition_table)
  132. // create a state machine "on the fly"
  133. BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
  134. init_ << Empty, // Init State
  135. no_action, // Entry
  136. no_action, // Exit
  137. attributes_ << no_attributes_, // Attributes
  138. configure_ << no_configure_, // configuration
  139. Log_No_Transition // no_transition handler
  140. ),
  141. player_) //fsm name
  142. // choice of back-end
  143. typedef msm::back::state_machine<player_> player;
  144. //
  145. // Testing utilities.
  146. //
  147. static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
  148. void pstate(player const& p)
  149. {
  150. std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
  151. }
  152. void test()
  153. {
  154. player p;
  155. // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
  156. p.start();
  157. // go to Open, call on_exit on Empty, then action, then on_entry on Open
  158. p.process_event(open_close); pstate(p);
  159. std::cout << "sending internal event (not rejected)" << std::endl;
  160. p.process_event(internal_event);
  161. std::cout << "sending open_close event. Conflict with internal transitions (rejecting event)" << std::endl;
  162. p.process_event(open_close); pstate(p);
  163. // will be rejected, wrong disk type
  164. p.process_event(
  165. cd_detected("louie, louie",DISK_DVD)); pstate(p);
  166. p.process_event(
  167. cd_detected("louie, louie",DISK_CD)); pstate(p);
  168. // no need to call play as the previous event does it in its action method
  169. //p.process_event(play);
  170. // at this point, Play is active
  171. // make transition happen inside it. Player has no idea about this event but it's ok.
  172. p.process_event(next_song);pstate(p); //2nd song active
  173. p.process_event(next_song);pstate(p);//3rd song active
  174. p.process_event(previous_song);pstate(p);//2nd song active
  175. // event handled internally in Playing, without region checking
  176. std::cout << "sending internal event (not rejected)" << std::endl;
  177. p.process_event(internal_event);
  178. p.process_event(pause); pstate(p);
  179. // go back to Playing
  180. p.process_event(end_pause); pstate(p);
  181. p.process_event(pause); pstate(p);
  182. p.process_event(stop); pstate(p);
  183. // event leading to the same state
  184. // no action method called as none is defined in the transition table
  185. p.process_event(stop); pstate(p);
  186. // test call to no_transition
  187. p.process_event(pause); pstate(p);
  188. }
  189. }
  190. int main()
  191. {
  192. test();
  193. return 0;
  194. }