• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <vector>
12 #include <set>
13 #include <string>
14 #include <iostream>
15 // we need more than the default 20 states
16 #define FUSION_MAX_VECTOR_SIZE 20
17 // we need more than the default 20 transitions
18 #include "boost/mpl/vector/vector50.hpp"
19 #include <boost/msm/back/state_machine.hpp>
20 #include <boost/msm/front/euml/euml.hpp>
21 
22 
23 using namespace std;
24 using namespace boost::msm::front::euml;
25 namespace msm = boost::msm;
26 
27 // attribute names and types
28 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_Selected)
29 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_SongIndex)
30 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_NumberOfSongs)
31 #include "ipod_functors.hpp"
32 
33 
34 namespace  // Concrete FSM implementation
35 {
36     //flags
37     BOOST_MSM_EUML_FLAG(MenuActive)
38     BOOST_MSM_EUML_FLAG(NoFastFwd)
39     // hardware-generated events
40     BOOST_MSM_EUML_EVENT(Hold)
41     BOOST_MSM_EUML_EVENT(NoHold)
42     BOOST_MSM_EUML_EVENT(SouthPressed)
43     BOOST_MSM_EUML_EVENT(SouthReleased)
44     BOOST_MSM_EUML_EVENT(MiddleButton)
45     BOOST_MSM_EUML_EVENT(EastPressed)
46     BOOST_MSM_EUML_EVENT(EastReleased)
47     BOOST_MSM_EUML_EVENT(Off)
48     BOOST_MSM_EUML_EVENT(MenuButton)
49     // internally defined events
50     BOOST_MSM_EUML_EVENT(PlayPause)
51     BOOST_MSM_EUML_EVENT(EndPlay)
52     struct CloseMenu_impl : euml_event<CloseMenu_impl>
53     {
CloseMenu_impl__anonab6d36350111::CloseMenu_impl54         CloseMenu_impl(){}//defined only for stt
55         template<class EVENT>
CloseMenu_impl__anonab6d36350111::CloseMenu_impl56         CloseMenu_impl(EVENT const &) {}
57     };
58     CloseMenu_impl const CloseMenu;
59     BOOST_MSM_EUML_EVENT(OnOffTimer)
60     BOOST_MSM_EUML_EVENT(MenuMiddleButton)
61     BOOST_MSM_EUML_EVENT(SelectSong)
62     BOOST_MSM_EUML_EVENT(SongFinished)
63 
64     BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_Selected ), StartSongAttributes)
65     BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(StartSong,StartSongAttributes)
66     BOOST_MSM_EUML_EVENT(PreviousSong)
67     BOOST_MSM_EUML_EVENT(NextSong)
68     BOOST_MSM_EUML_EVENT(ForwardTimer)
69     BOOST_MSM_EUML_EVENT(PlayingMiddleButton)
70 
71     // Concrete iPod implementation
72     // The list of iPod states
73     BOOST_MSM_EUML_STATE(( NotHolding_Entry ),NotHolding)
74     BOOST_MSM_EUML_INTERRUPT_STATE(( NoHold,Holding_Entry ),Holding)
75     BOOST_MSM_EUML_STATE(( NotPlaying_Entry ),NotPlaying)
76     BOOST_MSM_EUML_STATE(( NoMenuMode_Entry ),NoMenuMode)
77     BOOST_MSM_EUML_STATE(( NoOnOffButton_Entry ),NoOnOffButton)
78     BOOST_MSM_EUML_STATE(( OffDown_Entry ),OffDown)
79     BOOST_MSM_EUML_STATE(( PlayerOff_Entry ),PlayerOff)
80     BOOST_MSM_EUML_STATE(( CheckMiddleButton_Entry ),CheckMiddleButton)
81 
82     // Concrete PlayingMode_ implementation
83     // The list of PlayingMode_ states
84     BOOST_MSM_EUML_STATE(( Playing_Entry ),Playing)
85     BOOST_MSM_EUML_STATE(( WaitingForNextPrev_Entry ),WaitingForNextPrev)
86     BOOST_MSM_EUML_STATE(( Paused_Entry ),Paused)
87     BOOST_MSM_EUML_STATE(( WaitingForEnd_Entry ),WaitingForEnd)
88     BOOST_MSM_EUML_STATE(( NoForward_Entry ),NoForward)
89     BOOST_MSM_EUML_STATE(( ForwardPressed_Entry,ForwardPressed_Exit ),ForwardPressed)
90     BOOST_MSM_EUML_STATE(( FastForward_Entry,FastForward_Exit ),FastForward)
91     BOOST_MSM_EUML_STATE(( StdDisplay_Entry ),StdDisplay)
92     BOOST_MSM_EUML_STATE(( SetPosition_Entry ),SetPosition)
93     BOOST_MSM_EUML_STATE(( SetMark_Entry ),SetMark)
94     BOOST_MSM_EUML_EXIT_STATE(( EndPlay,PlayingExit_Entry ),PlayingExit)
95 
96     //stt
97     BOOST_MSM_EUML_TRANSITION_TABLE((
98         //  +------------------------------------------------------------------------------+
99         Paused             == Playing           + PlayPause                                            ,
100         Paused             == Playing           + Off                                                  ,
101         Playing            == Playing           + StartSong
102                              / (if_then_(event_(m_Selected) > Int_<0>() &&
103                                          event_(m_Selected) < fsm_(m_NumberOfSongs),
104                                          fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song)   ,
105         Playing            == Playing + SongFinished
106                              / (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs),  /*if*/
107                                              show_playing_song,                               /*then*/
108                                              (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay))/*else*/ ) )  ,
109         Playing            == Paused            + PlayPause                                             ,
110         Playing            == Paused            + StartSong
111                              / (if_then_(event_(m_Selected) > Int_<0>() &&
112                                          event_(m_Selected) < fsm_(m_NumberOfSongs),
113                                          fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song)    ,
114         WaitingForNextPrev == WaitingForNextPrev+ PreviousSong
115                              /( if_then_else_(--fsm_(m_SongIndex) > Int_<0>(),                  /*if*/
116                                               show_playing_song,                                /*then*/
117                                               (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay)) /*else*/ ) ) ,
118         WaitingForNextPrev == WaitingForNextPrev+ NextSong
119                                / (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs),      /*if*/
120                                                 show_playing_song,                               /*then*/
121                                                 (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay))  /*else*/ ) ),
122 
123         PlayingExit        == WaitingForEnd     + EndPlay                                                ,
124         ForwardPressed     == NoForward         + EastPressed [!is_flag_(NoFastFwd)]                   ,
125         NoForward          == ForwardPressed    + EastReleased      / process_(NextSong)               ,
126         FastForward        == ForwardPressed    + ForwardTimer    / do_fast_forward                    ,
127         FastForward        == FastForward       + ForwardTimer    / do_fast_forward                    ,
128         FastForward        == NoForward         + EastReleased                                           ,
129         SetPosition        == StdDisplay        + PlayingMiddleButton                                    ,
130         StdDisplay         == SetPosition       + StartSong                                              ,
131         SetMark            == SetPosition       + PlayingMiddleButton                                    ,
132         StdDisplay         == SetMark           + PlayingMiddleButton                                    ,
133         StdDisplay         == SetMark           + StartSong
134         //  +------------------------------------------------------------------------------+
135         ),playingmode_transition_table )
136 
137     BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playingmode_transition_table, //STT
138                                         init_ << Playing << WaitingForNextPrev << WaitingForEnd
139                                               << NoForward << StdDisplay, // Init States
140                                         fsm_(m_NumberOfSongs)=Int_<5>(), // entry
141                                         no_action, // exit
142                                         attributes_ << m_SongIndex << m_NumberOfSongs, //attributes
143                                         configure_<< NoFastFwd // Flags, Deferred events, configuration
144                                         ),PlayingMode_)
145 
146     // choice of back-end
147     typedef msm::back::state_machine<PlayingMode_> PlayingMode_type;
148     PlayingMode_type const PlayingMode;
149 
150     // Concrete MenuMode_ implementation
151     // The list of MenuMode_ states
152     BOOST_MSM_EUML_STATE(( WaitingForSongChoice_Entry ),WaitingForSongChoice)
153     BOOST_MSM_EUML_STATE(( StartCurrentSong_Entry ),StartCurrentSong)
154     BOOST_MSM_EUML_EXIT_STATE(( CloseMenu,MenuExit_Entry ),MenuExit)
155 
156     //stt
157     BOOST_MSM_EUML_TRANSITION_TABLE((
158         //  +------------------------------------------------------------------------------+
159         StartCurrentSong   == WaitingForSongChoice  + MenuMiddleButton  ,
160         MenuExit           == StartCurrentSong      + SelectSong
161         //  +------------------------------------------------------------------------------+
162         ),menumode_transition_table )
163 
164     BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (menumode_transition_table, //STT
165                                         init_ << WaitingForSongChoice, // Init States
166                                         no_action, // entry
167                                         no_action, // exit
168                                         attributes_ << no_attributes_, //attributes
169                                         configure_<< MenuActive // Flags, Deferred events, configuration
170                                         ),MenuMode_)
171 
172     typedef msm::back::state_machine<MenuMode_> MenuMode_type;
173     MenuMode_type const MenuMode;
174 
175     // iPod stt
176     BOOST_MSM_EUML_TRANSITION_TABLE((
177         //  +------------------------------------------------------------------------------+
178         Holding           == NotHolding                 + Hold                        ,
179         NotHolding        == Holding                    + NoHold                      ,
180         PlayingMode       == NotPlaying                 + PlayPause                   ,
181         NotPlaying        == exit_pt_(PlayingMode,PlayingExit)  + EndPlay
182                                 / process_(MenuButton)                                    ,
183         MenuMode          == NoMenuMode                 + MenuButton                  ,
184         NoMenuMode        == exit_pt_(MenuMode,MenuExit)+ CloseMenu
185                                 / process2_(StartSong,Int_<5>())                          ,
186         OffDown           == NoOnOffButton              + SouthPressed                ,
187         NoOnOffButton     == OffDown                    + SouthReleased
188                                 / process_(PlayPause)                                     ,
189         PlayerOff         == OffDown                    + OnOffTimer
190                                 / (show_player_off,process_(Off))                       ,
191         NoOnOffButton     == PlayerOff                  + SouthPressed / show_player_on ,
192         NoOnOffButton     == PlayerOff                  + NoHold / show_player_on   ,
193         CheckMiddleButton == CheckMiddleButton          + MiddleButton
194                                [is_flag_(MenuActive)] / process_(PlayingMiddleButton)   ,
195         CheckMiddleButton == CheckMiddleButton + MiddleButton
196                                [!is_flag_(MenuActive)] / process_(PlayingMiddleButton)
197         //  +------------------------------------------------------------------------------+
198         ),ipod_transition_table )
199 
200     BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( ipod_transition_table, //STT
201                                         init_ << NotHolding << NotPlaying << NoMenuMode
202                                         << NoOnOffButton << CheckMiddleButton
203                                         ),
204                                       iPod_) //fsm name
205     typedef msm::back::state_machine<iPod_> iPod;
206 
test()207     void test()
208     {
209         iPod sm;
210         sm.start();
211         // we first press Hold
212         std::cout << "pressing hold" << std::endl;
213         sm.process_event(Hold);
214         // pressing a button is now ignored
215         std::cout << "pressing a button" << std::endl;
216         sm.process_event(SouthPressed);
217         // or even one contained in a submachine
218         sm.process_event(EastPressed);
219         // no more holding
220         std::cout << "no more holding, end interrupt event sent" << std::endl;
221         sm.process_event(NoHold);
222         std::cout << "pressing South button a short time" << std::endl;
223         sm.process_event(SouthPressed);
224         // we suppose a short pressing leading to playing a song
225         sm.process_event(SouthReleased);
226         // we move to the next song
227         std::cout << "we move to the next song" << std::endl;
228         sm.process_event(NextSong);
229         // then back to no song => exit from playing, menu active
230         std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl;
231         sm.process_event(PreviousSong);
232         sm.process_event(PreviousSong);
233         // even in menu mode, pressing play will start playing the first song
234         std::cout << "pressing play/pause" << std::endl;
235         sm.process_event(SouthPressed);
236         sm.process_event(SouthReleased);
237         // of course pausing must be possible
238         std::cout << "pressing play/pause" << std::endl;
239         sm.process_event(SouthPressed);
240         sm.process_event(SouthReleased);
241         std::cout << "pressing play/pause" << std::endl;
242         sm.process_event(SouthPressed);
243         sm.process_event(SouthReleased);
244         // while playing, you can fast forward
245         std::cout << "pressing East button a long time" << std::endl;
246         sm.process_event(EastPressed);
247         // let's suppose the timer just fired
248         sm.process_event(ForwardTimer);
249         sm.process_event(ForwardTimer);
250         // end of fast forwarding
251         std::cout << "releasing East button" << std::endl;
252         sm.process_event(EastReleased);
253         // we now press the middle button to set playing at a given position
254         std::cout << "pressing Middle button, fast forwarding disabled" << std::endl;
255         sm.process_event(MiddleButton);
256         std::cout <<"pressing East button to fast forward" << std::endl;
257         sm.process_event(EastPressed);
258         // we switch off and on
259         std::cout <<"switch off player" << std::endl;
260         sm.process_event(SouthPressed);
261         sm.process_event(OnOffTimer);
262         std::cout <<"switch on player" << std::endl;
263         sm.process_event(SouthPressed);
264     }
265 }
266 
main()267 int main()
268 {
269     test();
270     return 0;
271 }
272