[DEV] add v1.66.0

This commit is contained in:
2018-01-12 21:47:58 +01:00
parent 87059bb1af
commit a97e9ae7d4
49032 changed files with 7668950 additions and 0 deletions

View File

@@ -0,0 +1,144 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace boost::msm::front::euml;
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(connect)
BOOST_MSM_EUML_EVENT(disconnect)
// flag
BOOST_MSM_EUML_FLAG(is_connected)
BOOST_MSM_EUML_ACTION(SignalConnect)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
// by default, this would be wrong (shows false)
cout << "SignalConnect. Connected? "
<< std::boolalpha
<< fsm.template is_flag_active<BOOST_MSM_EUML_FLAG_NAME(is_connected)>() << endl;
}
};
BOOST_MSM_EUML_ACTION(SignalDisconnect)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
// by default, this would be wrong (shows true)
cout << "SignalDisconnect. Connected? "
<< std::boolalpha
<< fsm.template is_flag_active<BOOST_MSM_EUML_FLAG_NAME(is_connected)>()
<< endl;
}
};
// The list of FSM states
BOOST_MSM_EUML_ACTION(Connected_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Connected" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Connected_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Connected" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( Connected_Entry,Connected_Exit,
attributes_ << no_attributes_,
configure_<< is_connected ),Connected)
BOOST_MSM_EUML_ACTION(Disconnected_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Disconnected" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Disconnected_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Disconnected" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( Disconnected_Entry,Disconnected_Exit ),Disconnected)
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Disconnected == Connected + disconnect / SignalDisconnect ,
Connected == Disconnected + connect / SignalConnect
// +------------------------------------------------------------------------------+
),transition_table)
BOOST_MSM_EUML_ACTION(Log_No_Transition)
{
template <class FSM,class Event>
void operator()(Event const& e,FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Disconnected, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << switch_active_before_transition, // configuration
Log_No_Transition // no_transition handler
),
Connection_) //fsm name
typedef msm::back::state_machine<Connection_> Connection;
void test()
{
Connection connection;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
connection.start();
// signal a connection
connection.process_event(connect);
// signal a disconnection
connection.process_event(disconnect);
connection.stop();
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,119 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// functors
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/euml/common.hpp>
using namespace std;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
namespace // Concrete FSM implementation
{
// events
struct disconnect {};
struct connect {};
// flag
struct is_connected{};
// front-end: define the FSM structure
struct Connection_ : public msm::front::state_machine_def<Connection_>
{
// when a transition is about to be taken, we already update our currently active state(s)
typedef msm::active_state_switch_before_transition active_state_switch_policy;
// The list of FSM states
struct Connected : public msm::front::state<>
{
// in this state, we are connected
typedef mpl::vector1<is_connected> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Connected" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Connected" << std::endl;}
};
struct Disconnected : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Disconnected" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Disconnected" << std::endl;}
};
// transition actions
struct SignalConnect
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&, FSM& fsm,SourceState& ,TargetState& )
{
// by default, this would be wrong (shows false)
cout << "SignalConnect. Connected? " << std::boolalpha << fsm.template is_flag_active<is_connected>() << endl;
}
};
struct SignalDisconnect
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&, FSM& fsm,SourceState& ,TargetState& )
{
// by default, this would be wrong (shows true)
cout << "SignalDisconnect. Connected? " << std::boolalpha << fsm.template is_flag_active<is_connected>() << endl;
}
};
// the initial state of the player SM. Must be defined
typedef Disconnected initial_state;
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +--------------+-------------+--------------+---------------------------+----------------------+
Row < Connected , disconnect , Disconnected , SignalDisconnect , none >,
Row < Disconnected , connect , Connected , SignalConnect , none >
// +--------------+-------------+--------------+---------------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<Connection_> Connection;
void test()
{
Connection connection;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
connection.start();
// signal a connection
connection.process_event(connect());
// signal a disconnection
connection.process_event(disconnect());
connection.stop();
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,133 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace boost::msm::front;
namespace
{
// events
struct event1 {};
// front-end: define the FSM structure
struct my_machine_ : public msm::front::state_machine_def<my_machine_>
{
// The list of FSM states
struct State1 : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: State1" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State1" << std::endl;}
};
struct State2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: State2" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State2" << std::endl;}
};
struct State3 : public msm::front::state<>
{
// when stopped, the CD is loaded
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: State3" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State3" << std::endl;}
};
struct State4 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: State4" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State4" << std::endl;}
};
// the initial state of the player SM. Must be defined
typedef State1 initial_state;
// transition actions
void State2ToState3(none const&) { std::cout << "my_machine::State2ToState3\n"; }
void State3ToState4(none const&) { std::cout << "my_machine::State3ToState4\n"; }
// guard conditions
bool always_true(none const& evt)
{
std::cout << "always_true" << std::endl;
return true;
}
bool always_false(none const& evt)
{
std::cout << "always_false" << std::endl;
return false;
}
typedef my_machine_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
_row < State1 , none , State2 >,
a_row < State2 , none , State3 , &p::State2ToState3 >,
// +---------+-------------+---------+---------------------+----------------------+
row < State3 , none , State4 , &p::State3ToState4 , &p::always_true >,
g_row < State3 , none , State4 , &p::always_false >,
_row < State4 , event1 , State1 >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<my_machine_> my_machine;
//
// Testing utilities.
//
static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
void pstate(my_machine const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
my_machine p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
// in this case it will also immediately trigger all anonymous transitions
p.start();
// this event will bring us back to the initial state and thus, a new "loop" will be started
p.process_event(event1());
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,175 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
namespace msm = boost::msm;
using namespace boost::msm::front::euml;
namespace
{
// events
BOOST_MSM_EUML_EVENT(event1)
BOOST_MSM_EUML_ACTION(State1_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: State1" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State1_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: State1" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State2_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: State2" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State2_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: State2" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State3_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: State3" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State3_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: State3" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State4_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: State4" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State4_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: State4" << std::endl;
}
};
// The list of FSM states
BOOST_MSM_EUML_STATE(( State1_Entry,State1_Exit ),State1)
BOOST_MSM_EUML_STATE(( State2_Entry,State2_Exit ),State2)
BOOST_MSM_EUML_STATE(( State3_Entry,State3_Exit ),State3)
BOOST_MSM_EUML_STATE(( State4_Entry,State4_Exit ),State4)
// transition actions
BOOST_MSM_EUML_ACTION(State2ToState3)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
std::cout << "my_machine::State2ToState3" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State3ToState4)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
std::cout << "my_machine::State3ToState4" << std::endl;
}
};
// guard conditions
BOOST_MSM_EUML_ACTION(always_true)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
std::cout << "always_true" << std::endl;
return true;
}
};
BOOST_MSM_EUML_ACTION(always_false)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
std::cout << "always_false" << std::endl;
return false;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
State2 == State1 ,
State3 == State2 / State2ToState3,
State4 == State3 [always_true] / State3ToState4,
State4 == State3 [always_false],
State1 == State4 + event1
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << State1 // Init State
),
my_machine_) //fsm name
// Pick a back-end
typedef msm::back::state_machine<my_machine_> my_machine;
//
// Testing utilities.
//
static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
void pstate(my_machine const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
my_machine p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
// in this case it will also immediately trigger all anonymous transitions
p.start();
// this event will bring us back to the initial state and thus, a new "loop" will be started
p.process_event(event1);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,158 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// functors
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/euml/common.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace boost::msm::front;
namespace
{
// events
struct event1 {};
// front-end: define the FSM structure
struct my_machine_ : public msm::front::state_machine_def<my_machine_>
{
// The list of FSM states
struct State1 : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: State1" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State1" << std::endl;}
};
struct State2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: State2" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State2" << std::endl;}
};
struct State3 : public msm::front::state<>
{
// when stopped, the CD is loaded
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: State3" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State3" << std::endl;}
};
struct State4 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: State4" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State4" << std::endl;}
};
// the initial state of the player SM. Must be defined
typedef State1 initial_state;
// transition actions
struct State2ToState3
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
std::cout << "my_machine::State2ToState3" << std::endl;
}
};
struct State3ToState4
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
std::cout << "my_machine::State3ToState4" << std::endl;
}
};
// guard conditions
struct always_true
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
{
std::cout << "always_true" << std::endl;
return true;
}
};
struct always_false
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
{
std::cout << "always_false" << std::endl;
return true;
}
};
typedef my_machine_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
Row < State1 , none , State2 >,
Row < State2 , none , State3 , State2ToState3 >,
Row < State3 , none , State4 , none , always_false >,
// +---------+-------------+---------+---------------------+----------------------+
Row < State3 , none , State4 , State3ToState4 , always_true >,
Row < State4 , event1 , State1 >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<my_machine_> my_machine;
//
// Testing utilities.
//
static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
void pstate(my_machine const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
my_machine p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
// in this case it will also immediately trigger all anonymous transitions
p.start();
// this event will bring us back to the initial state and thus, a new "loop" will be started
p.process_event(event1());
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,370 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/mpl/vector/vector50.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/back/tools.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
// event which every other event can convert to
struct AllSongsPlayed
{
template <class Event>
AllSongsPlayed(Event const&){}
};
struct PreviousSong {};
struct error_found {};
struct end_error {};
// Flags. Allow information about a property of the current state
struct CDLoaded {};
struct FirstSongPlaying {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(DiskTypeEnum diskType): disc_type(diskType) {}
DiskTypeEnum disc_type;
};
// Concrete FSM implementation
struct player_ : public msm::front::state_machine_def<player_>
{
// The list of FSM states
struct Empty : public msm::front::state<>
{
typedef mpl::vector<play> deferred_events;
// every (optional) entry/exit methods get the event packed as boost::any. Not useful very often.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
typedef mpl::vector1<CDLoaded> flag_list;
typedef mpl::vector<play> deferred_events;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
// a state needing a pointer to the containing state machine
// and using for this the non-default policy
// if policy used, set_sm_ptr is needed
struct Stopped : public msm::front::state<default_base_state,msm::front::sm_ptr>
{
// when stopped, the CD is loaded
typedef mpl::vector1<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
void set_sm_ptr(player_* pl){m_player=pl;}
player_* m_player;
};
// the player state machine contains a state which is himself a state machine
// it demonstrates Shallow History: if the state gets activated with end_pause
// then it will remember the last active state and reactivate it
// also possible: AlwaysHistory, the last active state will always be reactivated
// or NoHistory, always restart from the initial state
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
typedef mpl::vector<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// The list of FSM states
struct Song1 : public msm::front::state<>
{
typedef mpl::vector1<FirstSongPlaying> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
};
struct Song2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
struct CDFinished : public msm::front::exit_pseudo_state<AllSongsPlayed>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing::CDFinished" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing::CDFinished" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
void all_songs_played(NextSong const&) { std::cout << "Playing::all_songs_played\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+---------------+------------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >,
a_row < Song3 , NextSong , CDFinished , &pl::all_songs_played >
// +---------+---------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
// the player state machine contains a state which is himself a state machine (2 of them, Playing and Paused)
struct Paused : public msm::front::state<>
{
typedef mpl::vector<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
};
struct AllOk : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
};
struct ErrorMode : //public msm::front::terminate_state<>
public msm::front::interrupt_state<end_error>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
};
// the initial state of the player SM. Must be defined
typedef mpl::vector<Empty,AllOk> initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const&)
{
std::cout << "player::store_cd_info\n";
// generate another event to test the queue
//cd.m_player.process_event(play());
}
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void end_playback (AllSongsPlayed const&) { std::cout << "player::end_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
void report_error(error_found const&) {std::cout << "player::report_error\n";}
void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
// guard conditions
bool good_disk_format(cd_detected const& evt)
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +-------------+---------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +-------------+---------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +-------------+---------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
// +-------------+---------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
a_row < Playing::exit_pt<
Playing_::CDFinished> , AllSongsPlayed, Stopped , &p::end_playback >,
// +-------------+---------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >,
// +-------------+---------------+---------+---------------------+----------------------+
a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
a_row < ErrorMode ,end_error ,AllOk , &p::report_end_error >
// +-------------+---------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
void pstate(player const& p)
{
typedef player::stt Stt;
typedef msm::back::generate_state_set<Stt>::type all_states;
static char const* state_names[mpl::size<all_states>::value];
// fill the names of the states defined in the state machine
mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >
(msm::back::fill_state_names<Stt>(state_names));
for (unsigned int i=0;i<player::nr_regions::value;++i)
{
std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
}
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
// test deferred event
// deferred in Empty and Open, will be handled only after event cd_detected
std::cout << "play is not handled in the current state but is marked as delayed" << std::endl;
p.process_event(play()); pstate(p);
std::cout << "cd_detected will cause play to be handled also" << std::endl;
// will be rejected, wrong disk type
p.process_event(cd_detected(DISK_DVD)); pstate(p);
// will be accepted, wrong disk type
p.process_event(cd_detected(DISK_CD)); pstate(p);
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl; //=> true
p.process_event(NextSong());pstate(p);
// We are now in second song, Flag inactive
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
p.process_event(NextSong());pstate(p);
// 2nd song active
p.process_event(PreviousSong());pstate(p);
// Pause
p.process_event(pause()); pstate(p);
// go back to Playing
// but end_pause is an event activating the History
// => keep the last active State (SecondSong)
p.process_event(end_pause()); pstate(p);
// force an exit by listening all the songs
p.process_event(NextSong());
p.process_event(NextSong());pstate(p);
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
// go back to Playing
// but play is not leading to Shallow History => do not remember the last active State (SecondSong)
// and activate again FirstSong and LightOn
p.process_event(play()); pstate(p);
p.process_event(error_found()); pstate(p);
// try generating more events
std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
p.process_event(NextSong());pstate(p);
std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(end_error());pstate(p);
std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(NextSong());pstate(p);
// the states and events of the higher level FSM (player)
typedef player::stt Stt;
typedef msm::back::generate_state_set<Stt>::type simple_states;
std::cout << "the state list:" << std::endl;
mpl::for_each<simple_states,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
std::cout << "the event list:" << std::endl;
typedef msm::back::generate_event_set<Stt>::type event_list;
mpl::for_each<event_list,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
std::cout << std::endl;
// the states and events recursively searched
typedef msm::back::recursive_get_transition_table<player>::type recursive_stt;
std::cout << "the state list (including sub-SMs):" << std::endl;
typedef msm::back::generate_state_set<recursive_stt>::type all_states;
mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
std::cout << "the event list (including sub-SMs):" << std::endl;
typedef msm::back::generate_event_set<recursive_stt>::type all_events;
mpl::for_each<all_events,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,446 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <list>
#include <set>
#include <map>
#include <iostream>
// we need more than the default 10 states
#define FUSION_MAX_VECTOR_SIZE 15
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/stl.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
// how long the timer will ring when countdown elapsed.
#define RINGING_TIME 5
namespace // Concrete FSM implementation
{
// flag
BOOST_MSM_EUML_FLAG(SomeFlag)
// declares attributes with type and name. Can be used anywhere after
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_song_id)
// declare that a type inheriting from OneSongDef will get these 2 attributes
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song << m_song_id ), OneSongDef)
// events
// this event is done "manually", not using any predefined macro
struct OneSong_impl : euml_event<OneSong_impl>,OneSongDef
{
OneSong_impl(){}
OneSong_impl(const string& asong)
{
get_attribute(m_song)=asong;
get_attribute(m_song_id)=1;
}
OneSong_impl(const OneSong_impl& asong)
{
get_attribute(m_song)=asong.get_attribute(m_song);
get_attribute(m_song_id)=1;
}
const string& get_data() const {return get_attribute(m_song);}
};
// declare an instance for use in the transition table
OneSong_impl const OneSong;
struct SongComparator : euml_action<SongComparator>
{
bool operator()(const OneSong_impl& lhs,const OneSong_impl& rhs)const
{
return lhs.get_data() == rhs.get_data();
}
};
struct SongLessComparator : euml_action<SongLessComparator>
{
bool operator()(const OneSong_impl& lhs,const OneSong_impl& rhs)const
{
return lhs.get_data() < rhs.get_data();
}
};
struct Comparator
{
template <class T>
bool operator()(const T& lhs,const T& rhs)const
{
return lhs < rhs;
}
};
struct RemoveDummy
{
bool operator()(const OneSong_impl& lhs)const
{
return (lhs.get_attribute(m_song).compare(std::string("She-Dummy. Remove this one"))==0 );
}
};
template <int val>
struct LookFor
{
template <class T>
bool operator()(const T& lhs)const
{
return lhs == val;
}
};
template <int val>
struct LessThan
{
template <class T>
bool operator()(const T& lhs)const
{
return lhs < val;
}
};
BOOST_MSM_EUML_ACTION(SongDeleter)
{
bool operator()(const OneSong_impl& lhs)const
{
return lhs.get_data() == "Twist and Shout";
}
};
struct Generator
{
int operator()()const
{
return 1;
}
};
struct Print
{
template <class T>
void operator()(const T& lhs)const
{
std::cout << "Song:" << lhs.get_data() << endl;
}
};
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), NotFoundDef)
// declare an event instance called NotFound with the defined attributes
// these attributes can then be referenced anywhere (stt, state behaviors)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(NotFound,NotFoundDef)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), FoundDef)
struct Found_impl : euml_event<Found_impl>,FoundDef
{
Found_impl(){}
Found_impl (const string& data)
{
get_attribute(m_song)=data;
}
int foo()const {std::cout << "foo()" << std::endl; return 0;}
int foo(int i)const {std::cout << "foo(int):" << i << std::endl; return 1;}
int foo(int i,int j)const {std::cout << "foo(int,int):" << i <<"," << j << std::endl; return 2;}
};
Found_impl const Found;
// some functions to call
// this macro creates a functor and an eUML function wrapper. Now, foo_ can be used anywhere
BOOST_MSM_EUML_METHOD(FoundFoo_ , foo , foo_ , int , int )
template <class T>
int do_print(T& t ) {std::cout << "print(T):" << typeid(T).name() << std::endl;return 1;}
BOOST_MSM_EUML_FUNCTION(PrintState_ , do_print , print_ , int , int )
BOOST_MSM_EUML_EVENT(Done)
// Concrete FSM implementation
struct some_base
{
int foobar()const {std::cout << "foobar()" << std::endl; return 0;}
int foobar(int i)const {std::cout << "foobar(int):" << i << std::endl; return 1;}
int foobar(int i,int j)const {std::cout << "foobar(int,int):" << i <<"," << j << std::endl; return 2;}
};
// some functions to call
BOOST_MSM_EUML_METHOD(FooBar_ , foobar , foobar_ , int , int )
// fsm attributes
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>,m_src_container)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(list<OneSong_impl>,m_tgt_container)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(list<int>,m_var2)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(list<int>,m_var3)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(set<int>,m_var4)
typedef std::map<int,int> int_int_map;
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int_int_map,m_var5)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_var6)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_var7)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<int>,m_var8)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<int>,m_var9)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_var10)
// The list of FSM states
BOOST_MSM_EUML_STATE(( ( insert_(fsm_(m_tgt_container),end_(fsm_(m_tgt_container)),
append_(event_(m_song),fsm_(m_var7)) ),//foo_(event_,Int_<0>()) ,
//foo_(event_,Int_<0>(),Int_<1>()),print_(state_),
process_(Done/*,fsm_*/),if_then_(true_,true_) ),
no_action
),Insert)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_letters)
BOOST_MSM_EUML_STATE(( if_then_else_( (string_find_(event_(m_song),state_(m_letters),Size_t_<0>()) != Npos_<string>()&&
string_find_(event_(m_song),Char_<'S'>(),Size_t_<0>()) != Npos_<string>()&&
string_find_first_of_(event_(m_song),Char_<'S'>()) == Size_t_<0>() &&
string_compare_(event_(m_song),Int_<0>(),size_(event_(m_song)),event_(m_song)) == Int_<0>()
//&& is_flag_(SomeFlag(),fsm_())
//&& ( event_(m_song_id) == Int_<1>())
//&& string_find_(event_(m_song),String_<mpl::string<'Sh','e'> >())
// != Npos_<string>()
),
process2_(Found,
//string_insert_(event_(m_song),Size_t_<0>(),fsm_(m_var6)) ),
string_replace_(
string_assign_(
string_erase_(
string_insert_(
substr_(event_(m_song),Size_t_<1>()),
Size_t_<0>(),
Size_t_<1>(),
Char_<'S'>()),
Size_t_<0>(),
Size_t_<1>() ),
event_(m_song) ),
Size_t_<0>(),
Size_t_<1>(),
c_str_(fsm_(m_var6))
/*Size_t_<1>(),
Char_<'s'>()*/ ) ),
process2_(NotFound,event_(m_song),fsm_) ) ,
no_action,
attributes_ << m_letters,
configure_<< SomeFlag ),StringFind)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>::iterator,m_src_it)
BOOST_MSM_EUML_STATE(( if_then_( (state_(m_src_it) != end_(fsm_(m_src_container)) &&
//associative_find_(fsm_(m_var4),Int_<9>()) != end_(fsm_(m_var4))&&
//associative_count_(fsm_(m_var4),Int_<9>()) == Size_t_<1>() &&
//*associative_upper_bound_(fsm_(m_var4),Int_<8>()) == Int_<9>()&&
//*associative_lower_bound_(fsm_(m_var4),Int_<9>()) == Int_<9>() &&
//second_(associative_equal_range_(fsm_(m_var4),Int_<8>())) == associative_upper_bound_(fsm_(m_var4),Int_<8>()) &&
//first_(associative_equal_range_(fsm_(m_var4),Int_<8>())) == associative_lower_bound_(fsm_(m_var4),Int_<8>())&&
//second_(*associative_lower_bound_(fsm_(m_var5),Int_<0>())) == Int_<0>() && //map => pair as return
//find_if_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<LookFor<8> >()) != end_(fsm_(m_var4))&&
//*lower_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >()) == Int_<9>()&&
//*upper_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<8>(),Predicate_<std::less<int> >()) == Int_<9>() &&
//second_(equal_range_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<8>()))
// == upper_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<8>()) &&
//first_(equal_range_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >()))
// == lower_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >())&&
//binary_search_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >())&&
//binary_search_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>())&&
//count_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>()) == Int_<1>()&&
//count_if_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<LookFor<9> >()) == Int_<1>()&&
//distance_(begin_(fsm_(m_var4)),end_(fsm_(m_var4))) == Int_<2>()&&
//*min_element_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<std::less<int> >()) == Int_<8>()&&
//*max_element_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<std::less<int> >()) == Int_<9>()&&
//adjacent_find_(begin_(fsm_(m_var4)),end_(fsm_(m_var4))) == end_(fsm_(m_var4))&&
//*find_end_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))
// == Int_<1>()&&
//*find_first_of_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))
// == Int_<1>()&&
//equal_(begin_(fsm_(m_var9)),end_(fsm_(m_var9)),begin_(fsm_(m_var8)))&&
//*search_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))
// == Int_<1>()&&
//includes_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))&&
//!lexicographical_compare_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),
// begin_(fsm_(m_var9)),end_(fsm_(m_var9)))&&
//first_(mismatch_(begin_(fsm_(m_var9)),end_(fsm_(m_var9)),begin_(fsm_(m_var8))))
// == end_(fsm_(m_var9)) &&
accumulate_(begin_(fsm_(m_var9)),end_(fsm_(m_var9)),Int_<1>(),
Predicate_<std::plus<int> >()) == Int_<1>()
),
(process2_(OneSong,*(state_(m_src_it)++))/*,foobar_(fsm_,Int_<0>())*/ ) ),
no_action,
attributes_ << m_src_it
, configure_<< SomeFlag ),Foreach)
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
StringFind == Foreach + OneSong[if_then_else_(true_,true_,true_)],
Insert == StringFind + Found / (if_then_(true_,no_action)),
Foreach == StringFind + NotFound ,
Foreach == Insert + Done
// +------------------------------------------------------------------------------+
),transition_table )
BOOST_MSM_EUML_ACTION(Log_No_Transition)
{
template <class FSM,class Event>
void operator()(Event const& e,FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Foreach, // Init
//insert_(state_(m_var4),begin_(state_(m_var2)),end_(state_(m_var2))),
(insert_(state_(m_var4),Int_<5>()),insert_(state_(m_var4),Int_<6>()),insert_(state_(m_var4),Int_<7>()),
insert_(state_(m_var4),Int_<8>()),insert_(state_(m_var4),Int_<9>()),
associative_erase_(state_(m_var4),Int_<6>()),associative_erase_(state_(m_var4),begin_(state_(m_var4))),
associative_erase_(state_(m_var4),begin_(state_(m_var4)),++begin_(state_(m_var4))),
insert_(state_(m_var2),begin_(state_(m_var2)),begin_(state_(m_var3)),end_(state_(m_var3))),
state_(m_var5)[Int_<0>()]=Int_<0>(),state_(m_var5)[Int_<1>()]=Int_<1>()
,attribute_(substate_(Foreach,fsm_),m_src_it)
= begin_(fsm_(m_src_container))
//,fill_(begin_(state_(m_var9)),end_(state_(m_var9)),Int_<0>())
//,fill_n_(begin_(state_(m_var9)),Size_t_<2>(),Int_<0>())
//,transform_(begin_(state_(m_var4)),end_(state_(m_var4)),begin_(state_(m_var2)),begin_(state_(m_var4)),
// Predicate_<std::plus<int> >())
//,process_(Done,fsm_(),fsm_)
//,process_(Done,fsm_)
//,fsm_
//,foobar_(state_,Int_<0>(),Int_<1>())
//,nth_element_(begin_(state_(m_var9)),++begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
//,partial_sort_(begin_(state_(m_var9)),end_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
//,partial_sort_copy_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
//,list_sort_(state_(m_var2))
//,sort_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
//,inner_product_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),Int_<1>())
//,replace_copy_(begin_(state_(m_var4)),end_(state_(m_var4)),begin_(state_(m_var4)),Int_<8>(),Int_<7>())
//,replace_copy_if_(begin_(state_(m_var4)),end_(state_(m_var4)),begin_(state_(m_var4)),Predicate_<LookFor<9> >(),Int_<8>())
//,replace_(begin_(state_(m_var4)),end_(state_(m_var4)),Int_<8>(),Int_<7>())
//,replace_if_(begin_(state_(m_var4)),end_(state_(m_var4)),Predicate_<LookFor<9> >(),Int_<8>())
//,adjacent_difference_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)))
//,partial_sum_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)))
//,inner_product_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),Int_<1>())
//,next_permutation_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
//,prev_permutation_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
//,set_union_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)))
//,inplace_merge_(begin_(state_(m_var9)),end_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
//,merge_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),end_(state_(m_var9))
// ,begin_(state_(m_var9)),Predicate_<std::less<int> >())
//,stable_sort_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
//,partition_(begin_(state_(m_var2)),end_(state_(m_var2)),Predicate_<LessThan<3> >())
//,stable_partition_(begin_(state_(m_var2)),end_(state_(m_var2)),Predicate_<LessThan<3> >())
//,rotate_copy_(begin_(state_(m_var2)),++begin_(state_(m_var2)),end_(state_(m_var2)),begin_(state_(m_var2)))
//,rotate_(begin_(state_(m_var2)),++begin_(state_(m_var2)),end_(state_(m_var2)))
//,unique_(begin_(state_(m_var2)),end_(state_(m_var2)))
//,unique_copy_(begin_(state_(m_var2)),end_(state_(m_var2)),begin_(state_(m_var2)))
//,random_shuffle_(begin_(state_(m_var9)),end_(state_(m_var9)))
//,generate_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<Generator>())
//,generate_n_(begin_(state_(m_var9)),Int_<2>(),Predicate_<Generator>())
//,reverse_copy_(begin_(state_(m_var2)),end_(state_(m_var2)),begin_(state_(m_var2)))
//erase_(state_(m_src_container),
// remove_if_(begin_(state_(m_src_container)),end_(state_(m_src_container)),
// Predicate_<RemoveDummy>()),
// end_(state_(m_src_container))),
//list_remove_(state_(m_var2),Int_<3>()),
//remove_copy_if_(begin_(state_(m_var9)),end_(state_(m_var9)),back_inserter_(state_(m_var2)),
// Predicate_<LookFor<2> >() )
//for_each_(begin_(state_(m_src_container)),end_(state_m_src_container()),
// Predicate_<Print>() ),
//copy_(begin_(state_(m_var9)),end_(state_(m_var9)),inserter_(state_(m_var2),end_(state_(m_var2)))),
//reverse_(begin_(state_(m_var2)),end_(state_(m_var2)))
),
//no_action, // Entry
//splice_(state_(m_var2),begin_(state_(m_var2)),state_(m_var3),begin_(state_(m_var3)),end_(state_(m_var3))),
//(list_remove_(state_(m_var2),Int_<3>()),list_merge_(state_(m_var2),state_(m_var3),Comparator())),//no_action, // Entry
no_action, // Exit
attributes_ << m_src_container // song list
<< m_tgt_container // result
<< m_var2
<< m_var3
<< m_var4
<< m_var5
<< m_var6
<< m_var7
<< m_var8
<< m_var9
<< m_var10,
configure_<< no_configure_,
Log_No_Transition
),iPodSearch_helper)
struct iPodSearch_ : public iPodSearch_helper, public some_base
{
};
// choice of back-end
typedef msm::back::state_machine<iPodSearch_> iPodSearch;
void test()
{
iPodSearch search;
// fill our song list
//search.get_attribute<m_src_container>().push_back(OneSong("She-Dummy. Remove this one"));
search.get_attribute(m_src_container).push_back(OneSong_impl("Let it be"));
search.get_attribute(m_src_container).push_back(OneSong_impl("Yellow submarine"));
search.get_attribute(m_src_container).push_back(OneSong_impl("Twist and Shout"));
search.get_attribute(m_src_container).push_back(OneSong_impl("She Loves You"));
search.get_attribute(m_var2).push_back(1);
search.get_attribute(m_var2).push_back(3);
search.get_attribute(m_var2).push_back(4);
search.get_attribute(m_var3).push_back(2);
search.get_attribute(m_var3).push_back(4);
search.get_attribute(m_var6) = "S";
search.get_attribute(m_var7) = "- Some text";
search.get_attribute(m_var8).push_back(1);
search.get_attribute(m_var8).push_back(2);
search.get_attribute(m_var8).push_back(3);
search.get_attribute(m_var8).push_back(4);
search.get_attribute(m_var9).push_back(1);
search.get_attribute(m_var9).push_back(2);
// look for "She Loves You" using the first letters
// BOOST_MSM_EUML_STATE_NAME returns the name of the event type of which StringFind is an instance
search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="Sh";
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
search.start();
// display all the songs
for (list<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
it != search.get_attribute(m_tgt_container).end();++it)
{
cout << "candidate song:" << (*it).get_data() << endl;
}
for (list<int>::const_iterator iti = search.get_attribute(m_var2).begin();
iti != search.get_attribute(m_var2).end();++iti)
{
cout << "int in attribute m_var2:" << (*iti) << endl;
}
for (set<int>::const_iterator its = search.get_attribute(m_var4).begin();
its != search.get_attribute(m_var4).end();++its)
{
cout << "int in attribute m_var4:" << (*its) << endl;
}
cout << "search using more letters" << endl;
// look for "She Loves You" using more letters
search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="She";
search.get_attribute(m_tgt_container).clear();
search.start();
// display all the songs
for (list<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
it != search.get_attribute(m_tgt_container).end();++it)
{
cout << "candidate song:" << (*it).get_data() << endl;
}
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,244 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
// A "complicated" event type that carries some data.
struct cd_detected
{
cd_detected(std::string name)
: name(name)
{}
std::string name;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Player" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Player" << std::endl;}
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
// the player state machine contains a state which is himself a state machine
// as you see, no need to declare it anywhere so Playing can be developed separately
// by another team in another module. For simplicity I just declare it inside player
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// The list of FSM states
struct Song1 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
};
struct Song2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
typedef msm::back::state_machine<Playing_> Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const& cd) {std::cout << "player::store_cd_info\n";}
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
p.process_event(cd_detected("louie, louie"));
p.process_event(play());
// at this point, Play is active
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(NextSong());pstate(p); //2nd song active
p.process_event(NextSong());pstate(p);//3rd song active
p.process_event(PreviousSong());pstate(p);//2nd song active
p.process_event(pause()); pstate(p);
// go back to Playing
// as you see, it starts back from the original state
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
p.process_event(stop()); pstate(p);
// stop the fsm (call on_exit's, including the submachines)
p.process_event(play());
std::cout << "stop fsm" << std::endl;
p.stop();
std::cout << "restart fsm" << std::endl;
p.start();
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,182 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
BOOST_MSM_EUML_EVENT(next_song)
BOOST_MSM_EUML_EVENT(previous_song)
BOOST_MSM_EUML_EVENT(region2_evt)
// A "complicated" event type that carries some data.
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
// Concrete FSM implementation
// The list of FSM states
// state not defining any entry or exit
BOOST_MSM_EUML_STATE((),Paused)
BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
// Playing is now a state machine itself.
// It has 5 substates
BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
BOOST_MSM_EUML_STATE(( Region2State1_Entry,Region2State1_Exit ),Region2State1)
BOOST_MSM_EUML_STATE(( Region2State2_Entry,Region2State2_Exit ),Region2State2)
// Playing has a transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
Song2 == Song1 + next_song / start_next_song,
Song1 == Song2 + previous_song / start_prev_song,
Song3 == Song2 + next_song / start_next_song,
Song2 == Song3 + previous_song / start_prev_song,
Region2State2 == Region2State1 + region2_evt
// +------------------------------------------------------------------------------+
),playing_transition_table )
BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
init_ << Song1 << Region2State1 // Init State
),Playing_)
// choice of back-end
typedef msm::back::state_machine<Playing_> Playing_type;
Playing_type const Playing;
// guard conditions
BOOST_MSM_EUML_ACTION(good_disk_format)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.get_attribute(cd_type)!=DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
// just for logging, does not block any transition
return true;
}
std::cout << "good disk" << std::endl;
return true;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Playing == Stopped + play / start_playback ,
Playing == Paused + end_pause / resume_playback,
// +------------------------------------------------------------------------------+
Empty == Open + open_close / close_drawer,
// +------------------------------------------------------------------------------+
Open == Empty + open_close / open_drawer,
Open == Paused + open_close / stop_and_open,
Open == Stopped + open_close / open_drawer,
Open == Playing + open_close / stop_and_open,
// +------------------------------------------------------------------------------+
Paused == Playing + pause / pause_playback,
// +------------------------------------------------------------------------------+
Stopped == Playing + stop / stop_playback,
Stopped == Paused + stop / stop_playback,
Stopped == Empty + cd_detected [good_disk_format &&(event_(cd_type)==Int_<DISK_CD>())]
/ (store_cd_info,process_(play)),
Stopped == Stopped + stop
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
// choice of back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// note that we write open_close and not open_close(), like usual. Both are possible with eUML, but
// you now have less to type.
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play() as the previous event does it in its action method
//p.process_event(play);
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(next_song);pstate(p); //2nd song active
p.process_event(next_song);pstate(p);//3rd song active
p.process_event(previous_song);pstate(p);//2nd song active
// at this point, Play is active
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as none is defined in the transition table
p.process_event(stop); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,209 @@
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/euml/euml.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace std;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace
{
// events
struct play_impl : msm::front::euml::euml_event<play_impl> {};
struct end_pause_impl : msm::front::euml::euml_event<end_pause_impl>{};
struct stop_impl : msm::front::euml::euml_event<stop_impl>{};
struct pause_impl : msm::front::euml::euml_event<pause_impl>{};
struct open_close_impl : msm::front::euml::euml_event<open_close_impl>{};
struct cd_detected_impl : msm::front::euml::euml_event<cd_detected_impl>{};
struct next_song_impl : msm::front::euml::euml_event<next_song_impl>{};
struct previous_song_impl : msm::front::euml::euml_event<previous_song_impl>{};
// define some dummy instances for use in the transition table
// it is also possible to default-construct them instead:
// struct play {};
// inside the table: play()
play_impl play;
end_pause_impl end_pause;
stop_impl stop;
pause_impl pause;
open_close_impl open_close;
cd_detected_impl cd_detected;
next_song_impl next_song;
previous_song_impl previous_song;
// The list of FSM states
// they have to be declared outside of the front-end only to make VC happy :(
// note: gcc would have no problem
struct Empty_impl : public msm::front::state<> , public msm::front::euml::euml_state<Empty_impl>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open_impl : public msm::front::state<> , public msm::front::euml::euml_state<Open_impl>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped_impl : public msm::front::state<> , public msm::front::euml::euml_state<Stopped_impl>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
// Playing Submachine front-end
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
struct Song1_ : public msm::front::state<> , public msm::front::euml::euml_state<Song1_>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Song1" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Song1" << std::endl;}
};
struct Song2_ : public msm::front::state<> , public msm::front::euml::euml_state<Song2_>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Song2" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Song2" << std::endl;}
};
struct Song3_ : public msm::front::state<> , public msm::front::euml::euml_state<Song3_>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Song3" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Song3" << std::endl;}
};
// to make the transition table more readable
// VC seems to need them static
static Song1_ Song1;
static Song2_ Song2;
static Song3_ Song3;
typedef Song1_ initial_state;
// Playing has a transition table
BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
Song2 == Song1 + next_song / start_next_song,
Song1 == Song2 + previous_song / start_prev_song,
Song3 == Song2 + next_song / start_next_song,
Song2 == Song3 + previous_song / start_prev_song
// +------------------------------------------------------------------------------+
),transition_table )
};
// Playing Submachine back-end
typedef boost::msm::back::state_machine<Playing_> Playing_impl;
// state not defining any entry or exit
struct Paused_impl : public msm::front::state<> , public msm::front::euml::euml_state<Paused_impl>
{
};
//to make the transition table more readable
Empty_impl const Empty;
Open_impl const Open;
Stopped_impl const Stopped;
Playing_impl const Playing;
Paused_impl const Paused;
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// the initial state of the player SM. Must be defined
typedef Empty_impl initial_state;
// Transition table for player
// replaces the old transition table
BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
Stopped + play / start_playback == Playing ,
Stopped + open_close / open_drawer == Open ,
Stopped + stop == Stopped ,
// +------------------------------------------------------------------------------+
Open + open_close / close_drawer == Empty ,
// +------------------------------------------------------------------------------+
Empty + open_close / open_drawer == Open ,
Empty + cd_detected /(store_cd_info,
msm::front::euml::process_(play)) == Stopped ,
// +------------------------------------------------------------------------------+
Playing + stop / stop_playback == Stopped ,
Playing + pause / pause_playback == Paused ,
Playing + open_close / stop_and_open == Open ,
// +------------------------------------------------------------------------------+
Paused + end_pause / resume_playback == Playing ,
Paused + stop / stop_playback == Stopped ,
Paused + open_close / stop_and_open == Open
// +------------------------------------------------------------------------------+
),transition_table)
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
p.process_event(cd_detected); pstate(p);
// at this point, Play is active
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(next_song);pstate(p); //2nd song active
p.process_event(next_song);pstate(p);//3rd song active
p.process_event(previous_song);pstate(p);//2nd song active
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,292 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
struct SomeExternalContext
{
SomeExternalContext(int b):bla(b){}
int bla;
};
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
player_(SomeExternalContext& context,int someint)
:context_(context)
{
std::cout << "context value:" << context_.bla << " with value:" << someint << std::endl;
context.bla = 10;
}
SomeExternalContext& context_;
// The list of FSM states
struct Empty : public msm::front::state<>
{
int data_;
Empty():data_(0){}
Empty(int i):data_(i){}
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
int data_;
Open():data_(0){}
Open(int i):data_(i){}
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
// sm_ptr still supported but deprecated as functors are a much better way to do the same thing
struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
void set_sm_ptr(player_* pl)
{
m_player=pl;
}
player_* m_player;
};
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// The list of FSM states
struct Song1 : public msm::front::state<>
{
int data_;
Song1():data_(0){}
Song1(int i):data_(i){}
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
};
struct Song2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
typedef msm::back::state_machine<Playing_> Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; }
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
// guard conditions
bool good_disk_format(cd_detected const& evt)
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
// used to show a transition conflict. This guard will simply deactivate one transition and thus
// solve the conflict
bool auto_start(cd_detected const&)
{
return false;
}
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
_row < Stopped , stop , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
row < Empty , cd_detected , Playing , &p::store_cd_info ,&p::auto_start >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
SomeExternalContext ctx(3);
// example 1
// create a player with an argument by reference and an int
// (go to the constructor front-end)
player p1(boost::ref(ctx),5);
// example 2
// create a player with a copy of an Empty state, an argument by reference and an int
// (last 2 go to the constructor front-end)
player p2(msm::back::states_ << player_::Empty(1),boost::ref(ctx),5);
std::cout << "Empty's data should be 1. Is: " << p2.get_state<player_::Empty&>().data_ << std::endl;
std::cout << "Set a new Empty state" << std::endl;
p2.set_states(msm::back::states_ << player_::Empty(5));
std::cout << "Empty's data should be 5. Is: " << p2.get_state<player_::Empty&>().data_ << std::endl;
std::cout << "Set new Empty and Open states" << std::endl;
p2.set_states(msm::back::states_ << player_::Empty(7) << player_::Open(2));
std::cout << "Empty's data should be 7. Is: " << p2.get_state<player_::Empty&>().data_ << std::endl;
std::cout << "Open's data should be 2. Is: " << p2.get_state<player_::Open&>().data_ << std::endl;
// example 3
// create a player with a copy of an Empty state, a copy of a Playing submachine
// (which is itself created by a copy of Song1)
// an argument by reference and an int
// (last 2 go to the constructor front-end)
player p(msm::back::states_ << player_::Empty(1)
<< player_::Playing(msm::back::states_ << player_::Playing_::Song1(8)),
boost::ref(ctx),5);
std::cout << "Song1's data should be 8. Is: "
<< p.get_state<player_::Playing&>().get_state<player_::Playing_::Song1&>().data_ << std::endl;
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,386 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(event1)
BOOST_MSM_EUML_EVENT(event2)
BOOST_MSM_EUML_EVENT(event3)
BOOST_MSM_EUML_EVENT(event4)
BOOST_MSM_EUML_EVENT(event5)
// if we need something special, like a template constructor, we cannot use the helper macros
struct event6_impl : euml_event<event6_impl>
{
event6_impl(){}
template <class Event>
event6_impl(Event const&){}
};
event6_impl const event6;
//Sub fsm state definition
BOOST_MSM_EUML_ACTION(SubState1_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::SubState1" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SubState1_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::SubState1" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( SubState1_Entry,SubState1_Exit ),SubState1)
BOOST_MSM_EUML_ACTION(SubState1b_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::SubState1b" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SubState1b_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::SubState1b" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( SubState1b_Entry,SubState1b_Exit ),SubState1b)
BOOST_MSM_EUML_ACTION(SubState1c_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::SubState1c" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SubState1c_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::SubState1c" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( SubState1c_Entry,SubState1c_Exit ),SubState1c)
BOOST_MSM_EUML_ACTION(SubState2_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::SubState2" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SubState2_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::SubState2" << std::endl;
}
};
BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(0,( SubState2_Entry,SubState2_Exit ),SubState2)
BOOST_MSM_EUML_ACTION(SubState2b_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::SubState2b" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SubState2b_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::SubState2b" << std::endl;
}
};
BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(1,( SubState2b_Entry,SubState2b_Exit ),SubState2b)
BOOST_MSM_EUML_ACTION(SubState2c_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::SubState2c" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SubState2c_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::SubState2c" << std::endl;
}
};
BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(2,( SubState2c_Entry,SubState2c_Exit ),SubState2c)
BOOST_MSM_EUML_ACTION(PseudoEntry1_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::PseudoEntry1" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(PseudoEntry1_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::PseudoEntry1" << std::endl;
}
};
BOOST_MSM_EUML_ENTRY_STATE(0,( PseudoEntry1_Entry,PseudoEntry1_Exit ),PseudoEntry1)
BOOST_MSM_EUML_ACTION(SubState3_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::SubState3" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SubState3_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::SubState3" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( SubState3_Entry,SubState3_Exit ),SubState3)
BOOST_MSM_EUML_ACTION(SubState3b_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::SubState3b" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SubState3b_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::SubState3b" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( SubState3b_Entry,SubState3b_Exit ),SubState3b)
BOOST_MSM_EUML_ACTION(PseudoExit1_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2::PseudoExit1" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(PseudoExit1_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2::PseudoExit1" << std::endl;
}
};
BOOST_MSM_EUML_EXIT_STATE(( event6,PseudoExit1_Entry,PseudoExit1_Exit ),PseudoExit1)
// actions
BOOST_MSM_EUML_ACTION(entry_action)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(FSM& ,EVT const& ,SourceState& ,TargetState& )
{
cout << "calling entry_action" << endl;
}
};
// SubFsm definition
BOOST_MSM_EUML_ACTION(SubFsm2_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SubFsm2" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SubFsm2_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: SubFsm2" << std::endl;
}
};
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
SubState3 == PseudoEntry1 + event4 / entry_action ,
SubState1 == SubState2 + event6 ,
PseudoExit1 == SubState3 + event5
// +------------------------------------------------------------------------------+
), SubFsm2_transition_table)
BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (SubFsm2_transition_table, //STT
init_ << SubState1 << SubState1b << SubState1c, // Init State
SubFsm2_Entry, // Entry
SubFsm2_Exit
),SubFsm2_def)
// inherit to add some typedef
struct SubFsm2_ : public SubFsm2_def
{
// these 2 states are not found in the transition table because they are accessed only through
// a fork, so we need to create them explicitly
typedef mpl::vector<BOOST_MSM_EUML_STATE_NAME(SubState2b),
BOOST_MSM_EUML_STATE_NAME(SubState2c)> explicit_creation;
};
// back-end
typedef msm::back::state_machine<SubFsm2_> SubFsm2_type;
SubFsm2_type const SubFsm2;
// Fsm state definitions
BOOST_MSM_EUML_ACTION(State1_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: State1" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State1_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: State1" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( State1_Entry,State1_Exit ),State1)
BOOST_MSM_EUML_ACTION(State2_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: State2" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(State2_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: State2" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( State2_Entry,State2_Exit ),State2)
// Fsm definition
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
SubFsm2 == State1 + event1 ,
explicit_(SubFsm2,SubState2) == State1 + event2,
(explicit_(SubFsm2,SubState2),
explicit_(SubFsm2,SubState2b),
explicit_(SubFsm2,SubState2c)) == State1 + event3 ,
entry_pt_(SubFsm2,PseudoEntry1) == State1 + event4 ,
State1 == SubFsm2 + event1 ,
State2 == exit_pt_
(SubFsm2,PseudoExit1) + event6
// +------------------------------------------------------------------------------+
),transition_table )
BOOST_MSM_EUML_ACTION(Log_No_Transition)
{
template <class Event,class FSM,class STATE>
void operator()(Event const& e,FSM&,STATE& )
{
std::cout << "no transition in Fsm"
<< " on event " << typeid(e).name() << std::endl;
}
};
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << State1, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
Fsm_) //fsm name
//back-end
typedef msm::back::state_machine<Fsm_> Fsm;
//
// Testing utilities.
//
static char const* const state_names[] = { "State1", "SubFsm2","State2" };
void pstate(Fsm const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
Fsm p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
std::cout << "Simply move in and out of the composite, activate init states" << std::endl;
p.process_event(event1); pstate(p);
p.process_event(event1); pstate(p);
std::cout << "Direct entry into SubFsm2::SubState2, then transition to SubState1 and back to State1" << std::endl;
p.process_event(event2); pstate(p);
p.process_event(event6); pstate(p);
p.process_event(event1); pstate(p);
std::cout << "processing fork to SubFsm2::SubState2, SubFsm2::SubState2b and SubFsm2::SubState2c" << std::endl;
p.process_event(event3); pstate(p);
p.process_event(event1); pstate(p);
std::cout << "processing entry pseudo state" << std::endl;
p.process_event(event4); pstate(p);
p.process_event(event1); pstate(p);
std::cout << "processing entry + exit pseudo state" << std::endl;
p.process_event(event4); pstate(p);
std::cout << "using exit pseudo state" << std::endl;
p.process_event(event5); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,221 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace
{
// events
struct event1 {};
struct event2 {};
struct event3 {};
struct event4 {};
struct event5 {};
struct event6
{
event6(){}
template <class Event>
event6(Event const&){}
};
// front-end: define the FSM structure
struct Fsm_ : public msm::front::state_machine_def<Fsm_>
{
// The list of FSM states
struct State1 : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: State1" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State1" << std::endl;}
};
struct State2 : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: State2" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: State2" << std::endl;}
};
struct SubFsm2_ : public msm::front::state_machine_def<SubFsm2_>
{
typedef msm::back::state_machine<SubFsm2_> SubFsm2;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2" << std::endl;}
struct SubState1 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState1" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState1" << std::endl;}
};
struct SubState1b : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState1b" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState1b" << std::endl;}
};
struct SubState2 : public msm::front::state<> , public msm::front::explicit_entry<0>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState2" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState2" << std::endl;}
};
struct SubState2b : public msm::front::state<> , public msm::front::explicit_entry<1>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState2b" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState2b" << std::endl;}
};
// test with a pseudo entry
struct PseudoEntry1 : public msm::front::entry_pseudo_state<0>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::PseudoEntry1" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::PseudoEntry1" << std::endl;}
};
struct SubState3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState3" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState3" << std::endl;}
};
struct SubState3b : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState3b" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState3b" << std::endl;}
};
struct PseudoExit1 : public msm::front::exit_pseudo_state<event6>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::PseudoExit1" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::PseudoExit1" << std::endl;}
};
// action methods
void entry_action(event4 const&)
{
std::cout << "calling entry_action" << std::endl;
}
// the initial state. Must be defined
typedef mpl::vector<SubState1,SubState1b> initial_state;
typedef mpl::vector<SubState2b> explicit_creation;
// Transition table for SubFsm2
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +--------------+-------------+------------+------------------------+----------------------+
a_row < PseudoEntry1 , event4 , SubState3 ,&SubFsm2_::entry_action >,
_row < SubState2 , event6 , SubState1 >,
_row < SubState3 , event5 , PseudoExit1 >
// +--------------+-------------+------------+------------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<SubFsm2_> SubFsm2;
// the initial state of the player SM. Must be defined
typedef State1 initial_state;
// transition actions
// guard conditions
// Transition table for Fsm
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------------------+--------+------------------------------------+-------+--------+
_row < State1 , event1 , SubFsm2 >,
_row < State1 , event2 , SubFsm2::direct<SubFsm2_::SubState2> >,
_row < State1 , event3 , mpl::vector<SubFsm2::direct<SubFsm2_::SubState2>,
SubFsm2::direct<SubFsm2_::SubState2b> > >,
_row < State1 , event4 , SubFsm2::entry_pt
<SubFsm2_::PseudoEntry1> >,
// +---------------------+--------+------------------------------------+-------+--------+
_row < SubFsm2 , event1 , State1 >,
_row < SubFsm2::exit_pt
<SubFsm2_::PseudoExit1>, event6 , State2 >
// +---------------------+--------+------------------------------------+-------+--------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<Fsm_> Fsm;
//
// Testing utilities.
//
static char const* const state_names[] = { "State1", "SubFsm2","State2" };
void pstate(Fsm const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
Fsm p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
std::cout << "Simply move in and out of the composite, activate init states" << std::endl;
p.process_event(event1()); pstate(p);
p.process_event(event1()); pstate(p);
std::cout << "Direct entry into SubFsm2::SubState2, then transition to SubState1 and back to State1" << std::endl;
p.process_event(event2()); pstate(p);
p.process_event(event6()); pstate(p);
p.process_event(event1()); pstate(p);
std::cout << "processing fork to SubFsm2::SubState2 and SubFsm2::SubState2b" << std::endl;
p.process_event(event3()); pstate(p);
p.process_event(event1()); pstate(p);
std::cout << "processing entry pseudo state" << std::endl;
p.process_event(event4()); pstate(p);
p.process_event(event1()); pstate(p);
std::cout << "processing entry + exit pseudo state" << std::endl;
p.process_event(event4()); pstate(p);
std::cout << "using exit pseudo state" << std::endl;
p.process_event(event5()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,154 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
using namespace boost::msm::front;
namespace msm = boost::msm;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
BOOST_MSM_EUML_EVENT(internal_event)
// A "complicated" event type that carries some data.
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
// Concrete FSM implementation
// The list of FSM states
BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
// state not needing any entry or exit
BOOST_MSM_EUML_STATE((),Paused)
// guard conditions
BOOST_MSM_EUML_ACTION(good_disk_format)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.get_attribute(cd_type)!=DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
// just for logging, does not block any transition
return true;
}
std::cout << "good disk" << std::endl;
return true;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Playing == Stopped + play / start_playback ,
Playing == Paused + end_pause / resume_playback,
// +------------------------------------------------------------------------------+
Empty == Open + open_close / close_drawer,
// +------------------------------------------------------------------------------+
Open == Empty + open_close / open_drawer,
Open == Paused + open_close / stop_and_open,
Open == Stopped + open_close / open_drawer,
Open == Playing + open_close / stop_and_open,
Open + open_close [internal_guard1] / internal_action1,
Open + open_close [internal_guard2] / internal_action2,
Open + internal_event / internal_action ,
// +------------------------------------------------------------------------------+
Paused == Playing + pause / pause_playback,
// +------------------------------------------------------------------------------+
Stopped == Playing + stop / stop_playback,
Stopped == Paused + stop / stop_playback,
Stopped == Empty + cd_detected [good_disk_format&&
(event_(cd_type)==Int_<DISK_CD>())]
/ (store_cd_info,process_(play)),
Stopped == Stopped + stop
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
// choice of back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
std::cout << "sending internal event (not rejected)" << std::endl;
p.process_event(internal_event);
std::cout << "sending open_close event. Conflict with internal transitions (rejecting event)" << std::endl;
p.process_event(open_close); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play() as the previous event does it in its action method
//p.process_event(play);
// at this point, Play is active
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as none is defined in the transition table
p.process_event(stop); pstate(p);
// test call to no_transition
p.process_event(pause); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,218 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
using namespace boost::msm::front;
namespace msm = boost::msm;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace // Concrete FSM implementation
{
// events
// note that unlike the SimpleTutorial, events must derive from euml_event.
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
BOOST_MSM_EUML_EVENT(internal_event)
BOOST_MSM_EUML_EVENT(next_song)
BOOST_MSM_EUML_EVENT(previous_song)
// A "complicated" event type that carries some data.
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
// Concrete FSM implementation
// The list of FSM states
BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
// we just declare a state type but do not create any instance as we want to inherit from this type
BOOST_MSM_EUML_DECLARE_STATE((Open_Entry,Open_Exit),Open_def)
// derive to be able to add an internal transition table
struct Open_impl : public Open_def
{
BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
open_close [internal_guard1] / internal_action1 ,
open_close [internal_guard2] / internal_action2 ,
internal_event / internal_action
))
};
// declare an instance for the stt as we are manually declaring a state
Open_impl const Open;
BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
// Playing is a state machine itself.
// It has 3 substates
BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
// Playing has a transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
Song2 == Song1 + next_song / start_next_song,
Song1 == Song2 + previous_song / start_prev_song,
Song3 == Song2 + next_song / start_next_song,
Song2 == Song3 + previous_song / start_prev_song
// +------------------------------------------------------------------------------+
),playing_transition_table )
BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
init_ << Song1 // Init State
),Playing_def)
// some action for the internal transition
BOOST_MSM_EUML_ACTION(playing_internal_action)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
{
cout << "Playing::internal action" << endl;
}
};
// derive to be able to add an internal transition table
struct Playing_ : public Playing_def
{
BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
internal_event / playing_internal_action
))
};
// choice of back-end
typedef msm::back::state_machine<Playing_> Playing_type;
Playing_type const Playing;
// state not needing any entry or exit
BOOST_MSM_EUML_STATE((),Paused)
// guard conditions
BOOST_MSM_EUML_ACTION(good_disk_format)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.get_attribute(cd_type)!=DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
// just for logging, does not block any transition
return true;
}
std::cout << "good disk" << std::endl;
return true;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Stopped + play / start_playback == Playing ,
Stopped + open_close / open_drawer == Open ,
Stopped + stop == Stopped ,
// +------------------------------------------------------------------------------+
Open + open_close / close_drawer == Empty ,
// +------------------------------------------------------------------------------+
Empty + open_close / open_drawer == Open ,
Empty + cd_detected
[good_disk_format&&(event_(cd_type)==Int_<DISK_CD>())]
/ (store_cd_info,process_(play))
== Stopped ,
// +------------------------------------------------------------------------------+
Playing + stop / stop_playback == Stopped ,
Playing + pause / pause_playback == Paused ,
Playing + open_close / stop_and_open == Open ,
// +------------------------------------------------------------------------------+
Paused + end_pause / resume_playback == Playing ,
Paused + stop / stop_playback == Stopped ,
Paused + open_close / stop_and_open == Open
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
// choice of back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
std::cout << "sending internal event (not rejected)" << std::endl;
p.process_event(internal_event);
std::cout << "sending open_close event. Conflict with internal transitions (rejecting event)" << std::endl;
p.process_event(open_close); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play as the previous event does it in its action method
//p.process_event(play);
// at this point, Play is active
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(next_song);pstate(p); //2nd song active
p.process_event(next_song);pstate(p);//3rd song active
p.process_event(previous_song);pstate(p);//2nd song active
// event handled internally in Playing, without region checking
std::cout << "sending internal event (not rejected)" << std::endl;
p.process_event(internal_event);
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as none is defined in the transition table
p.process_event(stop); pstate(p);
// test call to no_transition
p.process_event(pause); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,222 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "stdafx.h"
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/stl.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace boost::msm::front::euml;
#include <iostream>
#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#endif
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
BOOST_MSM_EUML_EVENT(cd_detected)
BOOST_MSM_EUML_ACTION(start_playback)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
BOOST_MSM_EUML_ACTION(open_drawer)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
BOOST_MSM_EUML_ACTION(close_drawer)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
BOOST_MSM_EUML_ACTION(store_cd_info)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const&, FSM& fsm ,SourceState& ,TargetState& )
{
}
};
BOOST_MSM_EUML_ACTION(stop_playback)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
BOOST_MSM_EUML_ACTION(pause_playback)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
BOOST_MSM_EUML_ACTION(resume_playback)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
BOOST_MSM_EUML_ACTION(stop_and_open)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
BOOST_MSM_EUML_ACTION(stopped_again)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
// The list of FSM states
BOOST_MSM_EUML_STATE((),Empty)
BOOST_MSM_EUML_STATE((),Open)
BOOST_MSM_EUML_STATE((),Stopped)
BOOST_MSM_EUML_STATE((),Playing)
BOOST_MSM_EUML_STATE((),Paused)
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Playing == Stopped + play / start_playback ,
Playing == Paused + end_pause / resume_playback ,
// +------------------------------------------------------------------------------+
Empty == Open + open_close / close_drawer ,
// +------------------------------------------------------------------------------+
Open == Empty + open_close / open_drawer ,
Open == Paused + open_close / stop_and_open ,
Open == Stopped + open_close / open_drawer ,
Open == Playing + open_close / stop_and_open ,
// +------------------------------------------------------------------------------+
Paused == Playing + pause / pause_playback ,
// +------------------------------------------------------------------------------+
Stopped == Playing + stop / stop_playback ,
Stopped == Paused + stop / stop_playback ,
Stopped == Empty + cd_detected / store_cd_info ,
Stopped == Stopped + stop / stopped_again
// +------------------------------------------------------------------------------+
),transition_table)
BOOST_MSM_EUML_ACTION(Log_No_Transition)
{
template <class FSM,class Event>
void operator()(Event const& e,FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_exception << no_msg_queue, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
}
#ifndef WIN32
long mtime(struct timeval& tv1,struct timeval& tv2)
{
return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
}
#endif
int main()
{
// for timing
#ifdef WIN32
LARGE_INTEGER res;
::QueryPerformanceFrequency(&res);
LARGE_INTEGER li,li2;
#else
struct timeval tv1,tv2;
gettimeofday(&tv1,NULL);
#endif
player p2;
p2.start();
// for timing
#ifdef WIN32
::QueryPerformanceCounter(&li);
#else
gettimeofday(&tv1,NULL);
#endif
for (int i=0;i<100;++i)
{
p2.process_event(open_close);
p2.process_event(open_close);
p2.process_event(cd_detected);
p2.process_event(play);
p2.process_event(pause);
// go back to Playing
p2.process_event(end_pause);
p2.process_event(pause);
p2.process_event(stop);
// event leading to the same state
p2.process_event(stop);
p2.process_event(open_close);
p2.process_event(open_close);
}
#ifdef WIN32
::QueryPerformanceCounter(&li2);
#else
gettimeofday(&tv2,NULL);
#endif
#ifdef WIN32
std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
#else
std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
#endif
return 0;
}

View File

@@ -0,0 +1,299 @@
#include <vector>
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
// header for support of circular_buffer
#include <boost/msm/back/queue_container_circular.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// functors
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/euml/common.hpp>
// for And_ operator
#include <boost/msm/front/euml/operator.hpp>
using namespace std;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
// for And_ operator
using namespace msm::front::euml;
namespace // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
// as the functors are generic on events, fsm and source/target state,
// you can reuse them in another machine if you wish
struct TestFct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
{
cout << "transition with event:" << typeid(EVT).name() << endl;
}
};
struct start_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::start_playback" << endl;
}
};
struct open_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::open_drawer" << endl;
}
};
struct close_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::close_drawer" << endl;
}
};
struct store_cd_info
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}
};
struct stop_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_playback" << endl;
}
};
struct pause_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::pause_playback" << endl;
}
};
struct resume_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::resume_playback" << endl;
}
};
struct stop_and_open
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_and_open" << endl;
}
};
struct stopped_again
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stopped_again" << endl;
}
};
// guard conditions
struct DummyGuard
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
{
return true;
}
};
struct good_disk_format
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
};
struct always_true
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
return true;
}
};
// we want to define one row with the classic look.
bool auto_start(cd_detected const& evt)
{
return false;
}
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------------+----------------------+
Row < Stopped , play , Playing , ActionSequence_
<mpl::vector<
TestFct,start_playback> >
, DummyGuard >,
Row < Stopped , open_close , Open , open_drawer , none >,
Row < Stopped , stop , Stopped , none , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Open , open_close , Empty , close_drawer , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Empty , open_close , Open , open_drawer , none >,
Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
always_true> >,
// we here also mix with some "classical row"
g_row < Empty , cd_detected , Playing , &p::auto_start >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Playing , stop , Stopped , stop_playback , none >,
Row < Playing , pause , Paused , pause_playback , none >,
Row < Playing , open_close , Open , stop_and_open , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Paused , end_pause , Playing , resume_playback , none >,
Row < Paused , stop , Stopped , stop_playback , none >,
Row < Paused , open_close , Open , stop_and_open , none >
// +---------+-------------+---------+---------------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_, msm::back::queue_container_circular> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// we get the message queue and limit it to capacity 1
// get_message_queue returns the queue container (in this case circular_buffer)
p.get_message_queue().set_capacity(1);
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play() as the previous event does it in its action method
//p.process_event(play());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,254 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
// Flags. Allow information about a property of the current state
struct PlayingPaused{};
struct CDLoaded {};
struct FirstSongPlaying {};
// A "complicated" event type that carries some data.
struct cd_detected
{
cd_detected(std::string name)
: name(name)
{}
std::string name;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
typedef mpl::vector1<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
typedef mpl::vector1<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
// the player state machine contains a state which is himself a state machine
// as you see, no need to declare it anywhere so Playing can be developed separately
// by another team in another module. For simplicity I just declare it inside player
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// The list of FSM states
struct Song1 : public msm::front::state<>
{
typedef mpl::vector1<FirstSongPlaying> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
};
struct Song2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
typedef msm::back::state_machine<Playing_> Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const& cd) {std::cout << "player::store_cd_info\n";}
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// tests some flags
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
p.process_event(cd_detected("louie, louie"));
p.process_event(play());
// at this point, Play is active
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(NextSong());pstate(p); //2nd song active
p.process_event(NextSong());pstate(p);//3rd song active
p.process_event(PreviousSong());pstate(p);//2nd song active
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
p.process_event(pause()); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
// go back to Playing
// as you see, it starts back from the original state
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
// event leading to the same state
p.process_event(stop()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,169 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "FsmAsPtr.h"
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
// cpp: using directives are okay
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace
{
// events
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
BOOST_MSM_EUML_EVENT(cd_detected)
// Concrete FSM implementation
// The list of FSM states
// state not needing any entry or exit
BOOST_MSM_EUML_STATE((),Paused)
// it is also possible to define a state which you can implement normally
// just make it a state, as usual, and also a grammar terminal, euml_state
struct Empty_impl : public msm::front::state<> , public euml_state<Empty_impl>
{
// this allows us to add some functions
void activate_empty() {std::cout << "switching to Empty " << std::endl;}
// standard entry behavior
template <class Event,class FSM>
void on_entry(Event const& evt,FSM& fsm)
{
std::cout << "entering: Empty" << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const& evt,FSM& fsm)
{
std::cout << "leaving: Empty" << std::endl;
}
};
//instance for use in the transition table
Empty_impl const Empty;
// create a functor and a eUML function for the activate_empty method from Entry
BOOST_MSM_EUML_METHOD(ActivateEmpty_ , activate_empty , activate_empty_ , void , void )
// define more states
BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
// it is also possible to use a plain functor, with default-constructor in the transition table
struct start_play
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::start_play" << endl;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Playing == Stopped + play / start_play() ,
Playing == Paused + end_pause / resume_playback,
// +------------------------------------------------------------------------------+
Empty == Open + open_close / (close_drawer,activate_empty_(target_)),
// +------------------------------------------------------------------------------+
Open == Empty + open_close / open_drawer,
Open == Paused + open_close / stop_and_open,
Open == Stopped + open_close / open_drawer,
Open == Playing + open_close / stop_and_open,
// +------------------------------------------------------------------------------+
Paused == Playing + pause / pause_playback,
// +------------------------------------------------------------------------------+
Stopped == Playing + stop / stop_playback,
Stopped == Paused + stop / stop_playback,
Stopped == Empty + cd_detected / (store_cd_info,process_(play)),
Stopped == Stopped + stop
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
my_machine_impl_) //fsm name
// choice of back-end
typedef msm::back::state_machine<my_machine_impl_> my_machine_impl;
}
player::player()
: fsm_(new my_machine_impl)
{
boost::static_pointer_cast<my_machine_impl>(fsm_)->start();
}
void player::do_play()
{
boost::static_pointer_cast<my_machine_impl>(fsm_)->process_event(play);
}
void player::do_pause()
{
boost::static_pointer_cast<my_machine_impl>(fsm_)->process_event(pause);
}
void player::do_open_close()
{
boost::static_pointer_cast<my_machine_impl>(fsm_)->process_event(open_close);
}
void player::do_end_pause()
{
boost::static_pointer_cast<my_machine_impl>(fsm_)->process_event(end_pause);
}
void player::do_stop()
{
boost::static_pointer_cast<my_machine_impl>(fsm_)->process_event(stop);
}
void player::do_cd_detected()
{
boost::static_pointer_cast<my_machine_impl>(fsm_)->process_event(cd_detected);
}
int main()
{
player p;
// note that we write open_close and not open_close(), like usual. Both are possible with eUML, but
// you now have less to type.
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.do_open_close();
p.do_open_close();
p.do_cd_detected();
// no need to call play as the previous event does it in its action method
// at this point, Play is active
p.do_pause();
// go back to Playing
p.do_end_pause();
p.do_pause();
p.do_stop();
// event leading to the same state
// no action method called as none is defined in the transition table
p.do_stop();
// test call to no_transition
p.do_pause();
return 0;
}

