• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <iostream>
2 // back-end
3 #include <boost/msm/back/state_machine.hpp>
4 //front-end
5 #include <boost/msm/front/state_machine_def.hpp>
6 
7 // include headers that implement a archive in simple text format
8 #include <boost/archive/text_oarchive.hpp>
9 #include <boost/archive/text_iarchive.hpp>
10 #include <boost/serialization/tracking.hpp>
11 
12 #include <fstream>
13 
14 
15 namespace msm = boost::msm;
16 namespace mpl = boost::mpl;
17 
18 
19 namespace
20 {
21     // events
22     struct play {};
23     struct end_pause {};
24     struct stop {};
25     struct pause {};
26     struct open_close {};
27 
28     // A "complicated" event type that carries some data.
29 	enum DiskTypeEnum
30     {
31         DISK_CD=0,
32         DISK_DVD=1
33     };
34     struct cd_detected
35     {
cd_detected__anon7be274820111::cd_detected36         cd_detected(std::string name, DiskTypeEnum diskType)
37             : name(name),
38             disc_type(diskType)
39         {}
40 
41         std::string name;
42         DiskTypeEnum disc_type;
43     };
44 
45     // front-end: define the FSM structure
46     struct player_ : public msm::front::state_machine_def<player_>
47     {
48         //we might want to serialize some data contained by the front-end
49         int front_end_data;
player___anon7be274820111::player_50         player_():front_end_data(0){}
51         // to achieve this, ask for it
52         typedef int do_serialize;
53         // and provide a serialize
54         template<class Archive>
serialize__anon7be274820111::player_55         void serialize(Archive & ar, const unsigned int )
56         {
57             ar & front_end_data;
58         }
59         // The list of FSM states
60         struct Empty : public msm::front::state<>
61         {
62             // we want Empty to be serialized
63             typedef int do_serialize;
64             template<class Archive>
serialize__anon7be274820111::player_::Empty65             void serialize(Archive & ar, const unsigned int )
66             {
67                 ar & some_dummy_data;
68             }
Empty__anon7be274820111::player_::Empty69             Empty():some_dummy_data(0){}
70             // every (optional) entry/exit methods get the event passed.
71             template <class Event,class FSM>
on_entry__anon7be274820111::player_::Empty72             void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
73             template <class Event,class FSM>
on_exit__anon7be274820111::player_::Empty74             void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
75             int some_dummy_data;
76         };
77         struct Open : public msm::front::state<>
78         {
79             template <class Event,class FSM>
on_entry__anon7be274820111::player_::Open80             void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
81             template <class Event,class FSM>
on_exit__anon7be274820111::player_::Open82             void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
83         };
84 
85         // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
86         struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
87         {
88             template <class Event,class FSM>
on_entry__anon7be274820111::player_::Stopped89             void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
90             template <class Event,class FSM>
on_exit__anon7be274820111::player_::Stopped91             void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
set_sm_ptr__anon7be274820111::player_::Stopped92             void set_sm_ptr(player_* pl)
93             {
94                 m_player=pl;
95             }
96             player_* m_player;
97         };
98 
99         struct Playing : public msm::front::state<>
100         {
101             template <class Event,class FSM>
on_entry__anon7be274820111::player_::Playing102             void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
103             template <class Event,class FSM>
on_exit__anon7be274820111::player_::Playing104             void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
105         };
106 
107         // state not defining any entry or exit
108         struct Paused : public msm::front::state<>
109         {
110         };
111 
112         // the initial state of the player SM. Must be defined
113         typedef Empty initial_state;
114 
115         // transition actions
start_playback__anon7be274820111::player_116         void start_playback(play const&)       { std::cout << "player::start_playback\n"; }
open_drawer__anon7be274820111::player_117         void open_drawer(open_close const&)    { std::cout << "player::open_drawer\n"; }
close_drawer__anon7be274820111::player_118         void close_drawer(open_close const&)   { std::cout << "player::close_drawer\n"; }
store_cd_info__anon7be274820111::player_119         void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; }
stop_playback__anon7be274820111::player_120         void stop_playback(stop const&)        { std::cout << "player::stop_playback\n"; }
pause_playback__anon7be274820111::player_121         void pause_playback(pause const&)      { std::cout << "player::pause_playback\n"; }
resume_playback__anon7be274820111::player_122         void resume_playback(end_pause const&)      { std::cout << "player::resume_playback\n"; }
stop_and_open__anon7be274820111::player_123         void stop_and_open(open_close const&)  { std::cout << "player::stop_and_open\n"; }
stopped_again__anon7be274820111::player_124         void stopped_again(stop const&)	{std::cout << "player::stopped_again\n";}
125         // guard conditions
good_disk_format__anon7be274820111::player_126         bool good_disk_format(cd_detected const& evt)
127         {
128             // to test a guard condition, let's say we understand only CDs, not DVD
129             if (evt.disc_type != DISK_CD)
130             {
131                 std::cout << "wrong disk, sorry" << std::endl;
132                 return false;
133             }
134             return true;
135         }
136         // used to show a transition conflict. This guard will simply deactivate one transition and thus
137         // solve the conflict
auto_start__anon7be274820111::player_138         bool auto_start(cd_detected const&)
139         {
140             return false;
141         }
142 
143         typedef player_ p; // makes transition table cleaner
144 
145         // Transition table for player
146         struct transition_table : mpl::vector<
147             //    Start     Event         Next      Action				 Guard
148             //  +---------+-------------+---------+---------------------+----------------------+
149           a_row < Stopped , play        , Playing , &p::start_playback                         >,
150           a_row < Stopped , open_close  , Open    , &p::open_drawer                            >,
151            _row < Stopped , stop        , Stopped                                              >,
152             //  +---------+-------------+---------+---------------------+----------------------+
153           a_row < Open    , open_close  , Empty   , &p::close_drawer                           >,
154             //  +---------+-------------+---------+---------------------+----------------------+
155           a_row < Empty   , open_close  , Open    , &p::open_drawer                            >,
156             row < Empty   , cd_detected , Stopped , &p::store_cd_info   ,&p::good_disk_format  >,
157             row < Empty   , cd_detected , Playing , &p::store_cd_info   ,&p::auto_start        >,
158             //  +---------+-------------+---------+---------------------+----------------------+
159           a_row < Playing , stop        , Stopped , &p::stop_playback                          >,
160           a_row < Playing , pause       , Paused  , &p::pause_playback                         >,
161           a_row < Playing , open_close  , Open    , &p::stop_and_open                          >,
162             //  +---------+-------------+---------+---------------------+----------------------+
163           a_row < Paused  , end_pause   , Playing , &p::resume_playback                        >,
164           a_row < Paused  , stop        , Stopped , &p::stop_playback                          >,
165           a_row < Paused  , open_close  , Open    , &p::stop_and_open                          >
166             //  +---------+-------------+---------+---------------------+----------------------+
167         > {};
168         // Replaces the default no-transition response.
169         template <class FSM,class Event>
no_transition__anon7be274820111::player_170         void no_transition(Event const& e, FSM&,int state)
171         {
172             std::cout << "no transition from state " << state
173                 << " on event " << typeid(e).name() << std::endl;
174         }
175     };
176     // Pick a back-end
177     typedef msm::back::state_machine<player_> player;
178 
179     //
180     // Testing utilities.
181     //
182     static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
pstate(player const & p)183     void pstate(player const& p)
184     {
185         std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
186     }
187 
test()188     void test()
189     {
190 		player p;
191         // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
192         p.start();
193         p.get_state<player_::Empty&>().some_dummy_data=3;
194         p.front_end_data=4;
195 
196         // go to Open, call on_exit on Empty, then action, then on_entry on Open
197         p.process_event(open_close()); pstate(p);
198 
199         std::ofstream ofs("fsm.txt");
200         // save fsm to archive (current state is Open)
201         {
202             boost::archive::text_oarchive oa(ofs);
203             // write class instance to archive
204             oa << p;
205         }
206         // reload fsm in state Open
207         player p2;
208         {
209             // create and open an archive for input
210             std::ifstream ifs("fsm.txt");
211             boost::archive::text_iarchive ia(ifs);
212             // read class state from archive
213             ia >> p2;
214         }
215         // we now use p2 as it was loaded
216         // check that we kept Empty's data value
217         std::cout << "Empty's data should be 3:" << p2.get_state<player_::Empty&>().some_dummy_data << std::endl;
218         std::cout << "front-end data should be 4:" << p2.front_end_data << std::endl;
219 
220         p2.process_event(open_close()); pstate(p2);
221         // will be rejected, wrong disk type
222         p2.process_event(
223             cd_detected("louie, louie",DISK_DVD)); pstate(p2);
224         p2.process_event(
225             cd_detected("louie, louie",DISK_CD)); pstate(p2);
226 		p2.process_event(play());
227 
228         // at this point, Play is active
229         p2.process_event(pause()); pstate(p2);
230         // go back to Playing
231         p2.process_event(end_pause());  pstate(p2);
232         p2.process_event(pause()); pstate(p2);
233         p2.process_event(stop());  pstate(p2);
234         // event leading to the same state
235         // no action method called as it is not present in the transition table
236         p2.process_event(stop());  pstate(p2);
237     }
238 }
239 // eliminate object tracking (even if serialized through a pointer)
240 // at the risk of a programming error creating duplicate objects.
241 // this is to get rid of warning because p is not const
BOOST_CLASS_TRACKING(player,boost::serialization::track_never)242 BOOST_CLASS_TRACKING(player, boost::serialization::track_never)
243 
244 int main()
245 {
246     test();
247     return 0;
248 }
249