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