View File

@@ -0,0 +1,36 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef FSM_AS_PTR_H
#define FSM_AS_PTR_H
#include <boost/shared_ptr.hpp>
class player
{
public:
player();
virtual ~player(){}
// public interface
void do_play();
void do_pause();
void do_open_close();
void do_end_pause();
void do_stop();
void do_cd_detected();
private:
// my state machine, hidden
boost::shared_ptr<void> fsm_;
};
#endif //FSM_AS_PTR_H

View File

@@ -0,0 +1,240 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
// A "complicated" event type that carries some data.
struct cd_detected
{
cd_detected(std::string name)
: name(name)
{}
std::string name;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// The list of FSM states
struct Song1 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
};
struct Song2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
// demonstrates Shallow History: if the state gets activated with end_pause
// then it will remember the last active state and reactivate it
// also possible: AlwaysHistory, the last active state will always be reactivated
// or NoHistory, always restart from the initial state
typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const& cd) {std::cout << "player::store_cd_info\n";}
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
p.process_event(cd_detected("louie, louie"));
p.process_event(play());
// at this point, Play is active
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(NextSong());pstate(p); //2nd song active
p.process_event(NextSong());pstate(p);//3rd song active
p.process_event(PreviousSong());pstate(p);//2nd song active
p.process_event(pause()); pstate(p);
// go back to Playing
// as you see, remembers the original state as end_pause is an history trigger
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
p.process_event(stop()); pstate(p);
// play does not trigger shallow history => start back from 1st song
p.process_event(play()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,180 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
BOOST_MSM_EUML_EVENT(next_song)
BOOST_MSM_EUML_EVENT(previous_song)
// A "complicated" event type that carries some data.
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
// Concrete FSM implementation
// The list of FSM states
// state not defining any entry or exit
BOOST_MSM_EUML_STATE((),Paused)
BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
// Playing is now a state machine itself.
// It has 3 substates
BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
// Playing has a transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
Song2 == Song1 + next_song / start_next_song,
Song1 == Song2 + previous_song / start_prev_song,
Song3 == Song2 + next_song / start_next_song,
Song2 == Song3 + previous_song / start_prev_song
// +------------------------------------------------------------------------------+
),playing_transition_table )
// VC9 cannot compile the typedef with build_sm if one is also used for player
BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
init_ << Song1 // Init State
),Playing_)
// choice of back-end
typedef msm::back::state_machine<Playing_,
msm::back::ShallowHistory<mpl::vector<BOOST_MSM_EUML_EVENT_NAME(end_pause)> > > Playing_type;
Playing_type const Playing;
// guard conditions
BOOST_MSM_EUML_ACTION(good_disk_format)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.get_attribute(cd_type)!=DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
// just for logging, does not block any transition
return true;
}
std::cout << "good disk" << std::endl;
return true;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Playing == Stopped + play / start_playback,
Playing == Paused + end_pause / resume_playback,
// +------------------------------------------------------------------------------+
Empty == Open + open_close / close_drawer,
// +------------------------------------------------------------------------------+
Open == Empty + open_close / open_drawer,
Open == Paused + open_close / stop_and_open,
Open == Stopped + open_close / open_drawer,
Open == Playing + open_close / stop_and_open,
// +------------------------------------------------------------------------------+
Paused == Playing + pause / pause_playback,
// +------------------------------------------------------------------------------+
Stopped == Playing + stop / stop_playback,
Stopped == Paused + stop / stop_playback,
Stopped == Empty + cd_detected [good_disk_format&&
(event_(cd_type)==Int_<DISK_CD>())]
/ (store_cd_info,process_(play)),
Stopped == Stopped + stop
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
// choice of back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play as the previous event does it in its action method
//p.process_event(play);
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(next_song);pstate(p); //2nd song active
p.process_event(next_song);pstate(p);//3rd song active
p.process_event(previous_song);pstate(p);//2nd song active
// at this point, Play is active
p.process_event(pause); pstate(p);
// go back to Playing
// as you see, remembers the original state as end_pause is an history trigger
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as none is defined in the transition table
p.process_event(stop); pstate(p);
// test call to no_transition
p.process_event(play); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,243 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
#include <iostream>
#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#endif
namespace test_fsm // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct cd_detected{};
struct NextSong {};
struct PreviousSong {};
// Concrete FSM implementation
struct player_ : public msm::front::state_machine_def<player_>
{
// no need for exception handling or message queue
typedef int no_exception_thrown;
typedef int no_message_queue;
// The list of FSM states
struct Empty : public msm::front::state<>
{
// optional entry/exit methods
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
};
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// no need for exception handling or message queue
typedef int no_exception_thrown;
typedef int no_message_queue;
// The list of FSM states
struct Song1 : public msm::front::state<> {};
struct Song2 : public msm::front::state<> {};
struct Song3 : public msm::front::state<> {};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { /*std::cout << "Playing::start_next_song\n";*/ }
void start_prev_song(PreviousSong const&) { /*std::cout << "Playing::start_prev_song\n"; */}
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<Playing_> Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { }
void open_drawer(open_close const&) { }
void close_drawer(open_close const&) { }
void store_cd_info(cd_detected const& cd) { }
void stop_playback(stop const&) { }
void pause_playback(pause const&) { }
void resume_playback(end_pause const&) { }
void stop_and_open(open_close const&) { }
void stopped_again(stop const&){}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
}
#ifndef WIN32
long mtime(struct timeval& tv1,struct timeval& tv2)
{
return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
}
#endif
int main()
{
// for timing
#ifdef WIN32
LARGE_INTEGER res;
::QueryPerformanceFrequency(&res);
LARGE_INTEGER li,li2;
#else
struct timeval tv1,tv2;
gettimeofday(&tv1,NULL);
#endif
test_fsm::player p2;
p2.start();
// for timing
#ifdef WIN32
::QueryPerformanceCounter(&li);
#else
gettimeofday(&tv1,NULL);
#endif
for (int i=0;i<100;++i)
{
p2.process_event(test_fsm::open_close());
p2.process_event(test_fsm::open_close());
p2.process_event(test_fsm::cd_detected());
p2.process_event(test_fsm::play());
for (int j=0;j<100;++j)
{
p2.process_event(test_fsm::NextSong());
p2.process_event(test_fsm::NextSong());
p2.process_event(test_fsm::PreviousSong());
p2.process_event(test_fsm::PreviousSong());
}
p2.process_event(test_fsm::pause());
// go back to Playing
p2.process_event(test_fsm::end_pause());
p2.process_event(test_fsm::pause());
p2.process_event(test_fsm::stop());
// event leading to the same state
p2.process_event(test_fsm::stop());
p2.process_event(test_fsm::open_close());
p2.process_event(test_fsm::open_close());
}
#ifdef WIN32
::QueryPerformanceCounter(&li2);
#else
gettimeofday(&tv2,NULL);
#endif
#ifdef WIN32
std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
#else
std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
#endif
return 0;
}

