// 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 #include #include #include // we need more than the default 20 states #define FUSION_MAX_VECTOR_SIZE 20 // we need more than the default 20 transitions #include "boost/mpl/vector/vector50.hpp" #include #include using namespace std; using namespace boost::msm::front::euml; namespace msm = boost::msm; // attribute names and types BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_Selected) BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_SongIndex) BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_NumberOfSongs) #include "ipod_functors.hpp" namespace // Concrete FSM implementation { //flags BOOST_MSM_EUML_FLAG(MenuActive) BOOST_MSM_EUML_FLAG(NoFastFwd) // hardware-generated events BOOST_MSM_EUML_EVENT(Hold) BOOST_MSM_EUML_EVENT(NoHold) BOOST_MSM_EUML_EVENT(SouthPressed) BOOST_MSM_EUML_EVENT(SouthReleased) BOOST_MSM_EUML_EVENT(MiddleButton) BOOST_MSM_EUML_EVENT(EastPressed) BOOST_MSM_EUML_EVENT(EastReleased) BOOST_MSM_EUML_EVENT(Off) BOOST_MSM_EUML_EVENT(MenuButton) // internally defined events BOOST_MSM_EUML_EVENT(PlayPause) BOOST_MSM_EUML_EVENT(EndPlay) struct CloseMenu_impl : euml_event { CloseMenu_impl(){}//defined only for stt template CloseMenu_impl(EVENT const &) {} }; CloseMenu_impl const CloseMenu; BOOST_MSM_EUML_EVENT(OnOffTimer) BOOST_MSM_EUML_EVENT(MenuMiddleButton) BOOST_MSM_EUML_EVENT(SelectSong) BOOST_MSM_EUML_EVENT(SongFinished) BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_Selected ), StartSongAttributes) BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(StartSong,StartSongAttributes) BOOST_MSM_EUML_EVENT(PreviousSong) BOOST_MSM_EUML_EVENT(NextSong) BOOST_MSM_EUML_EVENT(ForwardTimer) BOOST_MSM_EUML_EVENT(PlayingMiddleButton) // Concrete iPod implementation // The list of iPod states BOOST_MSM_EUML_STATE(( NotHolding_Entry ),NotHolding) BOOST_MSM_EUML_INTERRUPT_STATE(( NoHold,Holding_Entry ),Holding) BOOST_MSM_EUML_STATE(( NotPlaying_Entry ),NotPlaying) BOOST_MSM_EUML_STATE(( NoMenuMode_Entry ),NoMenuMode) BOOST_MSM_EUML_STATE(( NoOnOffButton_Entry ),NoOnOffButton) BOOST_MSM_EUML_STATE(( OffDown_Entry ),OffDown) BOOST_MSM_EUML_STATE(( PlayerOff_Entry ),PlayerOff) BOOST_MSM_EUML_STATE(( CheckMiddleButton_Entry ),CheckMiddleButton) // Concrete PlayingMode_ implementation // The list of PlayingMode_ states BOOST_MSM_EUML_STATE(( Playing_Entry ),Playing) BOOST_MSM_EUML_STATE(( WaitingForNextPrev_Entry ),WaitingForNextPrev) BOOST_MSM_EUML_STATE(( Paused_Entry ),Paused) BOOST_MSM_EUML_STATE(( WaitingForEnd_Entry ),WaitingForEnd) BOOST_MSM_EUML_STATE(( NoForward_Entry ),NoForward) BOOST_MSM_EUML_STATE(( ForwardPressed_Entry,ForwardPressed_Exit ),ForwardPressed) BOOST_MSM_EUML_STATE(( FastForward_Entry,FastForward_Exit ),FastForward) BOOST_MSM_EUML_STATE(( StdDisplay_Entry ),StdDisplay) BOOST_MSM_EUML_STATE(( SetPosition_Entry ),SetPosition) BOOST_MSM_EUML_STATE(( SetMark_Entry ),SetMark) BOOST_MSM_EUML_EXIT_STATE(( EndPlay,PlayingExit_Entry ),PlayingExit) //stt BOOST_MSM_EUML_TRANSITION_TABLE(( // +------------------------------------------------------------------------------+ Paused == Playing + PlayPause , Paused == Playing + Off , Playing == Playing + StartSong / (if_then_(event_(m_Selected) > Int_<0>() && event_(m_Selected) < fsm_(m_NumberOfSongs), fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song) , Playing == Playing + SongFinished / (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs), /*if*/ show_playing_song, /*then*/ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay))/*else*/ ) ) , Playing == Paused + PlayPause , Playing == Paused + StartSong / (if_then_(event_(m_Selected) > Int_<0>() && event_(m_Selected) < fsm_(m_NumberOfSongs), fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song) , WaitingForNextPrev == WaitingForNextPrev+ PreviousSong /( if_then_else_(--fsm_(m_SongIndex) > Int_<0>(), /*if*/ show_playing_song, /*then*/ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay)) /*else*/ ) ) , WaitingForNextPrev == WaitingForNextPrev+ NextSong / (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs), /*if*/ show_playing_song, /*then*/ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay)) /*else*/ ) ), PlayingExit == WaitingForEnd + EndPlay , ForwardPressed == NoForward + EastPressed [!is_flag_(NoFastFwd)] , NoForward == ForwardPressed + EastReleased / process_(NextSong) , FastForward == ForwardPressed + ForwardTimer / do_fast_forward , FastForward == FastForward + ForwardTimer / do_fast_forward , FastForward == NoForward + EastReleased , SetPosition == StdDisplay + PlayingMiddleButton , StdDisplay == SetPosition + StartSong , SetMark == SetPosition + PlayingMiddleButton , StdDisplay == SetMark + PlayingMiddleButton , StdDisplay == SetMark + StartSong // +------------------------------------------------------------------------------+ ),playingmode_transition_table ) BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playingmode_transition_table, //STT init_ << Playing << WaitingForNextPrev << WaitingForEnd << NoForward << StdDisplay, // Init States fsm_(m_NumberOfSongs)=Int_<5>(), // entry no_action, // exit attributes_ << m_SongIndex << m_NumberOfSongs, //attributes configure_<< NoFastFwd // Flags, Deferred events, configuration ),PlayingMode_) // choice of back-end typedef msm::back::state_machine PlayingMode_type; PlayingMode_type const PlayingMode; // Concrete MenuMode_ implementation // The list of MenuMode_ states BOOST_MSM_EUML_STATE(( WaitingForSongChoice_Entry ),WaitingForSongChoice) BOOST_MSM_EUML_STATE(( StartCurrentSong_Entry ),StartCurrentSong) BOOST_MSM_EUML_EXIT_STATE(( CloseMenu,MenuExit_Entry ),MenuExit) //stt BOOST_MSM_EUML_TRANSITION_TABLE(( // +------------------------------------------------------------------------------+ StartCurrentSong == WaitingForSongChoice + MenuMiddleButton , MenuExit == StartCurrentSong + SelectSong // +------------------------------------------------------------------------------+ ),menumode_transition_table ) BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (menumode_transition_table, //STT init_ << WaitingForSongChoice, // Init States no_action, // entry no_action, // exit attributes_ << no_attributes_, //attributes configure_<< MenuActive // Flags, Deferred events, configuration ),MenuMode_) typedef msm::back::state_machine MenuMode_type; MenuMode_type const MenuMode; // iPod stt BOOST_MSM_EUML_TRANSITION_TABLE(( // +------------------------------------------------------------------------------+ Holding == NotHolding + Hold , NotHolding == Holding + NoHold , PlayingMode == NotPlaying + PlayPause , NotPlaying == exit_pt_(PlayingMode,PlayingExit) + EndPlay / process_(MenuButton) , MenuMode == NoMenuMode + MenuButton , NoMenuMode == exit_pt_(MenuMode,MenuExit)+ CloseMenu / process2_(StartSong,Int_<5>()) , OffDown == NoOnOffButton + SouthPressed , NoOnOffButton == OffDown + SouthReleased / process_(PlayPause) , PlayerOff == OffDown + OnOffTimer / (show_player_off,process_(Off)) , NoOnOffButton == PlayerOff + SouthPressed / show_player_on , NoOnOffButton == PlayerOff + NoHold / show_player_on , CheckMiddleButton == CheckMiddleButton + MiddleButton [is_flag_(MenuActive)] / process_(PlayingMiddleButton) , CheckMiddleButton == CheckMiddleButton + MiddleButton [!is_flag_(MenuActive)] / process_(PlayingMiddleButton) // +------------------------------------------------------------------------------+ ),ipod_transition_table ) BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( ipod_transition_table, //STT init_ << NotHolding << NotPlaying << NoMenuMode << NoOnOffButton << CheckMiddleButton ), iPod_) //fsm name typedef msm::back::state_machine iPod; 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; }