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