View File

@@ -0,0 +1,199 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
#include <iostream>
#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#endif
namespace test_fsm // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct cd_detected{};
// Concrete FSM implementation
struct player_ : public msm::front::state_machine_def<player_>
{
// no need for exception handling or message queue
typedef int no_exception_thrown;
typedef int no_message_queue;
// The list of FSM states
struct Empty : public msm::front::state<>
{
// optional entry/exit methods
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
};
struct Stopped : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Playing" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Playing" << std::endl;*/}
};
struct Paused : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { }
void open_drawer(open_close const&) { }
void close_drawer(open_close const&) { }
void store_cd_info(cd_detected const& cd) { }
void stop_playback(stop const&) { }
void pause_playback(pause const&) { }
void resume_playback(end_pause const&) { }
void stop_and_open(open_close const&) { }
void stopped_again(stop const&){}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
_row < Stopped , play , Playing >,
_row < Stopped , open_close , Open >,
_row < Stopped , stop , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
_row < Open , open_close , Empty >,
// +---------+-------------+---------+---------------------+----------------------+
_row < Empty , open_close , Open >,
_row < Empty , cd_detected , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
_row < Playing , stop , Stopped >,
_row < Playing , pause , Paused >,
_row < Playing , open_close , Open >,
// +---------+-------------+---------+---------------------+----------------------+
_row < Paused , end_pause , Playing >,
_row < Paused , stop , Stopped >,
_row < Paused , open_close , Open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
}
#ifndef WIN32
long mtime(struct timeval& tv1,struct timeval& tv2)
{
return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
}
#endif
int main()
{
// for timing
#ifdef WIN32
LARGE_INTEGER res;
::QueryPerformanceFrequency(&res);
LARGE_INTEGER li,li2;
#else
struct timeval tv1,tv2;
gettimeofday(&tv1,NULL);
#endif
test_fsm::player p2;
p2.start();
// for timing
#ifdef WIN32
::QueryPerformanceCounter(&li);
#else
gettimeofday(&tv1,NULL);
#endif
for (int i=0;i<100;++i)
{
p2.process_event(test_fsm::open_close());
p2.process_event(test_fsm::open_close());
p2.process_event(test_fsm::cd_detected());
p2.process_event(test_fsm::play());
p2.process_event(test_fsm::pause());
// go back to Playing
p2.process_event(test_fsm::end_pause());
p2.process_event(test_fsm::pause());
p2.process_event(test_fsm::stop());
// event leading to the same state
p2.process_event(test_fsm::stop());
p2.process_event(test_fsm::open_close());
p2.process_event(test_fsm::open_close());
}
#ifdef WIN32
::QueryPerformanceCounter(&li2);
#else
gettimeofday(&tv2,NULL);
#endif
#ifdef WIN32
std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
#else
std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
#endif
return 0;
}

View File

@@ -0,0 +1,254 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
#include <iostream>
#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#endif
namespace test_fsm // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct cd_detected{};
// Concrete FSM implementation
struct player_ : public msm::front::state_machine_def<player_>
{
// no need for exception handling or message queue
typedef int no_exception_thrown;
typedef int no_message_queue;
// The list of FSM states
struct Empty : public msm::front::state<>
{
// optional entry/exit methods
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Playing" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Playing" << std::endl;*/}
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
struct start_playback
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
struct open_drawer
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
struct close_drawer
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
struct store_cd_info
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const&, FSM& fsm ,SourceState& ,TargetState& )
{
}
};
struct stop_playback
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
struct pause_playback
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
struct resume_playback
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
struct stop_and_open
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
struct stopped_again
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
}
};
// guard conditions
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
Row < Stopped , play , Playing , start_playback >,
Row < Stopped , open_close , Open , open_drawer >,
Row < Stopped , stop , Stopped , stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
Row < Open , open_close , Empty , close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
Row < Empty , open_close , Open , open_drawer >,
Row < Empty , cd_detected , Stopped , store_cd_info >,
// +---------+-------------+---------+---------------------+----------------------+
Row < Playing , stop , Stopped , stop_playback >,
Row < Playing , pause , Paused , pause_playback >,
Row < Playing , open_close , Open , stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
Row < Paused , end_pause , Playing , resume_playback >,
Row < Paused , stop , Stopped , stop_playback >,
Row < Paused , open_close , Open , stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
}
#ifndef WIN32
long mtime(struct timeval& tv1,struct timeval& tv2)
{
return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
}
#endif
int main()
{
// for timing
#ifdef WIN32
LARGE_INTEGER res;
::QueryPerformanceFrequency(&res);
LARGE_INTEGER li,li2;
#else
struct timeval tv1,tv2;
gettimeofday(&tv1,NULL);
#endif
test_fsm::player p2;
p2.start();
// for timing
#ifdef WIN32
::QueryPerformanceCounter(&li);
#else
gettimeofday(&tv1,NULL);
#endif
for (int i=0;i<100;++i)
{
p2.process_event(test_fsm::open_close());
p2.process_event(test_fsm::open_close());
p2.process_event(test_fsm::cd_detected());
p2.process_event(test_fsm::play());
p2.process_event(test_fsm::pause());
// go back to Playing
p2.process_event(test_fsm::end_pause());
p2.process_event(test_fsm::pause());
p2.process_event(test_fsm::stop());
// event leading to the same state
p2.process_event(test_fsm::stop());
p2.process_event(test_fsm::open_close());
p2.process_event(test_fsm::open_close());
}
#ifdef WIN32
::QueryPerformanceCounter(&li2);
#else
gettimeofday(&tv2,NULL);
#endif
#ifdef WIN32
std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
#else
std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
#endif
return 0;
}

View File

