1 // Copyright 2010 Christophe Henry
2 // henry UNDERSCORE christophe AT hotmail DOT com
3 // This is an extended version of the state machine available in the boost::mpl library
4 // Distributed under the same license as the original.
5 // Copyright for the original version:
6 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
7 // under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 
11 #ifndef PLAYING_MODE_HPP
12 #define PLAYING_MODE_HPP
13 
14 #include <iostream>
15 #include <boost/any.hpp>
16 #define FUSION_MAX_VECTOR_SIZE 20
17 
18 #include "Events.hpp"
19 #include <boost/msm/back/favor_compile_time.hpp>
20 #include <boost/msm/back/state_machine.hpp>
21 #include <boost/msm/front/state_machine_def.hpp>
22 #include <boost/msm/front/euml/euml.hpp>
23 
24 using namespace std;
25 namespace msm = boost::msm;
26 namespace euml = boost::msm::front::euml;
27 
28 struct PlayingMode_ : public msm::front::state_machine_def<PlayingMode_>
29 {
30     //flags
31     struct NoFastFwd{};
32 
33     struct Playing : public msm::front::state<default_base_state,msm::front::sm_ptr>
34     {
35         template <class Event,class FSM>
on_entryPlayingMode_::Playing36         void on_entry(Event const&,FSM& )
37         {
38             std::cout << "starting: PlayingMode::Playing" << std::endl;
39             std::cout << "playing song:" << m_fsm->get_current_song() << std::endl;
40         }
41         template <class Event,class FSM>
on_exitPlayingMode_::Playing42         void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::Playing" << std::endl;}
set_sm_ptrPlayingMode_::Playing43         void set_sm_ptr(PlayingMode_* pl)
44         {
45             m_fsm = pl;
46         }
47     private:
48         PlayingMode_* m_fsm;
49     };
50     struct Paused : public msm::front::state<>
51     {
52         template <class Event,class FSM>
on_entryPlayingMode_::Paused53         void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::Paused" << std::endl;}
54         template <class Event,class FSM>
on_exitPlayingMode_::Paused55         void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::Paused" << std::endl;}
56     };
57     struct WaitingForNextPrev : public msm::front::state<>
58     {
59         template <class Event,class FSM>
on_entryPlayingMode_::WaitingForNextPrev60         void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::WaitingForNextPrev" << std::endl;}
61         template <class Event,class FSM>
on_exitPlayingMode_::WaitingForNextPrev62         void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::WaitingForNextPrev" << std::endl;}
63     };
64     struct WaitingForEnd : public msm::front::state<>
65     {
66         template <class Event,class FSM>
on_entryPlayingMode_::WaitingForEnd67         void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::WaitingForEnd" << std::endl;}
68         template <class Event,class FSM>
on_exitPlayingMode_::WaitingForEnd69         void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::WaitingForEnd" << std::endl;}
70     };
71     struct NoForward : public msm::front::state<>
72     {
73         template <class Event,class FSM>
on_entryPlayingMode_::NoForward74         void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::NoForward" << std::endl;}
75         template <class Event,class FSM>
on_exitPlayingMode_::NoForward76         void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::NoForward" << std::endl;}
77     };
78     struct ForwardPressed : public msm::front::state<>
79     {
80         template <class Event,class FSM>
on_entryPlayingMode_::ForwardPressed81         void on_entry(Event const&,FSM& )
82         {
83             std::cout << "starting: PlayingMode::ForwardPressed," << "start timer" << std::endl;
84         }
85         template <class Event,class FSM>
on_exitPlayingMode_::ForwardPressed86         void on_exit(Event const&,FSM& )
87         {
88             std::cout << "finishing: PlayingMode::ForwardPressed," << "stop timer" << std::endl;
89         }
90     };
91     struct FastForward : public msm::front::state<>
92     {
93         template <class Event,class FSM>
on_entryPlayingMode_::FastForward94         void on_entry(Event const&,FSM& )
95         {
96             std::cout << "starting: PlayingMode::FastForward," << "start timer" << std::endl;
97         }
98         template <class Event,class FSM>
on_exitPlayingMode_::FastForward99         void on_exit(Event const&,FSM& )
100         {
101             std::cout << "finishing: PlayingMode::FastForward," << "stop timer" << std::endl;
102         }
103     };
104     struct StdDisplay : public msm::front::state<>
105     {
106         template <class Event,class FSM>
on_entryPlayingMode_::StdDisplay107         void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::StdDisplay" << std::endl;}
108         template <class Event,class FSM>
on_exitPlayingMode_::StdDisplay109         void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::StdDisplay" << std::endl;}
110     };
111     struct SetPosition : public msm::front::state<>
112     {
113         typedef mpl::vector1<NoFastFwd>     flag_list;
114         template <class Event,class FSM>
on_entryPlayingMode_::SetPosition115         void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::SetPosition" << std::endl;}
116         template <class Event,class FSM>
on_exitPlayingMode_::SetPosition117         void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::SetPosition" << std::endl;}
118     };
119     struct SetMark : public msm::front::state<>
120     {
121         template <class Event,class FSM>
on_entryPlayingMode_::SetMark122         void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::SetMark" << std::endl;}
123         template <class Event,class FSM>
on_exitPlayingMode_::SetMark124         void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::SetMark" << std::endl;}
125     };
126     struct PlayingExit : public msm::front::exit_pseudo_state<EndPlay>
127     {
128         template <class Event,class FSM>
on_entryPlayingMode_::PlayingExit129         void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::PlayingExit" << std::endl;}
130         template <class Event,class FSM>
on_exitPlayingMode_::PlayingExit131         void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::PlayingExit" << std::endl;}
132     };
133     // transition action methods
134     struct inc_song_counter : euml::euml_action<inc_song_counter>
135     {
136         template <class FSM,class EVT,class SourceState,class TargetState>
operator ()PlayingMode_::inc_song_counter137         void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
138         {
139             if (++fsm.m_SongIndex <= fsm.m_NumberOfSongs )
140             {
141                 std::cout << "playing song:" << fsm.m_SongIndex << std::endl;
142             }
143             else
144             {
145                 // last song => end playing, next play will start at the beginning
146                 fsm.m_SongIndex = 1;
147                 fsm.process_event(EndPlay());
148             }
149         }
150     };
151 
select_songPlayingMode_152     void select_song(StartSong const& evt)
153     {
154         if ((evt.m_Selected>0) && (evt.m_Selected<=m_NumberOfSongs))
155         {
156             m_SongIndex = evt.m_Selected;
157             std::cout << "selecting song:" << m_SongIndex << std::endl;
158         }
159         else
160         {
161             // play current song
162             std::cout << "selecting song:" << m_SongIndex << std::endl;
163         }
164     }
165     struct dec_song_counter : euml::euml_action<dec_song_counter>
166     {
167         template <class FSM,class EVT,class SourceState,class TargetState>
operator ()PlayingMode_::dec_song_counter168         void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
169         {
170             if (--fsm.m_SongIndex >0 )
171             {
172                 std::cout << "playing song:" << fsm.m_SongIndex << std::endl;
173             }
174             else
175             {
176                 // before first song => end playing
177                 fsm.m_SongIndex = 1;
178                 fsm.process_event(EndPlay());
179             }
180         }
181     };
182     struct send_NextSong : euml::euml_action<send_NextSong>
183     {
184         template <class FSM,class EVT,class SourceState,class TargetState>
operator ()PlayingMode_::send_NextSong185         void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
186         {
187             fsm.process_event(NextSong());
188         }
189     };
190 
do_fast_forwardPlayingMode_191     void do_fast_forward(ForwardTimer const&)
192     {
193         std::cout << "moving song forward..." << std::endl;
194     }
195 
196     // transition guard methods
197     struct fast_fwd_ok : euml::euml_action<fast_fwd_ok>
198     {
199         template <class FSM,class EVT,class SourceState,class TargetState>
operator ()PlayingMode_::fast_fwd_ok200         bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
201         {
202             // guard accepts only if fast forward is possible (No SetPosition mode)
203             return !fsm.is_flag_active<NoFastFwd>();
204         }
205     };
206     // initial states / orthogonal zones
207     typedef mpl::vector5<Playing,WaitingForNextPrev,WaitingForEnd,NoForward,StdDisplay>
208                             initial_state;
209     typedef PlayingMode_ fsm; // makes transition table cleaner
210     // Transition table for player
211     struct transition_table : mpl::vector19<
212             //    Start                 Event                Next                 Action                     Guard
213             //   +--------------------+---------------------+--------------------+--------------------------+----------------------+
214             _row < Playing            , PlayPause           , Paused                                                               >,
215             _row < Playing            , Off                 , Paused                                                               >,
216            a_row < Playing            , StartSong           , Playing            , &fsm::select_song                               >,
217             _row < Paused             , PlayPause           , Playing                                                              >,
218  msm::front::Row < Playing            , SongFinished        , Playing            , inc_song_counter         , msm::front::none     >,
219            a_row < Paused             , StartSong           , Playing            , &fsm::select_song                               >,
220             //   +--------------------+---------------------+--------------------+--------------------------+----------------------+
221  msm::front::Row < WaitingForNextPrev , PreviousSong        , WaitingForNextPrev , dec_song_counter         , msm::front::none     >,
222  msm::front::Row < WaitingForNextPrev , NextSong            , WaitingForNextPrev , inc_song_counter         , msm::front::none     >,
223             //   +--------------------+---------------------+--------------------+--------------------------+----------------------+
224             _row < WaitingForEnd      , EndPlay             , PlayingExit                                                          >,
225             //   +--------------------+---------------------+--------------------+--------------------------+----------------------+
226  msm::front::Row < NoForward          , EastPressed         , ForwardPressed      , msm::front::none        , fast_fwd_ok          >,
227  msm::front::Row < ForwardPressed     , EastReleased        , NoForward           , send_NextSong           , msm::front::none     >,
228            a_row < ForwardPressed     , ForwardTimer        , FastForward         , &fsm::do_fast_forward                          >,
229            a_row < FastForward        , ForwardTimer        , FastForward         , &fsm::do_fast_forward                          >,
230             _row < FastForward        , EastReleased        , NoForward                                                            >,
231             //   +--------------------+---------------------+---------------------+--------------------------+----------------------+
232             _row < StdDisplay         , PlayingMiddleButton , SetPosition                                                          >,
233             _row < SetPosition        , StartSong           , StdDisplay                                                           >,
234             _row < SetPosition        , PlayingMiddleButton , SetMark                                                              >,
235             _row < SetMark            , PlayingMiddleButton , StdDisplay                                                           >,
236             _row < SetMark            , StartSong           , StdDisplay                                                           >
237             //   +--------------------+---------------------+---------------------+--------------------------+----------------------+
238     > {};
PlayingMode_PlayingMode_239     PlayingMode_():
240     m_SongIndex(1),
241     // for simplicity we decide there are 5 songs
242     m_NumberOfSongs(5){}
243 
get_current_songPlayingMode_244     int get_current_song(){return m_SongIndex;}
245     int m_SongIndex;
246     int m_NumberOfSongs;
247 
248 };
249 typedef msm::back::state_machine<PlayingMode_> PlayingMode;
250 
251 #endif // PLAYING_MODE_HPP
252