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 namespace mpl = boost::mpl;
21 
22 
23 namespace  // Concrete FSM implementation
24 {
25     // events
26     BOOST_MSM_EUML_EVENT(event1)
27     BOOST_MSM_EUML_EVENT(event2)
28     BOOST_MSM_EUML_EVENT(event3)
29     BOOST_MSM_EUML_EVENT(event4)
30     BOOST_MSM_EUML_EVENT(event5)
31     // if we need something special, like a template constructor, we cannot use the helper macros
32     struct event6_impl : euml_event<event6_impl>
33     {
event6_impl__anonb26f73940111::event6_impl34         event6_impl(){}
35         template <class Event>
event6_impl__anonb26f73940111::event6_impl36         event6_impl(Event const&){}
37     };
38     event6_impl const event6;
39 
40     //Sub fsm state definition
BOOST_MSM_EUML_ACTION(SubState1_Entry)41     BOOST_MSM_EUML_ACTION(SubState1_Entry)
42     {
43         template <class Event,class FSM,class STATE>
44         void operator()(Event const&,FSM&,STATE& )
45         {
46             std::cout << "entering: SubFsm2::SubState1" << std::endl;
47         }
48     };
BOOST_MSM_EUML_ACTION(SubState1_Exit)49     BOOST_MSM_EUML_ACTION(SubState1_Exit)
50     {
51         template <class Event,class FSM,class STATE>
52         void operator()(Event const&,FSM&,STATE& )
53         {
54             std::cout << "leaving: SubFsm2::SubState1" << std::endl;
55         }
56     };
57     BOOST_MSM_EUML_STATE(( SubState1_Entry,SubState1_Exit ),SubState1)
58 
BOOST_MSM_EUML_ACTION(SubState1b_Entry)59     BOOST_MSM_EUML_ACTION(SubState1b_Entry)
60     {
61         template <class Event,class FSM,class STATE>
62         void operator()(Event const&,FSM&,STATE& )
63         {
64             std::cout << "entering: SubFsm2::SubState1b" << std::endl;
65         }
66     };
BOOST_MSM_EUML_ACTION(SubState1b_Exit)67     BOOST_MSM_EUML_ACTION(SubState1b_Exit)
68     {
69         template <class Event,class FSM,class STATE>
70         void operator()(Event const&,FSM&,STATE& )
71         {
72             std::cout << "leaving: SubFsm2::SubState1b" << std::endl;
73         }
74     };
75     BOOST_MSM_EUML_STATE(( SubState1b_Entry,SubState1b_Exit ),SubState1b)
76 
BOOST_MSM_EUML_ACTION(SubState1c_Entry)77     BOOST_MSM_EUML_ACTION(SubState1c_Entry)
78     {
79         template <class Event,class FSM,class STATE>
80         void operator()(Event const&,FSM&,STATE& )
81         {
82             std::cout << "entering: SubFsm2::SubState1c" << std::endl;
83         }
84     };
BOOST_MSM_EUML_ACTION(SubState1c_Exit)85     BOOST_MSM_EUML_ACTION(SubState1c_Exit)
86     {
87         template <class Event,class FSM,class STATE>
88         void operator()(Event const&,FSM&,STATE& )
89         {
90             std::cout << "leaving: SubFsm2::SubState1c" << std::endl;
91         }
92     };
93     BOOST_MSM_EUML_STATE(( SubState1c_Entry,SubState1c_Exit ),SubState1c)
94 
BOOST_MSM_EUML_ACTION(SubState2_Entry)95     BOOST_MSM_EUML_ACTION(SubState2_Entry)
96     {
97         template <class Event,class FSM,class STATE>
98         void operator()(Event const&,FSM&,STATE& )
99         {
100             std::cout << "entering: SubFsm2::SubState2" << std::endl;
101         }
102     };
BOOST_MSM_EUML_ACTION(SubState2_Exit)103     BOOST_MSM_EUML_ACTION(SubState2_Exit)
104     {
105         template <class Event,class FSM,class STATE>
106         void operator()(Event const&,FSM&,STATE& )
107         {
108             std::cout << "leaving: SubFsm2::SubState2" << std::endl;
109         }
110     };
111     BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(0,( SubState2_Entry,SubState2_Exit ),SubState2)
112 
BOOST_MSM_EUML_ACTION(SubState2b_Entry)113     BOOST_MSM_EUML_ACTION(SubState2b_Entry)
114     {
115         template <class Event,class FSM,class STATE>
116         void operator()(Event const&,FSM&,STATE& )
117         {
118             std::cout << "entering: SubFsm2::SubState2b" << std::endl;
119         }
120     };
BOOST_MSM_EUML_ACTION(SubState2b_Exit)121     BOOST_MSM_EUML_ACTION(SubState2b_Exit)
122     {
123         template <class Event,class FSM,class STATE>
124         void operator()(Event const&,FSM&,STATE& )
125         {
126             std::cout << "leaving: SubFsm2::SubState2b" << std::endl;
127         }
128     };
129     BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(1,( SubState2b_Entry,SubState2b_Exit ),SubState2b)
130 
BOOST_MSM_EUML_ACTION(SubState2c_Entry)131     BOOST_MSM_EUML_ACTION(SubState2c_Entry)
132     {
133         template <class Event,class FSM,class STATE>
134         void operator()(Event const&,FSM&,STATE& )
135         {
136             std::cout << "entering: SubFsm2::SubState2c" << std::endl;
137         }
138     };
BOOST_MSM_EUML_ACTION(SubState2c_Exit)139     BOOST_MSM_EUML_ACTION(SubState2c_Exit)
140     {
141         template <class Event,class FSM,class STATE>
142         void operator()(Event const&,FSM&,STATE& )
143         {
144             std::cout << "leaving: SubFsm2::SubState2c" << std::endl;
145         }
146     };
147     BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(2,( SubState2c_Entry,SubState2c_Exit ),SubState2c)
148 
BOOST_MSM_EUML_ACTION(PseudoEntry1_Entry)149     BOOST_MSM_EUML_ACTION(PseudoEntry1_Entry)
150     {
151         template <class Event,class FSM,class STATE>
152         void operator()(Event const&,FSM&,STATE& )
153         {
154             std::cout << "entering: SubFsm2::PseudoEntry1" << std::endl;
155         }
156     };
BOOST_MSM_EUML_ACTION(PseudoEntry1_Exit)157     BOOST_MSM_EUML_ACTION(PseudoEntry1_Exit)
158     {
159         template <class Event,class FSM,class STATE>
160         void operator()(Event const&,FSM&,STATE& )
161         {
162             std::cout << "leaving: SubFsm2::PseudoEntry1" << std::endl;
163         }
164     };
165     BOOST_MSM_EUML_ENTRY_STATE(0,( PseudoEntry1_Entry,PseudoEntry1_Exit ),PseudoEntry1)
166 
BOOST_MSM_EUML_ACTION(SubState3_Entry)167     BOOST_MSM_EUML_ACTION(SubState3_Entry)
168     {
169         template <class Event,class FSM,class STATE>
170         void operator()(Event const&,FSM&,STATE& )
171         {
172             std::cout << "entering: SubFsm2::SubState3" << std::endl;
173         }
174     };
BOOST_MSM_EUML_ACTION(SubState3_Exit)175     BOOST_MSM_EUML_ACTION(SubState3_Exit)
176     {
177         template <class Event,class FSM,class STATE>
178         void operator()(Event const&,FSM&,STATE& )
179         {
180             std::cout << "leaving: SubFsm2::SubState3" << std::endl;
181         }
182     };
183     BOOST_MSM_EUML_STATE(( SubState3_Entry,SubState3_Exit ),SubState3)
184 
BOOST_MSM_EUML_ACTION(SubState3b_Entry)185     BOOST_MSM_EUML_ACTION(SubState3b_Entry)
186     {
187         template <class Event,class FSM,class STATE>
188         void operator()(Event const&,FSM&,STATE& )
189         {
190             std::cout << "entering: SubFsm2::SubState3b" << std::endl;
191         }
192     };
BOOST_MSM_EUML_ACTION(SubState3b_Exit)193     BOOST_MSM_EUML_ACTION(SubState3b_Exit)
194     {
195         template <class Event,class FSM,class STATE>
196         void operator()(Event const&,FSM&,STATE& )
197         {
198             std::cout << "leaving: SubFsm2::SubState3b" << std::endl;
199         }
200     };
201     BOOST_MSM_EUML_STATE(( SubState3b_Entry,SubState3b_Exit ),SubState3b)
202 
BOOST_MSM_EUML_ACTION(PseudoExit1_Entry)203     BOOST_MSM_EUML_ACTION(PseudoExit1_Entry)
204     {
205         template <class Event,class FSM,class STATE>
206         void operator()(Event const&,FSM&,STATE& )
207         {
208             std::cout << "entering: SubFsm2::PseudoExit1" << std::endl;
209         }
210     };
BOOST_MSM_EUML_ACTION(PseudoExit1_Exit)211     BOOST_MSM_EUML_ACTION(PseudoExit1_Exit)
212     {
213         template <class Event,class FSM,class STATE>
214         void operator()(Event const&,FSM&,STATE& )
215         {
216             std::cout << "leaving: SubFsm2::PseudoExit1" << std::endl;
217         }
218     };
219     BOOST_MSM_EUML_EXIT_STATE(( event6,PseudoExit1_Entry,PseudoExit1_Exit ),PseudoExit1)
220 
221     // actions
BOOST_MSM_EUML_ACTION(entry_action)222     BOOST_MSM_EUML_ACTION(entry_action)
223     {
224         template <class FSM,class EVT,class SourceState,class TargetState>
225         void operator()(FSM& ,EVT const& ,SourceState& ,TargetState& )
226         {
227             cout << "calling entry_action" << endl;
228         }
229     };
230     // SubFsm definition
BOOST_MSM_EUML_ACTION(SubFsm2_Entry)231     BOOST_MSM_EUML_ACTION(SubFsm2_Entry)
232     {
233         template <class Event,class FSM,class STATE>
234         void operator()(Event const&,FSM&,STATE& )
235         {
236             std::cout << "entering: SubFsm2" << std::endl;
237         }
238     };
BOOST_MSM_EUML_ACTION(SubFsm2_Exit)239     BOOST_MSM_EUML_ACTION(SubFsm2_Exit)
240     {
241         template <class Event,class FSM,class STATE>
242         void operator()(Event const&,FSM&,STATE& )
243         {
244             std::cout << "leaving: SubFsm2" << std::endl;
245         }
246     };
247     BOOST_MSM_EUML_TRANSITION_TABLE((
248         //  +------------------------------------------------------------------------------+
249             SubState3   == PseudoEntry1  + event4 / entry_action        ,
250             SubState1   == SubState2     + event6                       ,
251             PseudoExit1 == SubState3     + event5
252         //  +------------------------------------------------------------------------------+
253         ), SubFsm2_transition_table)
254 
255     BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (SubFsm2_transition_table, //STT
256                                     init_ << SubState1 << SubState1b << SubState1c, // Init State
257                                     SubFsm2_Entry, // Entry
258                                     SubFsm2_Exit
259                                     ),SubFsm2_def)
260     // inherit to add some typedef
261     struct SubFsm2_ : public SubFsm2_def
262     {
263         // these 2 states are not found in the transition table because they are accessed only through
264         // a fork, so we need to create them explicitly
265         typedef mpl::vector<BOOST_MSM_EUML_STATE_NAME(SubState2b),
266                             BOOST_MSM_EUML_STATE_NAME(SubState2c)> explicit_creation;
267     };
268 
269     // back-end
270     typedef msm::back::state_machine<SubFsm2_> SubFsm2_type;
271     SubFsm2_type const SubFsm2;
272 
273     // Fsm state definitions
BOOST_MSM_EUML_ACTION(State1_Entry)274     BOOST_MSM_EUML_ACTION(State1_Entry)
275     {
276         template <class Event,class FSM,class STATE>
277         void operator()(Event const&,FSM&,STATE& )
278         {
279             std::cout << "entering: State1" << std::endl;
280         }
281     };
BOOST_MSM_EUML_ACTION(State1_Exit)282     BOOST_MSM_EUML_ACTION(State1_Exit)
283     {
284         template <class Event,class FSM,class STATE>
285         void operator()(Event const&,FSM&,STATE& )
286         {
287             std::cout << "leaving: State1" << std::endl;
288         }
289     };
290     BOOST_MSM_EUML_STATE(( State1_Entry,State1_Exit ),State1)
291 
BOOST_MSM_EUML_ACTION(State2_Entry)292     BOOST_MSM_EUML_ACTION(State2_Entry)
293     {
294         template <class Event,class FSM,class STATE>
295         void operator()(Event const&,FSM&,STATE& )
296         {
297             std::cout << "entering: State2" << std::endl;
298         }
299     };
BOOST_MSM_EUML_ACTION(State2_Exit)300     BOOST_MSM_EUML_ACTION(State2_Exit)
301     {
302         template <class Event,class FSM,class STATE>
303         void operator()(Event const&,FSM&,STATE& )
304         {
305             std::cout << "leaving: State2" << std::endl;
306         }
307     };
308     BOOST_MSM_EUML_STATE(( State2_Entry,State2_Exit ),State2)
309 
310     // Fsm definition
311     BOOST_MSM_EUML_TRANSITION_TABLE((
312         //  +------------------------------------------------------------------------------+
313              SubFsm2                            == State1                + event1      ,
314              explicit_(SubFsm2,SubState2)       == State1                + event2,
315             (explicit_(SubFsm2,SubState2),
316              explicit_(SubFsm2,SubState2b),
317              explicit_(SubFsm2,SubState2c))     == State1                + event3      ,
318              entry_pt_(SubFsm2,PseudoEntry1)    == State1                + event4      ,
319              State1                             == SubFsm2               + event1      ,
320              State2                             == exit_pt_
321                                                   (SubFsm2,PseudoExit1)  + event6
322         //  +------------------------------------------------------------------------------+
323         ),transition_table )
324 
325 
BOOST_MSM_EUML_ACTION(Log_No_Transition)326     BOOST_MSM_EUML_ACTION(Log_No_Transition)
327     {
328         template <class Event,class FSM,class STATE>
329         void operator()(Event const& e,FSM&,STATE& )
330         {
331             std::cout << "no transition in Fsm"
332                 << " on event " << typeid(e).name() << std::endl;
333         }
334     };
335     BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
336                                         init_ << State1, // Init State
337                                         no_action, // Entry
338                                         no_action, // Exit
339                                         attributes_ << no_attributes_, // Attributes
340                                         configure_ << no_configure_, // configuration
341                                         Log_No_Transition // no_transition handler
342                                         ),
343                                       Fsm_) //fsm name
344 
345     //back-end
346     typedef msm::back::state_machine<Fsm_> Fsm;
347 
348     //
349     // Testing utilities.
350     //
351     static char const* const state_names[] = { "State1", "SubFsm2","State2" };
pstate(Fsm const & p)352     void pstate(Fsm const& p)
353     {
354         std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
355     }
356 
test()357     void test()
358     {
359         Fsm p;
360         // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
361         p.start();
362         std::cout << "Simply move in and out of the composite, activate init states" << std::endl;
363         p.process_event(event1); pstate(p);
364         p.process_event(event1); pstate(p);
365         std::cout << "Direct entry into SubFsm2::SubState2, then transition to SubState1 and back to State1" << std::endl;
366         p.process_event(event2); pstate(p);
367         p.process_event(event6); pstate(p);
368         p.process_event(event1); pstate(p);
369         std::cout << "processing fork to SubFsm2::SubState2, SubFsm2::SubState2b and SubFsm2::SubState2c" << std::endl;
370         p.process_event(event3); pstate(p);
371         p.process_event(event1); pstate(p);
372         std::cout << "processing entry pseudo state" << std::endl;
373         p.process_event(event4); pstate(p);
374         p.process_event(event1); pstate(p);
375         std::cout << "processing entry + exit pseudo state" << std::endl;
376         p.process_event(event4); pstate(p);
377         std::cout << "using exit pseudo state" << std::endl;
378         p.process_event(event5); pstate(p);
379     }
380 }
381 
main()382 int main()
383 {
384     test();
385      return 0;
386 }
387