iPod.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 <set>
  12. #include <string>
  13. #include <iostream>
  14. #define FUSION_MAX_VECTOR_SIZE 20
  15. #include "boost/mpl/vector/vector50.hpp"
  16. #include <boost/msm/back/state_machine.hpp>
  17. #include <boost/msm/front/state_machine_def.hpp>
  18. #include "Events.hpp"
  19. #include "PlayingMode.hpp"
  20. #include "MenuMode.hpp"
  21. using namespace std;
  22. namespace msm = boost::msm;
  23. namespace // Concrete FSM implementation
  24. {
  25. struct iPod_;
  26. typedef msm::back::state_machine<iPod_,
  27. ::boost::msm::back::favor_compile_time> iPod;
  28. // Concrete FSM implementation
  29. struct iPod_ : public msm::front::state_machine_def<iPod_>
  30. {
  31. // The list of FSM states
  32. struct NotHolding : public msm::front::state<>
  33. {
  34. template <class Event,class FSM>
  35. void on_entry(Event const&,FSM& ) {std::cout << "starting: NotHolding" << std::endl;}
  36. template <class Event,class FSM>
  37. void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotHolding" << std::endl;}
  38. };
  39. struct Holding : public msm::front::interrupt_state<NoHold>
  40. {
  41. template <class Event,class FSM>
  42. void on_entry(Event const&,FSM& ) {std::cout << "starting: Holding" << std::endl;}
  43. template <class Event,class FSM>
  44. void on_exit(Event const&,FSM& ) {std::cout << "finishing: Holding" << std::endl;}
  45. };
  46. struct NotPlaying : public msm::front::state<>
  47. {
  48. template <class Event,class FSM>
  49. void on_entry(Event const&,FSM& ) {std::cout << "starting: NotPlaying" << std::endl;}
  50. template <class Event,class FSM>
  51. void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotPlaying" << std::endl;}
  52. };
  53. struct NoMenuMode : public msm::front::state<>
  54. {
  55. template <class Event,class FSM>
  56. void on_entry(Event const&,FSM& ) {std::cout << "starting: NoMenuMode" << std::endl;}
  57. template <class Event,class FSM>
  58. void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoMenuMode" << std::endl;}
  59. };
  60. struct NoOnOffButton : public msm::front::state<>
  61. {
  62. template <class Event,class FSM>
  63. void on_entry(Event const&,FSM& ) {std::cout << "starting: NoOnOffButton" << std::endl;}
  64. template <class Event,class FSM>
  65. void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoOnOffButton" << std::endl;}
  66. };
  67. struct OffDown : public msm::front::state<>
  68. {
  69. template <class Event,class FSM>
  70. void on_entry(Event const&,FSM& ) {std::cout << "starting: OffDown, start timer" << std::endl;}
  71. template <class Event,class FSM>
  72. void on_exit(Event const&,FSM& ) {std::cout << "finishing: OffDown, end timer" << std::endl;}
  73. };
  74. struct PlayerOff : public msm::front::state<>
  75. {
  76. template <class Event,class FSM>
  77. void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayerOff" << std::endl;}
  78. template <class Event,class FSM>
  79. void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayerOff" << std::endl;}
  80. };
  81. struct CheckMiddleButton : public msm::front::state<>
  82. {
  83. template <class Event,class FSM>
  84. void on_entry(Event const&,FSM& ) {std::cout << "starting: CheckMiddleButton" << std::endl;}
  85. template <class Event,class FSM>
  86. void on_exit(Event const&,FSM& ) {std::cout << "finishing: CheckMiddleButton" << std::endl;}
  87. };
  88. // the initial state of the player SM. Must be defined
  89. typedef mpl::vector5<NotHolding,NotPlaying,NoMenuMode,NoOnOffButton,CheckMiddleButton>
  90. initial_state;
  91. // transition actions
  92. void send_ActivateMenu(EndPlay const&)
  93. {
  94. std::cout << "leaving Playing" << std::endl;
  95. // we need to activate the menu and simulate its button
  96. (static_cast<iPod*>(this))->process_event(MenuButton());
  97. }
  98. void send_StartSong(CloseMenu const&)
  99. {
  100. // we suppose the 5th song was selected
  101. (static_cast<iPod*>(this))->process_event(StartSong(5));
  102. }
  103. void send_PlayPause(SouthReleased const&)
  104. {
  105. // action using the message queue to generate another event
  106. (static_cast<iPod*>(this))->process_event(PlayPause());
  107. }
  108. void send_Off(OnOffTimer const&)
  109. {
  110. std::cout << "turning player off" << std::endl;
  111. (static_cast<iPod*>(this))->process_event(Off());
  112. }
  113. void send_PlayingMiddleButton(MiddleButton const&)
  114. {
  115. (static_cast<iPod*>(this))->process_event(PlayingMiddleButton());
  116. }
  117. void send_MenuMiddleButton(MiddleButton const&)
  118. {
  119. (static_cast<iPod*>(this))->process_event(MenuMiddleButton());
  120. }
  121. // guard conditions
  122. bool is_menu(MiddleButton const&)
  123. {
  124. return (static_cast<iPod*>(this))->is_flag_active<MenuActive>();
  125. }
  126. bool is_no_menu(MiddleButton const& evt)
  127. {
  128. return !is_menu(evt);
  129. }
  130. template <class EVENT>
  131. void switch_on(EVENT const&)
  132. {
  133. std::cout << "turning player on" << std::endl;
  134. }
  135. typedef iPod_ fsm; // makes transition table cleaner
  136. // Transition table for player
  137. struct transition_table : mpl::vector<
  138. // Start Event Next Action Guard
  139. // +-------------------+---------------+-------------------+--------------------------------+----------------------+
  140. _row < NotHolding , Hold , Holding >,
  141. _row < Holding , NoHold , NotHolding >,
  142. // +-------------------+---------------+-------------------+--------------------------------+----------------------+
  143. _row < NotPlaying , PlayPause , PlayingMode >,
  144. a_row < PlayingMode::exit_pt<PlayingMode_::
  145. PlayingExit> , EndPlay , NotPlaying , &fsm::send_ActivateMenu >,
  146. // +-------------------+---------------+-------------------+--------------------------------+----------------------+
  147. _row < NoMenuMode , MenuButton , MenuMode >,
  148. a_row < MenuMode::exit_pt<MenuMode_::
  149. MenuExit> , CloseMenu , NoMenuMode , &fsm::send_StartSong >,
  150. // +-------------------+---------------+-------------------+--------------------------------+----------------------+
  151. _row < NoOnOffButton , SouthPressed , OffDown >,
  152. a_row < OffDown , SouthReleased , NoOnOffButton , &fsm::send_PlayPause >,
  153. a_row < OffDown , OnOffTimer , PlayerOff , &fsm::send_Off >,
  154. a_row < PlayerOff , SouthPressed , NoOnOffButton , &fsm::switch_on >,
  155. a_row < PlayerOff , NoHold , NoOnOffButton , &fsm::switch_on >,
  156. // +-------------------+---------------+--------------------+--------------------------------+----------------------+
  157. row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_PlayingMiddleButton , &fsm::is_menu >,
  158. row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_MenuMiddleButton , &fsm::is_no_menu >
  159. // +-------------------+---------------+--------------------+--------------------------------+----------------------+
  160. > {};
  161. // Replaces the default no-transition response.
  162. template <class FSM,class Event>
  163. void no_transition(Event const& e, FSM&,int state)
  164. {
  165. std::cout << "no transition from state " << state
  166. << " on event " << typeid(e).name() << std::endl;
  167. }
  168. };
  169. void test()
  170. {
  171. iPod sm;
  172. sm.start();
  173. // we first press Hold
  174. std::cout << "pressing hold" << std::endl;
  175. sm.process_event(Hold());
  176. // pressing a button is now ignored
  177. std::cout << "pressing a button" << std::endl;
  178. sm.process_event(SouthPressed());
  179. // or even one contained in a submachine
  180. sm.process_event(EastPressed());
  181. // no more holding
  182. std::cout << "no more holding, end interrupt event sent" << std::endl;
  183. sm.process_event(NoHold());
  184. std::cout << "pressing South button a short time" << std::endl;
  185. sm.process_event(SouthPressed());
  186. // we suppose a short pressing leading to playing a song
  187. sm.process_event(SouthReleased());
  188. // we move to the next song
  189. std::cout << "we move to the next song" << std::endl;
  190. sm.process_event(NextSong());
  191. // then back to no song => exit from playing, menu active
  192. std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl;
  193. sm.process_event(PreviousSong());
  194. sm.process_event(PreviousSong());
  195. // even in menu mode, pressing play will start playing the first song
  196. std::cout << "pressing play/pause" << std::endl;
  197. sm.process_event(SouthPressed());
  198. sm.process_event(SouthReleased());
  199. // of course pausing must be possible
  200. std::cout << "pressing play/pause" << std::endl;
  201. sm.process_event(SouthPressed());
  202. sm.process_event(SouthReleased());
  203. std::cout << "pressing play/pause" << std::endl;
  204. sm.process_event(SouthPressed());
  205. sm.process_event(SouthReleased());
  206. // while playing, you can fast forward
  207. std::cout << "pressing East button a long time" << std::endl;
  208. sm.process_event(EastPressed());
  209. // let's suppose the timer just fired
  210. sm.process_event(ForwardTimer());
  211. sm.process_event(ForwardTimer());
  212. // end of fast forwarding
  213. std::cout << "releasing East button" << std::endl;
  214. sm.process_event(EastReleased());
  215. // we now press the middle button to set playing at a given position
  216. std::cout << "pressing Middle button, fast forwarding disabled" << std::endl;
  217. sm.process_event(MiddleButton());
  218. std::cout <<"pressing East button to fast forward" << std::endl;
  219. sm.process_event(EastPressed());
  220. // we switch off and on
  221. std::cout <<"switch off player" << std::endl;
  222. sm.process_event(SouthPressed());
  223. sm.process_event(OnOffTimer());
  224. std::cout <<"switch on player" << std::endl;
  225. sm.process_event(SouthPressed());
  226. }
  227. }
  228. int main()
  229. {
  230. test();
  231. return 0;
  232. }