• 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 <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 // entry/exit/action/guard logging functors
22 #include "logging_functors.h"
23 
24 namespace  // Concrete FSM implementation
25 {
26     // events
27     BOOST_MSM_EUML_EVENT(play)
28     BOOST_MSM_EUML_EVENT(end_pause)
29     BOOST_MSM_EUML_EVENT(stop)
30     BOOST_MSM_EUML_EVENT(pause)
31     BOOST_MSM_EUML_EVENT(open_close)
32     BOOST_MSM_EUML_EVENT(next_song)
33     BOOST_MSM_EUML_EVENT(previous_song)
34     BOOST_MSM_EUML_EVENT(region2_evt)
35 
36     // A "complicated" event type that carries some data.
37     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
38     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
39     BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
40     BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
41 
42     // Concrete FSM implementation
43 
44     // The list of FSM states
45     // state not defining any entry or exit
46     BOOST_MSM_EUML_STATE((),Paused)
47     BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
48     BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
49     BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
50 
51 
52     // Playing is now a state machine itself.
53 
54     // It has 5 substates
55     BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
56     BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
57     BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
58     BOOST_MSM_EUML_STATE(( Region2State1_Entry,Region2State1_Exit ),Region2State1)
59     BOOST_MSM_EUML_STATE(( Region2State2_Entry,Region2State2_Exit ),Region2State2)
60 
61     // Playing has a transition table
62    BOOST_MSM_EUML_TRANSITION_TABLE((
63         //  +------------------------------------------------------------------------------+
64             Song2         == Song1          + next_song       / start_next_song,
65             Song1         == Song2          + previous_song   / start_prev_song,
66             Song3         == Song2          + next_song       / start_next_song,
67             Song2         == Song3          + previous_song   / start_prev_song,
68             Region2State2 == Region2State1  + region2_evt
69         //  +------------------------------------------------------------------------------+
70         ),playing_transition_table )
71 
72     BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
73                                         init_ << Song1 << Region2State1 // Init State
74                                         ),Playing_)
75     // choice of back-end
76     typedef msm::back::state_machine<Playing_> Playing_type;
77     Playing_type const Playing;
78 
79     // guard conditions
BOOST_MSM_EUML_ACTION(good_disk_format)80     BOOST_MSM_EUML_ACTION(good_disk_format)
81     {
82         template <class FSM,class EVT,class SourceState,class TargetState>
83         bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
84         {
85             // to test a guard condition, let's say we understand only CDs, not DVD
86             if (evt.get_attribute(cd_type)!=DISK_CD)
87             {
88                 std::cout << "wrong disk, sorry" << std::endl;
89                 // just for logging, does not block any transition
90                 return true;
91             }
92             std::cout << "good disk" << std::endl;
93             return true;
94         }
95     };
96     // replaces the old transition table
97     BOOST_MSM_EUML_TRANSITION_TABLE((
98         Playing   == Stopped  + play        / start_playback ,
99         Playing   == Paused   + end_pause   / resume_playback,
100         //  +------------------------------------------------------------------------------+
101         Empty     == Open     + open_close  / close_drawer,
102         //  +------------------------------------------------------------------------------+
103         Open      == Empty    + open_close  / open_drawer,
104         Open      == Paused   + open_close  / stop_and_open,
105         Open      == Stopped  + open_close  / open_drawer,
106         Open      == Playing  + open_close  / stop_and_open,
107         //  +------------------------------------------------------------------------------+
108         Paused    == Playing  + pause       / pause_playback,
109         //  +------------------------------------------------------------------------------+
110         Stopped   == Playing  + stop        / stop_playback,
111         Stopped   == Paused   + stop        / stop_playback,
112         Stopped   == Empty    + cd_detected [good_disk_format &&(event_(cd_type)==Int_<DISK_CD>())]
113                         / (store_cd_info,process_(play)),
114         Stopped   == Stopped  + stop
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_ << Empty, // Init State
121                                         no_action, // Entry
122                                         no_action, // Exit
123                                         attributes_ << no_attributes_, // Attributes
124                                         configure_ << no_configure_, // configuration
125                                         Log_No_Transition // no_transition handler
126                                         ),
127                                       player_) //fsm name
128 
129     // choice of back-end
130     typedef msm::back::state_machine<player_> player;
131 
132     //
133     // Testing utilities.
134     //
135     static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
pstate(player const & p)136     void pstate(player const& p)
137     {
138         std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
139     }
140 
test()141     void test()
142     {
143         player p;
144         // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
145         p.start();
146         // note that we write open_close and not open_close(), like usual. Both are possible with eUML, but
147         // you now have less to type.
148         // go to Open, call on_exit on Empty, then action, then on_entry on Open
149         p.process_event(open_close); pstate(p);
150         p.process_event(open_close); pstate(p);
151         // will be rejected, wrong disk type
152         p.process_event(
153             cd_detected("louie, louie",DISK_DVD)); pstate(p);
154         p.process_event(
155             cd_detected("louie, louie",DISK_CD)); pstate(p);
156         // no need to call play() as the previous event does it in its action method
157         //p.process_event(play);
158 
159         // make transition happen inside it. Player has no idea about this event but it's ok.
160         p.process_event(next_song);pstate(p); //2nd song active
161         p.process_event(next_song);pstate(p);//3rd song active
162         p.process_event(previous_song);pstate(p);//2nd song active
163 
164         // at this point, Play is active
165         p.process_event(pause); pstate(p);
166 
167         // go back to Playing
168         p.process_event(end_pause);  pstate(p);
169         p.process_event(pause); pstate(p);
170         p.process_event(stop);  pstate(p);
171 
172         // event leading to the same state
173         // no action method called as none is defined in the transition table
174         p.process_event(stop);  pstate(p);
175     }
176 }
177 
main()178 int main()
179 {
180     test();
181     return 0;
182 }
183