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)
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>
24 using namespace boost::msm::front::euml
;
25 namespace msm
= boost::msm
;
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"
34 namespace // Concrete FSM implementation
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
>
54 CloseMenu_impl(){}//defined only for stt
56 CloseMenu_impl(EVENT
const &) {}
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
)
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
)
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
)
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
)
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*/ ) ),
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
)
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
142 attributes_
<< m_SongIndex
<< m_NumberOfSongs
, //attributes
143 configure_
<< NoFastFwd
// Flags, Deferred events, configuration
146 // choice of back-end
147 typedef msm::back::state_machine
<PlayingMode_
> PlayingMode_type
;
148 PlayingMode_type
const PlayingMode
;
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
)
157 BOOST_MSM_EUML_TRANSITION_TABLE((
158 // +------------------------------------------------------------------------------+
159 StartCurrentSong
== WaitingForSongChoice
+ MenuMiddleButton
,
160 MenuExit
== StartCurrentSong
+ SelectSong
161 // +------------------------------------------------------------------------------+
162 ),menumode_transition_table
)
164 BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (menumode_transition_table
, //STT
165 init_
<< WaitingForSongChoice
, // Init States
168 attributes_
<< no_attributes_
, //attributes
169 configure_
<< MenuActive
// Flags, Deferred events, configuration
172 typedef msm::back::state_machine
<MenuMode_
> MenuMode_type
;
173 MenuMode_type
const MenuMode
;
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
)
200 BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( ipod_transition_table
, //STT
201 init_
<< NotHolding
<< NotPlaying
<< NoMenuMode
202 << NoOnOffButton
<< CheckMiddleButton
205 typedef msm::back::state_machine
<iPod_
> iPod
;
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
);
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
);