SimpleTimer.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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. namespace msm = boost::msm;
  17. // how long the timer will ring when countdown elapsed.
  18. #define RINGING_TIME 5
  19. namespace // Concrete FSM implementation
  20. {
  21. // events
  22. BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_timer)
  23. BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_timer ), start_timer_attr)
  24. BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(start_timer,start_timer_attr)
  25. BOOST_MSM_EUML_EVENT(stop_timer)
  26. BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_tick)
  27. BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_tick ), tick_attr)
  28. BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(tick,tick_attr)
  29. BOOST_MSM_EUML_EVENT(start_ringing)
  30. // Concrete FSM implementation
  31. // The list of FSM states
  32. BOOST_MSM_EUML_ACTION(Stopped_Entry)
  33. {
  34. template <class Event,class FSM,class STATE>
  35. void operator()(Event const&,FSM&,STATE& )
  36. {
  37. std::cout << "entering: Stopped" << std::endl;
  38. }
  39. };
  40. BOOST_MSM_EUML_STATE(( Stopped_Entry ),Stopped)
  41. BOOST_MSM_EUML_ACTION(Started_Entry)
  42. {
  43. template <class Event,class FSM,class STATE>
  44. void operator()(Event const&,FSM&,STATE& )
  45. {
  46. std::cout << "entering: Started" << std::endl;
  47. }
  48. };
  49. BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_counter)
  50. BOOST_MSM_EUML_STATE(( Started_Entry,
  51. no_action,
  52. attributes_ << m_counter
  53. ),
  54. Started)
  55. BOOST_MSM_EUML_ACTION(Ringing_Entry)
  56. {
  57. template <class Event,class FSM,class STATE>
  58. void operator()(Event const&,FSM&,STATE& )
  59. {
  60. std::cout << "entering: Ringing" << std::endl;
  61. }
  62. };
  63. BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_ringing_cpt)
  64. BOOST_MSM_EUML_STATE(( Ringing_Entry,
  65. no_action,
  66. attributes_ << m_ringing_cpt
  67. ),
  68. Ringing)
  69. // external function
  70. void do_ring(int ringing_time) {std::cout << "ringing " << ringing_time << " s" << std::endl;}
  71. // create functor and eUML function
  72. BOOST_MSM_EUML_FUNCTION(Ring_ , do_ring , ring_ , void , void )
  73. // replaces the old transition table
  74. BOOST_MSM_EUML_TRANSITION_TABLE((
  75. // +------------------------------------------------------------------------------+
  76. // When we start the countdown, the countdown value is not hardcoded but contained in the start_timer event.
  77. // We copy this value into Started
  78. Started == Stopped + start_timer /(target_(m_counter)= event_(m_timer)) ,
  79. Stopped == Started + stop_timer ,
  80. // internal transition
  81. Started + tick
  82. // we here use the message queue to move to Started when the countdown is finished
  83. // to do this we put start_ringing into the message queue
  84. / if_then_( (source_(m_counter) -= event_(m_tick) ) <= Int_<0>(),
  85. process_(start_ringing) ) ,
  86. // when we start ringing, we give to the state its hard-coded ringing time.
  87. Ringing == Started + start_ringing
  88. / (target_(m_ringing_cpt) = Int_<RINGING_TIME>(),
  89. // call the external do_ring function
  90. ring_(Int_<RINGING_TIME>())) ,
  91. // to change a bit, we now do not use the message queue but a transition conflict to solve the same problem.
  92. // When tick is fired, we have an internal transition Ringing -> Ringing, as long as Counter > 0
  93. Ringing + tick [ source_(m_ringing_cpt) - event_(m_tick) > Int_<0>() ]
  94. /(target_(m_ringing_cpt) -= event_(m_tick) ) ,
  95. // And we move to Stopped when the counter is 0
  96. Stopped == Ringing + tick[source_(m_ringing_cpt)-event_(m_tick) <= Int_<0>()] ,
  97. // we let the user manually stop the ringing by pressing any button
  98. Stopped == Ringing + stop_timer ,
  99. Stopped == Ringing + start_timer
  100. // +------------------------------------------------------------------------------+
  101. ),transition_table)
  102. // create a state machine "on the fly"
  103. BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
  104. init_ << Stopped // Init State
  105. ),
  106. SimpleTimer_) //fsm name
  107. // choice of back-end
  108. typedef msm::back::state_machine<SimpleTimer_> SimpleTimer;
  109. //
  110. // Testing utilities.
  111. //
  112. static char const* const state_names[] = { "Stopped", "Started","Ringing" };
  113. void pstate(SimpleTimer const& p)
  114. {
  115. std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
  116. }
  117. void test()
  118. {
  119. SimpleTimer p;
  120. // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
  121. p.start();
  122. p.process_event(start_timer(5));pstate(p); //timer set to 5 ticks
  123. p.process_event(tick(2));pstate(p);
  124. p.process_event(tick(1));pstate(p);
  125. p.process_event(tick(1));pstate(p);
  126. p.process_event(tick(1));pstate(p);
  127. // we are now ringing, let it ring a bit
  128. p.process_event(tick(2));pstate(p);
  129. p.process_event(tick(1));pstate(p);
  130. p.process_event(tick(1));pstate(p);
  131. p.process_event(tick(1));pstate(p);
  132. }
  133. }
  134. int main()
  135. {
  136. test();
  137. return 0;
  138. }