@@ -0,0 +1,315 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
struct error_found {};
struct end_error {};
struct end_error2 {};
// Flags. Allow information about a property of the current state
struct PlayingPaused{};
struct CDLoaded {};
struct FirstSongPlaying {};
// A "complicated" event type that carries some data.
struct cd_detected
{
cd_detected(std::string name)
: name(name)
{}
std::string name;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&)
{
std::cout << "entering: Player" << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const&,FSM& )
{
std::cout << "leaving: Player" << std::endl;
}
// The list of FSM states
struct Empty : public msm::front::state<>
{
// if the play event arrives in this state, defer it until a state handles it or
// rejects it
typedef mpl::vector<play> deferred_events;
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
// if the play event arrives in this state, defer it until a state handles it or
// rejects it
typedef mpl::vector<play> deferred_events;
typedef mpl::vector1<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
typedef mpl::vector1<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
// the player state machine contains a state which is himself a state machine
// as you see, no need to declare it anywhere so Playing can be developed separately
// by another team in another module. For simplicity I just declare it inside player
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// The list of FSM states
struct Song1 : public msm::front::state<>
{
typedef mpl::vector1<FirstSongPlaying> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
};
struct Song2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
typedef msm::back::state_machine<Playing_> Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
};
struct AllOk : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
};
// this state is also made terminal so that all the events are blocked
struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine
public msm::front::interrupt_state<end_error/*mpl::vector<end_error,end_error2>*/ > // ErroMode just interrupts. Will resume if
// the event end_error is generated
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
};
// the initial state of the player SM. Must be defined
typedef mpl::vector<Empty,AllOk> initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const& cd) {std::cout << "player::store_cd_info\n";}
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
void report_error(error_found const&) {std::cout << "player::report_error\n";}
void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
void pstate(player const& p)
{
// we have now several active states, which we show
for (unsigned int i=0;i<player::nr_regions::value;++i)
{
std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
}
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// test deferred event
// deferred in Empty and Open, will be handled only after event cd_detected
p.process_event(play());
// tests some flags
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
p.process_event(cd_detected("louie, louie"));
// at this point, Play is active (was deferred)
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(NextSong());pstate(p); //2nd song active
p.process_event(NextSong());pstate(p);//3rd song active
p.process_event(PreviousSong());pstate(p);//2nd song active
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
p.process_event(pause()); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
// go back to Playing
// as you see, it starts back from the original state
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
// by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
// all of the active states
std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
// event leading to the same state
p.process_event(stop()); pstate(p);
// event leading to a terminal/interrupt state
p.process_event(error_found()); pstate(p);
// try generating more events
std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
p.process_event(play());pstate(p);
std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(end_error());pstate(p);
std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(play());pstate(p);
std::cout << "stop fsm" << std::endl;
p.stop();
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,303 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace boost::msm::front;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
struct error_found {};
struct end_error {};
// Flags. Allow information about a property of the current state
struct PlayingPaused{};
struct CDLoaded {};
struct FirstSongPlaying {};
// A "complicated" event type that carries some data.
struct cd_detected
{
cd_detected(std::string name)
: name(name)
{}
std::string name;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// we want deferred events and no state requires deferred events (only the fsm in the
// transition table), so the fsm does.
typedef int activate_deferred_events;
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
typedef mpl::vector1<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
typedef mpl::vector1<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
// the player state machine contains a state which is himself a state machine
// as you see, no need to declare it anywhere so Playing can be developed separately
// by another team in another module. For simplicity I just declare it inside player
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// The list of FSM states
struct Song1 : public msm::front::state<>
{
typedef mpl::vector1<FirstSongPlaying> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
};
struct Song2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
typedef msm::back::state_machine<Playing_> Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
};
struct AllOk : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
};
// this state is also made terminal so that all the events are blocked
struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine
public msm::front::interrupt_state<end_error> // ErroMode just interrupts. Will resume if
// the event end_error is generated
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
};
// the initial state of the player SM. Must be defined
typedef mpl::vector<Empty,AllOk> initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const& cd) {std::cout << "player::store_cd_info\n";}
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
void report_error(error_found const&) {std::cout << "player::report_error\n";}
void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
Row < Open , play , none , Defer , none >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
Row < Empty , play , none , Defer , none >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
void pstate(player const& p)
{
// we have now several active states, which we show
for (unsigned int i=0;i<player::nr_regions::value;++i)
{
std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
}
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// test deferred event
// deferred in Empty and Open, will be handled only after event cd_detected
p.process_event(play());
// tests some flags
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
p.process_event(cd_detected("louie, louie"));
// at this point, Play is active (was deferred)
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(NextSong());pstate(p); //2nd song active
p.process_event(NextSong());pstate(p);//3rd song active
p.process_event(PreviousSong());pstate(p);//2nd song active
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
p.process_event(pause()); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
// go back to Playing
// as you see, it starts back from the original state
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
// by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
// all of the active states
std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
// event leading to the same state
p.process_event(stop()); pstate(p);
// event leading to a terminal/interrupt state
p.process_event(error_found()); pstate(p);
// try generating more events
std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
p.process_event(play());pstate(p);
std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(end_error());pstate(p);
std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(play());pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,263 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
BOOST_MSM_EUML_EVENT(next_song)
BOOST_MSM_EUML_EVENT(previous_song)
BOOST_MSM_EUML_EVENT(end_error)
BOOST_MSM_EUML_EVENT(error_found)
// A "complicated" event type that carries some data.
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
// Flags. Allow information about a property of the current state
BOOST_MSM_EUML_FLAG(PlayingPaused)
BOOST_MSM_EUML_FLAG(CDLoaded)
BOOST_MSM_EUML_FLAG(FirstSongPlaying)
// Concrete FSM implementation
// The list of FSM states
BOOST_MSM_EUML_STATE(( Empty_Entry,
Empty_Exit,
attributes_ << no_attributes_,
configure_ << play // defer play
),
Empty)
BOOST_MSM_EUML_STATE(( Open_Entry,
Open_Exit,
attributes_ << no_attributes_,
configure_<< CDLoaded << play // defer play, flag state with CDLoaded
),
Open)
BOOST_MSM_EUML_STATE(( Stopped_Entry,
Stopped_Exit,
attributes_ << no_attributes_,
configure_<< CDLoaded // flag state with CDLoaded
),
Stopped)
// state not defining any entry or exit
BOOST_MSM_EUML_STATE(( no_action,
no_action,
attributes_ << no_attributes_,
configure_<< PlayingPaused << CDLoaded // flag state with CDLoaded and PlayingPaused
),
Paused)
BOOST_MSM_EUML_STATE(( AllOk_Entry,AllOk_Exit ),AllOk)
// a terminate state
//BOOST_MSM_EUML_TERMINATE_STATE(( ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
// or as an interrupt state
BOOST_MSM_EUML_INTERRUPT_STATE(( end_error,ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
// Playing is now a state machine itself.
// It has 3 substates
BOOST_MSM_EUML_STATE(( Song1_Entry,
Song1_Exit,
attributes_ << no_attributes_,
configure_<< FirstSongPlaying ),Song1)
BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
// Playing has a transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
Song2 == Song1 + next_song / start_next_song,
Song1 == Song2 + previous_song / start_prev_song,
Song3 == Song2 + next_song / start_next_song,
Song2 == Song3 + previous_song / start_prev_song
// +------------------------------------------------------------------------------+
),playing_transition_table )
BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
init_ << Song1, // Init State
no_action, // entry
no_action, // exit
attributes_ << no_attributes_, //attributes
configure_<< PlayingPaused << CDLoaded //flags
),Playing_)
// choice of back-end
typedef msm::back::state_machine<Playing_> Playing_type;
Playing_type const Playing;
// guard conditions
BOOST_MSM_EUML_ACTION(good_disk_format)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.get_attribute(cd_type)!=DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
// just for logging, does not block any transition
return true;
}
std::cout << "good disk" << std::endl;
return true;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Playing == Stopped + play / start_playback ,
Playing == Paused + end_pause / resume_playback,
// +------------------------------------------------------------------------------+
Empty == Open + open_close / close_drawer,
// +------------------------------------------------------------------------------+
Open == Empty + open_close / open_drawer,
Open == Paused + open_close / stop_and_open,
Open == Stopped + open_close / open_drawer,
Open == Playing + open_close / stop_and_open,
// +------------------------------------------------------------------------------+
Paused == Playing + pause / pause_playback,
// +------------------------------------------------------------------------------+
Stopped == Playing + stop / stop_playback,
Stopped == Paused + stop / stop_playback,
Stopped == Empty + cd_detected [good_disk_format&&
(event_(cd_type)==Int_<DISK_CD>())]
/ (store_cd_info,process_(play)),
Stopped == Stopped + stop,
ErrorMode == AllOk + error_found / report_error,
AllOk == ErrorMode+ end_error / report_end_error
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty<< AllOk, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
// choice of back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing","AllOk","ErrorMode" };
void pstate(player const& p)
{
// we have now several active states, which we show
for (unsigned int i=0;i<player::nr_regions::value;++i)
{
std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
}
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// tests some flags
std::cout << "CDLoaded active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl; //=> false (no CD yet)
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play as the previous event does it in its action method
//p.process_event(play);
// at this point, Play is active
std::cout << "PlayingPaused active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
std::cout << "FirstSong active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(FirstSongPlaying)>() << std::endl;//=> true
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(next_song);pstate(p); //2nd song active
p.process_event(next_song);pstate(p);//3rd song active
p.process_event(previous_song);pstate(p);//2nd song active
std::cout << "FirstSong active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(FirstSongPlaying)>() << std::endl;//=> false
std::cout << "PlayingPaused active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
// at this point, Play is active
p.process_event(pause); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> false
std::cout << "CDLoaded active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl;//=> true
// by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
// all of the active states
std::cout << "CDLoaded active with AND:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded),player::Flag_AND>() << std::endl;//=> false
// event leading to the same state
// no action method called as none is defined in the transition table
p.process_event(stop); pstate(p);
// event leading to a terminal/interrupt state
p.process_event(error_found); pstate(p);
// try generating more events
std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
p.process_event(play);pstate(p);
std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(end_error);pstate(p);
std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(play);pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,251 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
BOOST_MSM_EUML_EVENT(next_song)
BOOST_MSM_EUML_EVENT(previous_song)
BOOST_MSM_EUML_EVENT(end_error)
BOOST_MSM_EUML_EVENT(error_found)
// A "complicated" event type that carries some data.
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
// Flags. Allow information about a property of the current state
BOOST_MSM_EUML_FLAG(PlayingPaused)
BOOST_MSM_EUML_FLAG(CDLoaded)
BOOST_MSM_EUML_FLAG(FirstSongPlaying)
// Concrete FSM implementation
// The list of FSM states
BOOST_MSM_EUML_STATE(( Empty_Entry,
Empty_Exit,
attributes_ << no_attributes_,
configure_ << no_configure_
),
Empty)
BOOST_MSM_EUML_STATE(( Open_Entry,
Open_Exit,
attributes_ << no_attributes_,
configure_<< CDLoaded // flag state with CDLoaded
),
Open)
BOOST_MSM_EUML_STATE(( Stopped_Entry,
Stopped_Exit,
attributes_ << no_attributes_,
configure_<< CDLoaded // flag state with CDLoaded
),
Stopped)
// state not defining any entry or exit
BOOST_MSM_EUML_STATE(( no_action,
no_action,
attributes_ << no_attributes_,
configure_<< PlayingPaused << CDLoaded // flag state with CDLoaded and PlayingPaused
),
Paused)
BOOST_MSM_EUML_STATE(( AllOk_Entry,AllOk_Exit ),AllOk)
// a terminate state
//BOOST_MSM_EUML_TERMINATE_STATE(( ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
// or as an interrupt state
BOOST_MSM_EUML_INTERRUPT_STATE(( end_error,ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
// Playing is now a state machine itself.
// It has 3 substates
BOOST_MSM_EUML_STATE(( Song1_Entry,
Song1_Exit,
attributes_ << no_attributes_,
configure_<< FirstSongPlaying ),Song1)
BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
// Playing has a transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
Song2 == Song1 + next_song / start_next_song,
Song1 == Song2 + previous_song / start_prev_song,
Song3 == Song2 + next_song / start_next_song,
Song2 == Song3 + previous_song / start_prev_song
// +------------------------------------------------------------------------------+
),playing_transition_table )
BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
init_ << Song1, // Init State
no_action, // entry
no_action, // exit
attributes_ << no_attributes_, //attributes
configure_<< PlayingPaused << CDLoaded //flags
),Playing_)
// choice of back-end
typedef msm::back::state_machine<Playing_> Playing_type;
Playing_type const Playing;
// guard conditions
BOOST_MSM_EUML_ACTION(good_disk_format)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.get_attribute(cd_type)!=DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
// just for logging, does not block any transition
return true;
}
std::cout << "good disk" << std::endl;
return true;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Playing == Stopped + play / start_playback ,
Playing == Paused + end_pause / resume_playback ,
// +------------------------------------------------------------------------------+
Empty == Open + open_close / close_drawer,
// we now defer using the defer_ function. This will need deferred_events as config (see below)
Empty + play / defer_ ,
// +------------------------------------------------------------------------------+
Open == Empty + open_close / open_drawer ,
Open == Paused + open_close / stop_and_open ,
Open == Stopped + open_close / open_drawer ,
Open == Playing + open_close / stop_and_open ,
// we now defer using the defer_ function. This will need deferred_events as config (see below)
Open + play / defer_ ,
// +------------------------------------------------------------------------------+
Paused == Playing + pause / pause_playback ,
// +------------------------------------------------------------------------------+
Stopped == Playing + stop / stop_playback ,
Stopped == Paused + stop / stop_playback ,
Stopped == Empty + cd_detected [good_disk_format&&
(event_(cd_type)==Int_<DISK_CD>())]
/ (store_cd_info,process_(play)),
Stopped == Stopped + stop ,
ErrorMode == AllOk + error_found / report_error ,
AllOk == ErrorMode+ end_error / report_end_error
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty << AllOk, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << deferred_events, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
// choice of back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing","AllOk","ErrorMode" };
void pstate(player const& p)
{
// we have now several active states, which we show
for (unsigned int i=0;i<player::nr_regions::value;++i)
{
std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
}
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// tests some flags
std::cout << "CDLoaded active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl; //=> false (no CD yet)
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play as the previous event does it in its action method
//p.process_event(play);
// at this point, Play is active
p.process_event(pause); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> false
std::cout << "CDLoaded active:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl;//=> true
// by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
// all of the active states
std::cout << "CDLoaded active with AND:" << std::boolalpha
<< p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded),player::Flag_AND>() << std::endl;//=> false
// event leading to the same state
// no action method called as none is defined in the transition table
p.process_event(stop); pstate(p);
// event leading to a terminal/interrupt state
p.process_event(error_found); pstate(p);
// try generating more events
std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
p.process_event(play);pstate(p);
std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(end_error);pstate(p);
std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(play);pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,479 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#define FUSION_MAX_VECTOR_SIZE 20
#include <boost/msm/back/state_machine.hpp>
#include "char_event_dispatcher.hpp"
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/timer.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
#include <iostream>
#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#endif
// events
struct end_sub {template <class Event> end_sub(Event const&){}};
struct other_char {};
struct default_char {};
struct eos {};
namespace test_fsm // Concrete FSM implementation
{
// Concrete FSM implementation
struct parsing_ : public msm::front::state_machine_def<parsing_>
{
// no need for exception handling or message queue
typedef int no_exception_thrown;
typedef int no_message_queue;
struct Waiting : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Waiting" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Waiting" << std::endl;}
};
struct Digit1 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit1" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit1" << std::endl;}
};
struct Digit2 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit2" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit2" << std::endl;}
};
struct Digit3 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit3" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit3" << std::endl;}
};
struct Digit4 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit4" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit4" << std::endl;}
};
struct MinusChar1 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar1" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar1" << std::endl;}
};
struct Digit5 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit5" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit5" << std::endl;}
};
struct Digit6 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit6" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit6" << std::endl;}
};
struct Digit7 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit7" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit7" << std::endl;}
};
struct Digit8 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit8" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit8" << std::endl;}
};
struct MinusChar2 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar2" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar2" << std::endl;}
};
struct Digit9 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit9" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit9" << std::endl;}
};
struct Digit10 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit10" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit10" << std::endl;}
};
struct Digit11 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit11" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit11" << std::endl;}
};
struct Digit12 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit12" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit12" << std::endl;}
};
struct MinusChar3 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar3" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar3" << std::endl;}
};
struct Digit13 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit13" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit13" << std::endl;}
};
struct Digit14 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit14" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit14" << std::endl;}
};
struct Digit15 : public msm::front::state<>
{
// optional entry/exit methods
//template <class Event,class FSM>
//void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit15" << std::endl;}
//template <class Event,class FSM>
//void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit15" << std::endl;}
};
//struct Start : public msm::front::state<> {};
struct Parsed : public msm::front::state<> {};
//struct Failed : public msm::front::state<> {};
// the initial state of the player SM. Must be defined
typedef Waiting initial_state;
// transition actions
struct test_fct
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Parsed!" << std::endl;
}
};
// guard conditions
// Transition table for parsing_
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +-------------+-------------------+---------+---------------------+----------------------+
Row < Waiting , digit , Digit1 >,
Row < Digit1 , digit , Digit2 >,
Row < Digit2 , digit , Digit3 >,
Row < Digit3 , digit , Digit4 >,
Row < Digit4 , event_char<'-'> , MinusChar1 >,
Row < MinusChar1 , digit , Digit5 >,
Row < Digit5 , digit , Digit6 >,
Row < Digit6 , digit , Digit7 >,
Row < Digit7 , digit , Digit8 >,
Row < Digit8 , event_char<'-'> , MinusChar2 >,
Row < MinusChar2 , digit , Digit9 >,
Row < Digit9 , digit , Digit10 >,
Row < Digit10 , digit , Digit11 >,
Row < Digit11 , digit , Digit12 >,
Row < Digit12 , event_char<'-'> , MinusChar3 >,
Row < MinusChar3 , digit , Digit13 >,
Row < Digit13 , digit , Digit14 >,
Row < Digit14 , digit , Digit15 >,
Row < Digit15 , eos , Parsed >,
Row < Parsed , eos , Waiting >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<parsing_> parsing;
}
#ifndef WIN32
long mtime(struct timeval& tv1,struct timeval& tv2)
{
return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
}
#endif
// This declares the statically-initialized char_event_dispatcher instance.
template <class Fsm>
const msm::back::char_event_dispatcher<Fsm>
msm::back::char_event_dispatcher<Fsm>::instance;
struct Parser
{
Parser():p(){p.start();}
void new_char(char c)
{
typedef msm::back::char_event_dispatcher<test_fsm::parsing> table;
table::instance.process_event(p,c);
}
void finish_string(){p.process_event(eos());}
void reinit(){p.process_event(eos());}
test_fsm::parsing p;
};
void msm_match(const char* input)
{
test_fsm::parsing p;
p.start();
int j=0;
while(input[j])
//for (size_t j=0;j<len;++j)
{
switch (input[j])
{
case '0':
p.process_event(char_0());
break;
case '1':
p.process_event(char_1());
break;
case '2':
p.process_event(char_2());
break;
case '3':
p.process_event(char_3());
break;
case '4':
p.process_event(char_4());
break;
case '5':
p.process_event(char_5());
break;
case '6':
p.process_event(char_6());
break;
case '7':
p.process_event(char_7());
break;
case '8':
p.process_event(char_8());
break;
case '9':
p.process_event(char_9());
break;
case '-':
p.process_event(event_char<'-'>());
break;
default:
p.process_event(default_char());
break;
}
++j;
}
p.process_event(eos());
p.process_event(eos());
}
double time_match(const char* text)
{
boost::timer tim;
int iter = 1;
int counter, repeats;
double result = 0;
double run;
do
{
tim.restart();
for(counter = 0; counter < iter; ++counter)
{
msm_match( text);
}
result = tim.elapsed();
iter *= 2;
} while(result < 0.5);
iter /= 2;
// repeat test and report least value for consistency:
for(repeats = 0; repeats < 10; ++repeats)
{
tim.restart();
for(counter = 0; counter < iter; ++counter)
{
msm_match( text);
}
run = tim.elapsed();
result = (std::min)(run, result);
}
return result / iter;
}
int main()
{
// for timing
#ifdef WIN32
LARGE_INTEGER res;
::QueryPerformanceFrequency(&res);
LARGE_INTEGER li,li2;
#else
struct timeval tv1,tv2;
gettimeofday(&tv1,NULL);
#endif
test_fsm::parsing p;
p.start();
const char* input = "1234-5678-1234-456";
size_t len = strlen(input);
// for timing
#ifdef WIN32
::QueryPerformanceCounter(&li);
#else
gettimeofday(&tv1,NULL);
#endif
for (int i=0;i<1000;++i)
{
int j=0;
while(input[j])
//for (size_t j=0;j<len;++j)
{
switch (input[j])
{
case '0':
p.process_event(char_0());
break;
case '1':
p.process_event(char_1());
break;
case '2':
p.process_event(char_2());
break;
case '3':
p.process_event(char_3());
break;
case '4':
p.process_event(char_4());
break;
case '5':
p.process_event(char_5());
break;
case '6':
p.process_event(char_6());
break;
case '7':
p.process_event(char_7());
break;
case '8':
p.process_event(char_8());
break;
case '9':
p.process_event(char_9());
break;
case '-':
p.process_event(event_char<'-'>());
break;
default:
p.process_event(default_char());
break;
}
++j;
}
p.process_event(eos());
p.process_event(eos());
}
#ifdef WIN32
::QueryPerformanceCounter(&li2);
#else
gettimeofday(&tv2,NULL);
#endif
#ifdef WIN32
std::cout << "msm(1) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
#else
std::cout << "msm(1) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
#endif
Parser parse;
// for timing
#ifdef WIN32
::QueryPerformanceCounter(&li);
#else
gettimeofday(&tv1,NULL);
#endif
for (int i=0;i<1000;++i)
{
for (size_t j=0;j<len;++j)
{
parse.new_char(input[j]);
}
parse.finish_string();
parse.reinit();
}
#ifdef WIN32
::QueryPerformanceCounter(&li2);
#else
gettimeofday(&tv2,NULL);
#endif
#ifdef WIN32
std::cout << "msm(2) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
#else
std::cout << "msm(2) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
#endif
std::cout << "msm(3) took in s:" << time_match(input) <<"\n" <<std::endl;
return 0;
}

View File

@@ -0,0 +1,207 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/statechart/event.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/transition.hpp>
#include "boost/mpl/list.hpp"
#include <vector>
#include <iostream>
#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#endif
namespace sc = boost::statechart;
namespace mpl = boost::mpl;
namespace test_sc
{
//events
struct play : sc::event< play > {};
struct end_pause : sc::event< end_pause > {};
struct stop : sc::event< stop > {};
struct pause : sc::event< pause > {};
struct open_close : sc::event< open_close > {};
struct cd_detected : sc::event< cd_detected > {};
struct NextSong: sc::event< NextSong > {};
struct PreviousSong : sc::event< PreviousSong >{};
struct Empty;
struct Open;
struct Stopped;
struct Playing;
struct Paused;
// SM
struct player : sc::state_machine< player, Empty >
{
void open_drawer(open_close const&) { /*std::cout << "player::open_drawer\n";*/ }
void store_cd_info(cd_detected const& cd) {/*std::cout << "player::store_cd_info\n";*/ }
void close_drawer(open_close const&) { /*std::cout << "player::close_drawer\n";*/ }
void start_playback(play const&) { /*std::cout << "player::start_playback\n";*/ }
void stopped_again(stop const&) {/*std::cout << "player::stopped_again\n";*/}
void stop_playback(stop const&) { /*std::cout << "player::stop_playback\n";*/ }
void pause_playback(pause const&) { /*std::cout << "player::pause_playback\n"; */}
void stop_and_open(open_close const&) { /*std::cout << "player::stop_and_open\n";*/ }
void resume_playback(end_pause const&) { /*std::cout << "player::resume_playback\n";*/ }
};
struct Empty : sc::simple_state< Empty, player >
{
Empty() { /*std::cout << "entering Empty" << std::endl;*/ } // entry
~Empty() { /*std::cout << "leaving Empty" << std::endl;*/ } // exit
typedef mpl::list<
sc::transition< open_close, Open,
player, &player::open_drawer >,
sc::transition< cd_detected, Stopped,
player, &player::store_cd_info > > reactions;
};
struct Open : sc::simple_state< Open, player >
{
Open() { /*std::cout << "entering Open" << std::endl;*/ } // entry
~Open() { /*std::cout << "leaving Open" << std::endl;*/ } // exit
typedef sc::transition< open_close, Empty,
player, &player::close_drawer > reactions;
};
struct Stopped : sc::simple_state< Stopped, player >
{
Stopped() { /*std::cout << "entering Stopped" << std::endl;*/ } // entry
~Stopped() { /*std::cout << "leaving Stopped" << std::endl;*/ } // exit
typedef mpl::list<
sc::transition< play, Playing,
player, &player::start_playback >,
sc::transition< open_close, Open,
player, &player::open_drawer >,
sc::transition< stop, Stopped,
player, &player::stopped_again > > reactions;
};
struct Song1;
struct Playing : sc::simple_state< Playing, player,Song1 >
{
Playing() { /*std::cout << "entering Playing" << std::endl;*/ } // entry
~Playing() { /*std::cout << "leaving Playing" << std::endl;*/ } // exit
typedef mpl::list<
sc::transition< stop, Stopped,
player, &player::stop_playback >,
sc::transition< pause, Paused,
player, &player::pause_playback >,
sc::transition< open_close, Open,
player, &player::stop_and_open > > reactions;
void start_next_song(NextSong const&) { /*std::cout << "Playing::start_next_song\n";*/ }
void start_prev_song(PreviousSong const&) { /*std::cout << "Playing::start_prev_song\n";*/ }
};
struct Song2;
struct Song1 : sc::simple_state< Song1, Playing >
{
Song1() { /*std::cout << "entering Song1" << std::endl;*/ } // entry
~Song1() { /*std::cout << "leaving Song1" << std::endl;*/ } // exit
typedef sc::transition< NextSong, Song2,
Playing, &Playing::start_next_song > reactions;
};
struct Song3;
struct Song2 : sc::simple_state< Song2, Playing >
{
Song2() { /*std::cout << "entering Song2" << std::endl;*/ } // entry
~Song2() { /*std::cout << "leaving Song2" << std::endl;*/ } // exit
typedef mpl::list<
sc::transition< NextSong, Song3,
Playing, &Playing::start_next_song >,
sc::transition< PreviousSong, Song1,
Playing, &Playing::start_prev_song > > reactions;
};
struct Song3 : sc::simple_state< Song3, Playing >
{
Song3() { /*std::cout << "entering Song3" << std::endl;*/ } // entry
~Song3() { /*std::cout << "leaving Song3" << std::endl;*/ } // exit
typedef sc::transition< PreviousSong, Song2,
Playing, &Playing::start_prev_song > reactions;
};
struct Paused : sc::simple_state< Paused, player >
{
Paused() { /*std::cout << "entering Paused" << std::endl;*/ } // entry
~Paused() { /*std::cout << "leaving Paused" << std::endl;*/ } // exit
typedef mpl::list<
sc::transition< end_pause, Playing,
player, &player::resume_playback >,
sc::transition< stop, Stopped,
player, &player::stop_playback >,
sc::transition< open_close, Open,
player, &player::stop_and_open > > reactions;
};
}
#ifndef WIN32
long mtime(struct timeval& tv1,struct timeval& tv2)
{
return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
}
#endif
int main()
{
test_sc::player p;
p.initiate();
// for timing
#ifdef WIN32
LARGE_INTEGER res;
::QueryPerformanceFrequency(&res);
LARGE_INTEGER li,li2;
::QueryPerformanceCounter(&li);
#else
struct timeval tv1,tv2;
gettimeofday(&tv1,NULL);
#endif
for (int i=0;i<100;++i)
{
p.process_event(test_sc::open_close());
p.process_event(test_sc::open_close());
p.process_event(test_sc::cd_detected());
p.process_event(test_sc::play());
for (int j=0;j<100;++j)
{
p.process_event(test_sc::NextSong());
p.process_event(test_sc::NextSong());
p.process_event(test_sc::PreviousSong());
p.process_event(test_sc::PreviousSong());
}
p.process_event(test_sc::pause());
// go back to Playing
p.process_event(test_sc::end_pause());
p.process_event(test_sc::pause());
p.process_event(test_sc::stop());
// event leading to the same state
p.process_event(test_sc::stop());
p.process_event(test_sc::open_close());
p.process_event(test_sc::open_close());
}
#ifdef WIN32
::QueryPerformanceCounter(&li2);
#else
gettimeofday(&tv2,NULL);
#endif
#ifdef WIN32
std::cout << "sc took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
#else
std::cout << "sc took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
#endif
return 0;
}

View File

