From dfd4309a0ab3923d562694c330fe15fb667cbd38 Mon Sep 17 00:00:00 2001 From: jwellbelove Date: Thu, 25 May 2017 10:12:50 +0100 Subject: [PATCH] Added experimental FSM template. --- src/experimental/fsm.h | 110 ++++++++++++++++++++++++++++++++++------- 1 file changed, 91 insertions(+), 19 deletions(-) diff --git a/src/experimental/fsm.h b/src/experimental/fsm.h index 0f7ccb38..6c65c20a 100644 --- a/src/experimental/fsm.h +++ b/src/experimental/fsm.h @@ -14,9 +14,20 @@ namespace etl { - typedef uint32_t fsm_state_id_t; - typedef uint32_t fsm_event_id_t; +#if !defined(ETL_FSM_STATE_ID_TYPE) + typedef uint_least8_t fsm_state_id_t; +#else + typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t; +#endif +#if !defined(ETL_FSM_EVENT_ID_TYPE) + typedef uint_least8_t fsm_event_id_t; +#else + typedef ETL_FSM_STATE_ID_TYPE fsm_event_id_t; +#endif + + //*************************************************************************** + /// Base exception class for FSM. //*************************************************************************** class fsm_exception : public etl::exception { @@ -28,6 +39,8 @@ namespace etl } }; + //*************************************************************************** + /// Exception for null state pointer. //*************************************************************************** class fsm_nullstate_exception : public etl::fsm_exception { @@ -39,6 +52,8 @@ namespace etl } }; + //*************************************************************************** + /// Exception for invalid state id. //*************************************************************************** class fsm_state_id_exception : public etl::fsm_exception { @@ -50,11 +65,15 @@ namespace etl } }; + //*************************************************************************** + /// Interface class for FSM events. //*************************************************************************** class ifsm_event { public: + //******************************************* + /// Gets the id for this event. //******************************************* etl::fsm_event_id_t get_event_id() const { @@ -63,6 +82,8 @@ namespace etl protected: + //******************************************* + /// Constructor. //******************************************* ifsm_event(etl::fsm_event_id_t event_id_) : event_id(event_id_) @@ -71,9 +92,12 @@ namespace etl private: - etl::fsm_event_id_t event_id; + // The event id. + const etl::fsm_event_id_t event_id; }; + //*************************************************************************** + /// Base class for FSM events. //*************************************************************************** template class fsm_event : public etl::ifsm_event @@ -85,17 +109,24 @@ namespace etl EVENT_ID = EVENT_ID_ }; + //******************************************* + /// Constructor. + //******************************************* fsm_event() : ifsm_event(EVENT_ID) { } }; + //*************************************************************************** + /// Interface class for FSM states. //*************************************************************************** class ifsm_state { public: + //******************************************* + /// Gets the id for this state. //******************************************* etl::fsm_state_id_t get_state_id() const { @@ -106,38 +137,51 @@ namespace etl protected: + //******************************************* + /// Constructor. //******************************************* ifsm_state(etl::fsm_state_id_t state_id_) : state_id(state_id_) { } - virtual void on_enter_state() {}; - virtual void on_exit_state() {}; + virtual void on_enter_state() {}; // By default, do nothing. + virtual void on_exit_state() {}; // By default, do nothing. private: - etl::fsm_state_id_t state_id; + // The state id. + const etl::fsm_state_id_t state_id; + + // Disabled. + ifsm_state(const ifsm_state&); + ifsm_state& operator =(const ifsm_state&); }; //*************************************************************************** // To be COG generated. - template + /// Base class for FSM states. + //*************************************************************************** + template class fsm_state : public ifsm_state { public: enum { - THIS_STATE_ID = STATE_ID_ + STATE_ID = STATE_ID_ }; + //******************************************* + /// Constructor. //******************************************* fsm_state() - : ifsm_state(THIS_STATE_ID) + : ifsm_state(STATE_ID) { } + //******************************************* + /// Top level event handler for the state. //******************************************* etl::fsm_state_id_t on_event(const etl::ifsm_event& event) { @@ -147,17 +191,18 @@ namespace etl switch (id) { case T1::EVENT_ID: new_state_id = static_cast(*this).on_event(static_cast(event)); break; + case T2::EVENT_ID: new_state_id = static_cast(*this).on_event(static_cast(event)); break; default: new_state_id = static_cast(*this).on_unknown_event(event); break; } return new_state_id; } - //******************************************* - etl::fsm_state_id_t get_state_id() const - { - return THIS_STATE_ID; - } + private: + + // Disabled. + fsm_state(const fsm_state&); + fsm_state& operator =(const fsm_state&); }; //*************************************************************************** @@ -166,21 +211,36 @@ namespace etl { public: + //******************************************* + /// Constructor. //******************************************* fsm() + : p_state(nullptr) { state_list.fill(nullptr); } + //******************************************* + /// Starts the FSM. + /// Can only be called once. + /// Subsequent calls will do nothing. //******************************************* void start() { - p_state = state_list[0]; - ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_nullstate_exception)); + // Can only be started once. + if (p_state == nullptr) + { + p_state = state_list[0]; + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_nullstate_exception)); - p_state->on_enter_state(); + p_state->on_enter_state(); + } } + //******************************************* + /// Adds a state to the FSM. + /// If the state has the same id as one already added + /// then the current state will be overwritten. //******************************************* void add_state(etl::ifsm_state& state) { @@ -188,6 +248,8 @@ namespace etl state_list[state.get_state_id()] = &state; } + //******************************************* + /// Top level event handler for the FSM. //******************************************* void on_event(const etl::ifsm_event& event) { @@ -206,18 +268,24 @@ namespace etl } } + //******************************************* + /// Gets the current state id. //******************************************* etl::fsm_state_id_t get_state_id() const { return p_state->get_state_id(); } + //******************************************* + /// Gets a reference to the current state interface. //******************************************* ifsm_state& get_state() { return *p_state; } + //******************************************* + /// Gets a const reference to the current state interface. //******************************************* const ifsm_state& get_state() const { @@ -226,8 +294,12 @@ namespace etl private: - etl::ifsm_state* p_state; - etl::array state_list; + etl::ifsm_state* p_state; ///< A pointer to the current state. + etl::array state_list; ///< The list of added states. + + // Disabled. + fsm(const fsm&); + fsm& operator =(const fsm&); }; }