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>
on_entry__anon307d96c30111::iPod_::NotHolding41 void on_entry(Event const&,FSM& ) {std::cout << "starting: NotHolding" << std::endl;}
42 template <class Event,class FSM>
on_exit__anon307d96c30111::iPod_::NotHolding43 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>
on_entry__anon307d96c30111::iPod_::Holding48 void on_entry(Event const&,FSM& ) {std::cout << "starting: Holding" << std::endl;}
49 template <class Event,class FSM>
on_exit__anon307d96c30111::iPod_::Holding50 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>
on_entry__anon307d96c30111::iPod_::NotPlaying55 void on_entry(Event const&,FSM& ) {std::cout << "starting: NotPlaying" << std::endl;}
56 template <class Event,class FSM>
on_exit__anon307d96c30111::iPod_::NotPlaying57 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>
on_entry__anon307d96c30111::iPod_::NoMenuMode62 void on_entry(Event const&,FSM& ) {std::cout << "starting: NoMenuMode" << std::endl;}
63 template <class Event,class FSM>
on_exit__anon307d96c30111::iPod_::NoMenuMode64 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>
on_entry__anon307d96c30111::iPod_::NoOnOffButton69 void on_entry(Event const&,FSM& ) {std::cout << "starting: NoOnOffButton" << std::endl;}
70 template <class Event,class FSM>
on_exit__anon307d96c30111::iPod_::NoOnOffButton71 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>
on_entry__anon307d96c30111::iPod_::OffDown76 void on_entry(Event const&,FSM& ) {std::cout << "starting: OffDown, start timer" << std::endl;}
77 template <class Event,class FSM>
on_exit__anon307d96c30111::iPod_::OffDown78 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>
on_entry__anon307d96c30111::iPod_::PlayerOff83 void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayerOff" << std::endl;}
84 template <class Event,class FSM>
on_exit__anon307d96c30111::iPod_::PlayerOff85 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>
on_entry__anon307d96c30111::iPod_::CheckMiddleButton90 void on_entry(Event const&,FSM& ) {std::cout << "starting: CheckMiddleButton" << std::endl;}
91 template <class Event,class FSM>
on_exit__anon307d96c30111::iPod_::CheckMiddleButton92 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
send_ActivateMenu__anon307d96c30111::iPod_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 }
send_StartSong__anon307d96c30111::iPod_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 }
send_PlayPause__anon307d96c30111::iPod_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 }
send_Off__anon307d96c30111::iPod_115 void send_Off(OnOffTimer const&)
116 {
117 std::cout << "turning player off" << std::endl;
118 (static_cast<iPod*>(this))->process_event(Off());
119 }
send_PlayingMiddleButton__anon307d96c30111::iPod_120 void send_PlayingMiddleButton(MiddleButton const&)
121 {
122 (static_cast<iPod*>(this))->process_event(PlayingMiddleButton());
123 }
send_MenuMiddleButton__anon307d96c30111::iPod_124 void send_MenuMiddleButton(MiddleButton const&)
125 {
126 (static_cast<iPod*>(this))->process_event(MenuMiddleButton());
127 }
128 // guard conditions
is_menu__anon307d96c30111::iPod_129 bool is_menu(MiddleButton const&)
130 {
131 return (static_cast<iPod*>(this))->is_flag_active<MenuActive>();
132 }
is_no_menu__anon307d96c30111::iPod_133 bool is_no_menu(MiddleButton const& evt)
134 {
135 return !is_menu(evt);
136 }
137 template <class EVENT>
switch_on__anon307d96c30111::iPod_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>
no_transition__anon307d96c30111::iPod_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
test()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
main()239 int main()
240 {
241 test();
242 return 0;
243 }
244