• 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 using namespace boost::msm::front;
20 namespace msm = boost::msm;
21 
22 // entry/exit/action/guard logging functors
23 #include "logging_functors.h"
24 
25 namespace  // Concrete FSM implementation
26 {
27     // events
28     BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)29     BOOST_MSM_EUML_EVENT(end_pause)
30     BOOST_MSM_EUML_EVENT(stop)
31     BOOST_MSM_EUML_EVENT(pause)
32     BOOST_MSM_EUML_EVENT(open_close)
33     BOOST_MSM_EUML_EVENT(internal_event)
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 
43     // The list of FSM states
44     BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
45     BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
46     BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
47     BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
48     // state not needing any entry or exit
49     BOOST_MSM_EUML_STATE((),Paused)
50 
51     // guard conditions
52     BOOST_MSM_EUML_ACTION(good_disk_format)
53     {
54         template <class FSM,class EVT,class SourceState,class TargetState>
55         bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
56         {
57             // to test a guard condition, let's say we understand only CDs, not DVD
58             if (evt.get_attribute(cd_type)!=DISK_CD)
59             {
60                 std::cout << "wrong disk, sorry" << std::endl;
61                 // just for logging, does not block any transition
62                 return true;
63             }
64             std::cout << "good disk" << std::endl;
65             return true;
66         }
67     };
68     // replaces the old transition table
69     BOOST_MSM_EUML_TRANSITION_TABLE((
70           Playing   == Stopped  + play        / start_playback ,
71           Playing   == Paused   + end_pause   / resume_playback,
72           //  +------------------------------------------------------------------------------+
73           Empty     == Open     + open_close  / close_drawer,
74           //  +------------------------------------------------------------------------------+
75           Open      == Empty    + open_close  / open_drawer,
76           Open      == Paused   + open_close  / stop_and_open,
77           Open      == Stopped  + open_close  / open_drawer,
78           Open      == Playing  + open_close  / stop_and_open,
79           Open                  + open_close  [internal_guard1] / internal_action1,
80           Open                  + open_close  [internal_guard2] / internal_action2,
81           Open                  + internal_event / internal_action                  ,
82           //  +------------------------------------------------------------------------------+
83           Paused    == Playing  + pause       / pause_playback,
84           //  +------------------------------------------------------------------------------+
85           Stopped   == Playing  + stop        / stop_playback,
86           Stopped   == Paused   + stop        / stop_playback,
87           Stopped   == Empty    + cd_detected [good_disk_format&&
88                                                      (event_(cd_type)==Int_<DISK_CD>())]
89                                                     / (store_cd_info,process_(play)),
90           Stopped   == Stopped  + stop
91           //  +------------------------------------------------------------------------------+
92           ),transition_table)
93 
94 
95     // create a state machine "on the fly"
96     BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
97                                         init_ << Empty, // Init State
98                                         no_action, // Entry
99                                         no_action, // Exit
100                                         attributes_ << no_attributes_, // Attributes
101                                         configure_ << no_configure_, // configuration
102                                         Log_No_Transition // no_transition handler
103                                         ),
104                                       player_) //fsm name
105     // choice of back-end
106     typedef msm::back::state_machine<player_> player;
107 
108     //
109     // Testing utilities.
110     //
111     static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
pstate(player const & p)112     void pstate(player const& p)
113     {
114         std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
115     }
116 
test()117     void test()
118     {
119         player p;
120         // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
121         p.start();
122         // go to Open, call on_exit on Empty, then action, then on_entry on Open
123         p.process_event(open_close); pstate(p);
124         std::cout << "sending internal event (not rejected)" << std::endl;
125         p.process_event(internal_event);
126         std::cout << "sending open_close event. Conflict with internal transitions (rejecting event)" << std::endl;
127         p.process_event(open_close); pstate(p);
128         // will be rejected, wrong disk type
129         p.process_event(
130             cd_detected("louie, louie",DISK_DVD)); pstate(p);
131         p.process_event(
132             cd_detected("louie, louie",DISK_CD)); pstate(p);
133         // no need to call play() as the previous event does it in its action method
134         //p.process_event(play);
135 
136         // at this point, Play is active
137         p.process_event(pause); pstate(p);
138         // go back to Playing
139         p.process_event(end_pause);  pstate(p);
140         p.process_event(pause); pstate(p);
141         p.process_event(stop);  pstate(p);
142         // event leading to the same state
143         // no action method called as none is defined in the transition table
144         p.process_event(stop);  pstate(p);
145         // test call to no_transition
146         p.process_event(pause); pstate(p);
147     }
148 }
149 
main()150 int main()
151 {
152     test();
153     return 0;
154 }
155