Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com
Diff: fsm.h
- Revision:
- 0:b47c2a7920c2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fsm.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1216 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -ofsm.h -DHandlers=<n> fsm_generator.h +// Where <n> is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 events... +// python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_FSM__ +#define __ETL_FSM__ + +#include <stdint.h> + +#include "platform.h" +#include "array.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "user_type.h" +#include "message_router.h" +#include "integral_limits.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "34" + +#ifdef ETL_COMPILER_MICROSOFT +#undef max +#endif + +namespace etl +{ + class fsm; + + /// Allow alternative type for state id. +#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 + + // For internal FSM use. + typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t; + + //*************************************************************************** + /// Base exception class for FSM. + //*************************************************************************** + class fsm_exception : public etl::exception + { + public: + + fsm_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception for null state pointer. + //*************************************************************************** + class fsm_null_state_exception : public etl::fsm_exception + { + public: + + fsm_null_state_exception(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception for invalid state id. + //*************************************************************************** + class fsm_state_id_exception : public etl::fsm_exception + { + public: + + fsm_state_id_exception(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception for incompatible state list. + //*************************************************************************** + class fsm_state_list_exception : public etl::fsm_exception + { + public: + + fsm_state_list_exception(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Interface class for FSM states. + //*************************************************************************** + class ifsm_state + { + public: + + /// Allows ifsm_state functions to be private. + friend class etl::fsm; + + //******************************************* + /// Gets the id for this state. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + return state_id; + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ifsm_state(etl::fsm_state_id_t state_id_) + : state_id(state_id_), + p_context(std::nullptr) + { + } + + //******************************************* + inline etl::fsm& get_fsm_context() const + { + return *p_context; + } + + private: + + virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0; + + virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing. + virtual void on_exit_state() {} // By default, do nothing. + + //******************************************* + void set_fsm_context(etl::fsm& context) + { + p_context = &context; + } + + // The state id. + const etl::fsm_state_id_t state_id; + + // A pointer to the FSM context. + etl::fsm* p_context; + + // Disabled. + ifsm_state(const ifsm_state&); + ifsm_state& operator =(const ifsm_state&); + }; + + //*************************************************************************** + /// The FSM class. + //*************************************************************************** + class fsm : public etl::imessage_router + { + public: + + //******************************************* + /// Constructor. + //******************************************* + fsm(etl::message_router_id_t id) + : imessage_router(id), + p_state(std::nullptr) + { + } + + //******************************************* + /// Set the states for the FSM + //******************************************* + template <typename TSize> + void set_states(etl::ifsm_state** p_states, TSize size) + { + state_list = p_states; + number_of_states = etl::fsm_state_id_t(size); + + ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception)); + + for (etl::fsm_state_id_t i = 0; i < size; ++i) + { + ETL_ASSERT((state_list[i] != std::nullptr), ETL_ERROR(etl::fsm_null_state_exception)); + state_list[i]->set_fsm_context(*this); + } + } + + //******************************************* + /// Starts the FSM. + /// Can only be called once. + /// Subsequent calls will do nothing. + //******************************************* + void start() + { + // Can only be started once. + if (p_state == std::nullptr) + { + p_state = state_list[0]; + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + + p_state->on_enter_state(); + } + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, message); + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t next_state_id = p_state->process_event(source, message); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + etl::ifsm_state* p_next_state = state_list[next_state_id]; + + // Have we changed state? + if (p_next_state != p_state) + { + do + { + p_state->on_exit_state(); + p_state = p_next_state; + + next_state_id = p_state->on_enter_state(); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + p_next_state = state_list[next_state_id]; + + } while (p_next_state != p_state); // Have we changed state again? + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this FSM accept the message id? + /// Yes, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t id) const + { + return true; + } + + //******************************************* + /// Gets the current state id. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return p_state->get_state_id(); + } + + //******************************************* + /// Gets a reference to the current state interface. + //******************************************* + ifsm_state& get_state() + { + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Gets a const reference to the current state interface. + //******************************************* + const ifsm_state& get_state() const + { + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Checks if the FSM has been started. + //******************************************* + bool is_started() const + { + return p_state != std::nullptr; + } + + //******************************************* + /// Reset the FSM to pre-started state. + //******************************************* + void reset() + { + p_state = std::nullptr; + } + + private: + + etl::ifsm_state* p_state; ///< A pointer to the current state. + etl::ifsm_state** state_list; ///< The list of added states. + etl::fsm_state_id_t number_of_states; ///< The number of states. + }; + + //*************************************************************************** + // The definition for all 16 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void> + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break; + case T14::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T14&>(message)); break; + case T15::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T15&>(message)); break; + case T16::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T16&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 15 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13, typename T14, typename T15> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break; + case T14::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T14&>(message)); break; + case T15::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T15&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 14 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13, typename T14> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break; + case T14::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T14&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 13 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 12 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 11 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 10 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 9 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 8 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 7 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 6 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 5 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 4 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 3 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 2 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 1 message type. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1> + class fsm_state<TContext, TDerived, STATE_ID_, T1, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_> + class fsm_state<TContext, TDerived, STATE_ID_, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + return static_cast<TDerived*>(this)->on_event_unknown(source, message); + } + }; +} + +#undef ETL_FILE + +#ifdef ETL_COMPILER_MICROSOFT +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif +