mirror of
https://github.com/ETLCPP/etl.git
synced 2026-10-28 18:07:10 +08:00
Added etl::fsm_state_pack and corresponding constructor
This commit is contained in:
parent
7504646301
commit
1d4dbc8976
@ -60,6 +60,7 @@ SOFTWARE.
|
||||
#include "message_router.h"
|
||||
#include "integral_limits.h"
|
||||
#include "largest.h"
|
||||
#include "tuple.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -207,8 +208,78 @@ namespace etl
|
||||
|
||||
template <typename T>
|
||||
ETL_CONSTANT fsm_state_id_t ifsm_state_helper<T>::Self_Transition;
|
||||
|
||||
// Compile-time: TState::ID must equal its index in the type list (0..N-1)
|
||||
template <size_t Id, typename...> struct check_ids : etl::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <size_t Id, typename TState0, typename... TRest>
|
||||
struct check_ids<Id, TState0, TRest...>
|
||||
: etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
class ifsm_state;
|
||||
|
||||
//***************************************************************************
|
||||
/// A class to store FSM states.
|
||||
//***************************************************************************
|
||||
template <typename... TStates>
|
||||
class fsm_state_pack
|
||||
{
|
||||
public:
|
||||
|
||||
friend class etl::fsm;
|
||||
|
||||
ETL_STATIC_ASSERT((private_fsm::check_ids<0, TStates...>::value), "State IDs must be 0..N-1 and in order");
|
||||
ETL_STATIC_ASSERT(sizeof...(TStates) > 0, "At least one state is required");
|
||||
ETL_STATIC_ASSERT(sizeof...(TStates) < private_fsm::ifsm_state_helper<>::No_State_Change, "State IDs mst be less than ifsm_state::No_State_Change");
|
||||
|
||||
//*********************************
|
||||
// The number of states.
|
||||
//*********************************
|
||||
static constexpr size_t size()
|
||||
{
|
||||
return sizeof...(TStates);
|
||||
}
|
||||
|
||||
//*********************************
|
||||
/// Gets a reference to the state.
|
||||
//*********************************
|
||||
template <typename TState>
|
||||
TState& get()
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
}
|
||||
|
||||
//*********************************
|
||||
/// Gets a const reference to the state.
|
||||
//*********************************
|
||||
template <typename TState>
|
||||
const TState& get() const
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//*********************************
|
||||
/// Gets a pointer to the state list.
|
||||
//*********************************
|
||||
etl::ifsm_state** get_state_list()
|
||||
{
|
||||
return &states[0];
|
||||
}
|
||||
|
||||
/// A tuple to store the states.
|
||||
etl::tuple<TStates...> storage{};
|
||||
|
||||
/// Pointers to the states.
|
||||
etl::ifsm_state* states[sizeof...(TStates)]{ &etl::get<TStates>(storage)... };
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Interface class for FSM states.
|
||||
//***************************************************************************
|
||||
@ -333,8 +404,8 @@ namespace etl
|
||||
ifsm_state* p_default_child;
|
||||
|
||||
// Disabled.
|
||||
ifsm_state(const ifsm_state&);
|
||||
ifsm_state& operator =(const ifsm_state&);
|
||||
ifsm_state(const ifsm_state&) ETL_DELETE;
|
||||
ifsm_state& operator =(const ifsm_state&) ETL_DELETE;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
@ -360,6 +431,7 @@ namespace etl
|
||||
|
||||
//*******************************************
|
||||
/// Set the states for the FSM
|
||||
/// From a pointer to etl::ifsm_state and size.
|
||||
//*******************************************
|
||||
template <typename TSize>
|
||||
void set_states(etl::ifsm_state** p_states, TSize size)
|
||||
@ -378,6 +450,22 @@ namespace etl
|
||||
}
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Set the states for the FSM
|
||||
/// From an etl::fsm_state_pack.
|
||||
//*******************************************
|
||||
template <typename... TStates>
|
||||
void set_states(etl::fsm_state_pack<TStates...>& state_pack)
|
||||
{
|
||||
state_list = state_pack.get_state_list();
|
||||
number_of_states = etl::fsm_state_id_t(state_pack.size());
|
||||
|
||||
for (etl::fsm_state_id_t i = 0; i < number_of_states; ++i)
|
||||
{
|
||||
state_list[i]->set_fsm_context(*this);
|
||||
}
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Starts the FSM.
|
||||
/// Can only be called once.
|
||||
|
||||
@ -240,7 +240,7 @@ namespace etl
|
||||
//*********************************
|
||||
ETL_CONSTEXPR14
|
||||
tuple()
|
||||
: value(THead())
|
||||
: value()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -154,6 +154,14 @@ namespace
|
||||
ClearStatistics();
|
||||
}
|
||||
|
||||
//***********************************
|
||||
template <typename... TStates>
|
||||
void Initialise(etl::fsm_state_pack<TStates...>& state_pack)
|
||||
{
|
||||
set_states(state_pack);
|
||||
ClearStatistics();
|
||||
}
|
||||
|
||||
//***********************************
|
||||
void ClearStatistics()
|
||||
{
|
||||
@ -367,8 +375,6 @@ namespace
|
||||
//*************************************************************************
|
||||
TEST(test_fsm)
|
||||
{
|
||||
etl::null_message_router nmr;
|
||||
|
||||
CHECK(motorControl.is_producer());
|
||||
CHECK(motorControl.is_consumer());
|
||||
|
||||
@ -509,8 +515,6 @@ namespace
|
||||
//*************************************************************************
|
||||
TEST(test_fsm_emergency_stop)
|
||||
{
|
||||
etl::null_message_router nmr;
|
||||
|
||||
motorControl.Initialise(stateList, ETL_OR_STD17::size(stateList));
|
||||
motorControl.reset();
|
||||
motorControl.ClearStatistics();
|
||||
@ -558,8 +562,6 @@ namespace
|
||||
//*************************************************************************
|
||||
TEST(test_fsm_recursive_event)
|
||||
{
|
||||
etl::null_message_router nmr;
|
||||
|
||||
motorControl.Initialise(stateList, ETL_OR_STD17::size(stateList));
|
||||
motorControl.reset();
|
||||
motorControl.ClearStatistics();
|
||||
@ -680,5 +682,53 @@ namespace
|
||||
|
||||
CHECK_THROW(mc.receive(Start()), etl::fsm_not_started);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_fsm_initialise_from_state_pack)
|
||||
{
|
||||
MotorControl motorControl;
|
||||
|
||||
etl::fsm_state_pack<Idle, Running, WindingDown, Locked> statePack;
|
||||
|
||||
motorControl.Initialise(statePack);
|
||||
motorControl.reset();
|
||||
motorControl.ClearStatistics();
|
||||
|
||||
// Start the FSM.
|
||||
motorControl.start(false);
|
||||
CHECK(motorControl.is_started());
|
||||
|
||||
// Now in Idle state.
|
||||
CHECK_EQUAL(StateId::Idle, int(motorControl.get_state_id()));
|
||||
CHECK_EQUAL(StateId::Idle, int(motorControl.get_state().get_state_id()));
|
||||
|
||||
// Send Start event.
|
||||
motorControl.receive(Start());
|
||||
|
||||
// Now in Running state.
|
||||
CHECK_EQUAL(StateId::Running, int(motorControl.get_state_id()));
|
||||
CHECK_EQUAL(StateId::Running, int(motorControl.get_state().get_state_id()));
|
||||
|
||||
// Send SetSpeed event.
|
||||
motorControl.receive(SetSpeed(100));
|
||||
|
||||
// Still in Running state.
|
||||
CHECK_EQUAL(StateId::Running, int(motorControl.get_state_id()));
|
||||
CHECK_EQUAL(StateId::Running, int(motorControl.get_state().get_state_id()));
|
||||
|
||||
// Send Stop event.
|
||||
motorControl.receive(Stop());
|
||||
|
||||
// Now in WindingDown state.
|
||||
CHECK_EQUAL(StateId::Winding_Down, int(motorControl.get_state_id()));
|
||||
CHECK_EQUAL(StateId::Winding_Down, int(motorControl.get_state().get_state_id()));
|
||||
|
||||
// Send Stopped event.
|
||||
motorControl.receive(Stopped());
|
||||
|
||||
// Now in Locked state via Idle state.
|
||||
CHECK_EQUAL(StateId::Locked, int(motorControl.get_state_id()));
|
||||
CHECK_EQUAL(StateId::Locked, int(motorControl.get_state().get_state_id()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user