• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <iostream>
12 // back-end
13 #include <boost/msm/back/state_machine.hpp>
14 //front-end
15 #include <boost/msm/front/state_machine_def.hpp>
16 #include <boost/msm/front/functor_row.hpp>
17 #include <boost/msm/front/euml/common.hpp>
18 // for And_ operator
19 #include <boost/msm/front/euml/operator.hpp>
20 
21 using namespace std;
22 namespace msm = boost::msm;
23 using namespace msm::front;
24 namespace mpl = boost::mpl;
25 // for And_ operator
26 using namespace msm::front::euml;
27 
28 namespace
29 {
30     // events
31     struct play {};
32     struct end_pause {};
33     struct stop {};
34     struct pause {};
35     struct open_close {};
36 
37     // A "complicated" event type that carries some data.
38     enum DiskTypeEnum
39     {
40         DISK_CD=0,
41         DISK_DVD=1
42     };
43     struct cd_detected
44     {
cd_detected__anon6a38dc240111::cd_detected45         cd_detected(std::string name, DiskTypeEnum diskType)
46             : name(name),
47             disc_type(diskType)
48         {}
49 
50         std::string name;
51         DiskTypeEnum disc_type;
52     };
53 
54     // front-end: define the FSM structure
55     struct player_ : public msm::front::state_machine_def<player_>
56     {
57         // The list of FSM states
58         struct Empty : public msm::front::state<>
59         {
60             // every (optional) entry/exit methods get the event passed.
61             template <class Event,class FSM>
on_entry__anon6a38dc240111::player_::Empty62             void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
63             template <class Event,class FSM>
on_exit__anon6a38dc240111::player_::Empty64             void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
65             struct internal_guard_fct
66             {
67                 template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::Empty::internal_guard_fct68                 bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
69                 {
70                     std::cout << "Empty::internal_transition_table guard\n";
71                     return false;
72                 }
73             };
74             struct internal_action_fct
75             {
76                 template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::Empty::internal_action_fct77                 void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
78                 {
79                     std::cout << "Empty::internal_transition_table action" << std::endl;
80                 }
81             };
82             // Transition table for Empty
83             struct internal_transition_table : mpl::vector<
84                 //    Start     Event         Next      Action               Guard
85            Internal <           cd_detected           , internal_action_fct ,internal_guard_fct    >
86                 //  +---------+-------------+---------+---------------------+----------------------+
87             > {};
88         };
89         struct Open : public msm::front::state<>
90         {
91             template <class Event,class FSM>
on_entry__anon6a38dc240111::player_::Open92             void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
93             template <class Event,class FSM>
on_exit__anon6a38dc240111::player_::Open94             void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
95         };
96 
97         struct Stopped : public msm::front::state<>
98         {
99             template <class Event,class FSM>
on_entry__anon6a38dc240111::player_::Stopped100             void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
101             template <class Event,class FSM>
on_exit__anon6a38dc240111::player_::Stopped102             void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
103         };
104 
105         struct Playing : public msm::front::state<>
106         {
107             template <class Event,class FSM>
on_entry__anon6a38dc240111::player_::Playing108             void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
109             template <class Event,class FSM>
on_exit__anon6a38dc240111::player_::Playing110             void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
111         };
112 
113         // state not defining any entry or exit
114         struct Paused : public msm::front::state<>
115         {
116         };
117 
118         // the initial state of the player SM. Must be defined
119         typedef Empty initial_state;
120 
121         // transition actions
122         // as the functors are generic on events, fsm and source/target state,
123         // you can reuse them in another machine if you wish
124         struct TestFct
125         {
126             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::TestFct127             void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
128             {
129                 cout << "transition with event:" << typeid(EVT).name() << endl;
130             }
131         };
132         struct start_playback
133         {
134             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::start_playback135             void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
136             {
137                 cout << "player::start_playback" << endl;
138             }
139         };
140         struct open_drawer
141         {
142             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::open_drawer143             void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
144             {
145                 cout << "player::open_drawer" << endl;
146             }
147         };
148         struct close_drawer
149         {
150             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::close_drawer151             void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
152             {
153                 cout << "player::close_drawer" << endl;
154             }
155         };
156         struct store_cd_info
157         {
158             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::store_cd_info159             void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
160             {
161                 cout << "player::store_cd_info" << endl;
162                 fsm.process_event(play());
163             }
164         };
165         struct stop_playback
166         {
167             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::stop_playback168             void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
169             {
170                 cout << "player::stop_playback" << endl;
171             }
172         };
173         struct pause_playback
174         {
175             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::pause_playback176             void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
177             {
178                 cout << "player::pause_playback" << endl;
179             }
180         };
181         struct resume_playback
182         {
183             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::resume_playback184             void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
185             {
186                 cout << "player::resume_playback" << endl;
187             }
188         };
189         struct stop_and_open
190         {
191             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::stop_and_open192             void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
193             {
194                 cout << "player::stop_and_open" << endl;
195             }
196         };
197         struct stopped_again
198         {
199             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::stopped_again200             void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
201             {
202                 cout << "player::stopped_again" << endl;
203             }
204         };
205         // guard conditions
206         struct DummyGuard
207         {
208             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::DummyGuard209             bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
210             {
211                 return true;
212             }
213         };
214         struct good_disk_format
215         {
216             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::good_disk_format217             bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
218             {
219                 // to test a guard condition, let's say we understand only CDs, not DVD
220                 if (evt.disc_type != DISK_CD)
221                 {
222                     std::cout << "wrong disk, sorry" << std::endl;
223                     return false;
224                 }
225                 return true;
226             }
227         };
228         struct always_true
229         {
230             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::always_true231             bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
232             {
233                 return true;
234             }
235         };
236         struct internal_guard
237         {
238             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon6a38dc240111::player_::internal_guard239             bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
240             {
241                 std::cout << "Empty::internal guard\n";
242                 return false;
243             }
244         };
245         // Transition table for player
246         struct transition_table : mpl::vector<
247             //    Start     Event         Next      Action                     Guard
248             //  +---------+-------------+---------+---------------------------+----------------------+
249             Row < Stopped , play        , Playing , ActionSequence_
250                                                      <mpl::vector<
251                                                      TestFct,start_playback> >
252                                                                               , DummyGuard           >,
253             Row < Stopped , open_close  , Open    , open_drawer               , none                 >,
254             Row < Stopped , stop        , Stopped , none                      , none                 >,
255             //  +---------+-------------+---------+---------------------------+----------------------+
256             Row < Open    , open_close  , Empty   , close_drawer              , none                 >,
257             //  +---------+-------------+---------+---------------------------+----------------------+
258             Row < Empty   , open_close  , Open    , open_drawer               , none                 >,
259             Row < Empty   , cd_detected , Stopped , store_cd_info             , And_<good_disk_format,
260                                                                                      always_true>    >,
261             // internal transition inside the stt: none as Target
262             Row < Empty   , cd_detected , none    , none                      , internal_guard       >,
263             //  +---------+-------------+---------+---------------------------+----------------------+
264             Row < Playing , stop        , Stopped , stop_playback             , none                 >,
265             Row < Playing , pause       , Paused  , pause_playback            , none                 >,
266             Row < Playing , open_close  , Open    , stop_and_open             , none                 >,
267             //  +---------+-------------+---------+---------------------------+----------------------+
268             Row < Paused  , end_pause   , Playing , resume_playback           , none                 >,
269             Row < Paused  , stop        , Stopped , stop_playback             , none                 >,
270             Row < Paused  , open_close  , Open    , stop_and_open             , none                 >
271             //  +---------+-------------+---------+---------------------------+----------------------+
272         > {};
273         // Replaces the default no-transition response.
274         template <class FSM,class Event>
no_transition__anon6a38dc240111::player_275         void no_transition(Event const& e, FSM&,int state)
276         {
277             std::cout << "no transition from state " << state
278                 << " on event " << typeid(e).name() << std::endl;
279         }
280     };
281     // Pick a back-end
282     typedef msm::back::state_machine<player_> player;
283 
284     //
285     // Testing utilities.
286     //
287     static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
pstate(player const & p)288     void pstate(player const& p)
289     {
290         std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
291     }
292 
test()293     void test()
294     {
295         player p;
296         // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
297         p.start();
298         // go to Open, call on_exit on Empty, then action, then on_entry on Open
299         p.process_event(open_close()); pstate(p);
300         p.process_event(open_close()); pstate(p);
301         // will be rejected, wrong disk type
302         p.process_event(
303             cd_detected("louie, louie",DISK_DVD)); pstate(p);
304         p.process_event(
305             cd_detected("louie, louie",DISK_CD)); pstate(p);
306         // no need to call play() as the previous transition does it in its action method
307         //p.process_event(play());
308 
309         // at this point, Play is active
310         p.process_event(pause()); pstate(p);
311         // go back to Playing
312         p.process_event(end_pause());  pstate(p);
313         p.process_event(pause()); pstate(p);
314         p.process_event(stop());  pstate(p);
315         // event leading to the same state
316         // no action method called as it is not present in the transition table
317         p.process_event(stop());  pstate(p);
318     }
319 }
320 
main()321 int main()
322 {
323     test();
324     return 0;
325 }
326