CompositeTutorialWithEumlTable.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #include <iostream>
  2. // back-end
  3. #include <boost/msm/back/state_machine.hpp>
  4. //front-end
  5. #include <boost/msm/front/state_machine_def.hpp>
  6. #include <boost/msm/front/euml/euml.hpp>
  7. namespace msm = boost::msm;
  8. namespace mpl = boost::mpl;
  9. using namespace std;
  10. // entry/exit/action/guard logging functors
  11. #include "logging_functors.h"
  12. namespace
  13. {
  14. // events
  15. struct play_impl : msm::front::euml::euml_event<play_impl> {};
  16. struct end_pause_impl : msm::front::euml::euml_event<end_pause_impl>{};
  17. struct stop_impl : msm::front::euml::euml_event<stop_impl>{};
  18. struct pause_impl : msm::front::euml::euml_event<pause_impl>{};
  19. struct open_close_impl : msm::front::euml::euml_event<open_close_impl>{};
  20. struct cd_detected_impl : msm::front::euml::euml_event<cd_detected_impl>{};
  21. struct next_song_impl : msm::front::euml::euml_event<next_song_impl>{};
  22. struct previous_song_impl : msm::front::euml::euml_event<previous_song_impl>{};
  23. // define some dummy instances for use in the transition table
  24. // it is also possible to default-construct them instead:
  25. // struct play {};
  26. // inside the table: play()
  27. play_impl play;
  28. end_pause_impl end_pause;
  29. stop_impl stop;
  30. pause_impl pause;
  31. open_close_impl open_close;
  32. cd_detected_impl cd_detected;
  33. next_song_impl next_song;
  34. previous_song_impl previous_song;
  35. // The list of FSM states
  36. // they have to be declared outside of the front-end only to make VC happy :(
  37. // note: gcc would have no problem
  38. struct Empty_impl : public msm::front::state<> , public msm::front::euml::euml_state<Empty_impl>
  39. {
  40. // every (optional) entry/exit methods get the event passed.
  41. template <class Event,class FSM>
  42. void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
  43. template <class Event,class FSM>
  44. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
  45. };
  46. struct Open_impl : public msm::front::state<> , public msm::front::euml::euml_state<Open_impl>
  47. {
  48. template <class Event,class FSM>
  49. void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
  50. template <class Event,class FSM>
  51. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
  52. };
  53. struct Stopped_impl : public msm::front::state<> , public msm::front::euml::euml_state<Stopped_impl>
  54. {
  55. template <class Event,class FSM>
  56. void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
  57. template <class Event,class FSM>
  58. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
  59. };
  60. // Playing Submachine front-end
  61. struct Playing_ : public msm::front::state_machine_def<Playing_>
  62. {
  63. template <class Event,class FSM>
  64. void on_entry(Event const& ,FSM&) {std::cout << "entering: Playing" << std::endl;}
  65. template <class Event,class FSM>
  66. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
  67. struct Song1_ : public msm::front::state<> , public msm::front::euml::euml_state<Song1_>
  68. {
  69. template <class Event,class FSM>
  70. void on_entry(Event const& ,FSM&) {std::cout << "entering: Song1" << std::endl;}
  71. template <class Event,class FSM>
  72. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Song1" << std::endl;}
  73. };
  74. struct Song2_ : public msm::front::state<> , public msm::front::euml::euml_state<Song2_>
  75. {
  76. template <class Event,class FSM>
  77. void on_entry(Event const& ,FSM&) {std::cout << "entering: Song2" << std::endl;}
  78. template <class Event,class FSM>
  79. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Song2" << std::endl;}
  80. };
  81. struct Song3_ : public msm::front::state<> , public msm::front::euml::euml_state<Song3_>
  82. {
  83. template <class Event,class FSM>
  84. void on_entry(Event const& ,FSM&) {std::cout << "entering: Song3" << std::endl;}
  85. template <class Event,class FSM>
  86. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Song3" << std::endl;}
  87. };
  88. // to make the transition table more readable
  89. // VC seems to need them static
  90. static Song1_ Song1;
  91. static Song2_ Song2;
  92. static Song3_ Song3;
  93. typedef Song1_ initial_state;
  94. // Playing has a transition table
  95. BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
  96. // +------------------------------------------------------------------------------+
  97. Song2 == Song1 + next_song / start_next_song,
  98. Song1 == Song2 + previous_song / start_prev_song,
  99. Song3 == Song2 + next_song / start_next_song,
  100. Song2 == Song3 + previous_song / start_prev_song
  101. // +------------------------------------------------------------------------------+
  102. ),transition_table )
  103. };
  104. // Playing Submachine back-end
  105. typedef boost::msm::back::state_machine<Playing_> Playing_impl;
  106. // state not defining any entry or exit
  107. struct Paused_impl : public msm::front::state<> , public msm::front::euml::euml_state<Paused_impl>
  108. {
  109. };
  110. //to make the transition table more readable
  111. Empty_impl const Empty;
  112. Open_impl const Open;
  113. Stopped_impl const Stopped;
  114. Playing_impl const Playing;
  115. Paused_impl const Paused;
  116. // front-end: define the FSM structure
  117. struct player_ : public msm::front::state_machine_def<player_>
  118. {
  119. // the initial state of the player SM. Must be defined
  120. typedef Empty_impl initial_state;
  121. // Transition table for player
  122. // replaces the old transition table
  123. BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
  124. Stopped + play / start_playback == Playing ,
  125. Stopped + open_close / open_drawer == Open ,
  126. Stopped + stop == Stopped ,
  127. // +------------------------------------------------------------------------------+
  128. Open + open_close / close_drawer == Empty ,
  129. // +------------------------------------------------------------------------------+
  130. Empty + open_close / open_drawer == Open ,
  131. Empty + cd_detected /(store_cd_info,
  132. msm::front::euml::process_(play)) == Stopped ,
  133. // +------------------------------------------------------------------------------+
  134. Playing + stop / stop_playback == Stopped ,
  135. Playing + pause / pause_playback == Paused ,
  136. Playing + open_close / stop_and_open == Open ,
  137. // +------------------------------------------------------------------------------+
  138. Paused + end_pause / resume_playback == Playing ,
  139. Paused + stop / stop_playback == Stopped ,
  140. Paused + open_close / stop_and_open == Open
  141. // +------------------------------------------------------------------------------+
  142. ),transition_table)
  143. // Replaces the default no-transition response.
  144. template <class FSM,class Event>
  145. void no_transition(Event const& e, FSM&,int state)
  146. {
  147. std::cout << "no transition from state " << state
  148. << " on event " << typeid(e).name() << std::endl;
  149. }
  150. };
  151. // Pick a back-end
  152. typedef msm::back::state_machine<player_> player;
  153. //
  154. // Testing utilities.
  155. //
  156. static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
  157. void pstate(player const& p)
  158. {
  159. std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
  160. }
  161. void test()
  162. {
  163. player p;
  164. // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
  165. p.start();
  166. // go to Open, call on_exit on Empty, then action, then on_entry on Open
  167. p.process_event(open_close); pstate(p);
  168. p.process_event(open_close); pstate(p);
  169. p.process_event(cd_detected); pstate(p);
  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. p.process_event(pause); pstate(p);
  176. // go back to Playing
  177. p.process_event(end_pause); pstate(p);
  178. p.process_event(pause); pstate(p);
  179. p.process_event(stop); pstate(p);
  180. // event leading to the same state
  181. // no action method called as it is not present in the transition table
  182. p.process_event(stop); pstate(p);
  183. }
  184. }
  185. int main()
  186. {
  187. test();
  188. return 0;
  189. }