@@ -0,0 +1,169 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/statechart/event.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/transition.hpp>
#include "boost/mpl/list.hpp"
#include <vector>
#include <iostream>
#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#endif
namespace sc = boost::statechart;
namespace mpl = boost::mpl;
namespace test_sc
{
//events
struct play : sc::event< play > {};
struct end_pause : sc::event< end_pause > {};
struct stop : sc::event< stop > {};
struct pause : sc::event< pause > {};
struct open_close : sc::event< open_close > {};
struct cd_detected : sc::event< cd_detected > {};
struct Empty;
struct Open;
struct Stopped;
struct Playing;
struct Paused;
// SM
struct player : sc::state_machine< player, Empty >
{
void open_drawer(open_close const&) { /*std::cout << "player::open_drawer\n";*/ }
void store_cd_info(cd_detected const& cd) {/*std::cout << "player::store_cd_info\n";*/ }
void close_drawer(open_close const&) { /*std::cout << "player::close_drawer\n";*/ }
void start_playback(play const&) { /*std::cout << "player::start_playback\n";*/ }
void stopped_again(stop const&) {/*std::cout << "player::stopped_again\n";*/}
void stop_playback(stop const&) { /*std::cout << "player::stop_playback\n";*/ }
void pause_playback(pause const&) { /*std::cout << "player::pause_playback\n"; */}
void stop_and_open(open_close const&) { /*std::cout << "player::stop_and_open\n";*/ }
void resume_playback(end_pause const&) { /*std::cout << "player::resume_playback\n";*/ }
};
struct Empty : sc::simple_state< Empty, player >
{
Empty() { /*std::cout << "entering Empty" << std::endl;*/ } // entry
~Empty() { /*std::cout << "leaving Empty" << std::endl;*/ } // exit
typedef mpl::list<
sc::transition< open_close, Open,
player, &player::open_drawer >,
sc::transition< cd_detected, Stopped,
player, &player::store_cd_info > > reactions;
};
struct Open : sc::simple_state< Open, player >
{
Open() { /*std::cout << "entering Open" << std::endl;*/ } // entry
~Open() { /*std::cout << "leaving Open" << std::endl;*/ } // exit
typedef sc::transition< open_close, Empty,
player, &player::close_drawer > reactions;
};
struct Stopped : sc::simple_state< Stopped, player >
{
Stopped() { /*std::cout << "entering Stopped" << std::endl;*/ } // entry
~Stopped() { /*std::cout << "leaving Stopped" << std::endl;*/ } // exit
typedef mpl::list<
sc::transition< play, Playing,
player, &player::start_playback >,
sc::transition< open_close, Open,
player, &player::open_drawer >,
sc::transition< stop, Stopped,
player, &player::stopped_again > > reactions;
};
struct Playing : sc::simple_state< Playing, player >
{
Playing() { /*std::cout << "entering Playing" << std::endl;*/ } // entry
~Playing() { /*std::cout << "leaving Playing" << std::endl;*/ } // exit
typedef mpl::list<
sc::transition< stop, Stopped,
player, &player::stop_playback >,
sc::transition< pause, Paused,
player, &player::pause_playback >,
sc::transition< open_close, Open,
player, &player::stop_and_open > > reactions;
};
struct Paused : sc::simple_state< Paused, player >
{
Paused() { /*std::cout << "entering Paused" << std::endl;*/ } // entry
~Paused() { /*std::cout << "leaving Paused" << std::endl;*/ } // exit
typedef mpl::list<
sc::transition< end_pause, Playing,
player, &player::resume_playback >,
sc::transition< stop, Stopped,
player, &player::stop_playback >,
sc::transition< open_close, Open,
player, &player::stop_and_open > > reactions;
};
}
#ifndef WIN32
long mtime(struct timeval& tv1,struct timeval& tv2)
{
return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
}
#endif
int main()
{
test_sc::player p;
p.initiate();
// for timing
#ifdef WIN32
LARGE_INTEGER res;
::QueryPerformanceFrequency(&res);
LARGE_INTEGER li,li2;
::QueryPerformanceCounter(&li);
#else
struct timeval tv1,tv2;
gettimeofday(&tv1,NULL);
#endif
for (int i=0;i<100;++i)
{
p.process_event(test_sc::open_close());
p.process_event(test_sc::open_close());
p.process_event(test_sc::cd_detected());
p.process_event(test_sc::play());
p.process_event(test_sc::pause());
// go back to Playing
p.process_event(test_sc::end_pause());
p.process_event(test_sc::pause());
p.process_event(test_sc::stop());
// event leading to the same state
p.process_event(test_sc::stop());
p.process_event(test_sc::open_close());
p.process_event(test_sc::open_close());
}
#ifdef WIN32
::QueryPerformanceCounter(&li2);
#else
gettimeofday(&tv2,NULL);
#endif
#ifdef WIN32
std::cout << "sc took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
#else
std::cout << "sc took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
#endif
return 0;
}

View File

