]>
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 | #define FUSION_MAX_VECTOR_SIZE 20 | |
16 | ||
17 | #include "boost/mpl/vector/vector50.hpp" | |
18 | #include <boost/msm/back/state_machine.hpp> | |
19 | #include <boost/msm/front/state_machine_def.hpp> | |
20 | ||
21 | #include "Events.hpp" | |
22 | #include "PlayingMode.hpp" | |
23 | #include "MenuMode.hpp" | |
24 | ||
25 | using namespace std; | |
26 | namespace msm = boost::msm; | |
27 | ||
28 | namespace // Concrete FSM implementation | |
29 | { | |
30 | struct iPod_; | |
31 | typedef msm::back::state_machine<iPod_, | |
32 | ::boost::msm::back::favor_compile_time> iPod; | |
33 | ||
34 | // Concrete FSM implementation | |
35 | struct iPod_ : public msm::front::state_machine_def<iPod_> | |
36 | { | |
37 | // The list of FSM states | |
38 | struct NotHolding : public msm::front::state<> | |
39 | { | |
40 | template <class Event,class FSM> | |
41 | void on_entry(Event const&,FSM& ) {std::cout << "starting: NotHolding" << std::endl;} | |
42 | template <class Event,class FSM> | |
43 | void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotHolding" << std::endl;} | |
44 | }; | |
45 | struct Holding : public msm::front::interrupt_state<NoHold> | |
46 | { | |
47 | template <class Event,class FSM> | |
48 | void on_entry(Event const&,FSM& ) {std::cout << "starting: Holding" << std::endl;} | |
49 | template <class Event,class FSM> | |
50 | void on_exit(Event const&,FSM& ) {std::cout << "finishing: Holding" << std::endl;} | |
51 | }; | |
52 | struct NotPlaying : public msm::front::state<> | |
53 | { | |
54 | template <class Event,class FSM> | |
55 | void on_entry(Event const&,FSM& ) {std::cout << "starting: NotPlaying" << std::endl;} | |
56 | template <class Event,class FSM> | |
57 | void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotPlaying" << std::endl;} | |
58 | }; | |
59 | struct NoMenuMode : public msm::front::state<> | |
60 | { | |
61 | template <class Event,class FSM> | |
62 | void on_entry(Event const&,FSM& ) {std::cout << "starting: NoMenuMode" << std::endl;} | |
63 | template <class Event,class FSM> | |
64 | void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoMenuMode" << std::endl;} | |
65 | }; | |
66 | struct NoOnOffButton : public msm::front::state<> | |
67 | { | |
68 | template <class Event,class FSM> | |
69 | void on_entry(Event const&,FSM& ) {std::cout << "starting: NoOnOffButton" << std::endl;} | |
70 | template <class Event,class FSM> | |
71 | void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoOnOffButton" << std::endl;} | |
72 | }; | |
73 | struct OffDown : public msm::front::state<> | |
74 | { | |
75 | template <class Event,class FSM> | |
76 | void on_entry(Event const&,FSM& ) {std::cout << "starting: OffDown, start timer" << std::endl;} | |
77 | template <class Event,class FSM> | |
78 | void on_exit(Event const&,FSM& ) {std::cout << "finishing: OffDown, end timer" << std::endl;} | |
79 | }; | |
80 | struct PlayerOff : public msm::front::state<> | |
81 | { | |
82 | template <class Event,class FSM> | |
83 | void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayerOff" << std::endl;} | |
84 | template <class Event,class FSM> | |
85 | void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayerOff" << std::endl;} | |
86 | }; | |
87 | struct CheckMiddleButton : public msm::front::state<> | |
88 | { | |
89 | template <class Event,class FSM> | |
90 | void on_entry(Event const&,FSM& ) {std::cout << "starting: CheckMiddleButton" << std::endl;} | |
91 | template <class Event,class FSM> | |
92 | void on_exit(Event const&,FSM& ) {std::cout << "finishing: CheckMiddleButton" << std::endl;} | |
93 | }; | |
94 | ||
95 | // the initial state of the player SM. Must be defined | |
96 | typedef mpl::vector5<NotHolding,NotPlaying,NoMenuMode,NoOnOffButton,CheckMiddleButton> | |
97 | initial_state; | |
98 | // transition actions | |
99 | void send_ActivateMenu(EndPlay const&) | |
100 | { | |
101 | std::cout << "leaving Playing" << std::endl; | |
102 | // we need to activate the menu and simulate its button | |
103 | (static_cast<iPod*>(this))->process_event(MenuButton()); | |
104 | } | |
105 | void send_StartSong(CloseMenu const&) | |
106 | { | |
107 | // we suppose the 5th song was selected | |
108 | (static_cast<iPod*>(this))->process_event(StartSong(5)); | |
109 | } | |
110 | void send_PlayPause(SouthReleased const&) | |
111 | { | |
112 | // action using the message queue to generate another event | |
113 | (static_cast<iPod*>(this))->process_event(PlayPause()); | |
114 | } | |
115 | void send_Off(OnOffTimer const&) | |
116 | { | |
117 | std::cout << "turning player off" << std::endl; | |
118 | (static_cast<iPod*>(this))->process_event(Off()); | |
119 | } | |
120 | void send_PlayingMiddleButton(MiddleButton const&) | |
121 | { | |
122 | (static_cast<iPod*>(this))->process_event(PlayingMiddleButton()); | |
123 | } | |
124 | void send_MenuMiddleButton(MiddleButton const&) | |
125 | { | |
126 | (static_cast<iPod*>(this))->process_event(MenuMiddleButton()); | |
127 | } | |
128 | // guard conditions | |
129 | bool is_menu(MiddleButton const&) | |
130 | { | |
131 | return (static_cast<iPod*>(this))->is_flag_active<MenuActive>(); | |
132 | } | |
133 | bool is_no_menu(MiddleButton const& evt) | |
134 | { | |
135 | return !is_menu(evt); | |
136 | } | |
137 | template <class EVENT> | |
138 | void switch_on(EVENT const&) | |
139 | { | |
140 | std::cout << "turning player on" << std::endl; | |
141 | } | |
142 | typedef iPod_ fsm; // makes transition table cleaner | |
143 | ||
144 | // Transition table for player | |
145 | struct transition_table : mpl::vector< | |
146 | // Start Event Next Action Guard | |
147 | // +-------------------+---------------+-------------------+--------------------------------+----------------------+ | |
148 | _row < NotHolding , Hold , Holding >, | |
149 | _row < Holding , NoHold , NotHolding >, | |
150 | // +-------------------+---------------+-------------------+--------------------------------+----------------------+ | |
151 | _row < NotPlaying , PlayPause , PlayingMode >, | |
152 | a_row < PlayingMode::exit_pt<PlayingMode_:: | |
153 | PlayingExit> , EndPlay , NotPlaying , &fsm::send_ActivateMenu >, | |
154 | // +-------------------+---------------+-------------------+--------------------------------+----------------------+ | |
155 | _row < NoMenuMode , MenuButton , MenuMode >, | |
156 | a_row < MenuMode::exit_pt<MenuMode_:: | |
157 | MenuExit> , CloseMenu , NoMenuMode , &fsm::send_StartSong >, | |
158 | // +-------------------+---------------+-------------------+--------------------------------+----------------------+ | |
159 | _row < NoOnOffButton , SouthPressed , OffDown >, | |
160 | a_row < OffDown , SouthReleased , NoOnOffButton , &fsm::send_PlayPause >, | |
161 | a_row < OffDown , OnOffTimer , PlayerOff , &fsm::send_Off >, | |
162 | a_row < PlayerOff , SouthPressed , NoOnOffButton , &fsm::switch_on >, | |
163 | a_row < PlayerOff , NoHold , NoOnOffButton , &fsm::switch_on >, | |
164 | // +-------------------+---------------+--------------------+--------------------------------+----------------------+ | |
165 | row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_PlayingMiddleButton , &fsm::is_menu >, | |
166 | row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_MenuMiddleButton , &fsm::is_no_menu > | |
167 | // +-------------------+---------------+--------------------+--------------------------------+----------------------+ | |
168 | > {}; | |
169 | ||
170 | // Replaces the default no-transition response. | |
171 | template <class FSM,class Event> | |
172 | void no_transition(Event const& e, FSM&,int state) | |
173 | { | |
174 | std::cout << "no transition from state " << state | |
175 | << " on event " << typeid(e).name() << std::endl; | |
176 | } | |
177 | }; | |
178 | ||
179 | void test() | |
180 | { | |
181 | iPod sm; | |
182 | sm.start(); | |
183 | // we first press Hold | |
184 | std::cout << "pressing hold" << std::endl; | |
185 | sm.process_event(Hold()); | |
186 | // pressing a button is now ignored | |
187 | std::cout << "pressing a button" << std::endl; | |
188 | sm.process_event(SouthPressed()); | |
189 | // or even one contained in a submachine | |
190 | sm.process_event(EastPressed()); | |
191 | // no more holding | |
192 | std::cout << "no more holding, end interrupt event sent" << std::endl; | |
193 | sm.process_event(NoHold()); | |
194 | std::cout << "pressing South button a short time" << std::endl; | |
195 | sm.process_event(SouthPressed()); | |
196 | // we suppose a short pressing leading to playing a song | |
197 | sm.process_event(SouthReleased()); | |
198 | // we move to the next song | |
199 | std::cout << "we move to the next song" << std::endl; | |
200 | sm.process_event(NextSong()); | |
201 | // then back to no song => exit from playing, menu active | |
202 | std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl; | |
203 | sm.process_event(PreviousSong()); | |
204 | sm.process_event(PreviousSong()); | |
205 | // even in menu mode, pressing play will start playing the first song | |
206 | std::cout << "pressing play/pause" << std::endl; | |
207 | sm.process_event(SouthPressed()); | |
208 | sm.process_event(SouthReleased()); | |
209 | // of course pausing must be possible | |
210 | std::cout << "pressing play/pause" << std::endl; | |
211 | sm.process_event(SouthPressed()); | |
212 | sm.process_event(SouthReleased()); | |
213 | std::cout << "pressing play/pause" << std::endl; | |
214 | sm.process_event(SouthPressed()); | |
215 | sm.process_event(SouthReleased()); | |
216 | // while playing, you can fast forward | |
217 | std::cout << "pressing East button a long time" << std::endl; | |
218 | sm.process_event(EastPressed()); | |
219 | // let's suppose the timer just fired | |
220 | sm.process_event(ForwardTimer()); | |
221 | sm.process_event(ForwardTimer()); | |
222 | // end of fast forwarding | |
223 | std::cout << "releasing East button" << std::endl; | |
224 | sm.process_event(EastReleased()); | |
225 | // we now press the middle button to set playing at a given position | |
226 | std::cout << "pressing Middle button, fast forwarding disabled" << std::endl; | |
227 | sm.process_event(MiddleButton()); | |
228 | std::cout <<"pressing East button to fast forward" << std::endl; | |
229 | sm.process_event(EastPressed()); | |
230 | // we switch off and on | |
231 | std::cout <<"switch off player" << std::endl; | |
232 | sm.process_event(SouthPressed()); | |
233 | sm.process_event(OnOffTimer()); | |
234 | std::cout <<"switch on player" << std::endl; | |
235 | sm.process_event(SouthPressed()); | |
236 | } | |
237 | } | |
238 | ||
239 | int main() | |
240 | { | |
241 | test(); | |
242 | return 0; | |
243 | } |