• 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 #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