@@ -0,0 +1,469 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include <string>
#include "boost/mpl/vector/vector30.hpp"
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/back/tools.hpp>
using namespace std;
namespace msm = boost::msm;
namespace // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
struct ThreeSec {};
struct TenSec {};
struct go_sleep {};
struct error_found {};
struct end_error {};
// Flags. Allow information about a property of the current state
struct PlayingPaused{};
struct CDLoaded {};
struct FirstSongPlaying {};
// A "complicated" event type that carries some data.
struct cd_detected
{
cd_detected(std::string name)
: name(name)
{}
std::string name;
};
// an easy visitor
struct SomeVisitor
{
template <class T>
void visit_state(T* astate,int i)
{
std::cout << "visiting state:" << typeid(*astate).name()
<< " with data:" << i << std::endl;
}
};
// overwrite of the base state (not default)
struct my_visitable_state
{
// signature of the accept function
typedef msm::back::args<void,SomeVisitor&,int> accept_sig;
// we also want polymorphic states
virtual ~my_visitable_state() {}
// default implementation for states who do not need to be visited
void accept(SomeVisitor&,int) const {}
};
// Concrete FSM implementation
struct player_ : public msm::front::state_machine_def<player_,my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: player" << std::endl;}
// The list of FSM states
struct Empty : public msm::front::state<my_visitable_state>
{
typedef mpl::vector<play> deferred_events;
// every (optional) entry/exit methods get the event packed as boost::any. Not useful very often.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
void accept(SomeVisitor& vis,int i) const
{
vis.visit_state(this,i);
}
};
struct Open : public msm::front::state<my_visitable_state>
{
typedef mpl::vector1<CDLoaded> flag_list;
typedef mpl::vector<play> deferred_events;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
void accept(SomeVisitor& vis,int i) const
{
vis.visit_state(this,i);
}
};
// a state needing a pointer to the containing state machine
// and using for this the non-default policy
// if policy used, set_sm_ptr is needed
struct Stopped : public msm::front::state<my_visitable_state>
{
// when stopped, the CD is loaded
typedef mpl::vector1<CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
// the player state machine contains a state which is himself a state machine
// it demonstrates Shallow History: if the state gets activated with end_pause
// then it will remember the last active state and reactivate it
// also possible: AlwaysHistory, the last active state will always be reactivated
// or NoHistory, always restart from the initial state
struct Playing_ : public msm::front::state_machine_def<Playing_,my_visitable_state >
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
void accept(SomeVisitor& vis,int i) const
{
// note that visiting will recursively visit sub-states
vis.visit_state(this,i);
}
// The list of FSM states
// the Playing state machine contains a state which is himself a state machine
// so we have a SM containing a SM containing a SM
struct Song1_ : public msm::front::state_machine_def<Song1_,my_visitable_state>
{
typedef mpl::vector1<FirstSongPlaying> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
void accept(SomeVisitor& vis,int i) const
{
vis.visit_state(this,i);
}
struct LightOn : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: LightOn" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: LightOn" << std::endl;}
};
struct LightOff : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: LightOff" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: LightOff" << std::endl;}
};
// the initial state. Must be defined
typedef LightOn initial_state;
// transition actions
void turn_light_off(ThreeSec const&) { std::cout << "3s off::turn light off\n"; }
// guard conditions
typedef Song1_ s; // makes transition table cleaner
// Transition table for Song1
struct transition_table : mpl::vector1<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < LightOn , ThreeSec , LightOff, &s::turn_light_off >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<Song1_> Song1;
struct Song2 : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
// the player state machine contains a state which is himself a state machine (2 of them, Playing and Paused)
struct Paused_ : public msm::front::state_machine_def<Paused_,my_visitable_state>
{
typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
// The list of FSM states
struct StartBlinking : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: StartBlinking" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: StartBlinking" << std::endl;}
};
struct StopBlinking : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: StopBlinking" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: StopBlinking" << std::endl;}
};
// the initial state. Must be defined
typedef StartBlinking initial_state;
// transition actions
void start_blinking(TenSec const&) { std::cout << "Paused::start_blinking\n"; }
void stop_blinking(TenSec const&) { std::cout << "Paused::stop_blinking\n"; }
// guard conditions
typedef Paused_ pa; // makes transition table cleaner
// Transition table
struct transition_table : mpl::vector2<
// Start Event Next Action Guard
// +---------------+-------------+--------------+---------------------+----------------------+
a_row < StartBlinking , TenSec , StopBlinking , &pa::stop_blinking >,
a_row < StopBlinking , TenSec , StartBlinking , &pa::start_blinking >
// +---------------+-------------+---------------+--------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<Paused_> Paused;
struct SleepMode : public msm::front::state<my_visitable_state>
{
}; // dummy state just to test the automatic id generation
struct AllOk : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
};
struct ErrorMode : //public terminate_state<>
public msm::front::interrupt_state<end_error,my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
};
// the initial state of the player SM. Must be defined
typedef mpl::vector<Empty,AllOk> initial_state;
//typedef Empty initial_state; // this is to have only one active state
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const&)
{
std::cout << "player::store_cd_info\n";
// generate another event to test the queue
//process_event(play());
}
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
void start_sleep(go_sleep const&) { }
void report_error(error_found const&) {std::cout << "player::report_error\n";}
void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >,
a_row < Paused , go_sleep ,SleepMode, &p::start_sleep >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
void pstate(player const& p)
{
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode","SleepMode" };
for (unsigned int i=0;i<player::nr_regions::value;++i)
{
std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
}
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
// test deferred event
// deferred in Empty and Open, will be handled only after event cd_detected
p.process_event(play());
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
// visiting Paused and AllOk, but only Paused cares
SomeVisitor vis;
p.visit_current_states(boost::ref(vis),1);
p.process_event(open_close()); pstate(p);
// visiting Empty and AllOk, but only Empty cares
p.visit_current_states(boost::ref(vis),2);
p.process_event(cd_detected("louie, louie"));
// no need to call play() as the previous event does it in its action method
//p.process_event(play());
// at this point, Play is active, along FirstSong and LightOn
pstate(p);
// visiting Playing+Song1 and AllOk, but only Playing+Song1 care
p.visit_current_states(boost::ref(vis),3);
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
// call on_exit on LightOn,FirstSong,Play like stated in the UML spec.
// and of course on_entry on Paused and StartBlinking
p.process_event(pause()); pstate(p);
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
// forward events to Paused
p.process_event(TenSec());
p.process_event(TenSec());
// go back to Playing
p.process_event(end_pause()); pstate(p);
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl; //=> true
p.process_event(ThreeSec()); pstate(p);
p.process_event(NextSong());pstate(p);
// We are now in second song, Flag inactive
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
// visiting Playing+Song2 and AllOk, but only Playing cares
p.visit_current_states(boost::ref(vis),4);
p.process_event(NextSong());pstate(p);
// 2nd song active
p.process_event(PreviousSong());pstate(p);
// Pause
p.process_event(pause()); pstate(p);
// go back to Playing
// but end_pause is an event activating the History
// => keep the last active State (SecondSong)
p.process_event(end_pause()); pstate(p);
// test of an event from a state to itself. According to UML spec, call again exit/entry from Stopped
p.process_event(stop()); pstate(p);
p.process_event(stop()); pstate(p);
std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
std::cout << "CDLoaded active with OR:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_OR>() << std::endl;//=> true
// go back to Playing
// but play is not leading to Shallow History => do not remember the last active State (SecondSong)
// and activate again FirstSong and LightOn
p.process_event(play()); pstate(p);
p.process_event(error_found()); pstate(p);
// try generating more events
std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
p.process_event(NextSong());pstate(p);
std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(end_error());pstate(p);
std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
p.process_event(NextSong());pstate(p);
std::cout << "Simulate error. Event play is not valid" << std::endl;
p.process_event(play()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,248 @@
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/tracking.hpp>
#include <fstream>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
//we might want to serialize some data contained by the front-end
int front_end_data;
player_():front_end_data(0){}
// to achieve this, ask for it
typedef int do_serialize;
// and provide a serialize
template<class Archive>
void serialize(Archive & ar, const unsigned int )
{
ar & front_end_data;
}
// The list of FSM states
struct Empty : public msm::front::state<>
{
// we want Empty to be serialized
typedef int do_serialize;
template<class Archive>
void serialize(Archive & ar, const unsigned int )
{
ar & some_dummy_data;
}
Empty():some_dummy_data(0){}
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
int some_dummy_data;
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
// sm_ptr still supported but deprecated as functors are a much better way to do the same thing
struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
void set_sm_ptr(player_* pl)
{
m_player=pl;
}
player_* m_player;
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; }
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
// guard conditions
bool good_disk_format(cd_detected const& evt)
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
// used to show a transition conflict. This guard will simply deactivate one transition and thus
// solve the conflict
bool auto_start(cd_detected const&)
{
return false;
}
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
_row < Stopped , stop , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
row < Empty , cd_detected , Playing , &p::store_cd_info ,&p::auto_start >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
p.get_state<player_::Empty&>().some_dummy_data=3;
p.front_end_data=4;
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
std::ofstream ofs("fsm.txt");
// save fsm to archive (current state is Open)
{
boost::archive::text_oarchive oa(ofs);
// write class instance to archive
oa << p;
}
// reload fsm in state Open
player p2;
{
// create and open an archive for input
std::ifstream ifs("fsm.txt");
boost::archive::text_iarchive ia(ifs);
// read class state from archive
ia >> p2;
}
// we now use p2 as it was loaded
// check that we kept Empty's data value
std::cout << "Empty's data should be 3:" << p2.get_state<player_::Empty&>().some_dummy_data << std::endl;
std::cout << "front-end data should be 4:" << p2.front_end_data << std::endl;
p2.process_event(open_close()); pstate(p2);
// will be rejected, wrong disk type
p2.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p2);
p2.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p2);
p2.process_event(play());
// at this point, Play is active
p2.process_event(pause()); pstate(p2);
// go back to Playing
p2.process_event(end_pause()); pstate(p2);
p2.process_event(pause()); pstate(p2);
p2.process_event(stop()); pstate(p2);
// event leading to the same state
// no action method called as it is not present in the transition table
p2.process_event(stop()); pstate(p2);
}
}
// eliminate object tracking (even if serialized through a pointer)
// at the risk of a programming error creating duplicate objects.
// this is to get rid of warning because p is not const
BOOST_CLASS_TRACKING(player, boost::serialization::track_never)
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,266 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/tracking.hpp>
#include <fstream>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
// A "complicated" event type that carries some data.
struct cd_detected
{
cd_detected(std::string name)
: name(name)
{}
std::string name;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// The list of FSM states
struct Song1 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
};
struct Song2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
// demonstrates Shallow History: if the state gets activated with end_pause
// then it will remember the last active state and reactivate it
// also possible: AlwaysHistory, the last active state will always be reactivated
// or NoHistory, always restart from the initial state
typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const& cd) {std::cout << "player::store_cd_info\n";}
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
p.process_event(cd_detected("louie, louie"));
p.process_event(play());
// at this point, Play is active
// make transition happen inside it. Player has no idea about this event but it's ok.
p.process_event(NextSong());pstate(p); //2nd song active
p.process_event(NextSong());pstate(p);//3rd song active
p.process_event(PreviousSong());pstate(p);//2nd song active
p.process_event(pause()); pstate(p);
std::ofstream ofs("fsm.txt");
// save fsm to archive (current state is Pause, Playing is in Song2)
{
boost::archive::text_oarchive oa(ofs);
// write class instance to archive
oa << p;
}
// reload fsm in state Open
player p2;
{
// create and open an archive for input
std::ifstream ifs("fsm.txt");
boost::archive::text_iarchive ia(ifs);
// read class state from archive
ia >> p2;
}
// go back to Playing
// as you see, remembers the original state as end_pause is an history trigger
p2.process_event(end_pause()); pstate(p2);
p2.process_event(pause()); pstate(p2);
p2.process_event(stop()); pstate(p2);
// event leading to the same state
p2.process_event(stop()); pstate(p2);
// play does not trigger shallow history => start back from 1st song
p2.process_event(play()); pstate(p2);
}
}
// eliminate object tracking (even if serialized through a pointer)
// at the risk of a programming error creating duplicate objects.
// this is to get rid of warning because p is not const
BOOST_CLASS_TRACKING(player, boost::serialization::track_never)
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,258 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/phoenix/phoenix.hpp>
// add phoenix support in eUML
#define BOOST_MSM_EUML_PHOENIX_SUPPORT
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
using namespace boost::phoenix;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
struct play_event : boost::msm::front::euml::euml_event<play_event>
{
};
play_event play;
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
// A "complicated" event type that carries some data.
struct cd_detected_event : boost::msm::front::euml::euml_event<cd_detected_event>
{
cd_detected_event(){}
cd_detected_event(std::string const& name,DiskTypeEnum disk):cd_name(name),cd_type(disk){}
std::string cd_name;
DiskTypeEnum cd_type;
};
// define an instance for a nicer transition table
cd_detected_event cd_detected;
// Concrete FSM implementation
// The list of FSM states
// state not needing any entry or exit
BOOST_MSM_EUML_STATE((),Paused)
// states with standard eUML actions
BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
// a "standard" msm state
struct Empty_impl : public msm::front::state<> , public euml_state<Empty_impl>
{
// this allows us to add some functions
void foo() {std::cout << "Empty::foo " << std::endl;}
// standard entry behavior
template <class Event,class FSM>
void on_entry(Event const& evt,FSM& fsm)
{
std::cout << "entering: Empty" << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const& evt,FSM& fsm)
{
std::cout << "leaving: Empty" << std::endl;
}
};
//instance for use in the transition table
Empty_impl const Empty;
// entry and exit actions as phoenix functions
struct open_entry_impl
{
typedef void result_type;
void operator()()
{
cout << "entering: Open" << endl;
}
};
boost::phoenix::function<open_entry_impl> open_entry;
struct open_exit_impl
{
typedef void result_type;
void operator()()
{
cout << "leaving: Open" << endl;
}
};
boost::phoenix::function<open_exit_impl> open_exit;
// a state using phoenix for entry/exit actions
BOOST_MSM_EUML_STATE(( open_entry(),open_exit() ),Open)
// actions and guards using boost::phoenix
struct start_playback_impl
{
typedef void result_type;
void operator()()
{
cout << "calling: start_playback" << endl;
}
};
boost::phoenix::function<start_playback_impl> start_playback;
// a guard taking the event as argument
struct good_disk_format_impl
{
typedef bool result_type;
template <class Event>
bool operator()(Event const& evt)
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.cd_type!=DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
std::cout << "good disk" << std::endl;
return true;
}
};
boost::phoenix::function<good_disk_format_impl> good_disk_format;
// a simple action
struct store_cd_info_impl
{
typedef void result_type;
void operator()()
{
cout << "calling: store_cd_info" << endl;
}
};
boost::phoenix::function<store_cd_info_impl> store_cd_info;
// an action taking the fsm as argument and sending it a new event
struct process_play_impl
{
typedef void result_type;
template <class Fsm>
void operator()(Fsm& fsm)
{
cout << "queuing a play event" << endl;
fsm.process_event(play);
}
};
// it is also possible to use BOOST_PHOENIX_ADAPT_CALLABLE to avoid defining a global variable
BOOST_PHOENIX_ADAPT_CALLABLE(process_play, process_play_impl, 1)
// transition table. Actions and guards are written as phoenix functions
BOOST_MSM_EUML_TRANSITION_TABLE((
//an action without arguments
Playing == Stopped + play / start_playback() ,
Playing == Paused + end_pause ,
// +------------------------------------------------------------------------------+
Empty == Open + open_close ,
// +------------------------------------------------------------------------------+
Open == Empty + open_close ,
Open == Paused + open_close ,
Open == Stopped + open_close ,
Open == Playing + open_close ,
// +------------------------------------------------------------------------------+
Paused == Playing + pause ,
// +------------------------------------------------------------------------------+
Stopped == Playing + stop ,
Stopped == Paused + stop ,
// a guard taking the event as argument
// and an action made of a phoenix expression of 2 actions
// _event is a placeholder for the current event
// _fsm is a placeholder for the current state machine
Stopped == Empty + cd_detected [good_disk_format(_event)]
/ (store_cd_info(),process_play(_fsm)),
Stopped == Stopped + stop
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
// or simply, if no no_transition handler needed:
//BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
// Empty // Init State
// ),player_)
// choice of back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected_event("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected_event("louie, louie",DISK_CD)); pstate(p);
// no need to call play as the previous event does it in its action method
//p.process_event(play);
// at this point, Play is active
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as none is defined in the transition table
p.process_event(stop); pstate(p);
// test call to no_transition
p.process_event(pause); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,159 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
// how long the timer will ring when countdown elapsed.
#define RINGING_TIME 5
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_timer)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_timer ), start_timer_attr)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(start_timer,start_timer_attr)
BOOST_MSM_EUML_EVENT(stop_timer)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_tick)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_tick ), tick_attr)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(tick,tick_attr)
BOOST_MSM_EUML_EVENT(start_ringing)
// Concrete FSM implementation
// The list of FSM states
BOOST_MSM_EUML_ACTION(Stopped_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Stopped" << std::endl;
}
};
BOOST_MSM_EUML_STATE(( Stopped_Entry ),Stopped)
BOOST_MSM_EUML_ACTION(Started_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Started" << std::endl;
}
};
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_counter)
BOOST_MSM_EUML_STATE(( Started_Entry,
no_action,
attributes_ << m_counter
),
Started)
BOOST_MSM_EUML_ACTION(Ringing_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Ringing" << std::endl;
}
};
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_ringing_cpt)
BOOST_MSM_EUML_STATE(( Ringing_Entry,
no_action,
attributes_ << m_ringing_cpt
),
Ringing)
// external function
void do_ring(int ringing_time) {std::cout << "ringing " << ringing_time << " s" << std::endl;}
// create functor and eUML function
BOOST_MSM_EUML_FUNCTION(Ring_ , do_ring , ring_ , void , void )
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
// When we start the countdown, the countdown value is not hardcoded but contained in the start_timer event.
// We copy this value into Started
Started == Stopped + start_timer /(target_(m_counter)= event_(m_timer)) ,
Stopped == Started + stop_timer ,
// internal transition
Started + tick
// we here use the message queue to move to Started when the countdown is finished
// to do this we put start_ringing into the message queue
/ if_then_( (source_(m_counter) -= event_(m_tick) ) <= Int_<0>(),
process_(start_ringing) ) ,
// when we start ringing, we give to the state its hard-coded ringing time.
Ringing == Started + start_ringing
/ (target_(m_ringing_cpt) = Int_<RINGING_TIME>(),
// call the external do_ring function
ring_(Int_<RINGING_TIME>())) ,
// to change a bit, we now do not use the message queue but a transition conflict to solve the same problem.
// When tick is fired, we have an internal transition Ringing -> Ringing, as long as Counter > 0
Ringing + tick [ source_(m_ringing_cpt) - event_(m_tick) > Int_<0>() ]
/(target_(m_ringing_cpt) -= event_(m_tick) ) ,
// And we move to Stopped when the counter is 0
Stopped == Ringing + tick[source_(m_ringing_cpt)-event_(m_tick) <= Int_<0>()] ,
// we let the user manually stop the ringing by pressing any button
Stopped == Ringing + stop_timer ,
Stopped == Ringing + start_timer
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Stopped // Init State
),
SimpleTimer_) //fsm name
// choice of back-end
typedef msm::back::state_machine<SimpleTimer_> SimpleTimer;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Started","Ringing" };
void pstate(SimpleTimer const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
SimpleTimer p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
p.process_event(start_timer(5));pstate(p); //timer set to 5 ticks
p.process_event(tick(2));pstate(p);
p.process_event(tick(1));pstate(p);
p.process_event(tick(1));pstate(p);
p.process_event(tick(1));pstate(p);
// we are now ringing, let it ring a bit
p.process_event(tick(2));pstate(p);
p.process_event(tick(1));pstate(p);
p.process_event(tick(1));pstate(p);
p.process_event(tick(1));pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,213 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&)
{
std::cout << "entering: Player" << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const&,FSM& )
{
std::cout << "leaving: Player" << std::endl;
}
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
// sm_ptr still supported but deprecated as functors are a much better way to do the same thing
struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
void set_sm_ptr(player_* pl)
{
m_player=pl;
}
player_* m_player;
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; }
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
// guard conditions
bool good_disk_format(cd_detected const& evt)
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
// used to show a transition conflict. This guard will simply deactivate one transition and thus
// solve the conflict
bool auto_start(cd_detected const&)
{
return false;
}
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
_row < Stopped , stop , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
row < Empty , cd_detected , Playing , &p::store_cd_info ,&p::auto_start >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
p.process_event(play());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
std::cout << "stop fsm" << std::endl;
p.stop();
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,227 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/row2.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&)
{
std::cout << "entering: Player" << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const&,FSM& )
{
std::cout << "leaving: Player" << std::endl;
}
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
void open_drawer(open_close const&) { std::cout << "Empty::open_drawer\n"; }
// actions for Empty's internal transitions
void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
bool internal_guard(cd_detected const&)
{
std::cout << "Empty::internal guard\n";
return false;
}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
void close_drawer(open_close const&) { std::cout << "Open::close_drawer\n"; }
void stop_and_open(open_close const&) { std::cout << "Open::stop_and_open\n"; }
};
// sm_ptr still supported but deprecated as functors are a much better way to do the same thing
struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
void set_sm_ptr(player_* pl)
{
m_player=pl;
}
player_* m_player;
void start_playback(play const&) { std::cout << "Stopped::start_playback\n"; }
void stop_playback(stop const&) { std::cout << "Stopped::stop_playback\n"; }
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// guard conditions
// used to show a transition conflict. This guard will simply deactivate one transition and thus
// solve the conflict
bool auto_start(cd_detected const&)
{
return false;
}
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
void pause_playback(pause const&) { std::cout << "Paused::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "Paused::resume_playback\n"; }
};
// action
void store_cd_info(cd_detected const&) { std::cout << "Player::store_cd_info\n"; }
// guard
bool good_disk_format(cd_detected const& evt)
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action/Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row2 < Stopped , play , Playing , Stopped , &Stopped::start_playback >,
a_row2 < Stopped , open_close , Open , Empty , &Empty::open_drawer >,
_row < Stopped , stop , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
a_row2 < Open , open_close , Empty , Open , &Open::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row2 < Empty , open_close , Open , Empty ,&Empty::open_drawer >,
row2 < Empty , cd_detected , Stopped , player_ ,&player_::store_cd_info
, player_ ,&player_::good_disk_format >,
row2 < Empty , cd_detected , Playing , player_ ,&player_::store_cd_info
, Playing ,&Playing::auto_start >,
// conflict with some internal rows
irow2 < Empty , cd_detected , Empty ,&Empty::internal_action
, Empty ,&Empty::internal_guard >,
g_irow2 < Empty , cd_detected , Empty ,&Empty::internal_guard >,
// +---------+-------------+---------+---------------------+----------------------+
a_row2 < Playing , stop , Stopped , Stopped ,&Stopped::stop_playback >,
a_row2 < Playing , pause , Paused , Paused ,&Paused::pause_playback >,
a_row2 < Playing , open_close , Open , Open ,&Open::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row2 < Paused , end_pause , Playing , Paused ,&Paused::resume_playback >,
a_row2 < Paused , stop , Stopped , Stopped ,&Stopped::stop_playback >,
a_row2 < Paused , open_close , Open , Open ,&Open::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
p.process_event(play());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
std::cout << "stop fsm" << std::endl;
p.stop();
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,187 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
// A "complicated" event type that carries some data.
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
// Concrete FSM implementation
// The list of FSM states
// state not needing any entry or exit
BOOST_MSM_EUML_STATE((),Paused)
// it is also possible to define a state which you can implement normally
// just make it a state, as usual, and also a grammar terminal, euml_state
struct Empty_impl : public msm::front::state<> , public euml_state<Empty_impl>
{
// this allows us to add some functions
void activate_empty() {std::cout << "switching to Empty " << std::endl;}
// standard entry behavior
template <class Event,class FSM>
void on_entry(Event const& evt,FSM& fsm)
{
std::cout << "entering: Empty" << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const& evt,FSM& fsm)
{
std::cout << "leaving: Empty" << std::endl;
}
};
//instance for use in the transition table
Empty_impl const Empty;
// create a functor and a eUML function for the activate_empty method from Entry
BOOST_MSM_EUML_METHOD(ActivateEmpty_ , activate_empty , activate_empty_ , void , void )
// define more states
BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
// guard conditions
BOOST_MSM_EUML_ACTION(good_disk_format)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.get_attribute(cd_type)!=DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
// just for logging, does not block any transition
return true;
}
std::cout << "good disk" << std::endl;
return true;
}
};
// it is also possible to use a plain functor, with default-constructor in the transition table
struct start_play
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::start_play" << endl;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Playing == Stopped + play / start_play() ,
Playing == Paused + end_pause / resume_playback,
// +------------------------------------------------------------------------------+
Empty == Open + open_close / (close_drawer,activate_empty_(target_)),
// +------------------------------------------------------------------------------+
Open == Empty + open_close / open_drawer,
Open == Paused + open_close / stop_and_open,
Open == Stopped + open_close / open_drawer,
Open == Playing + open_close / stop_and_open,
// +------------------------------------------------------------------------------+
Paused == Playing + pause / pause_playback,
// +------------------------------------------------------------------------------+
Stopped == Playing + stop / stop_playback,
Stopped == Paused + stop / stop_playback,
Stopped == Empty + cd_detected [good_disk_format &&
(event_(cd_type)==Int_<DISK_CD>())]
/ (store_cd_info,process_(play)),
Stopped == Stopped + stop
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
// or simply, if no no_transition handler needed:
//BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
// Empty // Init State
// ),player_)
// choice of back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// note that we write open_close and not open_close(), like usual. Both are possible with eUML, but
// you now have less to type.
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play as the previous event does it in its action method
//p.process_event(play);
// at this point, Play is active
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as none is defined in the transition table
p.process_event(stop); pstate(p);
// test call to no_transition
p.process_event(pause); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,149 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace // Concrete FSM implementation
{
// events
// note that unlike the SimpleTutorial, events must derive from euml_event.
BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)
BOOST_MSM_EUML_EVENT(stop)
BOOST_MSM_EUML_EVENT(pause)
BOOST_MSM_EUML_EVENT(open_close)
// A "complicated" event type that carries some data.
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
// Concrete FSM implementation
// The list of FSM states
// state not needing any entry or exit
BOOST_MSM_EUML_STATE((),Paused)
BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
// guard conditions
BOOST_MSM_EUML_ACTION(good_disk_format)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.get_attribute(cd_type)!=DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
// just for logging, does not block any transition
return true;
}
std::cout << "good disk" << std::endl;
return true;
}
};
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
Stopped + play / start_playback == Playing ,
Stopped + open_close / open_drawer == Open ,
Stopped + stop == Stopped,
// +------------------------------------------------------------------------------+
Open + open_close / close_drawer == Empty ,
// +------------------------------------------------------------------------------+
Empty + open_close / open_drawer == Open ,
Empty + cd_detected
[good_disk_format &&(event_(cd_type)==Int_<DISK_CD>())]
/ (store_cd_info,process_(play)) == Stopped ,
// +------------------------------------------------------------------------------+
Playing + stop / stop_playback == Stopped ,
Playing + pause / pause_playback == Paused ,
Playing + open_close / stop_and_open == Open ,
// +------------------------------------------------------------------------------+
Paused + end_pause / resume_playback == Playing ,
Paused + stop / stop_playback == Stopped ,
Paused + open_close / stop_and_open == Open
// +------------------------------------------------------------------------------+
),transition_table)
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Empty, // Init State
no_action, // Entry
no_action, // Exit
attributes_ << no_attributes_, // Attributes
configure_ << no_configure_, // configuration
Log_No_Transition // no_transition handler
),
player_) //fsm name
// choice of back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play as the previous event does it in its action method
//p.process_event(play);
// at this point, Play is active
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as none is defined in the transition table
p.process_event(stop); pstate(p);
// test call to no_transition
p.process_event(pause); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,226 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct to_ignore {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
// sm_ptr still supported but deprecated as functors are a much better way to do the same thing
struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
void set_sm_ptr(player_* pl)
{
m_player=pl;
}
player_* m_player;
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; }
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
// guard conditions
bool good_disk_format(cd_detected const& evt)
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
// transitions internal to Empty
void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
bool internal_guard(cd_detected const&)
{
std::cout << "Empty::internal guard\n";
return false;
}
struct internal_guard_fct
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Empty::internal guard functor\n";
return false;
}
};
struct internal_action_fct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
std::cout << "Empty::internal action functor" << std::endl;
}
};
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
_row < Stopped , stop , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
irow < Empty , cd_detected , &p::internal_action ,&p::internal_guard >,
_irow < Empty , to_ignore >,
g_irow < Empty , cd_detected ,&p::internal_guard >,
Row < Empty , cd_detected , none , internal_action_fct ,internal_guard_fct >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// this event will be ignored and not call no_transition
p.process_event(to_ignore());
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
p.process_event(play());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,231 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
namespace msm = boost::msm;
using namespace msm::front;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// actions for Empty's internal transitions
void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
bool internal_guard(cd_detected const&)
{
std::cout << "Empty::internal guard\n";
return false;
}
struct internal_guard_fct
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Empty::internal guard functor\n";
return false;
}
};
struct internal_action_fct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
std::cout << "Empty::internal action functor" << std::endl;
}
};
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
// Transition table for Empty
struct internal_transition_table : mpl::vector<
// Start Event Next Action Guard
Internal < cd_detected , internal_action_fct ,internal_guard_fct >
// +---------+-------------+---------+---------------------+----------------------+
> {};
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
// sm_ptr still supported but deprecated as functors are a much better way to do the same thing
struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
void set_sm_ptr(player_* pl)
{
m_player=pl;
}
player_* m_player;
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; }
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
// guard conditions
bool good_disk_format(cd_detected const& evt)
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
_row < Stopped , stop , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
// conflict between a normal and 2 internal transitions (irow/g_irow)
row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
irow < Empty , cd_detected , &p::internal_action ,&p::internal_guard >,
g_irow < Empty , cd_detected ,&p::internal_guard >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
typedef int no_message_queue;
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
p.process_event(play());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,325 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/euml/common.hpp>
// for And_ operator
#include <boost/msm/front/euml/operator.hpp>
using namespace std;
namespace msm = boost::msm;
using namespace msm::front;
namespace mpl = boost::mpl;
// for And_ operator
using namespace msm::front::euml;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
struct internal_guard_fct
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Empty::internal_transition_table guard\n";
return false;
}
};
struct internal_action_fct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
std::cout << "Empty::internal_transition_table action" << std::endl;
}
};
// Transition table for Empty
struct internal_transition_table : mpl::vector<
// Start Event Next Action Guard
Internal < cd_detected , internal_action_fct ,internal_guard_fct >
// +---------+-------------+---------+---------------------+----------------------+
> {};
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
// as the functors are generic on events, fsm and source/target state,
// you can reuse them in another machine if you wish
struct TestFct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
{
cout << "transition with event:" << typeid(EVT).name() << endl;
}
};
struct start_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::start_playback" << endl;
}
};
struct open_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::open_drawer" << endl;
}
};
struct close_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::close_drawer" << endl;
}
};
struct store_cd_info
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}
};
struct stop_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_playback" << endl;
}
};
struct pause_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::pause_playback" << endl;
}
};
struct resume_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::resume_playback" << endl;
}
};
struct stop_and_open
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_and_open" << endl;
}
};
struct stopped_again
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stopped_again" << endl;
}
};
// guard conditions
struct DummyGuard
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
{
return true;
}
};
struct good_disk_format
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
};
struct always_true
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
return true;
}
};
struct internal_guard
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Empty::internal guard\n";
return false;
}
};
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------------+----------------------+
Row < Stopped , play , Playing , ActionSequence_
<mpl::vector<
TestFct,start_playback> >
, DummyGuard >,
Row < Stopped , open_close , Open , open_drawer , none >,
Row < Stopped , stop , Stopped , none , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Open , open_close , Empty , close_drawer , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Empty , open_close , Open , open_drawer , none >,
Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
always_true> >,
// internal transition inside the stt: none as Target
Row < Empty , cd_detected , none , none , internal_guard >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Playing , stop , Stopped , stop_playback , none >,
Row < Playing , pause , Paused , pause_playback , none >,
Row < Playing , open_close , Open , stop_and_open , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Paused , end_pause , Playing , resume_playback , none >,
Row < Paused , stop , Stopped , stop_playback , none >,
Row < Paused , open_close , Open , stop_and_open , none >
// +---------+-------------+---------+---------------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play() as the previous transition does it in its action method
//p.process_event(play());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,158 @@
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/euml/euml.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace std;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace
{
// events
struct play_impl : msm::front::euml::euml_event<play_impl> {};
struct end_pause_impl : msm::front::euml::euml_event<end_pause_impl>{};
struct stop_impl : msm::front::euml::euml_event<stop_impl>{};
struct pause_impl : msm::front::euml::euml_event<pause_impl>{};
struct open_close_impl : msm::front::euml::euml_event<open_close_impl>{};
struct cd_detected_impl : msm::front::euml::euml_event<cd_detected_impl>{};
// define some dummy instances for use in the transition table
// it is also possible to default-construct them instead:
// struct play {};
// inside the table: play()
play_impl play;
end_pause_impl end_pause;
stop_impl stop;
pause_impl pause;
open_close_impl open_close;
cd_detected_impl cd_detected;
// The list of FSM states
// they have to be declared outside of the front-end only to make VC happy :(
// note: gcc would have no problem
struct Empty_impl : public msm::front::state<> , public msm::front::euml::euml_state<Empty_impl>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open_impl : public msm::front::state<> , public msm::front::euml::euml_state<Open_impl>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped_impl : public msm::front::state<> , public msm::front::euml::euml_state<Stopped_impl>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
struct Playing_impl : public msm::front::state<> , public msm::front::euml::euml_state<Playing_impl>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused_impl : public msm::front::state<> , public msm::front::euml::euml_state<Paused_impl>
{
};
//to make the transition table more readable
Empty_impl const Empty;
Open_impl const Open;
Stopped_impl const Stopped;
Playing_impl const Playing;
Paused_impl const Paused;
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// the initial state of the player SM. Must be defined
typedef Empty_impl initial_state;
// Transition table for player
// replaces the old transition table
BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
Stopped + play / start_playback == Playing ,
Stopped + open_close / open_drawer == Open ,
Stopped + stop == Stopped ,
// +------------------------------------------------------------------------------+
Open + open_close / close_drawer == Empty ,
// +------------------------------------------------------------------------------+
Empty + open_close / open_drawer == Open ,
Empty + cd_detected /(store_cd_info,
msm::front::euml::process_(play)) == Stopped ,
// +------------------------------------------------------------------------------+
Playing + stop / stop_playback == Stopped ,
Playing + pause / pause_playback == Paused ,
Playing + open_close / stop_and_open == Open ,
// +------------------------------------------------------------------------------+
Paused + end_pause / resume_playback == Playing ,
Paused + stop / stop_playback == Stopped ,
Paused + open_close / stop_and_open == Open
// +------------------------------------------------------------------------------+
),transition_table)
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
p.process_event(cd_detected); pstate(p);
// at this point, Play is active
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,169 @@
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/euml/euml.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace std;
using namespace msm::front::euml;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
namespace
{
// events
struct play_impl : msm::front::euml::euml_event<play_impl> {};
struct end_pause_impl : msm::front::euml::euml_event<end_pause_impl>{};
struct stop_impl : msm::front::euml::euml_event<stop_impl>{};
struct pause_impl : msm::front::euml::euml_event<pause_impl>{};
struct open_close_impl : msm::front::euml::euml_event<open_close_impl>{};
struct cd_detected_impl : msm::front::euml::euml_event<cd_detected_impl>{};
// define some dummy instances for use in the transition table
// it is also possible to default-construct them instead:
// struct play {};
// inside the table: play()
play_impl play;
end_pause_impl end_pause;
stop_impl stop;
pause_impl pause;
open_close_impl open_close;
cd_detected_impl cd_detected;
// The list of FSM states
// they have to be declared outside of the front-end only to make VC happy :(
// note: gcc would have no problem
struct Empty_impl : public msm::front::state<> , public msm::front::euml::euml_state<Empty_impl>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open_impl : public msm::front::state<> , public msm::front::euml::euml_state<Open_impl>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped_impl : public msm::front::state<> , public msm::front::euml::euml_state<Stopped_impl>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
struct Playing_impl : public msm::front::state<> , public msm::front::euml::euml_state<Playing_impl>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused_impl : public msm::front::state<> , public msm::front::euml::euml_state<Paused_impl>
{
};
//to make the transition table more readable
Empty_impl const Empty;
Open_impl const Open;
Stopped_impl const Stopped;
Playing_impl const Playing;
Paused_impl const Paused;
BOOST_MSM_EUML_ACTION(pause_playback2)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
cout << "player::pause_playback2" << endl;
std::cout << "event type: " << typeid(EVT).name() << std::endl;
std::cout << "pause_playback2 with any event: " << evt.type().name() << std::endl;
}
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// the initial state of the player SM. Must be defined
typedef Empty_impl initial_state;
// Transition table for player
// replaces the old transition table
BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
Stopped + play / start_playback == Playing ,
Stopped + open_close / open_drawer == Open ,
Stopped + stop == Stopped ,
// +------------------------------------------------------------------------------+
Open + open_close / close_drawer == Empty ,
// +------------------------------------------------------------------------------+
Empty + open_close / open_drawer == Open ,
Empty + cd_detected /(store_cd_info,
msm::front::euml::process_(play)) == Stopped ,
// +------------------------------------------------------------------------------+
Playing + stop / stop_playback == Stopped ,
Playing + kleene / pause_playback2 == Paused ,
Playing + open_close / stop_and_open == Open ,
// +------------------------------------------------------------------------------+
Paused + end_pause / resume_playback == Playing ,
Paused + stop / stop_playback == Stopped ,
Paused + open_close / stop_and_open == Open
// +------------------------------------------------------------------------------+
),transition_table)
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
p.process_event(cd_detected); pstate(p);
// at this point, Play is active
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,205 @@
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/event_traits.hpp>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/constructible.hpp>
#include <boost/type_erasure/relaxed_match.hpp>
#include <boost/type_erasure/any_cast.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace std;
using namespace msm::front::euml;
// entry/exit/action/guard logging functors
#include "logging_functors.h"
BOOST_TYPE_ERASURE_MEMBER((has_getNumber), getNumber, 0);
//type erasure event
typedef ::boost::mpl::vector<
has_getNumber<int(), const boost::type_erasure::_self>,
boost::type_erasure::relaxed_match,
boost::type_erasure::copy_constructible<>,
boost::type_erasure::typeid_<>
> any_number_event_concept;
struct any_number_event : boost::type_erasure::any<any_number_event_concept>,
msm::front::euml::euml_event<any_number_event>
{
template <class U>
any_number_event(U const& u): boost::type_erasure::any<any_number_event_concept> (u){}
any_number_event(): boost::type_erasure::any<any_number_event_concept> (){}
};
namespace boost { namespace msm{
template<>
struct is_kleene_event< any_number_event >
{
typedef boost::mpl::true_ type;
};
}}
namespace
{
// events
struct play_impl : msm::front::euml::euml_event<play_impl> {int getNumber()const {return 0;}};
struct end_pause_impl : msm::front::euml::euml_event<end_pause_impl>{int getNumber()const {return 1;}};
struct stop_impl : msm::front::euml::euml_event<stop_impl>{int getNumber()const {return 2;}};
struct pause_impl : msm::front::euml::euml_event<pause_impl>{int getNumber()const {return 3;}};
struct open_close_impl : msm::front::euml::euml_event<open_close_impl>{int getNumber()const {return 4;}};
struct cd_detected_impl : msm::front::euml::euml_event<cd_detected_impl>{int getNumber()const {return 5;}};
// define some dummy instances for use in the transition table
// it is also possible to default-construct them instead:
// struct play {};
// inside the table: play()
play_impl play;
end_pause_impl end_pause;
stop_impl stop;
pause_impl pause;
open_close_impl open_close;
cd_detected_impl cd_detected;
any_number_event number_event;
// The list of FSM states
// they have to be declared outside of the front-end only to make VC happy :(
// note: gcc would have no problem
struct Empty_impl : public msm::front::state<> , public msm::front::euml::euml_state<Empty_impl>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open_impl : public msm::front::state<> , public msm::front::euml::euml_state<Open_impl>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped_impl : public msm::front::state<> , public msm::front::euml::euml_state<Stopped_impl>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
struct Playing_impl : public msm::front::state<> , public msm::front::euml::euml_state<Playing_impl>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused_impl : public msm::front::state<> , public msm::front::euml::euml_state<Paused_impl>
{
};
//to make the transition table more readable
Empty_impl const Empty;
Open_impl const Open;
Stopped_impl const Stopped;
Playing_impl const Playing;
Paused_impl const Paused;
BOOST_MSM_EUML_ACTION(pause_playback2)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
{
cout << "player::pause_playback2" << endl;
std::cout << "event type: " << typeid(EVT).name() << std::endl;
std::cout << "event's number: " << evt.getNumber() << std::endl;
}
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// the initial state of the player SM. Must be defined
typedef Empty_impl initial_state;
// Transition table for player
// replaces the old transition table
BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
Stopped + play / start_playback == Playing ,
Stopped + open_close / open_drawer == Open ,
Stopped + stop == Stopped ,
// +------------------------------------------------------------------------------+
Open + open_close / close_drawer == Empty ,
// +------------------------------------------------------------------------------+
Empty + open_close / open_drawer == Open ,
Empty + cd_detected /(store_cd_info,
msm::front::euml::process_(play)) == Stopped ,
// +------------------------------------------------------------------------------+
Playing + stop / stop_playback == Stopped ,
Playing + number_event / pause_playback == Paused ,
Playing + open_close / stop_and_open == Open ,
// +------------------------------------------------------------------------------+
Paused + end_pause / resume_playback == Playing ,
Paused + stop / stop_playback == Stopped ,
Paused + open_close / stop_and_open == Open
// +------------------------------------------------------------------------------+
),transition_table)
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close); pstate(p);
p.process_event(open_close); pstate(p);
p.process_event(cd_detected); pstate(p);
// at this point, Play is active
p.process_event(pause); pstate(p);
// go back to Playing
p.process_event(end_pause); pstate(p);
p.process_event(pause); pstate(p);
p.process_event(stop); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,318 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// functors
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/euml/common.hpp>
// for And_ operator
#include <boost/msm/front/euml/operator.hpp>
using namespace std;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
// for And_ operator
using namespace msm::front::euml;
namespace // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&)
{
std::cout << "entering: Player" << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const&,FSM& )
{
std::cout << "leaving: Player" << std::endl;
}
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
// when stopped, the CD is loaded
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
struct Playing : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
// as the functors are generic on events, fsm and source/target state,
// you can reuse them in another machine if you wish
struct TestFct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
{
cout << "transition with event:" << typeid(EVT).name() << endl;
}
};
struct start_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::start_playback" << endl;
}
};
struct open_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::open_drawer" << endl;
}
};
struct close_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::close_drawer" << endl;
}
};
struct store_cd_info
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}
};
struct stop_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_playback" << endl;
}
};
struct pause_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::pause_playback" << endl;
}
};
struct resume_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::resume_playback" << endl;
}
};
struct stop_and_open
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_and_open" << endl;
}
};
struct stopped_again
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stopped_again" << endl;
}
};
// guard conditions
struct DummyGuard
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
{
return true;
}
};
struct good_disk_format
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
};
struct always_true
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
return true;
}
};
// we want to define one row with the classic look.
bool auto_start(cd_detected const& evt)
{
return false;
}
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------------+----------------------+
Row < Stopped , play , Playing , ActionSequence_
<mpl::vector<
TestFct,start_playback> >
, DummyGuard >,
Row < Stopped , open_close , Open , open_drawer , none >,
Row < Stopped , stop , Stopped , none , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Open , open_close , Empty , close_drawer , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Empty , open_close , Open , open_drawer , none >,
Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
always_true> >,
// we here also mix with some "classical row"
g_row < Empty , cd_detected , Playing , &p::auto_start >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Playing , stop , Stopped , stop_playback , none >,
Row < Playing , pause , Paused , pause_playback , none >,
Row < Playing , open_close , Open , stop_and_open , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Paused , end_pause , Playing , resume_playback , none >,
Row < Paused , stop , Stopped , stop_playback , none >,
Row < Paused , open_close , Open , stop_and_open , none >
// +---------+-------------+---------+---------------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play() as the previous event does it in its action method
//p.process_event(play());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
std::cout << "stop fsm" << std::endl;
p.stop();
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,320 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// functors
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/euml/common.hpp>
// for And_ operator
#include <boost/msm/front/euml/operator.hpp>
// for func_state and func_state_machine
#include <boost/msm/front/euml/state_grammar.hpp>
using namespace std;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
// for And_ operator
using namespace msm::front::euml;
namespace // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// The list of FSM states
// entry and exit functors for Empty
struct Empty_Entry
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Empty" << std::endl;
}
};
struct Empty_Exit
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Empty" << std::endl;
}
};
// definition of Empty
struct Empty_tag {};
typedef msm::front::euml::func_state<Empty_tag,Empty_Entry,Empty_Exit> Empty;
struct Open_Entry
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Open" << std::endl;
}
};
struct Open_Exit
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Open" << std::endl;
}
};
struct Open_tag {};
typedef msm::front::euml::func_state<Open_tag,Open_Entry,Open_Exit> Open;
// states without entry/exit actions (can be declared as functor state, just without functors ;-) )
struct Stopped_tag {};
typedef msm::front::euml::func_state<Stopped_tag> Stopped;
struct Playing_tag {};
typedef msm::front::euml::func_state<Playing_tag> Playing;
// state not defining any entry or exit (declared as simple state. Equivalent)
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
// as the functors are generic on events, fsm and source/target state,
// you can reuse them in another machine if you wish
struct TestFct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
{
cout << "transition with event:" << typeid(EVT).name() << endl;
}
};
struct start_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::start_playback" << endl;
}
};
struct open_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::open_drawer" << endl;
}
};
struct close_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::close_drawer" << endl;
}
};
struct store_cd_info
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}
};
struct stop_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_playback" << endl;
}
};
struct pause_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::pause_playback" << endl;
}
};
struct resume_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::resume_playback" << endl;
}
};
struct stop_and_open
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_and_open" << endl;
}
};
struct stopped_again
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stopped_again" << endl;
}
};
// guard conditions
struct DummyGuard
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
{
return true;
}
};
struct good_disk_format
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
};
struct always_true
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
return true;
}
};
// we want to define one row with the classic look.
bool auto_start(cd_detected const& evt)
{
return false;
}
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------------+----------------------+
Row < Stopped , play , Playing , ActionSequence_
<mpl::vector<
TestFct,start_playback> >
, DummyGuard >,
Row < Stopped , open_close , Open , open_drawer , none >,
Row < Stopped , stop , Stopped , none , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Open , open_close , Empty , close_drawer , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Empty , open_close , Open , open_drawer , none >,
Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
always_true> >,
// we here also mix with some "classical row"
g_row < Empty , cd_detected , Playing , &p::auto_start >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Playing , stop , Stopped , stop_playback , none >,
Row < Playing , pause , Paused , pause_playback , none >,
Row < Playing , open_close , Open , stop_and_open , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Paused , end_pause , Playing , resume_playback , none >,
Row < Paused , stop , Stopped , stop_playback , none >,
Row < Paused , open_close , Open , stop_and_open , none >
// +---------+-------------+---------+---------------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play() as the previous event does it in its action method
//p.process_event(play());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,307 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// functors
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/euml/common.hpp>
// for And_ operator
#include <boost/msm/front/euml/operator.hpp>
// for func_state and func_state_machine
#include <boost/msm/front/euml/state_grammar.hpp>
using namespace std;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
// for And_ operator
using namespace msm::front::euml;
namespace // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// The list of FSM states
// entry and exit functors for Empty
struct Empty_Entry
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Empty" << std::endl;
}
};
struct Empty_Exit
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Empty" << std::endl;
}
};
// definition of Empty
struct Empty_tag {};
typedef msm::front::euml::func_state<Empty_tag,Empty_Entry,Empty_Exit> Empty;
struct Open_Entry
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Open" << std::endl;
}
};
struct Open_Exit
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Open" << std::endl;
}
};
struct Open_tag {};
typedef msm::front::euml::func_state<Open_tag,Open_Entry,Open_Exit> Open;
// states without entry/exit actions (can be declared as functor state, just without functors ;-) )
struct Stopped_tag {};
typedef msm::front::euml::func_state<Stopped_tag> Stopped;
struct Playing_tag {};
typedef msm::front::euml::func_state<Playing_tag> Playing;
// state not defining any entry or exit (declared as simple state. Equivalent)
struct Paused_tag {};
typedef msm::front::euml::func_state<Paused_tag> Paused;
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
// transition actions
// as the functors are generic on events, fsm and source/target state,
// you can reuse them in another machine if you wish
struct TestFct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
{
cout << "transition with event:" << typeid(EVT).name() << endl;
}
};
struct start_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::start_playback" << endl;
}
};
struct open_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::open_drawer" << endl;
}
};
struct close_drawer
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::close_drawer" << endl;
}
};
struct store_cd_info
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}
};
struct stop_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_playback" << endl;
}
};
struct pause_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::pause_playback" << endl;
}
};
struct resume_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::resume_playback" << endl;
}
};
struct stop_and_open
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stop_and_open" << endl;
}
};
struct stopped_again
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
cout << "player::stopped_again" << endl;
}
};
// guard conditions
struct DummyGuard
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
{
return true;
}
};
struct good_disk_format
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
};
struct always_true
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
return true;
}
};
// Transition table for player
struct player_transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------------+----------------------+
Row < Stopped , play , Playing , ActionSequence_
<mpl::vector<
TestFct,start_playback> >
, DummyGuard >,
Row < Stopped , open_close , Open , open_drawer , none >,
Row < Stopped , stop , Stopped , none , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Open , open_close , Empty , close_drawer , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Empty , open_close , Open , open_drawer , none >,
Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
always_true> >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Playing , stop , Stopped , stop_playback , none >,
Row < Playing , pause , Paused , pause_playback , none >,
Row < Playing , open_close , Open , stop_and_open , none >,
// +---------+-------------+---------+---------------------------+----------------------+
Row < Paused , end_pause , Playing , resume_playback , none >,
Row < Paused , stop , Stopped , stop_playback , none >,
Row < Paused , open_close , Open , stop_and_open , none >
// +---------+-------------+---------+---------------------------+----------------------+
> {};
// fsm definition
struct player_tag {};
typedef msm::front::euml::func_state_machine<Playing_tag,
// transition table
player_transition_table,
//Initial state
Empty> player_;
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
// no need to call play() as the previous event does it in its action method
//p.process_event(play());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,119 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/back/mpl_graph_fsm_check.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::back;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct cd_detected{};
struct error_found {};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// The list of FSM states
struct Empty : public msm::front::state<>
{
};
struct Open : public msm::front::state<>
{
};
// sm_ptr still supported but deprecated as functors are a much better way to do the same thing
struct Stopped : public msm::front::state<>
{
};
struct Playing : public msm::front::state<>
{
};
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
struct AllOk : public msm::front::state<>
{
};
struct ErrorMode : public msm::front::state<>
{
};
struct State1 : public msm::front::state<>
{
};
struct State2 : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef mpl::vector<Empty,AllOk> initial_state;
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
// adding this line makes non-reachable states and should cause a static assert
//_row < State1 , open_close , State2 >,
// adding this line makes non-orthogonal regions and should cause a static assert
//_row < Paused , error_found , ErrorMode >,
_row < Stopped , play , Playing >,
_row < Stopped , open_close , Open >,
_row < Stopped , stop , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
_row < Open , open_close , Empty >,
// +---------+-------------+---------+---------------------+----------------------+
_row < Empty , open_close , Open >,
_row < Empty , cd_detected , Stopped >,
_row < Empty , cd_detected , Playing >,
// +---------+-------------+---------+---------------------+----------------------+
_row < Playing , stop , Stopped >,
_row < Playing , pause , Paused >,
_row < Playing , open_close , Open >,
// +---------+-------------+---------+---------------------+----------------------+
_row < Paused , end_pause , Playing >,
_row < Paused , stop , Stopped >,
_row < Paused , open_close , Open >,
_row < AllOk , error_found , ErrorMode >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
}
};
// Pick a back-end
typedef msm::back::state_machine<player_,msm::back::mpl_graph_fsm_check> player;
void test()
{
player p;
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,337 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include "boost/mpl/vector/vector30.hpp"
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/internal_row.hpp>
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
namespace
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct internal_event {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
struct to_ignore {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; }
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
// guard conditions
bool good_disk_format(cd_detected const& evt)
{
// to test a guard condition, let's say we understand only CDs, not DVD
if (evt.disc_type != DISK_CD)
{
std::cout << "wrong disk, sorry" << std::endl;
return false;
}
return true;
}
// transitions internal to Empty
void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
bool internal_guard(cd_detected const&)
{
std::cout << "Empty::internal guard\n";
return false;
}
void internal_action(internal_event const&){ std::cout << "Playing::internal action\n"; }
bool internal_guard(internal_event const&)
{
std::cout << "Playing::internal guard\n";
return false;
}
// The list of FSM states
struct Empty : public msm::front::state<>
{
// every (optional) entry/exit methods get the event passed.
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
struct internal_guard_fct
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Empty::internal guard functor\n";
return false;
}
};
struct internal_action_fct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
{
std::cout << "Empty::internal action functor" << std::endl;
}
};
void internal_action(to_ignore const&) { std::cout << "Empty::(almost)ignoring event\n"; }
// Transition table for Empty
struct internal_transition_table : mpl::vector<
// Start Event Next Action Guard
Row < Empty , cd_detected , none , internal_action_fct ,internal_guard_fct >,
Internal < cd_detected , internal_action_fct ,internal_guard_fct >,
a_internal< to_ignore , Empty,&Empty::internal_action >
// +---------+-------------+----------+------------------------+----------------------+
> {};
};
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
};
struct Stopped : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
};
struct Playing_ : public msm::front::state_machine_def<Playing_>
{
// when playing, the CD is loaded and we are in either pause or playing (duh)
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
// The list of FSM states
struct Song1 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
};
struct Song2 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&){std::cout << "Playing: start_next_song" << std::endl;}
void start_prev_song(PreviousSong const&){std::cout << "Playing: start_prev_song" << std::endl;}
// guard conditions
struct playing_internal_guard
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Playing::internal guard fct\n";
return true;
}
};
struct playing_false_guard
{
template <class EVT,class FSM,class SourceState,class TargetState>
bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Playing::false guard\n";
return false;
}
};
struct playing_internal_fct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Playing::internal fct\n";
}
};
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+---------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong , Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong , Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Internal transition table for Playing
// +---------+----------------+---------+---------------------+-----------------------+
struct internal_transition_table : mpl::vector<
// normal internal transition
// Start Event Next Action Guard
Internal < internal_event , playing_internal_fct,playing_internal_guard >,
// conflict between internal and the external defined above
Internal < PreviousSong , playing_internal_fct,playing_false_guard >,
internal < internal_event , player_,&player_::internal_action,
player_,&player_::internal_guard >
// +---------+----------------+---------+---------------------+-----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
typedef msm::back::state_machine<Playing_> Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
{
};
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
_row < Stopped , stop , Stopped >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
// conflict between a normal and 2 internal transitions (irow/g_irow)
// + a state-defined internals defined 2 ways (see Empty)
row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
irow < Empty , cd_detected , &p::internal_action ,&p::internal_guard >,
g_irow < Empty , cd_detected ,&p::internal_guard >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// this event will be ignored and not call no_transition
p.process_event(to_ignore());
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
// will be rejected, wrong disk type
p.process_event(
cd_detected("louie, louie",DISK_DVD)); pstate(p);
p.process_event(
cd_detected("louie, louie",DISK_CD)); pstate(p);
p.process_event(play());
p.process_event(NextSong());
std::cout << "sending an internal event" << std::endl;
p.process_event(internal_event());
std::cout << "conflict between the internal and normal transition. Internal is tried last" << std::endl;
p.process_event(PreviousSong());
// at this point, Play is active
p.process_event(pause()); pstate(p);
// go back to Playing
p.process_event(end_pause()); pstate(p);
p.process_event(pause()); pstate(p);
p.process_event(stop()); pstate(p);
// event leading to the same state
// no action method called as it is not present in the transition table
p.process_event(stop()); pstate(p);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,368 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include <string>
#include "boost/mpl/vector/vector30.hpp"
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/back/tools.hpp>
using namespace std;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
namespace // Concrete FSM implementation
{
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
struct NextSong {};
struct PreviousSong {};
struct ThreeSec {};
struct TenSec {};
struct error_found {};
struct end_error {};
struct cd_detected {};
// a simple visitor
struct SomeVisitor
{
template <class T>
void visit_state(T* astate,int i)
{
std::cout << "visiting state:" << typeid(*astate).name()
<< " with data:" << i << std::endl;
}
};
// base state for all states of ths fsm, to make them visitable
struct my_visitable_state
{
// signature of the accept function
typedef msm::back::args<void,SomeVisitor&,int> accept_sig;
// we also want polymorphic states
virtual ~my_visitable_state() {}
// default implementation for states who do not need to be visited
void accept(SomeVisitor&,int) const {}
// or if you want all states to be visited, provide an implementation
/*
void accept(SomeVisitor& vis,int i) const
{
vis.visit_state(this,i);
}
*/
};
// Concrete FSM implementation
struct player_ : public msm::front::state_machine_def<player_,my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: player" << std::endl;}
// The list of FSM states
struct Empty : public msm::front::state<my_visitable_state>
{
typedef mpl::vector<play> deferred_events;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
// this state wants to be visited
void accept(SomeVisitor& vis,int i) const
{
vis.visit_state(this,i);
}
};
struct Open : public msm::front::state<my_visitable_state>
{
typedef mpl::vector<play> deferred_events;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
// this state wants to be visited
void accept(SomeVisitor& vis,int i) const
{
vis.visit_state(this,i);
}
};
struct Stopped : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
// this state wants to be visited
void accept(SomeVisitor& vis,int i) const
{
// note that visiting will recursively visit sub-states
vis.visit_state(this,i);
}
};
struct Playing_ : public msm::front::state_machine_def<Playing_,my_visitable_state >
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
void accept(SomeVisitor& vis,int i) const
{
// note that visiting will recursively visit sub-states
vis.visit_state(this,i);
}
// The list of FSM states
// the Playing state machine contains a state which is himself a state machine
// so we have a SM containing a SM containing a SM
struct Song1_ : public msm::front::state_machine_def<Song1_,my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
void accept(SomeVisitor& vis,int i) const
{
vis.visit_state(this,i);
}
struct LightOn : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: LightOn" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: LightOn" << std::endl;}
void accept(SomeVisitor& vis,int i) const
{
// note that visiting will recursively visit sub-states
vis.visit_state(this,i);
}
};
struct LightOff : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: LightOff" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: LightOff" << std::endl;}
};
// the initial state. Must be defined
typedef LightOn initial_state;
// transition actions
void turn_light_off(ThreeSec const&) { std::cout << "3s off::turn light off\n"; }
// guard conditions
typedef Song1_ s; // makes transition table cleaner
// Transition table for Song1
struct transition_table : mpl::vector1<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < LightOn , ThreeSec , LightOff, &s::turn_light_off >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<Song1_> Song1;
struct Song2 : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
};
struct Song3 : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
};
// the initial state. Must be defined
typedef Song1 initial_state;
// transition actions
void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
// guard conditions
typedef Playing_ pl; // makes transition table cleaner
// Transition table for Playing
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
struct Paused : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
};
struct AllOk : public msm::front::state<my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
};
struct ErrorMode :
public msm::front::interrupt_state<end_error,my_visitable_state>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
void accept(SomeVisitor& vis,int i) const
{
vis.visit_state(this,i);
}
};
// the initial state of the player SM. Must be defined
typedef mpl::vector<Empty,AllOk> initial_state;
// transition actions
void start_playback(play const&) { std::cout << "player::start_playback\n"; }
void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
void store_cd_info(cd_detected const&)
{
std::cout << "player::store_cd_info\n";
}
void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
void report_error(error_found const&) {std::cout << "player::report_error\n";}
void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
// guard conditions
typedef player_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
a_row < Stopped , play , Playing , &p::start_playback >,
a_row < Stopped , open_close , Open , &p::open_drawer >,
a_row < Stopped , stop , Stopped , &p::stopped_again >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Open , open_close , Empty , &p::close_drawer >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Empty , open_close , Open , &p::open_drawer >,
a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Playing , stop , Stopped , &p::stop_playback >,
a_row < Playing , pause , Paused , &p::pause_playback >,
a_row < Playing , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < Paused , end_pause , Playing , &p::resume_playback >,
a_row < Paused , stop , Stopped , &p::stop_playback >,
a_row < Paused , open_close , Open , &p::stop_and_open >,
// +---------+-------------+---------+---------------------+----------------------+
a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
void pstate(player const& p)
{
static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode","SleepMode" };
for (unsigned int i=0;i<player::nr_regions::value;++i)
{
std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
}
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// test deferred event
// deferred in Empty and Open, will be handled only after event cd_detected
p.process_event(play());
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
// visiting Paused and AllOk, but only Paused cares
SomeVisitor vis;
p.visit_current_states(boost::ref(vis),1);
p.process_event(open_close()); pstate(p);
// visiting Empty and AllOk, but only Empty cares
p.visit_current_states(boost::ref(vis),2);
p.process_event(cd_detected());
// no need to call play() as the previous event does it in its action method
//p.process_event(play());
// at this point, Play is active, along FirstSong and LightOn
pstate(p);
// visiting Playing+Song1+LightOn and AllOk, but only Playing+Song1+LightOn care
p.visit_current_states(boost::ref(vis),3);
// Stop will be active
p.process_event(stop()); pstate(p);
// visiting when both regions have an active state who wants to be visited
p.process_event(error_found());
p.visit_current_states(boost::ref(vis),5);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,92 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MSM_CHAR_EVENT_DISPATCHER_HPP
#define BOOST_MSM_CHAR_EVENT_DISPATCHER_HPP
#include <boost/msm/back/common_types.hpp>
struct digit {};
struct char_0 : public digit {};
struct char_1 : public digit {};
struct char_2 : public digit {};
struct char_3 : public digit {};
struct char_4 : public digit {};
struct char_5 : public digit {};
struct char_6 : public digit {};
struct char_7 : public digit {};
struct char_8 : public digit {};
struct char_9 : public digit {};
struct minus_char {};
template <char c>
struct event_char{};
template <>
struct event_char<'0'> : public digit{};
template <>
struct event_char<'1'> : public digit{};
template <>
struct event_char<'2'> : public digit{};
template <>
struct event_char<'3'> : public digit{};
template <>
struct event_char<'4'> : public digit{};
template <>
struct event_char<'5'> : public digit{};
template <>
struct event_char<'6'> : public digit{};
template <>
struct event_char<'7'> : public digit{};
template <>
struct event_char<'8'> : public digit{};
template <>
struct event_char<'9'> : public digit{};
namespace boost { namespace msm { namespace back {
template <class Fsm>
struct char_event_dispatcher
{
template <char c>
struct dispatch_event_helper
{
static execute_return apply(Fsm& fsm)
{
return fsm.process_event(event_char<c>());
}
};
char_event_dispatcher()
{
entries[0x30]=&dispatch_event_helper<'0'>::apply;
entries[0x31]=&dispatch_event_helper<'1'>::apply;
entries[0x32]=&dispatch_event_helper<'2'>::apply;
entries[0x33]=&dispatch_event_helper<'3'>::apply;
entries[0x34]=&dispatch_event_helper<'4'>::apply;
entries[0x35]=&dispatch_event_helper<'5'>::apply;
entries[0x36]=&dispatch_event_helper<'6'>::apply;
entries[0x37]=&dispatch_event_helper<'7'>::apply;
entries[0x38]=&dispatch_event_helper<'8'>::apply;
entries[0x39]=&dispatch_event_helper<'9'>::apply;
entries[0x2D]=&dispatch_event_helper<'-'>::apply;
entries[0x2B]=&dispatch_event_helper<'+'>::apply;
}
execute_return process_event(Fsm& fsm,char c) const
{
return entries[c](fsm);
}
// The singleton instance.
static const char_event_dispatcher instance;
typedef execute_return (*cell)(Fsm&);
cell entries[255];
};
}}} // boost::msm::back
#endif //BOOST_MSM_CHAR_EVENT_DISPATCHER_HPP

View File

@@ -0,0 +1,74 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// functors
#include <boost/msm/front/functor_row.hpp>
#include <boost/msm/front/euml/common.hpp>
#include "Empty.hpp"
#include "Open.hpp"
using namespace std;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
{
// the initial state of the player SM. Must be defined
typedef Empty initial_state;
typedef mpl::vector<Empty,Open> explicit_creation;
typedef player_ p; // makes transition table cleaner
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// Pick a back-end
typedef msm::back::state_machine<player_> player;
//
// Testing utilities.
//
static char const* const state_names[] = { "Empty", "Open" };
void pstate(player const& p)
{
std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
}
void test()
{
player p;
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
p.start();
// go to Open, call on_exit on Empty, then action, then on_entry on Open
p.process_event(open_close()); pstate(p);
p.process_event(open_close()); pstate(p);
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,17 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include "Empty.hpp"
void Empty::open_drawer(open_close const&)
{
std::cout << "Empty::open_drawer\n";
}

View File

@@ -0,0 +1,43 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef EMPTY_HPP
#define EMPTY_HPP
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/row2.hpp>
#include "Events.hpp"
struct Open;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
struct Empty : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
void open_drawer(open_close const&);
struct internal_transition_table : mpl::vector<
// Start Event Next Action Guard
//+-------------+---------+-------------+---------+---------------------------+----------------------+
msm::front::a_row2 < Empty , open_close , Open , Empty,&Empty::open_drawer >
//+-------------+---------+-------------+---------+---------------------------+----------------------+
> {};
};
#endif

View File

@@ -0,0 +1,39 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef EVENTS_HPP
#define EVENTS_HPP
// events
struct play {};
struct end_pause {};
struct stop {};
struct pause {};
struct open_close {};
// A "complicated" event type that carries some data.
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
struct cd_detected
{
cd_detected(std::string name, DiskTypeEnum diskType)
: name(name),
disc_type(diskType)
{}
std::string name;
DiskTypeEnum disc_type;
};
#endif

View File

@@ -0,0 +1,17 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include "Open.hpp"
void Open::close_drawer(open_close const&)
{
std::cout << "Open::close_drawer\n";
}

View File

@@ -0,0 +1,44 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef OPEN_HPP
#define OPEN_HPP
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/row2.hpp>
#include "Events.hpp"
struct Empty;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
struct Open : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
void close_drawer(open_close const&);
struct internal_transition_table : mpl::vector<
// Start Event Next Action Guard
//+-------------+---------+-------------+---------+---------------------------+----------------------+
msm::front::a_row2 < Open , open_close , Empty , Open,&Open::close_drawer >
//+-------------+---------+-------------+---------+---------------------------+----------------------+
> {};
};
#endif

View File

@@ -0,0 +1,271 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <set>
#include <string>
#include <iostream>
// we need more than the default 20 states
#define FUSION_MAX_VECTOR_SIZE 20
// we need more than the default 20 transitions
#include "boost/mpl/vector/vector50.hpp"
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
// attribute names and types
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_Selected)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_SongIndex)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_NumberOfSongs)
#include "ipod_functors.hpp"
namespace // Concrete FSM implementation
{
//flags
BOOST_MSM_EUML_FLAG(MenuActive)
BOOST_MSM_EUML_FLAG(NoFastFwd)
// hardware-generated events
BOOST_MSM_EUML_EVENT(Hold)
BOOST_MSM_EUML_EVENT(NoHold)
BOOST_MSM_EUML_EVENT(SouthPressed)
BOOST_MSM_EUML_EVENT(SouthReleased)
BOOST_MSM_EUML_EVENT(MiddleButton)
BOOST_MSM_EUML_EVENT(EastPressed)
BOOST_MSM_EUML_EVENT(EastReleased)
BOOST_MSM_EUML_EVENT(Off)
BOOST_MSM_EUML_EVENT(MenuButton)
// internally defined events
BOOST_MSM_EUML_EVENT(PlayPause)
BOOST_MSM_EUML_EVENT(EndPlay)
struct CloseMenu_impl : euml_event<CloseMenu_impl>
{
CloseMenu_impl(){}//defined only for stt
template<class EVENT>
CloseMenu_impl(EVENT const &) {}
};
CloseMenu_impl const CloseMenu;
BOOST_MSM_EUML_EVENT(OnOffTimer)
BOOST_MSM_EUML_EVENT(MenuMiddleButton)
BOOST_MSM_EUML_EVENT(SelectSong)
BOOST_MSM_EUML_EVENT(SongFinished)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_Selected ), StartSongAttributes)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(StartSong,StartSongAttributes)
BOOST_MSM_EUML_EVENT(PreviousSong)
BOOST_MSM_EUML_EVENT(NextSong)
BOOST_MSM_EUML_EVENT(ForwardTimer)
BOOST_MSM_EUML_EVENT(PlayingMiddleButton)
// Concrete iPod implementation
// The list of iPod states
BOOST_MSM_EUML_STATE(( NotHolding_Entry ),NotHolding)
BOOST_MSM_EUML_INTERRUPT_STATE(( NoHold,Holding_Entry ),Holding)
BOOST_MSM_EUML_STATE(( NotPlaying_Entry ),NotPlaying)
BOOST_MSM_EUML_STATE(( NoMenuMode_Entry ),NoMenuMode)
BOOST_MSM_EUML_STATE(( NoOnOffButton_Entry ),NoOnOffButton)
BOOST_MSM_EUML_STATE(( OffDown_Entry ),OffDown)
BOOST_MSM_EUML_STATE(( PlayerOff_Entry ),PlayerOff)
BOOST_MSM_EUML_STATE(( CheckMiddleButton_Entry ),CheckMiddleButton)
// Concrete PlayingMode_ implementation
// The list of PlayingMode_ states
BOOST_MSM_EUML_STATE(( Playing_Entry ),Playing)
BOOST_MSM_EUML_STATE(( WaitingForNextPrev_Entry ),WaitingForNextPrev)
BOOST_MSM_EUML_STATE(( Paused_Entry ),Paused)
BOOST_MSM_EUML_STATE(( WaitingForEnd_Entry ),WaitingForEnd)
BOOST_MSM_EUML_STATE(( NoForward_Entry ),NoForward)
BOOST_MSM_EUML_STATE(( ForwardPressed_Entry,ForwardPressed_Exit ),ForwardPressed)
BOOST_MSM_EUML_STATE(( FastForward_Entry,FastForward_Exit ),FastForward)
BOOST_MSM_EUML_STATE(( StdDisplay_Entry ),StdDisplay)
BOOST_MSM_EUML_STATE(( SetPosition_Entry ),SetPosition)
BOOST_MSM_EUML_STATE(( SetMark_Entry ),SetMark)
BOOST_MSM_EUML_EXIT_STATE(( EndPlay,PlayingExit_Entry ),PlayingExit)
//stt
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
Paused == Playing + PlayPause ,
Paused == Playing + Off ,
Playing == Playing + StartSong
/ (if_then_(event_(m_Selected) > Int_<0>() &&
event_(m_Selected) < fsm_(m_NumberOfSongs),
fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song) ,
Playing == Playing + SongFinished
/ (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs), /*if*/
show_playing_song, /*then*/
(fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay))/*else*/ ) ) ,
Playing == Paused + PlayPause ,
Playing == Paused + StartSong
/ (if_then_(event_(m_Selected) > Int_<0>() &&
event_(m_Selected) < fsm_(m_NumberOfSongs),
fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song) ,
WaitingForNextPrev == WaitingForNextPrev+ PreviousSong
/( if_then_else_(--fsm_(m_SongIndex) > Int_<0>(), /*if*/
show_playing_song, /*then*/
(fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay)) /*else*/ ) ) ,
WaitingForNextPrev == WaitingForNextPrev+ NextSong
/ (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs), /*if*/
show_playing_song, /*then*/
(fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay)) /*else*/ ) ),
PlayingExit == WaitingForEnd + EndPlay ,
ForwardPressed == NoForward + EastPressed [!is_flag_(NoFastFwd)] ,
NoForward == ForwardPressed + EastReleased / process_(NextSong) ,
FastForward == ForwardPressed + ForwardTimer / do_fast_forward ,
FastForward == FastForward + ForwardTimer / do_fast_forward ,
FastForward == NoForward + EastReleased ,
SetPosition == StdDisplay + PlayingMiddleButton ,
StdDisplay == SetPosition + StartSong ,
SetMark == SetPosition + PlayingMiddleButton ,
StdDisplay == SetMark + PlayingMiddleButton ,
StdDisplay == SetMark + StartSong
// +------------------------------------------------------------------------------+
),playingmode_transition_table )
BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playingmode_transition_table, //STT
init_ << Playing << WaitingForNextPrev << WaitingForEnd
<< NoForward << StdDisplay, // Init States
fsm_(m_NumberOfSongs)=Int_<5>(), // entry
no_action, // exit
attributes_ << m_SongIndex << m_NumberOfSongs, //attributes
configure_<< NoFastFwd // Flags, Deferred events, configuration
),PlayingMode_)
// choice of back-end
typedef msm::back::state_machine<PlayingMode_> PlayingMode_type;
PlayingMode_type const PlayingMode;
// Concrete MenuMode_ implementation
// The list of MenuMode_ states
BOOST_MSM_EUML_STATE(( WaitingForSongChoice_Entry ),WaitingForSongChoice)
BOOST_MSM_EUML_STATE(( StartCurrentSong_Entry ),StartCurrentSong)
BOOST_MSM_EUML_EXIT_STATE(( CloseMenu,MenuExit_Entry ),MenuExit)
//stt
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
StartCurrentSong == WaitingForSongChoice + MenuMiddleButton ,
MenuExit == StartCurrentSong + SelectSong
// +------------------------------------------------------------------------------+
),menumode_transition_table )
BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (menumode_transition_table, //STT
init_ << WaitingForSongChoice, // Init States
no_action, // entry
no_action, // exit
attributes_ << no_attributes_, //attributes
configure_<< MenuActive // Flags, Deferred events, configuration
),MenuMode_)
typedef msm::back::state_machine<MenuMode_> MenuMode_type;
MenuMode_type const MenuMode;
// iPod stt
BOOST_MSM_EUML_TRANSITION_TABLE((
// +------------------------------------------------------------------------------+
Holding == NotHolding + Hold ,
NotHolding == Holding + NoHold ,
PlayingMode == NotPlaying + PlayPause ,
NotPlaying == exit_pt_(PlayingMode,PlayingExit) + EndPlay
/ process_(MenuButton) ,
MenuMode == NoMenuMode + MenuButton ,
NoMenuMode == exit_pt_(MenuMode,MenuExit)+ CloseMenu
/ process2_(StartSong,Int_<5>()) ,
OffDown == NoOnOffButton + SouthPressed ,
NoOnOffButton == OffDown + SouthReleased
/ process_(PlayPause) ,
PlayerOff == OffDown + OnOffTimer
/ (show_player_off,process_(Off)) ,
NoOnOffButton == PlayerOff + SouthPressed / show_player_on ,
NoOnOffButton == PlayerOff + NoHold / show_player_on ,
CheckMiddleButton == CheckMiddleButton + MiddleButton
[is_flag_(MenuActive)] / process_(PlayingMiddleButton) ,
CheckMiddleButton == CheckMiddleButton + MiddleButton
[!is_flag_(MenuActive)] / process_(PlayingMiddleButton)
// +------------------------------------------------------------------------------+
),ipod_transition_table )
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( ipod_transition_table, //STT
init_ << NotHolding << NotPlaying << NoMenuMode
<< NoOnOffButton << CheckMiddleButton
),
iPod_) //fsm name
typedef msm::back::state_machine<iPod_> iPod;
void test()
{
iPod sm;
sm.start();
// we first press Hold
std::cout << "pressing hold" << std::endl;
sm.process_event(Hold);
// pressing a button is now ignored
std::cout << "pressing a button" << std::endl;
sm.process_event(SouthPressed);
// or even one contained in a submachine
sm.process_event(EastPressed);
// no more holding
std::cout << "no more holding, end interrupt event sent" << std::endl;
sm.process_event(NoHold);
std::cout << "pressing South button a short time" << std::endl;
sm.process_event(SouthPressed);
// we suppose a short pressing leading to playing a song
sm.process_event(SouthReleased);
// we move to the next song
std::cout << "we move to the next song" << std::endl;
sm.process_event(NextSong);
// then back to no song => exit from playing, menu active
std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl;
sm.process_event(PreviousSong);
sm.process_event(PreviousSong);
// even in menu mode, pressing play will start playing the first song
std::cout << "pressing play/pause" << std::endl;
sm.process_event(SouthPressed);
sm.process_event(SouthReleased);
// of course pausing must be possible
std::cout << "pressing play/pause" << std::endl;
sm.process_event(SouthPressed);
sm.process_event(SouthReleased);
std::cout << "pressing play/pause" << std::endl;
sm.process_event(SouthPressed);
sm.process_event(SouthReleased);
// while playing, you can fast forward
std::cout << "pressing East button a long time" << std::endl;
sm.process_event(EastPressed);
// let's suppose the timer just fired
sm.process_event(ForwardTimer);
sm.process_event(ForwardTimer);
// end of fast forwarding
std::cout << "releasing East button" << std::endl;
sm.process_event(EastReleased);
// we now press the middle button to set playing at a given position
std::cout << "pressing Middle button, fast forwarding disabled" << std::endl;
sm.process_event(MiddleButton);
std::cout <<"pressing East button to fast forward" << std::endl;
sm.process_event(EastPressed);
// we switch off and on
std::cout <<"switch off player" << std::endl;
sm.process_event(SouthPressed);
sm.process_event(OnOffTimer);
std::cout <<"switch on player" << std::endl;
sm.process_event(SouthPressed);
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,208 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <set>
#include <string>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
using namespace std;
namespace msm = boost::msm;
namespace // Concrete FSM implementation
{
// events
struct OneSong
{
OneSong(string const& asong):m_Song(asong){}
const string& get_data() const {return m_Song;}
private:
string m_Song;
};
template <class DATA>
struct NotFound
{
DATA get_data() const {return m_Data;}
DATA m_Data;
};
template <class DATA>
struct Found
{
DATA get_data() const {return m_Data;}
DATA m_Data;
};
struct Done {};
template <class Container,class BASE_TYPE,class FSMType>
struct Insert : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const& evt,FSM& )
{
//TODO other containers
if (m_Cont)
{
m_Cont->insert(evt.get_data());
}
m_fsm->process_event(Done());
}
void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
void set_container(Container* cont){m_Cont=cont;}
Container* m_Cont;
private:
FSMType* m_fsm;
};
template <class BASE_TYPE,class FSMType>
struct StringFind : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const& evt,FSM& )
{
//TODO other containers
// if the element in the event is found
if (evt.get_data().find(m_Cont) != std::string::npos )
{
Found<std::string> res;
res.m_Data = evt.get_data();
m_fsm->process_event(res);
}
// data not found
else
{
NotFound<std::string> res;
res.m_Data = evt.get_data();
m_fsm->process_event(res);
}
}
void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
void set_container(const char* cont){m_Cont=cont;}
private:
std::string m_Cont;
FSMType* m_fsm;
};
template <class EventType,class Container,class BASE_TYPE,class FSMType>
struct Foreach : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const& evt,FSM& )
{
//TODO other containers
if (!m_Cont.empty())
{
typename Container::value_type next_event = *m_Cont.begin();
m_Cont.erase(m_Cont.begin());
m_fsm->process_event(EventType(next_event));
}
}
void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
void set_container(Container* cont){m_Cont=*cont;}
private:
Container m_Cont;
FSMType* m_fsm;
};
// Concrete FSM implementation
struct iPodSearch_ : public msm::front::state_machine_def<iPodSearch_>
{
typedef msm::back::state_machine<iPodSearch_> iPodSearch;
// The list of FSM states
typedef std::set<std::string> Songset;
typedef Insert<Songset,boost::msm::front::default_base_state,iPodSearch> MyInsert;
typedef StringFind<boost::msm::front::default_base_state,iPodSearch> MyFind;
typedef Foreach<OneSong,Songset,boost::msm::front::default_base_state,iPodSearch> MyForeach;
// the initial state of the player SM. Must be defined
typedef MyForeach initial_state;
// transition actions
// guard conditions
typedef iPodSearch_ fsm; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector4<
// Start Event Next Action Guard
// +-----------+------------------+------------+---------------------+----------------------+
_row < MyForeach , OneSong , MyFind >,
_row < MyFind , NotFound<string> , MyForeach >,
_row < MyFind , Found<string> , MyInsert >,
_row < MyInsert , Done , MyForeach >
// +-----------+------------------+------------+---------------------+----------------------+
> {};
iPodSearch_():m_AllSongs(),m_ResultSearch()
{
// add a few songs for testing
m_AllSongs.insert("Let it be");
m_AllSongs.insert("Yellow submarine");
m_AllSongs.insert("Twist and Shout");
m_AllSongs.insert("She Loves You");
}
template <class Event,class FSM>
void on_entry(Event const&,FSM& fsm)
{
fsm.template get_state<MyForeach&>().set_container(&m_AllSongs);
fsm.template get_state<MyInsert&>().set_container(&m_ResultSearch);
}
const Songset& get_result(){return m_ResultSearch;}
void reset_search(){m_ResultSearch.clear();}
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
private:
Songset m_AllSongs;
Songset m_ResultSearch;
};
typedef msm::back::state_machine<iPodSearch_> iPodSearch;
void test()
{
iPodSearch search;
// look for "She Loves You" using the first letters
search.get_state<iPodSearch::MyFind*>()->set_container("Sh");// will find 2 songs
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
search.start();
// display all the songs
const iPodSearch::Songset& res = search.get_result();
for (iPodSearch::Songset::const_iterator it = res.begin();it != res.end();++it)
{
cout << "candidate song:" << *it << endl;
}
cout << "search using more letters" << endl;
// look for "She Loves You" using more letters
search.reset_search();
search.get_state<iPodSearch::MyFind*>()->set_container("She");// will find 1 song
search.start();
const iPodSearch::Songset& res2 = search.get_result();
for (iPodSearch::Songset::const_iterator it = res2.begin();it != res2.end();++it)
{
cout << "candidate song:" << *it << endl;
}
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,166 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// same as iPodSearch.cpp but using eUML
// requires boost >= v1.40 because using mpl::string
#include <vector>
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/stl.hpp>
using namespace std;
using namespace boost::msm::front::euml;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
// how long the timer will ring when countdown elapsed.
#define RINGING_TIME 5
namespace // Concrete FSM implementation
{
// events
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), OneSongDef)
struct OneSong_impl : euml_event<OneSong_impl>,OneSongDef
{
OneSong_impl(){}
OneSong_impl(const string& asong)
{
get_attribute(m_song)=asong;
}
OneSong_impl(const char* asong)
{
get_attribute(m_song)=asong;
}
OneSong_impl(const OneSong_impl& asong)
{
get_attribute(m_song)=asong.get_attribute(m_song);
}
const string& get_data() const {return get_attribute(m_song);}
};
OneSong_impl const OneSong;
// attribute definitions
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>,m_src_container)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>,m_tgt_container)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_letters)
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>::iterator,m_src_it)
// the same attribute name can be reused
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), NotFoundDef)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(NotFound,NotFoundDef)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), FoundDef)
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(Found,FoundDef)
BOOST_MSM_EUML_EVENT(Done)
// Concrete FSM implementation
// The list of FSM states
BOOST_MSM_EUML_STATE(( (push_back_(fsm_(m_tgt_container),event_(m_song))
,process_(Done)),
no_action ),Insert)
BOOST_MSM_EUML_STATE(( if_then_else_( string_find_(event_(m_song),state_(m_letters)) != Npos_<string>() ,
process2_(Found,event_(m_song)),
process2_(NotFound,event_(m_song)) ) ,
no_action,
attributes_ << m_letters ),StringFind)
BOOST_MSM_EUML_STATE(( if_then_( state_(m_src_it) != end_(fsm_(m_src_container)),
process2_(OneSong,*(state_(m_src_it)++)) ),
no_action,
attributes_ << m_src_it ),Foreach)
// replaces the old transition table
BOOST_MSM_EUML_TRANSITION_TABLE((
StringFind == Foreach + OneSong ,
Insert == StringFind + Found ,
Foreach == StringFind + NotFound ,
Foreach == Insert + Done
// +------------------------------------------------------------------------------+
),transition_table )
BOOST_MSM_EUML_ACTION(Log_No_Transition)
{
template <class FSM,class Event>
void operator()(Event const& e,FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
// create a state machine "on the fly"
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
init_ << Foreach, // Init
(
clear_(fsm_(m_src_container)), //clear source
clear_(fsm_(m_tgt_container)), //clear results
push_back_(fsm_(m_src_container),
String_<mpl::string<'Let ','it ','be'> >()),//add a song
push_back_(fsm_(m_src_container),
String_<mpl::string<'Yell','ow s','ubma','rine'> >()),//add a song
push_back_(fsm_(m_src_container),
String_<mpl::string<'Twis','t an','d Sh','out'> >()),//add a song
push_back_(fsm_(m_src_container),
String_<mpl::string<'She ','love','s yo','u'> >()),//add a song
attribute_(substate_(Foreach()),m_src_it)
= begin_(fsm_(m_src_container)) //set the search begin
), // Entry
no_action, // Exit
attributes_ << m_src_container // song list
<< m_tgt_container, // result
configure_<< no_configure_,
Log_No_Transition
),
iPodSearch_) //fsm name
// choice of back-end
typedef msm::back::state_machine<iPodSearch_> iPodSearch;
void test()
{
iPodSearch search;
// look for "She Loves You" using the first letters
search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="Sh";// will find 2 songs
// needed to start the highest-level SM. This will call on_entry and mark the start of the SM
search.start();
// display all the songs
for (vector<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
it != search.get_attribute(m_tgt_container).end();++it)
{
cout << "candidate song:" << (*it).get_attribute(m_song) << endl;
}
cout << "search using more letters" << endl;
// look for "She Loves You" using more letters
search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="She";// will find 1 song
search.start();
// display all the songs
for (vector<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
it != search.get_attribute(m_tgt_container).end();++it)
{
cout << "candidate song:" << (*it).get_attribute(m_song) << endl;
}
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,50 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef EVENTS_HPP
#define EVENTS_HPP
//flags
struct MenuActive{};
// hardware-generated events
struct Hold {};
struct NoHold {};
struct SouthPressed {};
struct SouthReleased {};
struct MiddleButton {};
struct EastPressed{};
struct EastReleased{};
struct Off {};
struct MenuButton {};
// internally used events
struct PlayPause {};
struct EndPlay {};
struct CloseMenu
{
template<class EVENT>
CloseMenu(EVENT const &) {}
};
struct OnOffTimer {};
struct MenuMiddleButton {};
struct SelectSong {};
struct SongFinished {};
struct StartSong
{
StartSong (int song_index):m_Selected(song_index){}
int m_Selected;
};
struct PreviousSong{};
struct NextSong{};
struct NextSongDerived : public NextSong{};
struct ForwardTimer{};
struct PlayingMiddleButton{};
#endif // EVENTS_HPP

View File

@@ -0,0 +1,12 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "MenuMode.hpp"
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(MenuMode)

View File

@@ -0,0 +1,62 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MENU_MODE_HPP
#define MENU_MODE_HPP
#include <iostream>
#include <boost/any.hpp>
#include "Events.hpp"
#include <boost/msm/back/favor_compile_time.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
using namespace std;
namespace msm = boost::msm;
struct MenuMode_ : public msm::front::state_machine_def<MenuMode_>
{
typedef mpl::vector1<MenuActive> flag_list;
struct WaitingForSongChoice : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: MenuMode::WaitingForSongChoice" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: MenuMode::WaitingForSongChoice" << std::endl;}
};
struct StartCurrentSong : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: MenuMode::StartCurrentSong" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: MenuMode::StartCurrentSong" << std::endl;}
};
struct MenuExit : public msm::front::exit_pseudo_state<CloseMenu>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: MenuMode::WaitingForSongChoice" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: MenuMode::WaitingForSongChoice" << std::endl;}
};
typedef WaitingForSongChoice initial_state;
typedef MenuMode_ fsm; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector2<
// Start Event Next Action Guard
// +---------------------+------------------+-------------------+---------------------+----------------------+
_row < WaitingForSongChoice , MenuMiddleButton , StartCurrentSong >,
_row < StartCurrentSong , SelectSong , MenuExit >
// +---------------------+------------------+-------------------+---------------------+----------------------+
> {};
};
typedef msm::back::state_machine<MenuMode_> MenuMode;
#endif

