123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- // Copyright 2010 Christophe Henry
- // henry UNDERSCORE christophe AT hotmail DOT com
- // This is an extended version of the state machine available in the boost::mpl library
- // Distributed under the same license as the original.
- // Copyright for the original version:
- // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
- // under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #include <vector>
- #include <set>
- #include <string>
- #include <iostream>
- #define FUSION_MAX_VECTOR_SIZE 20
- #include "boost/mpl/vector/vector50.hpp"
- #include <boost/msm/back/state_machine.hpp>
- #include <boost/msm/front/state_machine_def.hpp>
- #include "Events.hpp"
- #include "PlayingMode.hpp"
- #include "MenuMode.hpp"
- using namespace std;
- namespace msm = boost::msm;
- namespace // Concrete FSM implementation
- {
- struct iPod_;
- typedef msm::back::state_machine<iPod_,
- ::boost::msm::back::favor_compile_time> iPod;
- // Concrete FSM implementation
- struct iPod_ : public msm::front::state_machine_def<iPod_>
- {
- // The list of FSM states
- struct NotHolding : public msm::front::state<>
- {
- template <class Event,class FSM>
- void on_entry(Event const&,FSM& ) {std::cout << "starting: NotHolding" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotHolding" << std::endl;}
- };
- struct Holding : public msm::front::interrupt_state<NoHold>
- {
- template <class Event,class FSM>
- void on_entry(Event const&,FSM& ) {std::cout << "starting: Holding" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "finishing: Holding" << std::endl;}
- };
- struct NotPlaying : public msm::front::state<>
- {
- template <class Event,class FSM>
- void on_entry(Event const&,FSM& ) {std::cout << "starting: NotPlaying" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotPlaying" << std::endl;}
- };
- struct NoMenuMode : public msm::front::state<>
- {
- template <class Event,class FSM>
- void on_entry(Event const&,FSM& ) {std::cout << "starting: NoMenuMode" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoMenuMode" << std::endl;}
- };
- struct NoOnOffButton : public msm::front::state<>
- {
- template <class Event,class FSM>
- void on_entry(Event const&,FSM& ) {std::cout << "starting: NoOnOffButton" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoOnOffButton" << std::endl;}
- };
- struct OffDown : public msm::front::state<>
- {
- template <class Event,class FSM>
- void on_entry(Event const&,FSM& ) {std::cout << "starting: OffDown, start timer" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "finishing: OffDown, end timer" << std::endl;}
- };
- struct PlayerOff : public msm::front::state<>
- {
- template <class Event,class FSM>
- void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayerOff" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayerOff" << std::endl;}
- };
- struct CheckMiddleButton : public msm::front::state<>
- {
- template <class Event,class FSM>
- void on_entry(Event const&,FSM& ) {std::cout << "starting: CheckMiddleButton" << std::endl;}
- template <class Event,class FSM>
- void on_exit(Event const&,FSM& ) {std::cout << "finishing: CheckMiddleButton" << std::endl;}
- };
- // the initial state of the player SM. Must be defined
- typedef mpl::vector5<NotHolding,NotPlaying,NoMenuMode,NoOnOffButton,CheckMiddleButton>
- initial_state;
- // transition actions
- void send_ActivateMenu(EndPlay const&)
- {
- std::cout << "leaving Playing" << std::endl;
- // we need to activate the menu and simulate its button
- (static_cast<iPod*>(this))->process_event(MenuButton());
- }
- void send_StartSong(CloseMenu const&)
- {
- // we suppose the 5th song was selected
- (static_cast<iPod*>(this))->process_event(StartSong(5));
- }
- void send_PlayPause(SouthReleased const&)
- {
- // action using the message queue to generate another event
- (static_cast<iPod*>(this))->process_event(PlayPause());
- }
- void send_Off(OnOffTimer const&)
- {
- std::cout << "turning player off" << std::endl;
- (static_cast<iPod*>(this))->process_event(Off());
- }
- void send_PlayingMiddleButton(MiddleButton const&)
- {
- (static_cast<iPod*>(this))->process_event(PlayingMiddleButton());
- }
- void send_MenuMiddleButton(MiddleButton const&)
- {
- (static_cast<iPod*>(this))->process_event(MenuMiddleButton());
- }
- // guard conditions
- bool is_menu(MiddleButton const&)
- {
- return (static_cast<iPod*>(this))->is_flag_active<MenuActive>();
- }
- bool is_no_menu(MiddleButton const& evt)
- {
- return !is_menu(evt);
- }
- template <class EVENT>
- void switch_on(EVENT const&)
- {
- std::cout << "turning player on" << std::endl;
- }
- typedef iPod_ fsm; // makes transition table cleaner
- // Transition table for player
- struct transition_table : mpl::vector<
- // Start Event Next Action Guard
- // +-------------------+---------------+-------------------+--------------------------------+----------------------+
- _row < NotHolding , Hold , Holding >,
- _row < Holding , NoHold , NotHolding >,
- // +-------------------+---------------+-------------------+--------------------------------+----------------------+
- _row < NotPlaying , PlayPause , PlayingMode >,
- a_row < PlayingMode::exit_pt<PlayingMode_::
- PlayingExit> , EndPlay , NotPlaying , &fsm::send_ActivateMenu >,
- // +-------------------+---------------+-------------------+--------------------------------+----------------------+
- _row < NoMenuMode , MenuButton , MenuMode >,
- a_row < MenuMode::exit_pt<MenuMode_::
- MenuExit> , CloseMenu , NoMenuMode , &fsm::send_StartSong >,
- // +-------------------+---------------+-------------------+--------------------------------+----------------------+
- _row < NoOnOffButton , SouthPressed , OffDown >,
- a_row < OffDown , SouthReleased , NoOnOffButton , &fsm::send_PlayPause >,
- a_row < OffDown , OnOffTimer , PlayerOff , &fsm::send_Off >,
- a_row < PlayerOff , SouthPressed , NoOnOffButton , &fsm::switch_on >,
- a_row < PlayerOff , NoHold , NoOnOffButton , &fsm::switch_on >,
- // +-------------------+---------------+--------------------+--------------------------------+----------------------+
- row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_PlayingMiddleButton , &fsm::is_menu >,
- row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_MenuMiddleButton , &fsm::is_no_menu >
- // +-------------------+---------------+--------------------+--------------------------------+----------------------+
- > {};
-
- // 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;
- }
- };
-
- void test()
- {
- iPod sm;
- sm.start();
- // we first press Hold
- std::cout << "pressing hold" << std::endl;
- sm.process_event(Hold());
- // pressing a button is now ignored
- std::cout << "pressing a button" << std::endl;
- sm.process_event(SouthPressed());
- // or even one contained in a submachine
- sm.process_event(EastPressed());
- // no more holding
- std::cout << "no more holding, end interrupt event sent" << std::endl;
- sm.process_event(NoHold());
- std::cout << "pressing South button a short time" << std::endl;
- sm.process_event(SouthPressed());
- // we suppose a short pressing leading to playing a song
- sm.process_event(SouthReleased());
- // we move to the next song
- std::cout << "we move to the next song" << std::endl;
- sm.process_event(NextSong());
- // then back to no song => exit from playing, menu active
- std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl;
- sm.process_event(PreviousSong());
- sm.process_event(PreviousSong());
- // even in menu mode, pressing play will start playing the first song
- std::cout << "pressing play/pause" << std::endl;
- sm.process_event(SouthPressed());
- sm.process_event(SouthReleased());
- // of course pausing must be possible
- std::cout << "pressing play/pause" << std::endl;
- sm.process_event(SouthPressed());
- sm.process_event(SouthReleased());
- std::cout << "pressing play/pause" << std::endl;
- sm.process_event(SouthPressed());
- sm.process_event(SouthReleased());
- // while playing, you can fast forward
- std::cout << "pressing East button a long time" << std::endl;
- sm.process_event(EastPressed());
- // let's suppose the timer just fired
- sm.process_event(ForwardTimer());
- sm.process_event(ForwardTimer());
- // end of fast forwarding
- std::cout << "releasing East button" << std::endl;
- sm.process_event(EastReleased());
- // we now press the middle button to set playing at a given position
- std::cout << "pressing Middle button, fast forwarding disabled" << std::endl;
- sm.process_event(MiddleButton());
- std::cout <<"pressing East button to fast forward" << std::endl;
- sm.process_event(EastPressed());
- // we switch off and on
- std::cout <<"switch off player" << std::endl;
- sm.process_event(SouthPressed());
- sm.process_event(OnOffTimer());
- std::cout <<"switch on player" << std::endl;
- sm.process_event(SouthPressed());
- }
- }
- int main()
- {
- test();
- return 0;
- }
|