• 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 <boost/msm/back/state_machine.hpp>
12 #include <boost/msm/front/state_machine_def.hpp>
13 
14 namespace msm = boost::msm;
15 namespace mpl = boost::mpl;
16 
17 #include <iostream>
18 #ifdef WIN32
19 #include "windows.h"
20 #else
21 #include <sys/time.h>
22 #endif
23 
24 namespace test_fsm // Concrete FSM implementation
25 {
26     // events
27     struct play {};
28     struct end_pause {};
29     struct stop {};
30     struct pause {};
31     struct open_close {};
32     struct cd_detected{};
33     struct NextSong {};
34     struct PreviousSong {};
35 
36 
37     // Concrete FSM implementation
38     struct player_ : public msm::front::state_machine_def<player_>
39     {
40         // no need for exception handling or message queue
41         typedef int no_exception_thrown;
42         typedef int no_message_queue;
43 
44         // The list of FSM states
45         struct Empty : public msm::front::state<>
46         {
47             // optional entry/exit methods
48             template <class Event,class FSM>
on_entrytest_fsm::player_::Empty49             void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
50             template <class Event,class FSM>
on_exittest_fsm::player_::Empty51             void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
52         };
53         struct Open : public msm::front::state<>
54         {
55             template <class Event,class FSM>
on_entrytest_fsm::player_::Open56             void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
57             template <class Event,class FSM>
on_exittest_fsm::player_::Open58             void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
59         };
60 
61         struct Stopped : public msm::front::state<>
62         {
63             // when stopped, the CD is loaded
64             template <class Event,class FSM>
on_entrytest_fsm::player_::Stopped65             void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
66             template <class Event,class FSM>
on_exittest_fsm::player_::Stopped67             void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
68         };
69 
70         struct Playing_ : public msm::front::state_machine_def<Playing_>
71         {
72             // no need for exception handling or message queue
73             typedef int no_exception_thrown;
74             typedef int no_message_queue;
75 
76             // The list of FSM states
77             struct Song1 : public msm::front::state<> {};
78             struct Song2 : public msm::front::state<> {};
79             struct Song3 : public msm::front::state<> {};
80             // the initial state. Must be defined
81             typedef Song1 initial_state;
82             // transition actions
start_next_songtest_fsm::player_::Playing_83             void start_next_song(NextSong const&)       { /*std::cout << "Playing::start_next_song\n";*/ }
start_prev_songtest_fsm::player_::Playing_84             void start_prev_song(PreviousSong const&)       { /*std::cout << "Playing::start_prev_song\n"; */}
85             // guard conditions
86 
87             typedef Playing_ pl; // makes transition table cleaner
88             // Transition table for Playing
89             struct transition_table : mpl::vector4<
90                 //    Start     Event         Next      Action                 Guard
91                 //    +---------+-------------+---------+---------------------+----------------------+
92                 a_row < Song1   , NextSong    , Song2   , &pl::start_next_song                     >,
93                 a_row < Song2   , PreviousSong, Song1   , &pl::start_prev_song                     >,
94                 a_row < Song2   , NextSong    , Song3   , &pl::start_next_song                     >,
95                 a_row < Song3   , PreviousSong, Song2   , &pl::start_prev_song                     >
96                 //    +---------+-------------+---------+---------------------+----------------------+
97             > {};
98             // Replaces the default no-transition response.
99             template <class FSM,class Event>
no_transitiontest_fsm::player_::Playing_100             void no_transition(Event const& e, FSM&,int state)
101             {
102                 std::cout << "no transition from state " << state
103                     << " on event " << typeid(e).name() << std::endl;
104             }
105         };
106         typedef msm::back::state_machine<Playing_> Playing;
107 
108         // state not defining any entry or exit
109         struct Paused : public msm::front::state<>
110         {
111             template <class Event,class FSM>
on_entrytest_fsm::player_::Paused112             void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
113             template <class Event,class FSM>
on_exittest_fsm::player_::Paused114             void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
115         };
116 
117         // the initial state of the player SM. Must be defined
118         typedef Empty initial_state;
119 
120         // transition actions
start_playbacktest_fsm::player_121         void start_playback(play const&)       {  }
open_drawertest_fsm::player_122         void open_drawer(open_close const&)    {  }
close_drawertest_fsm::player_123         void close_drawer(open_close const&)   {  }
store_cd_infotest_fsm::player_124         void store_cd_info(cd_detected const& cd) { }
stop_playbacktest_fsm::player_125         void stop_playback(stop const&)        {  }
pause_playbacktest_fsm::player_126         void pause_playback(pause const&)      { }
resume_playbacktest_fsm::player_127         void resume_playback(end_pause const&)      {  }
stop_and_opentest_fsm::player_128         void stop_and_open(open_close const&)  {  }
stopped_againtest_fsm::player_129         void stopped_again(stop const&){}
130         // guard conditions
131 
132         typedef player_ p; // makes transition table cleaner
133 
134         // Transition table for player
135         struct transition_table : mpl::vector<
136             //    Start     Event         Next      Action                 Guard
137             //    +---------+-------------+---------+---------------------+----------------------+
138             a_row < Stopped , play        , Playing , &p::start_playback                       >,
139             a_row < Stopped , open_close  , Open    , &p::open_drawer                          >,
140             a_row < Stopped , stop        , Stopped , &p::stopped_again                        >,
141             //    +---------+-------------+---------+---------------------+----------------------+
142             a_row < Open    , open_close  , Empty   , &p::close_drawer                         >,
143             //    +---------+-------------+---------+---------------------+----------------------+
144             a_row < Empty   , open_close  , Open    , &p::open_drawer                          >,
145             a_row < Empty   , cd_detected , Stopped , &p::store_cd_info                        >,
146             //    +---------+-------------+---------+---------------------+----------------------+
147             a_row < Playing , stop        , Stopped , &p::stop_playback                        >,
148             a_row < Playing , pause       , Paused  , &p::pause_playback                       >,
149             a_row < Playing , open_close  , Open    , &p::stop_and_open                        >,
150             //    +---------+-------------+---------+---------------------+----------------------+
151             a_row < Paused  , end_pause   , Playing , &p::resume_playback                      >,
152             a_row < Paused  , stop        , Stopped , &p::stop_playback                        >,
153             a_row < Paused  , open_close  , Open    , &p::stop_and_open                        >
154             //    +---------+-------------+---------+---------------------+----------------------+
155         > {};
156 
157         // Replaces the default no-transition response.
158         template <class FSM,class Event>
no_transitiontest_fsm::player_159         void no_transition(Event const& e, FSM&,int state)
160         {
161             std::cout << "no transition from state " << state
162                 << " on event " << typeid(e).name() << std::endl;
163         }
164     };
165     typedef msm::back::state_machine<player_> player;
166 
167     //
168     // Testing utilities.
169     //
170     static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
171 
pstate(player const & p)172     void pstate(player const& p)
173     {
174         std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
175     }
176 
177 }
178 
179 #ifndef WIN32
mtime(struct timeval & tv1,struct timeval & tv2)180 long mtime(struct timeval& tv1,struct timeval& tv2)
181 {
182     return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
183 }
184 #endif
185 
186 
main()187 int main()
188 {
189     // for timing
190 #ifdef WIN32
191     LARGE_INTEGER res;
192     ::QueryPerformanceFrequency(&res);
193     LARGE_INTEGER li,li2;
194 #else
195     struct timeval tv1,tv2;
196     gettimeofday(&tv1,NULL);
197 #endif
198 
199     test_fsm::player p2;
200     p2.start();
201     // for timing
202 #ifdef WIN32
203     ::QueryPerformanceCounter(&li);
204 #else
205     gettimeofday(&tv1,NULL);
206 #endif
207     for (int i=0;i<100;++i)
208     {
209         p2.process_event(test_fsm::open_close());
210         p2.process_event(test_fsm::open_close());
211         p2.process_event(test_fsm::cd_detected());
212         p2.process_event(test_fsm::play());
213         for (int j=0;j<100;++j)
214         {
215             p2.process_event(test_fsm::NextSong());
216             p2.process_event(test_fsm::NextSong());
217             p2.process_event(test_fsm::PreviousSong());
218             p2.process_event(test_fsm::PreviousSong());
219         }
220 
221         p2.process_event(test_fsm::pause());
222         // go back to Playing
223         p2.process_event(test_fsm::end_pause());
224         p2.process_event(test_fsm::pause());
225         p2.process_event(test_fsm::stop());
226         // event leading to the same state
227         p2.process_event(test_fsm::stop());
228         p2.process_event(test_fsm::open_close());
229         p2.process_event(test_fsm::open_close());
230     }
231 #ifdef WIN32
232     ::QueryPerformanceCounter(&li2);
233 #else
234     gettimeofday(&tv2,NULL);
235 #endif
236 #ifdef WIN32
237     std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
238 #else
239     std::cout << "msm took in us:" <<  mtime(tv1,tv2) <<"\n" <<std::endl;
240 #endif
241     return 0;
242 }
243 
244