View File

@@ -0,0 +1,12 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "PlayingMode.hpp"
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(PlayingMode)

View File

@@ -0,0 +1,251 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef PLAYING_MODE_HPP
#define PLAYING_MODE_HPP
#include <iostream>
#include <boost/any.hpp>
#define FUSION_MAX_VECTOR_SIZE 20
#include "Events.hpp"
#include <boost/msm/back/favor_compile_time.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/euml/euml.hpp>
using namespace std;
namespace msm = boost::msm;
namespace euml = boost::msm::front::euml;
struct PlayingMode_ : public msm::front::state_machine_def<PlayingMode_>
{
//flags
struct NoFastFwd{};
struct Playing : public msm::front::state<default_base_state,msm::front::sm_ptr>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& )
{
std::cout << "starting: PlayingMode::Playing" << std::endl;
std::cout << "playing song:" << m_fsm->get_current_song() << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::Playing" << std::endl;}
void set_sm_ptr(PlayingMode_* pl)
{
m_fsm = pl;
}
private:
PlayingMode_* m_fsm;
};
struct Paused : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::Paused" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::Paused" << std::endl;}
};
struct WaitingForNextPrev : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::WaitingForNextPrev" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::WaitingForNextPrev" << std::endl;}
};
struct WaitingForEnd : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::WaitingForEnd" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::WaitingForEnd" << std::endl;}
};
struct NoForward : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::NoForward" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::NoForward" << std::endl;}
};
struct ForwardPressed : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& )
{
std::cout << "starting: PlayingMode::ForwardPressed," << "start timer" << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const&,FSM& )
{
std::cout << "finishing: PlayingMode::ForwardPressed," << "stop timer" << std::endl;
}
};
struct FastForward : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& )
{
std::cout << "starting: PlayingMode::FastForward," << "start timer" << std::endl;
}
template <class Event,class FSM>
void on_exit(Event const&,FSM& )
{
std::cout << "finishing: PlayingMode::FastForward," << "stop timer" << std::endl;
}
};
struct StdDisplay : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::StdDisplay" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::StdDisplay" << std::endl;}
};
struct SetPosition : public msm::front::state<>
{
typedef mpl::vector1<NoFastFwd> flag_list;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::SetPosition" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::SetPosition" << std::endl;}
};
struct SetMark : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::SetMark" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::SetMark" << std::endl;}
};
struct PlayingExit : public msm::front::exit_pseudo_state<EndPlay>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::PlayingExit" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::PlayingExit" << std::endl;}
};
// transition action methods
struct inc_song_counter : euml::euml_action<inc_song_counter>
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
if (++fsm.m_SongIndex <= fsm.m_NumberOfSongs )
{
std::cout << "playing song:" << fsm.m_SongIndex << std::endl;
}
else
{
// last song => end playing, next play will start at the beginning
fsm.m_SongIndex = 1;
fsm.process_event(EndPlay());
}
}
};
void select_song(StartSong const& evt)
{
if ((evt.m_Selected>0) && (evt.m_Selected<=m_NumberOfSongs))
{
m_SongIndex = evt.m_Selected;
std::cout << "selecting song:" << m_SongIndex << std::endl;
}
else
{
// play current song
std::cout << "selecting song:" << m_SongIndex << std::endl;
}
}
struct dec_song_counter : euml::euml_action<dec_song_counter>
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
if (--fsm.m_SongIndex >0 )
{
std::cout << "playing song:" << fsm.m_SongIndex << std::endl;
}
else
{
// before first song => end playing
fsm.m_SongIndex = 1;
fsm.process_event(EndPlay());
}
}
};
struct send_NextSong : euml::euml_action<send_NextSong>
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
fsm.process_event(NextSong());
}
};
void do_fast_forward(ForwardTimer const&)
{
std::cout << "moving song forward..." << std::endl;
}
// transition guard methods
struct fast_fwd_ok : euml::euml_action<fast_fwd_ok>
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
// guard accepts only if fast forward is possible (No SetPosition mode)
return !fsm.is_flag_active<NoFastFwd>();
}
};
// initial states / orthogonal zones
typedef mpl::vector5<Playing,WaitingForNextPrev,WaitingForEnd,NoForward,StdDisplay>
initial_state;
typedef PlayingMode_ fsm; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector19<
// Start Event Next Action Guard
// +--------------------+---------------------+--------------------+--------------------------+----------------------+
_row < Playing , PlayPause , Paused >,
_row < Playing , Off , Paused >,
a_row < Playing , StartSong , Playing , &fsm::select_song >,
_row < Paused , PlayPause , Playing >,
msm::front::Row < Playing , SongFinished , Playing , inc_song_counter , msm::front::none >,
a_row < Paused , StartSong , Playing , &fsm::select_song >,
// +--------------------+---------------------+--------------------+--------------------------+----------------------+
msm::front::Row < WaitingForNextPrev , PreviousSong , WaitingForNextPrev , dec_song_counter , msm::front::none >,
msm::front::Row < WaitingForNextPrev , NextSong , WaitingForNextPrev , inc_song_counter , msm::front::none >,
// +--------------------+---------------------+--------------------+--------------------------+----------------------+
_row < WaitingForEnd , EndPlay , PlayingExit >,
// +--------------------+---------------------+--------------------+--------------------------+----------------------+
msm::front::Row < NoForward , EastPressed , ForwardPressed , msm::front::none , fast_fwd_ok >,
msm::front::Row < ForwardPressed , EastReleased , NoForward , send_NextSong , msm::front::none >,
a_row < ForwardPressed , ForwardTimer , FastForward , &fsm::do_fast_forward >,
a_row < FastForward , ForwardTimer , FastForward , &fsm::do_fast_forward >,
_row < FastForward , EastReleased , NoForward >,
// +--------------------+---------------------+---------------------+--------------------------+----------------------+
_row < StdDisplay , PlayingMiddleButton , SetPosition >,
_row < SetPosition , StartSong , StdDisplay >,
_row < SetPosition , PlayingMiddleButton , SetMark >,
_row < SetMark , PlayingMiddleButton , StdDisplay >,
_row < SetMark , StartSong , StdDisplay >
// +--------------------+---------------------+---------------------+--------------------------+----------------------+
> {};
PlayingMode_():
m_SongIndex(1),
// for simplicity we decide there are 5 songs
m_NumberOfSongs(5){}
int get_current_song(){return m_SongIndex;}
int m_SongIndex;
int m_NumberOfSongs;
};
typedef msm::back::state_machine<PlayingMode_> PlayingMode;
#endif // PLAYING_MODE_HPP

