• 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 #include <boost/msm/back/state_machine.hpp>
13 #include <boost/msm/front/euml/euml.hpp>
14 
15 #ifndef BOOST_MSM_NONSTANDALONE_TEST
16 #define BOOST_TEST_MODULE MyTest
17 #endif
18 #include <boost/test/unit_test.hpp>
19 
20 using namespace std;
21 using namespace boost::msm::front::euml;
22 namespace msm = boost::msm;
23 
24 namespace
25 {
26     // A "complicated" event type that carries some data.
27     enum DiskTypeEnum
28     {
29         DISK_CD=0,
30         DISK_DVD=1
31     };
32     // events
33     BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)34     BOOST_MSM_EUML_EVENT(end_pause)
35     BOOST_MSM_EUML_EVENT(stop)
36     BOOST_MSM_EUML_EVENT(pause)
37     BOOST_MSM_EUML_EVENT(open_close)
38     // A "complicated" event type that carries some data.
39     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
40     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
41     BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
42     BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
43 
44     //states
45     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
46     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
47 
48     BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Empty)
49     BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Open)
50     BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Stopped)
51     BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Playing)
52     BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Paused)
53 
54     //fsm
55     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
56     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
57     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,test_fct_counter)
58     BOOST_MSM_EUML_ACTION(No_Transition)
59     {
60         template <class FSM,class Event>
61         void operator()(Event const&,FSM&,int)
62         {
63             BOOST_FAIL("no_transition called!");
64         }
65     };
BOOST_MSM_EUML_ACTION(good_disk_format)66     BOOST_MSM_EUML_ACTION(good_disk_format)
67     {
68         template <class FSM,class EVT,class SourceState,class TargetState>
69         bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
70         {
71             if (evt.get_attribute(cd_type)!=DISK_CD)
72             {
73                 return false;
74             }
75             return true;
76         }
77     };
78     BOOST_MSM_EUML_TRANSITION_TABLE((
79           Playing   == Stopped  + play        / (++fsm_(start_playback_counter),++fsm_(test_fct_counter) ),
80           Playing   == Paused   + end_pause   ,
81           //  +------------------------------------------------------------------------------+
82           Empty     == Open     + open_close  / ++fsm_(can_close_drawer_counter),
83           //  +------------------------------------------------------------------------------+
84           Open      == Empty    + open_close  ,
85           Open      == Paused   + open_close  ,
86           Open      == Stopped  + open_close  ,
87           Open      == Playing  + open_close  ,
88           //  +------------------------------------------------------------------------------+
89           Paused    == Playing  + pause       ,
90           //  +------------------------------------------------------------------------------+
91           Stopped   == Playing  + stop        ,
92           Stopped   == Paused   + stop        ,
93           Stopped   == Empty    + cd_detected [good_disk_format ||
94                                                 (event_(cd_type)==Int_<DISK_CD>())] / process_(play) ,
95           Stopped   == Stopped  + stop
96           //  +------------------------------------------------------------------------------+
97          ),transition_table)
98 
99     BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
100                                         init_ << Empty, // Init State
101                                         no_action, // Entry
102                                         no_action, // Exit
103                                         attributes_ << start_playback_counter
104                                                     << can_close_drawer_counter << test_fct_counter, // Attributes
105                                         configure_ << no_configure_, // configuration
106                                         No_Transition // no_transition handler
107                                         ),
108                                       player_) //fsm name
109 
110     typedef msm::back::state_machine<player_> player;
111 
112 //    static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
113 
114 
BOOST_AUTO_TEST_CASE(my_test)115     BOOST_AUTO_TEST_CASE( my_test )
116     {
117         player p;
118 
119         p.start();
120         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 1,
121                             "Empty entry not called correctly");
122 
123         p.process_event(open_close());
124         BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Open should be active"); //Open
125         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 1,
126                             "Empty exit not called correctly");
127         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(entry_counter) == 1,
128                             "Open entry not called correctly");
129 
130         p.process_event(open_close());
131         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
132         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
133                             "Open exit not called correctly");
134         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
135                             "Empty entry not called correctly");
136         BOOST_CHECK_MESSAGE(p.get_attribute(can_close_drawer_counter) == 1,"guard not called correctly");
137 
138         p.process_event(
139             cd_detected("louie, louie",DISK_DVD));
140         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
141         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
142                             "Open exit not called correctly");
143         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
144                             "Empty entry not called correctly");
145 
146         p.process_event(
147             cd_detected("louie, louie",DISK_CD));
148         BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
149         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 2,
150                             "Empty exit not called correctly");
151         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
152                             "Stopped entry not called correctly");
153         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
154                             "Stopped exit not called correctly");
155         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 1,
156                             "Playing entry not called correctly");
157         BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
158         BOOST_CHECK_MESSAGE(p.get_attribute(test_fct_counter) == 1,"action not called correctly");
159 
160         p.process_event(pause());
161         BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
162         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 1,
163                             "Playing exit not called correctly");
164         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
165                             "Paused entry not called correctly");
166 
167         // go back to Playing
168         p.process_event(end_pause());
169         BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
170         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
171                             "Paused exit not called correctly");
172         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 2,
173                             "Playing entry not called correctly");
174 
175         p.process_event(pause());
176         BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
177         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 2,
178                             "Playing exit not called correctly");
179         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
180                             "Paused entry not called correctly");
181 
182         p.process_event(stop());
183         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
184         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
185                             "Paused exit not called correctly");
186         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
187                             "Stopped entry not called correctly");
188 
189         p.process_event(stop());
190         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
191         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
192                             "Stopped exit not called correctly");
193         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
194                             "Stopped entry not called correctly");
195     }
196 }
197 
198