123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- #include <iostream>
- // back-end
- #include <boost/msm/back/state_machine.hpp>
- //front-end
- #include <boost/msm/front/state_machine_def.hpp>
- #include <boost/msm/front/euml/euml.hpp>
- namespace msm = boost::msm;
- namespace mpl = boost::mpl;
- using namespace std;
- // entry/exit/action/guard logging functors
- #include "logging_functors.h"
- namespace
- {
- // events
- struct play_impl : msm::front::euml::euml_event<play_impl> {};
- struct end_pause_impl : msm::front::euml::euml_event<end_pause_impl>{};
- struct stop_impl : msm::front::euml::euml_event<stop_impl>{};
- struct pause_impl : msm::front::euml::euml_event<pause_impl>{};
- struct open_close_impl : msm::front::euml::euml_event<open_close_impl>{};
- struct cd_detected_impl : msm::front::euml::euml_event<cd_detected_impl>{};
- struct next_song_impl : msm::front::euml::euml_event<next_song_impl>{};
- struct previous_song_impl : msm::front::euml::euml_event<previous_song_impl>{};
- // define some dummy instances for use in the transition table
- // it is also possible to default-construct them instead:
- // struct play {};
- // inside the table: play()
- play_impl play;
- end_pause_impl end_pause;
- stop_impl stop;
- pause_impl pause;
- open_close_impl open_close;
- cd_detected_impl cd_detected;
- next_song_impl next_song;
- previous_song_impl previous_song;
- // The list of FSM states
- // they have to be declared outside of the front-end only to make VC happy :(
- // note: gcc would have no problem
- struct Empty_impl : public msm::front::state<> , public msm::front::euml::euml_state<Empty_impl>
- {
- // every (optional) entry/exit methods get the event passed.
- template <class Event,class FSM>
- void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
- };
- struct Open_impl : public msm::front::state<> , public msm::front::euml::euml_state<Open_impl>
- {
- template <class Event,class FSM>
- void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
- };
- struct Stopped_impl : public msm::front::state<> , public msm::front::euml::euml_state<Stopped_impl>
- {
- template <class Event,class FSM>
- void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
- };
- // Playing Submachine front-end
- struct Playing_ : public msm::front::state_machine_def<Playing_>
- {
- template <class Event,class FSM>
- void on_entry(Event const& ,FSM&) {std::cout << "entering: Playing" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
- struct Song1_ : public msm::front::state<> , public msm::front::euml::euml_state<Song1_>
- {
- template <class Event,class FSM>
- void on_entry(Event const& ,FSM&) {std::cout << "entering: Song1" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "leaving: Song1" << std::endl;}
- };
- struct Song2_ : public msm::front::state<> , public msm::front::euml::euml_state<Song2_>
- {
- template <class Event,class FSM>
- void on_entry(Event const& ,FSM&) {std::cout << "entering: Song2" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "leaving: Song2" << std::endl;}
- };
- struct Song3_ : public msm::front::state<> , public msm::front::euml::euml_state<Song3_>
- {
- template <class Event,class FSM>
- void on_entry(Event const& ,FSM&) {std::cout << "entering: Song3" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "leaving: Song3" << std::endl;}
- };
- // to make the transition table more readable
- // VC seems to need them static
- static Song1_ Song1;
- static Song2_ Song2;
- static Song3_ Song3;
- typedef Song1_ initial_state;
- // Playing has a transition table
- BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
- // +------------------------------------------------------------------------------+
- Song2 == Song1 + next_song / start_next_song,
- Song1 == Song2 + previous_song / start_prev_song,
- Song3 == Song2 + next_song / start_next_song,
- Song2 == Song3 + previous_song / start_prev_song
- // +------------------------------------------------------------------------------+
- ),transition_table )
- };
- // Playing Submachine back-end
- typedef boost::msm::back::state_machine<Playing_> Playing_impl;
- // state not defining any entry or exit
- struct Paused_impl : public msm::front::state<> , public msm::front::euml::euml_state<Paused_impl>
- {
- };
- //to make the transition table more readable
- Empty_impl const Empty;
- Open_impl const Open;
- Stopped_impl const Stopped;
- Playing_impl const Playing;
- Paused_impl const Paused;
- // front-end: define the FSM structure
- struct player_ : public msm::front::state_machine_def<player_>
- {
- // the initial state of the player SM. Must be defined
- typedef Empty_impl initial_state;
- // Transition table for player
- // replaces the old transition table
- BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
- Stopped + play / start_playback == Playing ,
- Stopped + open_close / open_drawer == Open ,
- Stopped + stop == Stopped ,
- // +------------------------------------------------------------------------------+
- Open + open_close / close_drawer == Empty ,
- // +------------------------------------------------------------------------------+
- Empty + open_close / open_drawer == Open ,
- Empty + cd_detected /(store_cd_info,
- msm::front::euml::process_(play)) == Stopped ,
- // +------------------------------------------------------------------------------+
- Playing + stop / stop_playback == Stopped ,
- Playing + pause / pause_playback == Paused ,
- Playing + open_close / stop_and_open == Open ,
- // +------------------------------------------------------------------------------+
- Paused + end_pause / resume_playback == Playing ,
- Paused + stop / stop_playback == Stopped ,
- Paused + open_close / stop_and_open == Open
- // +------------------------------------------------------------------------------+
- ),transition_table)
- // Replaces the default no-transition response.
- template <class FSM,class Event>
- void no_transition(Event const& e, FSM&,int state)
- {
- std::cout << "no transition from state " << state
- << " on event " << typeid(e).name() << std::endl;
- }
- };
- // Pick a back-end
- typedef msm::back::state_machine<player_> player;
- //
- // Testing utilities.
- //
- static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
- void pstate(player const& p)
- {
- std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
- }
- void test()
- {
- player p;
- // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
- p.start();
- // go to Open, call on_exit on Empty, then action, then on_entry on Open
- p.process_event(open_close); pstate(p);
- p.process_event(open_close); pstate(p);
- p.process_event(cd_detected); pstate(p);
- // at this point, Play is active
- // make transition happen inside it. Player has no idea about this event but it's ok.
- p.process_event(next_song);pstate(p); //2nd song active
- p.process_event(next_song);pstate(p);//3rd song active
- p.process_event(previous_song);pstate(p);//2nd song active
- p.process_event(pause); pstate(p);
- // go back to Playing
- p.process_event(end_pause); pstate(p);
- p.process_event(pause); pstate(p);
- p.process_event(stop); pstate(p);
- // event leading to the same state
- // no action method called as it is not present in the transition table
- p.process_event(stop); pstate(p);
- }
- }
- int main()
- {
- test();
- return 0;
- }
|