// 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 // back-end #include //front-end #include namespace msm = boost::msm; namespace mpl = boost::mpl; namespace { // events struct play {}; struct end_pause {}; struct stop {}; struct pause {}; struct open_close {}; struct NextSong {}; struct PreviousSong {}; struct cd_detected { cd_detected(std::string name) : name(name) {} std::string name; }; // front-end: define the FSM structure struct player_ : public msm::front::state_machine_def { unsigned int start_playback_counter; unsigned int can_close_drawer_counter; player_(): start_playback_counter(0), can_close_drawer_counter(0) {} // The list of FSM states struct Empty : public msm::front::state<> { template void on_entry(Event const&,FSM& ) {++entry_counter;} template void on_exit(Event const&,FSM& ) {++exit_counter;} int entry_counter; int exit_counter; }; struct Open : public msm::front::state<> { template void on_entry(Event const&,FSM& ) {++entry_counter;} template void on_exit(Event const&,FSM& ) {++exit_counter;} int entry_counter; int exit_counter; }; // sm_ptr still supported but deprecated as functors are a much better way to do the same thing struct Stopped : public msm::front::state<> { template void on_entry(Event const&,FSM& ) {++entry_counter;} template void on_exit(Event const&,FSM& ) {++exit_counter;} int entry_counter; int exit_counter; }; struct Playing_ : public msm::front::state_machine_def { template void on_entry(Event const&,FSM& ) {++entry_counter;} template void on_exit(Event const&,FSM& ) {++exit_counter;} int entry_counter; int exit_counter; unsigned int start_next_song_counter; unsigned int start_prev_song_guard_counter; Playing_(): start_next_song_counter(0), start_prev_song_guard_counter(0) {} // The list of FSM states struct Song1 : public msm::front::state<> { template void on_entry(Event const&,FSM& ) {++entry_counter;} template void on_exit(Event const&,FSM& ) {++exit_counter;} int entry_counter; int exit_counter; }; struct Song2 : public msm::front::state<> { template void on_entry(Event const&,FSM& ) {++entry_counter;} template void on_exit(Event const&,FSM& ) {++exit_counter;} int entry_counter; int exit_counter; }; struct Song3 : public msm::front::state<> { template void on_entry(Event const&,FSM& ) {++entry_counter;} template void on_exit(Event const&,FSM& ) {++exit_counter;} int entry_counter; int exit_counter; }; // the initial state. Must be defined typedef Song1 initial_state; // transition actions void start_next_song(NextSong const&) {++start_next_song_counter; } void start_prev_song(PreviousSong const&) { } // guard conditions bool start_prev_song_guard(PreviousSong const&) {++start_prev_song_guard_counter;return true; } typedef Playing_ pl; // makes transition table cleaner // Transition table for Playing struct transition_table : mpl::vector4< // Start Event Next Action Guard // +---------+-------------+---------+---------------------+----------------------+ _row < Song1 , NextSong , Song2 >, row < Song2 , PreviousSong, Song1 , &pl::start_prev_song,&pl::start_prev_song_guard>, a_row < Song2 , NextSong , Song3 , &pl::start_next_song >, g_row < Song3 , PreviousSong, Song2 ,&pl::start_prev_song_guard> // +---------+-------------+---------+---------------------+----------------------+ > {}; // Replaces the default no-transition response. template void no_transition(Event const&, FSM&,int) { } }; // back-end typedef msm::back::state_machine > > Playing; // state not defining any entry or exit struct Paused : public msm::front::state<> { template void on_entry(Event const&,FSM& ) {++entry_counter;} template void on_exit(Event const&,FSM& ) {++exit_counter;} int entry_counter; int exit_counter; }; // the initial state of the player SM. Must be defined typedef Empty initial_state; // transition actions void start_playback(play const&) {++start_playback_counter; } void open_drawer(open_close const&) { } void store_cd_info(cd_detected const&) { } void stop_playback(stop const&) { } void pause_playback(pause const&) { } void resume_playback(end_pause const&) { } void stop_and_open(open_close const&) { } void stopped_again(stop const&) {} //guards bool can_close_drawer(open_close const&) { ++can_close_drawer_counter; return true; } typedef player_ p; // makes transition table cleaner // Transition table for player struct transition_table : mpl::vector< // Start Event Next Action Guard // +---------+-------------+---------+---------------------+----------------------+ a_row < Stopped , play , Playing , &p::start_playback >, a_row < Stopped , open_close , Open , &p::open_drawer >, _row < Stopped , stop , Stopped >, // +---------+-------------+---------+---------------------+----------------------+ g_row < Open , open_close , Empty , &p::can_close_drawer >, // +---------+-------------+---------+---------------------+----------------------+ a_row < Empty , open_close , Open , &p::open_drawer >, a_row < Empty , cd_detected , Stopped , &p::store_cd_info >, // +---------+-------------+---------+---------------------+----------------------+ a_row < Playing , stop , Stopped , &p::stop_playback >, a_row < Playing , pause , Paused , &p::pause_playback >, a_row < Playing , open_close , Open , &p::stop_and_open >, // +---------+-------------+---------+---------------------+----------------------+ a_row < Paused , end_pause , Playing , &p::resume_playback >, a_row < Paused , stop , Stopped , &p::stop_playback >, a_row < Paused , open_close , Open , &p::stop_and_open > // +---------+-------------+---------+---------------------+----------------------+ > {}; // Replaces the default no-transition response. template void no_transition(Event const& e, FSM&,int state) { } // init counters template void on_entry(Event const&,FSM& fsm) { fsm.template get_state().entry_counter=0; fsm.template get_state().exit_counter=0; fsm.template get_state().entry_counter=0; fsm.template get_state().exit_counter=0; fsm.template get_state().entry_counter=0; fsm.template get_state().exit_counter=0; fsm.template get_state().entry_counter=0; fsm.template get_state().exit_counter=0; fsm.template get_state().template get_state().entry_counter=0; fsm.template get_state().template get_state().exit_counter=0; fsm.template get_state().template get_state().entry_counter=0; fsm.template get_state().template get_state().exit_counter=0; fsm.template get_state().template get_state().entry_counter=0; fsm.template get_state().template get_state().exit_counter=0; fsm.template get_state().entry_counter=0; fsm.template get_state().exit_counter=0; } }; // Pick a back-end typedef msm::back::state_machine player; // static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" }; } int main() { player p; p.start(); return 0; }