View File

@@ -0,0 +1,243 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <vector>
#include <set>
#include <string>
#include <iostream>
#define FUSION_MAX_VECTOR_SIZE 20
#include "boost/mpl/vector/vector50.hpp"
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include "Events.hpp"
#include "PlayingMode.hpp"
#include "MenuMode.hpp"
using namespace std;
namespace msm = boost::msm;
namespace // Concrete FSM implementation
{
struct iPod_;
typedef msm::back::state_machine<iPod_,
::boost::msm::back::favor_compile_time> iPod;
// Concrete FSM implementation
struct iPod_ : public msm::front::state_machine_def<iPod_>
{
// The list of FSM states
struct NotHolding : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: NotHolding" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotHolding" << std::endl;}
};
struct Holding : public msm::front::interrupt_state<NoHold>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: Holding" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: Holding" << std::endl;}
};
struct NotPlaying : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: NotPlaying" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotPlaying" << std::endl;}
};
struct NoMenuMode : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: NoMenuMode" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoMenuMode" << std::endl;}
};
struct NoOnOffButton : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: NoOnOffButton" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoOnOffButton" << std::endl;}
};
struct OffDown : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: OffDown, start timer" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: OffDown, end timer" << std::endl;}
};
struct PlayerOff : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayerOff" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayerOff" << std::endl;}
};
struct CheckMiddleButton : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {std::cout << "starting: CheckMiddleButton" << std::endl;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {std::cout << "finishing: CheckMiddleButton" << std::endl;}
};
// the initial state of the player SM. Must be defined
typedef mpl::vector5<NotHolding,NotPlaying,NoMenuMode,NoOnOffButton,CheckMiddleButton>
initial_state;
// transition actions
void send_ActivateMenu(EndPlay const&)
{
std::cout << "leaving Playing" << std::endl;
// we need to activate the menu and simulate its button
(static_cast<iPod*>(this))->process_event(MenuButton());
}
void send_StartSong(CloseMenu const&)
{
// we suppose the 5th song was selected
(static_cast<iPod*>(this))->process_event(StartSong(5));
}
void send_PlayPause(SouthReleased const&)
{
// action using the message queue to generate another event
(static_cast<iPod*>(this))->process_event(PlayPause());
}
void send_Off(OnOffTimer const&)
{
std::cout << "turning player off" << std::endl;
(static_cast<iPod*>(this))->process_event(Off());
}
void send_PlayingMiddleButton(MiddleButton const&)
{
(static_cast<iPod*>(this))->process_event(PlayingMiddleButton());
}
void send_MenuMiddleButton(MiddleButton const&)
{
(static_cast<iPod*>(this))->process_event(MenuMiddleButton());
}
// guard conditions
bool is_menu(MiddleButton const&)
{
return (static_cast<iPod*>(this))->is_flag_active<MenuActive>();
}
bool is_no_menu(MiddleButton const& evt)
{
return !is_menu(evt);
}
template <class EVENT>
void switch_on(EVENT const&)
{
std::cout << "turning player on" << std::endl;
}
typedef iPod_ fsm; // makes transition table cleaner
// Transition table for player
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +-------------------+---------------+-------------------+--------------------------------+----------------------+
_row < NotHolding , Hold , Holding >,
_row < Holding , NoHold , NotHolding >,
// +-------------------+---------------+-------------------+--------------------------------+----------------------+
_row < NotPlaying , PlayPause , PlayingMode >,
a_row < PlayingMode::exit_pt<PlayingMode_::
PlayingExit> , EndPlay , NotPlaying , &fsm::send_ActivateMenu >,
// +-------------------+---------------+-------------------+--------------------------------+----------------------+
_row < NoMenuMode , MenuButton , MenuMode >,
a_row < MenuMode::exit_pt<MenuMode_::
MenuExit> , CloseMenu , NoMenuMode , &fsm::send_StartSong >,
// +-------------------+---------------+-------------------+--------------------------------+----------------------+
_row < NoOnOffButton , SouthPressed , OffDown >,
a_row < OffDown , SouthReleased , NoOnOffButton , &fsm::send_PlayPause >,
a_row < OffDown , OnOffTimer , PlayerOff , &fsm::send_Off >,
a_row < PlayerOff , SouthPressed , NoOnOffButton , &fsm::switch_on >,
a_row < PlayerOff , NoHold , NoOnOffButton , &fsm::switch_on >,
// +-------------------+---------------+--------------------+--------------------------------+----------------------+
row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_PlayingMiddleButton , &fsm::is_menu >,
row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_MenuMiddleButton , &fsm::is_no_menu >
// +-------------------+---------------+--------------------+--------------------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const& e, FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
void test()
{
iPod sm;
sm.start();
// we first press Hold
std::cout << "pressing hold" << std::endl;
sm.process_event(Hold());
// pressing a button is now ignored
std::cout << "pressing a button" << std::endl;
sm.process_event(SouthPressed());
// or even one contained in a submachine
sm.process_event(EastPressed());
// no more holding
std::cout << "no more holding, end interrupt event sent" << std::endl;
sm.process_event(NoHold());
std::cout << "pressing South button a short time" << std::endl;
sm.process_event(SouthPressed());
// we suppose a short pressing leading to playing a song
sm.process_event(SouthReleased());
// we move to the next song
std::cout << "we move to the next song" << std::endl;
sm.process_event(NextSong());
// then back to no song => exit from playing, menu active
std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl;
sm.process_event(PreviousSong());
sm.process_event(PreviousSong());
// even in menu mode, pressing play will start playing the first song
std::cout << "pressing play/pause" << std::endl;
sm.process_event(SouthPressed());
sm.process_event(SouthReleased());
// of course pausing must be possible
std::cout << "pressing play/pause" << std::endl;
sm.process_event(SouthPressed());
sm.process_event(SouthReleased());
std::cout << "pressing play/pause" << std::endl;
sm.process_event(SouthPressed());
sm.process_event(SouthReleased());
// while playing, you can fast forward
std::cout << "pressing East button a long time" << std::endl;
sm.process_event(EastPressed());
// let's suppose the timer just fired
sm.process_event(ForwardTimer());
sm.process_event(ForwardTimer());
// end of fast forwarding
std::cout << "releasing East button" << std::endl;
sm.process_event(EastReleased());
// we now press the middle button to set playing at a given position
std::cout << "pressing Middle button, fast forwarding disabled" << std::endl;
sm.process_event(MiddleButton());
std::cout <<"pressing East button to fast forward" << std::endl;
sm.process_event(EastPressed());
// we switch off and on
std::cout <<"switch off player" << std::endl;
sm.process_event(SouthPressed());
sm.process_event(OnOffTimer());
std::cout <<"switch on player" << std::endl;
sm.process_event(SouthPressed());
}
}
int main()
{
test();
return 0;
}

View File

@@ -0,0 +1,248 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef IPOD_FUNCTORS_HPP
#define IPOD_FUNCTORS_HPP
#include <boost/msm/front/euml/euml.hpp>
BOOST_MSM_EUML_ACTION(NotHolding_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: NotHolding" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Holding_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Holding" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(NotPlaying_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: NotPlaying" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(NoMenuMode_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: NoMenuMode" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(NoOnOffButton_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: NoOnOffButton" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(OffDown_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: OffDown" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(PlayerOff_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: PlayerOff" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(CheckMiddleButton_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: CheckMiddleButton" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Playing_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM& fsm,STATE& )
{
std::cout << "entering: Playing" << std::endl;
std::cout << "playing song:" << fsm.get_attribute(m_SongIndex) << std::endl;
}
};
BOOST_MSM_EUML_ACTION(WaitingForNextPrev_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: WaitingForNextPrev" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Paused_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Paused" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(WaitingForEnd_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: OffDown" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(NoForward_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: NoForward" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(ForwardPressed_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: ForwardPressed" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(ForwardPressed_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: ForwardPressed" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(FastForward_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: FastForward" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(FastForward_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: FastForward" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(StdDisplay_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: StdDisplay" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SetPosition_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SetPosition" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(SetMark_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: SetMark" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(PlayingExit_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: PlayingExit" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(WaitingForSongChoice_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: WaitingForSongChoice" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(StartCurrentSong_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: StartCurrentSong" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(MenuExit_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: MenuExit" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(show_selected_song)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
std::cout << "selecting song:" << fsm.get_attribute(m_SongIndex) << std::endl;
}
};
BOOST_MSM_EUML_ACTION(do_fast_forward)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
std::cout << "moving song forward..." << std::endl;
}
};
BOOST_MSM_EUML_ACTION(show_playing_song)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
std::cout << "playing song:" << fsm.get_attribute(m_SongIndex) << std::endl;
}
};
BOOST_MSM_EUML_ACTION(show_player_off)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
std::cout << "turning player off" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(show_player_on)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
{
std::cout << "turning player on" << std::endl;
}
};
#endif

View File

@@ -0,0 +1,370 @@
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef LOGGING_FUNCTORS
#define LOGGING_FUNCTORS
BOOST_MSM_EUML_ACTION(Empty_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Empty" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Empty_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Empty" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Open_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Open" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Open_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Open" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Stopped_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Stopped" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Stopped_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Stopped" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(AllOk_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "starting: AllOk" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(AllOk_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "finishing: AllOk" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(ErrorMode_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "starting: ErrorMode" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(ErrorMode_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "finishing: ErrorMode" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Playing_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "entering: Playing" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Playing_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "leaving: Playing" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Song1_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "starting: First song" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Song1_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "finishing: First Song" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Song2_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "starting: Second song" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Song2_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "finishing: Second Song" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Song3_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "starting: Third song" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Song3_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "finishing: Third Song" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Region2State1_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "starting: Region2State1" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Region2State1_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "finishing: Region2State1" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Region2State2_Entry)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "starting: Region2State2" << std::endl;
}
};
BOOST_MSM_EUML_ACTION(Region2State2_Exit)
{
template <class Event,class FSM,class STATE>
void operator()(Event const&,FSM&,STATE& )
{
std::cout << "finishing: Region2State2" << std::endl;
}
};
// transition actions for Playing
BOOST_MSM_EUML_ACTION(start_next_song)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Playing::start_next_song" << endl;
}
};
BOOST_MSM_EUML_ACTION(start_prev_song)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
std::cout << "Playing::start_prev_song" << endl;
}
};
// transition actions
BOOST_MSM_EUML_ACTION(start_playback)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::start_playback" << endl;
}
};
BOOST_MSM_EUML_ACTION(open_drawer)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::open_drawer" << endl;
}
};
BOOST_MSM_EUML_ACTION(close_drawer)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::close_drawer" << endl;
}
};
BOOST_MSM_EUML_ACTION(store_cd_info)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
{
cout << "player::store_cd_info" << endl;
// it is now easy to use the message queue.
// alternatively to the proces_ in the transition table, we could write:
// fsm.process_event(play());
}
};
BOOST_MSM_EUML_ACTION(stop_playback)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::stop_playback" << endl;
}
};
BOOST_MSM_EUML_ACTION(pause_playback)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::pause_playback" << endl;
}
};
BOOST_MSM_EUML_ACTION(resume_playback)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::resume_playback" << endl;
}
};
BOOST_MSM_EUML_ACTION(stop_and_open)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::stop_and_open" << endl;
}
};
BOOST_MSM_EUML_ACTION(stopped_again)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::stopped_again" << endl;
}
};
BOOST_MSM_EUML_ACTION(report_error)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::report_error" << endl;
}
};
BOOST_MSM_EUML_ACTION(report_end_error)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
{
cout << "player::report_end_error" << endl;
}
};
BOOST_MSM_EUML_ACTION(internal_action1)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
{
cout << "Open::internal action1" << endl;
}
};
BOOST_MSM_EUML_ACTION(internal_action2)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
{
cout << "Open::internal action2" << endl;
}
};
BOOST_MSM_EUML_ACTION(internal_action)
{
template <class FSM,class EVT,class SourceState,class TargetState>
void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
{
cout << "Open::internal action" << endl;
}
};
enum DiskTypeEnum
{
DISK_CD=0,
DISK_DVD=1
};
// Handler called when no_transition detected
BOOST_MSM_EUML_ACTION(Log_No_Transition)
{
template <class FSM,class Event>
void operator()(Event const& e,FSM&,int state)
{
std::cout << "no transition from state " << state
<< " on event " << typeid(e).name() << std::endl;
}
};
BOOST_MSM_EUML_ACTION(internal_guard1)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
{
cout << "Open::internal guard1" << endl;
return false;
}
};
BOOST_MSM_EUML_ACTION(internal_guard2)
{
template <class FSM,class EVT,class SourceState,class TargetState>
bool operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
{
cout << "Open::internal guard2" << endl;
return false;
}
};
#endif // LOGGING_FUNCTORS