ExampleCircularBuffer.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #include <vector>
  2. #include <iostream>
  3. // back-end
  4. #include <boost/msm/back/state_machine.hpp>
  5. // header for support of circular_buffer
  6. #include <boost/msm/back/queue_container_circular.hpp>
  7. //front-end
  8. #include <boost/msm/front/state_machine_def.hpp>
  9. // functors
  10. #include <boost/msm/front/functor_row.hpp>
  11. #include <boost/msm/front/euml/common.hpp>
  12. // for And_ operator
  13. #include <boost/msm/front/euml/operator.hpp>
  14. using namespace std;
  15. namespace msm = boost::msm;
  16. namespace mpl = boost::mpl;
  17. using namespace msm::front;
  18. // for And_ operator
  19. using namespace msm::front::euml;
  20. namespace // Concrete FSM implementation
  21. {
  22. // events
  23. struct play {};
  24. struct end_pause {};
  25. struct stop {};
  26. struct pause {};
  27. struct open_close {};
  28. // A "complicated" event type that carries some data.
  29. enum DiskTypeEnum
  30. {
  31. DISK_CD=0,
  32. DISK_DVD=1
  33. };
  34. struct cd_detected
  35. {
  36. cd_detected(std::string name, DiskTypeEnum diskType)
  37. : name(name),
  38. disc_type(diskType)
  39. {}
  40. std::string name;
  41. DiskTypeEnum disc_type;
  42. };
  43. // front-end: define the FSM structure
  44. struct player_ : public msm::front::state_machine_def<player_>
  45. {
  46. // The list of FSM states
  47. struct Empty : public msm::front::state<>
  48. {
  49. // every (optional) entry/exit methods get the event passed.
  50. template <class Event,class FSM>
  51. void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
  52. template <class Event,class FSM>
  53. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
  54. };
  55. struct Open : public msm::front::state<>
  56. {
  57. template <class Event,class FSM>
  58. void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
  59. template <class Event,class FSM>
  60. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
  61. };
  62. struct Stopped : public msm::front::state<>
  63. {
  64. // when stopped, the CD is loaded
  65. template <class Event,class FSM>
  66. void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
  67. template <class Event,class FSM>
  68. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
  69. };
  70. struct Playing : public msm::front::state<>
  71. {
  72. template <class Event,class FSM>
  73. void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
  74. template <class Event,class FSM>
  75. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
  76. };
  77. // state not defining any entry or exit
  78. struct Paused : public msm::front::state<>
  79. {
  80. };
  81. // the initial state of the player SM. Must be defined
  82. typedef Empty initial_state;
  83. // transition actions
  84. // as the functors are generic on events, fsm and source/target state,
  85. // you can reuse them in another machine if you wish
  86. struct TestFct
  87. {
  88. template <class EVT,class FSM,class SourceState,class TargetState>
  89. void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
  90. {
  91. cout << "transition with event:" << typeid(EVT).name() << endl;
  92. }
  93. };
  94. struct start_playback
  95. {
  96. template <class EVT,class FSM,class SourceState,class TargetState>
  97. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  98. {
  99. cout << "player::start_playback" << endl;
  100. }
  101. };
  102. struct open_drawer
  103. {
  104. template <class EVT,class FSM,class SourceState,class TargetState>
  105. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  106. {
  107. cout << "player::open_drawer" << endl;
  108. }
  109. };
  110. struct close_drawer
  111. {
  112. template <class EVT,class FSM,class SourceState,class TargetState>
  113. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  114. {
  115. cout << "player::close_drawer" << endl;
  116. }
  117. };
  118. struct store_cd_info
  119. {
  120. template <class EVT,class FSM,class SourceState,class TargetState>
  121. void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
  122. {
  123. cout << "player::store_cd_info" << endl;
  124. fsm.process_event(play());
  125. }
  126. };
  127. struct stop_playback
  128. {
  129. template <class EVT,class FSM,class SourceState,class TargetState>
  130. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  131. {
  132. cout << "player::stop_playback" << endl;
  133. }
  134. };
  135. struct pause_playback
  136. {
  137. template <class EVT,class FSM,class SourceState,class TargetState>
  138. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  139. {
  140. cout << "player::pause_playback" << endl;
  141. }
  142. };
  143. struct resume_playback
  144. {
  145. template <class EVT,class FSM,class SourceState,class TargetState>
  146. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  147. {
  148. cout << "player::resume_playback" << endl;
  149. }
  150. };
  151. struct stop_and_open
  152. {
  153. template <class EVT,class FSM,class SourceState,class TargetState>
  154. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  155. {
  156. cout << "player::stop_and_open" << endl;
  157. }
  158. };
  159. struct stopped_again
  160. {
  161. template <class EVT,class FSM,class SourceState,class TargetState>
  162. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  163. {
  164. cout << "player::stopped_again" << endl;
  165. }
  166. };
  167. // guard conditions
  168. struct DummyGuard
  169. {
  170. template <class EVT,class FSM,class SourceState,class TargetState>
  171. bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
  172. {
  173. return true;
  174. }
  175. };
  176. struct good_disk_format
  177. {
  178. template <class EVT,class FSM,class SourceState,class TargetState>
  179. bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
  180. {
  181. // to test a guard condition, let's say we understand only CDs, not DVD
  182. if (evt.disc_type != DISK_CD)
  183. {
  184. std::cout << "wrong disk, sorry" << std::endl;
  185. return false;
  186. }
  187. return true;
  188. }
  189. };
  190. struct always_true
  191. {
  192. template <class EVT,class FSM,class SourceState,class TargetState>
  193. bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
  194. {
  195. return true;
  196. }
  197. };
  198. // we want to define one row with the classic look.
  199. bool auto_start(cd_detected const& evt)
  200. {
  201. return false;
  202. }
  203. typedef player_ p; // makes transition table cleaner
  204. // Transition table for player
  205. struct transition_table : mpl::vector<
  206. // Start Event Next Action Guard
  207. // +---------+-------------+---------+---------------------------+----------------------+
  208. Row < Stopped , play , Playing , ActionSequence_
  209. <mpl::vector<
  210. TestFct,start_playback> >
  211. , DummyGuard >,
  212. Row < Stopped , open_close , Open , open_drawer , none >,
  213. Row < Stopped , stop , Stopped , none , none >,
  214. // +---------+-------------+---------+---------------------------+----------------------+
  215. Row < Open , open_close , Empty , close_drawer , none >,
  216. // +---------+-------------+---------+---------------------------+----------------------+
  217. Row < Empty , open_close , Open , open_drawer , none >,
  218. Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
  219. always_true> >,
  220. // we here also mix with some "classical row"
  221. g_row < Empty , cd_detected , Playing , &p::auto_start >,
  222. // +---------+-------------+---------+---------------------------+----------------------+
  223. Row < Playing , stop , Stopped , stop_playback , none >,
  224. Row < Playing , pause , Paused , pause_playback , none >,
  225. Row < Playing , open_close , Open , stop_and_open , none >,
  226. // +---------+-------------+---------+---------------------------+----------------------+
  227. Row < Paused , end_pause , Playing , resume_playback , none >,
  228. Row < Paused , stop , Stopped , stop_playback , none >,
  229. Row < Paused , open_close , Open , stop_and_open , none >
  230. // +---------+-------------+---------+---------------------------+----------------------+
  231. > {};
  232. // Replaces the default no-transition response.
  233. template <class FSM,class Event>
  234. void no_transition(Event const& e, FSM&,int state)
  235. {
  236. std::cout << "no transition from state " << state
  237. << " on event " << typeid(e).name() << std::endl;
  238. }
  239. };
  240. // Pick a back-end
  241. typedef msm::back::state_machine<player_, msm::back::queue_container_circular> player;
  242. //
  243. // Testing utilities.
  244. //
  245. static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
  246. void pstate(player const& p)
  247. {
  248. std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
  249. }
  250. void test()
  251. {
  252. player p;
  253. // we get the message queue and limit it to capacity 1
  254. // get_message_queue returns the queue container (in this case circular_buffer)
  255. p.get_message_queue().set_capacity(1);
  256. // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
  257. p.start();
  258. // go to Open, call on_exit on Empty, then action, then on_entry on Open
  259. p.process_event(open_close()); pstate(p);
  260. p.process_event(open_close()); pstate(p);
  261. // will be rejected, wrong disk type
  262. p.process_event(
  263. cd_detected("louie, louie",DISK_DVD)); pstate(p);
  264. p.process_event(
  265. cd_detected("louie, louie",DISK_CD)); pstate(p);
  266. // no need to call play() as the previous event does it in its action method
  267. //p.process_event(play());
  268. // at this point, Play is active
  269. p.process_event(pause()); pstate(p);
  270. // go back to Playing
  271. p.process_event(end_pause()); pstate(p);
  272. p.process_event(pause()); pstate(p);
  273. p.process_event(stop()); pstate(p);
  274. // event leading to the same state
  275. // no action method called as it is not present in the transition table
  276. p.process_event(stop()); pstate(p);
  277. }
  278. }
  279. int main()
  280. {
  281. test();
  282. return 0;
  283. }