]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | { | |
54 | CloseMenu_impl(){}//defined only for stt | |
55 | template<class EVENT> | |
56 | 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 | ||
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 | ||
267 | int main() | |
268 | { | |
269 | test(); | |
270 | return 0; | |
271 | } |