From 0a6e22ae2ae76f1463d2bfb37260b5620852e9e7 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 15 Jan 2022 19:06:20 +0000 Subject: [PATCH 1/8] Initial state_chart changes --- include/etl/state_chart.h | 425 ++++++++++-------- test/test_state_chart.cpp | 138 ++++++ test/test_state_chart_with_data_parameter.cpp | 18 +- ...state_chart_with_rvalue_data_parameter.cpp | 1 + 4 files changed, 393 insertions(+), 189 deletions(-) diff --git a/include/etl/state_chart.h b/include/etl/state_chart.h index 7533ae0f..e72a1fd6 100644 --- a/include/etl/state_chart.h +++ b/include/etl/state_chart.h @@ -36,21 +36,127 @@ SOFTWARE. #include "array.h" #include "array_view.h" #include "utility.h" +#include "delegate.h" namespace etl { - //*************************************************************************** - /// Simple Finite State Machine Interface - //*************************************************************************** + namespace private_state_chart + { + typedef uint_least8_t state_id_t; + typedef uint_least8_t event_id_t; + + //************************************************************************* + /// Transition definition + //************************************************************************* + template + struct transition + { + ETL_CONSTEXPR transition(const state_id_t current_state_id_, + const event_id_t event_id_, + const state_id_t next_state_id_, + void (TObject::* const action_)(TParameter) = ETL_NULLPTR, + bool (TObject::* const guard_)() = ETL_NULLPTR) + : current_state_id(current_state_id_) + , event_id(event_id_) + , next_state_id(next_state_id_) + , action(action_) + , guard(guard_) + , from_any_state(false) + { + } + + ETL_CONSTEXPR transition(const event_id_t event_id_, + const state_id_t next_state_id_, + void (TObject::* const action_)(TParameter) = ETL_NULLPTR, + bool (TObject::* const guard_)() = ETL_NULLPTR) + : current_state_id(0) + , event_id(event_id_) + , next_state_id(next_state_id_) + , action(action_) + , guard(guard_) + , from_any_state(true) + { + } + + const state_id_t current_state_id; + const event_id_t event_id; + const state_id_t next_state_id; + void (TObject::* const action)(TParameter); + bool (TObject::* const guard)(); + const bool from_any_state; + }; + + //************************************************************************* + /// Transition definition + //************************************************************************* + template + struct transition + { + ETL_CONSTEXPR transition(const state_id_t current_state_id_, + const event_id_t event_id_, + const state_id_t next_state_id_, + void (TObject::* const action_)() = ETL_NULLPTR, + bool (TObject::* const guard_)() = ETL_NULLPTR) + : current_state_id(current_state_id_) + , event_id(event_id_) + , next_state_id(next_state_id_) + , action(action_) + , guard(guard_) + , from_any_state(false) + { + } + + ETL_CONSTEXPR transition(const event_id_t event_id_, + const state_id_t next_state_id_, + void (TObject::* const action_)() = ETL_NULLPTR, + bool (TObject::* const guard_)() = ETL_NULLPTR) + : current_state_id(0) + , event_id(event_id_) + , next_state_id(next_state_id_) + , action(action_) + , guard(guard_) + , from_any_state(true) + { + } + + const state_id_t current_state_id; + const event_id_t event_id; + const state_id_t next_state_id; + void (TObject::* const action)(); + bool (TObject::* const guard)(); + const bool from_any_state; + }; + + //************************************************************************* + /// State definition + //************************************************************************* + template + struct state + { + ETL_CONSTEXPR state(const state_id_t state_id_, + void (TObject::* const on_entry_)() = ETL_NULLPTR, + void (TObject::* const on_exit_)() = ETL_NULLPTR) + : state_id(state_id_) + , on_entry(on_entry_) + , on_exit(on_exit_) + { + } + + state_id_t state_id; + void (TObject::* const on_entry)(); + void (TObject::* const on_exit)(); + }; + } + + //************************************************************************* + /// istate_chart + //************************************************************************* class istate_chart { public: - typedef int state_id_t; - typedef int event_id_t; - - virtual void start(const bool on_entry_initial = true) = 0; - virtual void process_event(const event_id_t event_id) = 0; + typedef private_state_chart::state_id_t state_id_t; + typedef private_state_chart::event_id_t event_id_t; //************************************************************************* /// Gets the current state id. @@ -61,10 +167,6 @@ namespace etl return current_state_id; } - virtual ~istate_chart() - { - } - protected: istate_chart(state_id_t current_state_id_) @@ -84,66 +186,10 @@ namespace etl { public: - typedef TParameter parameter_t; - - //************************************************************************* - /// Transition definition - //************************************************************************* - struct transition - { - ETL_CONSTEXPR transition(const state_id_t current_state_id_, - const event_id_t event_id_, - const state_id_t next_state_id_, - void (TObject::* const action_)(parameter_t) = ETL_NULLPTR, - bool (TObject::* const guard_)() = ETL_NULLPTR) - : from_any_state(false), - current_state_id(current_state_id_), - event_id(event_id_), - next_state_id(next_state_id_), - action(action_), - guard(guard_) - { - } - - ETL_CONSTEXPR transition(const event_id_t event_id_, - const state_id_t next_state_id_, - void (TObject::* const action_)(parameter_t) = ETL_NULLPTR, - bool (TObject::* const guard_)() = ETL_NULLPTR) - : from_any_state(true), - current_state_id(0), - event_id(event_id_), - next_state_id(next_state_id_), - action(action_), - guard(guard_) - { - } - - const bool from_any_state; - const state_id_t current_state_id; - const event_id_t event_id; - const state_id_t next_state_id; - void (TObject::* const action)(parameter_t); - bool (TObject::* const guard)(); - }; - - //************************************************************************* - /// State definition - //************************************************************************* - struct state - { - ETL_CONSTEXPR state(const state_id_t state_id_, - void (TObject::* const on_entry_)() = ETL_NULLPTR, - void (TObject::* const on_exit_)() = ETL_NULLPTR) - : state_id(state_id_), - on_entry(on_entry_), - on_exit(on_exit_) - { - } - - state_id_t state_id; - void (TObject::* const on_entry)(); - void (TObject::* const on_exit)(); - }; + typedef TParameter parameter_t; + typedef etl::delegate delegate_t; + typedef private_state_chart::transition transition; + typedef private_state_chart::state state; //************************************************************************* /// Constructor. @@ -152,13 +198,16 @@ namespace etl /// \param transition_table_end_ The end of the table of transitions. /// \param state_id_ The initial state id. //************************************************************************* - ETL_CONSTEXPR state_chart(TObject& object_, - const transition* transition_table_begin_, - const transition* transition_table_end_, - const state_id_t state_id_) + ETL_CONSTEXPR state_chart(TObject& object_, + const transition* const transition_table_begin_, + const transition* const transition_table_end_, + const state_id_t state_id_) : istate_chart(state_id_), object(object_), - transition_table(transition_table_begin_, transition_table_end_), + transition_table_begin(transition_table_begin_), + state_table_begin(ETL_NULLPTR), + transition_table_size(transition_table_end_ - transition_table_begin_), + state_table_size(0U), started(false) { } @@ -172,16 +221,18 @@ namespace etl /// \param state_table_end_ The end of the state table. /// \param state_id_ The initial state id. //************************************************************************* - ETL_CONSTEXPR state_chart(TObject& object_, - const transition* transition_table_begin_, - const transition* transition_table_end_, - const state* state_table_begin_, - const state* state_table_end_, - const state_id_t state_id_) + ETL_CONSTEXPR state_chart(TObject& object_, + const transition* const transition_table_begin_, + const transition* const transition_table_end_, + const state* const state_table_begin_, + const state* const state_table_end_, + const state_id_t state_id_) : istate_chart(state_id_), object(object_), - transition_table(transition_table_begin_, transition_table_end_), - state_table(state_table_begin_, state_table_end_), + transition_table_begin(transition_table_begin_), + state_table_begin(state_table_begin_), + transition_table_size(transition_table_end_ - transition_table_begin_), + state_table_size(state_table_end_ - state_table_begin_), started(false) { } @@ -194,7 +245,8 @@ namespace etl void set_transition_table(const transition* transition_table_begin_, const transition* transition_table_end_) { - transition_table.assign(transition_table_begin_, transition_table_end_); + transition_table_begin = transition_table_begin_; + transition_table_size = transition_table_end_ - transition_table_begin_; } //************************************************************************* @@ -205,7 +257,8 @@ namespace etl void set_state_table(const state* state_table_begin_, const state* state_table_end_) { - state_table.assign(state_table_begin_, state_table_end_); + state_table_begin = state_table_begin_; + state_table_size = state_table_end_ - state_table_begin_; } //************************************************************************* @@ -232,22 +285,22 @@ namespace etl //************************************************************************* const state* find_state(state_id_t state_id) { - if (state_table.empty()) + if (state_table_begin == ETL_NULLPTR) { - return state_table.end(); + return state_table_end(); } else { - return etl::find_if(state_table.begin(), - state_table.end(), + return etl::find_if(state_table_begin, + state_table_end(), is_state(state_id)); } } //************************************************************************* - /// + /// Start the state chart. //************************************************************************* - virtual void start(const bool on_entry_initial = true) ETL_OVERRIDE + void start(const bool on_entry_initial = true) { if (!started) { @@ -257,7 +310,7 @@ namespace etl const state* s = find_state(current_state_id); // If the initial state has an 'on_entry' then call it. - if ((s != state_table.end()) && (s->on_entry != ETL_NULLPTR)) + if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR)) { (object.*(s->on_entry))(); } @@ -273,7 +326,7 @@ namespace etl /// that satisfies the conditions for executing the action. /// \param event_id The id of the event to process. //************************************************************************* - virtual void process_event(const event_id_t event_id) ETL_OVERRIDE + void process_event(const event_id_t event_id) { process_event(event_id, typename etl::types::type()); } @@ -289,18 +342,18 @@ namespace etl { if (started) { - const transition* t = transition_table.begin(); + const transition* t = transition_table_begin; // Keep looping until we execute a transition or reach the end of the table. - while (t != transition_table.end()) + while (t != transition_table_end()) { // Scan the transition table from the latest position. t = etl::find_if(t, - transition_table.end(), + transition_table_end(), is_transition(event_id, current_state_id)); // Found an entry? - if (t != transition_table.end()) + if (t != transition_table_end()) { // Shall we execute the transition? if ((t->guard == ETL_NULLPTR) || ((object.*t->guard)())) @@ -324,7 +377,7 @@ namespace etl s = find_state(current_state_id); // If the current state has an 'on_exit' then call it. - if ((s != state_table.end()) && (s->on_exit != ETL_NULLPTR)) + if ((s != state_table_end()) && (s->on_exit != ETL_NULLPTR)) { (object.*(s->on_exit))(); } @@ -335,13 +388,13 @@ namespace etl s = find_state(current_state_id); // If the new state has an 'on_entry' then call it. - if ((s != state_table.end()) && (s->on_entry != ETL_NULLPTR)) + if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR)) { (object.*(s->on_entry))(); } } - t = transition_table.end(); + t = transition_table_end(); } else { @@ -353,8 +406,28 @@ namespace etl } } + //************************************************************************* + /// Get a delegate to the process_event function. + //************************************************************************* + delegate_t get_process_event_delegate() + { + return delegate_t::template create, &state_chart::process_event>(*this); + } + private: + //************************************************************************* + const transition* const transition_table_end() const + { + return transition_table_begin + transition_table_size; + } + + //************************************************************************* + const state* const state_table_end() const + { + return state_table_begin + state_table_size; + } + //************************************************************************* struct is_transition { @@ -393,10 +466,12 @@ namespace etl state_chart(const state_chart&) ETL_DELETE; state_chart& operator =(const state_chart&) ETL_DELETE; - TObject& object; ///< The object that supplies guard and action member functions. - const etl::array_view transition_table; ///< The table of transitions. - etl::array_view state_table; ///< The table of states. - bool started; ///< Set if the state chart has been started. + TObject& object; ///< The object that supplies guard and action member functions. + const transition* transition_table_begin; ///< The start of the table of transitions. + const state* state_table_begin; ///< The start of the table of states. + uint_least8_t transition_table_size; ///< The size of the table of transitions. + uint_least8_t state_table_size; ///< The size of the table of states. + bool started; ///< Set if the state chart has been started. }; //*************************************************************************** @@ -407,64 +482,9 @@ namespace etl { public: - //************************************************************************* - /// Transition definition - //************************************************************************* - struct transition - { - ETL_CONSTEXPR transition(const state_id_t current_state_id_, - const event_id_t event_id_, - const state_id_t next_state_id_, - void (TObject::* const action_)() = ETL_NULLPTR, - bool (TObject::* const guard_)() = ETL_NULLPTR) - : from_any_state(false), - current_state_id(current_state_id_), - event_id(event_id_), - next_state_id(next_state_id_), - action(action_), - guard(guard_) - { - } - - ETL_CONSTEXPR transition(const event_id_t event_id_, - const state_id_t next_state_id_, - void (TObject::* const action_)() = ETL_NULLPTR, - bool (TObject::* const guard_)() = ETL_NULLPTR) - : from_any_state(true), - current_state_id(0), - event_id(event_id_), - next_state_id(next_state_id_), - action(action_), - guard(guard_) - { - } - - const bool from_any_state; - const state_id_t current_state_id; - const event_id_t event_id; - const state_id_t next_state_id; - void (TObject::* const action)(); - bool (TObject::* const guard)(); - }; - - //************************************************************************* - /// State definition - //************************************************************************* - struct state - { - ETL_CONSTEXPR state(const state_id_t state_id_, - void (TObject::* const on_entry_)() = ETL_NULLPTR, - void (TObject::* const on_exit_)() = ETL_NULLPTR) - : state_id(state_id_), - on_entry(on_entry_), - on_exit(on_exit_) - { - } - - state_id_t state_id; - void (TObject::* const on_entry)(); - void (TObject::* const on_exit)(); - }; + typedef etl::delegate delegate_t; + typedef private_state_chart::transition transition; + typedef private_state_chart::state state; //************************************************************************* /// Constructor. @@ -479,7 +499,10 @@ namespace etl const state_id_t state_id_) : istate_chart(state_id_), object(object_), - transition_table(transition_table_begin_, transition_table_end_), + transition_table_begin(transition_table_begin_), + state_table_begin(ETL_NULLPTR), + transition_table_size(transition_table_end_ - transition_table_begin_), + state_table_size(0U), started(false) { } @@ -501,8 +524,10 @@ namespace etl const state_id_t state_id_) : istate_chart(state_id_), object(object_), - transition_table(transition_table_begin_, transition_table_end_), - state_table(state_table_begin_, state_table_end_), + transition_table_begin(transition_table_begin_), + state_table_begin(state_table_begin_), + transition_table_size(transition_table_end_ - transition_table_begin_), + state_table_size(state_table_end_ - state_table_begin_), started(false) { } @@ -515,7 +540,8 @@ namespace etl void set_transition_table(const transition* transition_table_begin_, const transition* transition_table_end_) { - transition_table.assign(transition_table_begin_, transition_table_end_); + transition_table_begin = transition_table_begin_; + transition_table_size = transition_table_end_ - transition_table_begin_; } //************************************************************************* @@ -526,7 +552,8 @@ namespace etl void set_state_table(const state* state_table_begin_, const state* state_table_end_) { - state_table.assign(state_table_begin_, state_table_end_); + state_table_begin = state_table_begin_; + state_table_size = state_table_end_ - state_table_begin_; } //************************************************************************* @@ -553,22 +580,22 @@ namespace etl //************************************************************************* const state* find_state(state_id_t state_id) { - if (state_table.empty()) + if (state_table_begin == ETL_NULLPTR) { - return state_table.end(); + return state_table_end(); } else { - return etl::find_if(state_table.begin(), - state_table.end(), + return etl::find_if(state_table_begin, + state_table_end(), is_state(state_id)); } } //************************************************************************* - /// + /// Start the state chart. //************************************************************************* - virtual void start(const bool on_entry_initial = true) ETL_OVERRIDE + void start(const bool on_entry_initial = true) { if (!started) { @@ -578,7 +605,7 @@ namespace etl const state* s = find_state(current_state_id); // If the initial state has an 'on_entry' then call it. - if ((s != state_table.end()) && (s->on_entry != ETL_NULLPTR)) + if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR)) { (object.*(s->on_entry))(); } @@ -594,22 +621,22 @@ namespace etl /// that satisfies the conditions for executing the action. /// \param event_id The id of the event to process. //************************************************************************* - virtual void process_event(const event_id_t event_id) ETL_OVERRIDE + void process_event(const event_id_t event_id) { if (started) { - const transition* t = transition_table.begin(); + const transition* t = transition_table_begin; // Keep looping until we execute a transition or reach the end of the table. - while (t != transition_table.end()) + while (t != transition_table_end()) { // Scan the transition table from the latest position. t = etl::find_if(t, - transition_table.end(), + transition_table_end(), is_transition(event_id, current_state_id)); // Found an entry? - if (t != transition_table.end()) + if (t != transition_table_end()) { // Shall we execute the transition? if ((t->guard == ETL_NULLPTR) || ((object.*t->guard)())) @@ -629,7 +656,7 @@ namespace etl s = find_state(current_state_id); // If the current state has an 'on_exit' then call it. - if ((s != state_table.end()) && (s->on_exit != ETL_NULLPTR)) + if ((s != state_table_end()) && (s->on_exit != ETL_NULLPTR)) { (object.*(s->on_exit))(); } @@ -640,13 +667,13 @@ namespace etl s = find_state(current_state_id); // If the new state has an 'on_entry' then call it. - if ((s != state_table.end()) && (s->on_entry != ETL_NULLPTR)) + if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR)) { (object.*(s->on_entry))(); } } - t = transition_table.end(); + t = transition_table_end(); } else { @@ -658,8 +685,28 @@ namespace etl } } + //************************************************************************* + /// Get a delegate to the process_event function. + //************************************************************************* + delegate_t get_process_event_delegate() + { + return delegate_t::template create, &state_chart::process_event>(*this); + } + private: + //************************************************************************* + const transition* const transition_table_end() const + { + return transition_table_begin + transition_table_size; + } + + //************************************************************************* + const state* const state_table_end() const + { + return state_table_begin + state_table_size; + } + //************************************************************************* struct is_transition { @@ -698,10 +745,12 @@ namespace etl state_chart(const state_chart&) ETL_DELETE; state_chart& operator =(const state_chart&) ETL_DELETE; - TObject& object; ///< The object that supplies guard and action member functions. - const etl::array_view transition_table; ///< The table of transitions. - etl::array_view state_table; ///< The table of states. - bool started; ///< Set if the state chart has been started. + TObject& object; ///< The object that supplies guard and action member functions. + const transition* transition_table_begin; ///< The start of the table of transitions. + const state* state_table_begin; ///< The start of the table of states. + uint_least8_t transition_table_size; ///< The size of the table of transitions. + uint_least8_t state_table_size; ///< The size of the table of states. + bool started; ///< Set if the state chart has been started. }; } diff --git a/test/test_state_chart.cpp b/test/test_state_chart.cpp index 821b921f..b8286b5d 100644 --- a/test/test_state_chart.cpp +++ b/test/test_state_chart.cpp @@ -398,6 +398,143 @@ namespace CHECK_EQUAL(1, motorControl.null); } + //************************************************************************* + TEST(test_state_chart_with_delegate) + { + motorControl.ClearStatistics(); + + auto process_event = motorControl.get_process_event_delegate(); + + // Start the state chart + motorControl.guard = true; + motorControl.start(); + + // Send unhandled events. + process_event(EventId::STOP); + process_event(EventId::STOPPED); + + CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + + // Send Start event. + motorControl.guard = false; + process_event(EventId::START); + + // Still in Idle state. + + CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Start event. + motorControl.guard = true; + process_event(EventId::START); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send unhandled events. + process_event(EventId::START); + process_event(EventId::STOPPED); + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send SetSpeed event. + process_event(EventId::SET_SPEED); + + // Still in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Stop event. + process_event(EventId::STOP); + + // Now in WindingDown state. + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(1, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send unhandled events. + process_event(EventId::START); + process_event(EventId::STOP); + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(1, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Stopped event. + process_event(EventId::STOPPED); + + // Now in Idle state. + CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(1, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + } + //************************************************************************* TEST(test_fsm_emergency_stop) { @@ -447,6 +584,7 @@ namespace // Now in Running state. + // Send abort event. motorControl.process_event(EventId::ABORT); CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); diff --git a/test/test_state_chart_with_data_parameter.cpp b/test/test_state_chart_with_data_parameter.cpp index 59857dac..ddfbe6f8 100644 --- a/test/test_state_chart_with_data_parameter.cpp +++ b/test/test_state_chart_with_data_parameter.cpp @@ -463,19 +463,35 @@ namespace // Send Start event. motorControl.process_event(EventId::START, 1); + int state = int(motorControl.get_state_id()); + int check = StateId::RUNNING; + // Now in Running state. + // Send abort event. motorControl.process_event(EventId::ABORT, 2); - CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + + state = int(motorControl.get_state_id()); + check = StateId::IDLE; + + CHECK_EQUAL(check, state); + //CHECK_EQUAL(StateId::IDLE, state); + //CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); // Send Start event. motorControl.process_event(EventId::START, 3); // Now in Running state. + state = int(motorControl.get_state_id()); + check = StateId::RUNNING; + // Send Stop event. motorControl.process_event(EventId::STOP, 4); + state = int(motorControl.get_state_id()); + check = StateId::WINDING_DOWN; + // Now in WindingDown state. motorControl.process_event(EventId::ABORT, 5); CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); diff --git a/test/test_state_chart_with_rvalue_data_parameter.cpp b/test/test_state_chart_with_rvalue_data_parameter.cpp index f6c43b6d..4c6e2223 100644 --- a/test/test_state_chart_with_rvalue_data_parameter.cpp +++ b/test/test_state_chart_with_rvalue_data_parameter.cpp @@ -496,6 +496,7 @@ namespace // Now in Running state. + // Send abort event. motorControl.process_event(EventId::ABORT, Data(2)); CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); From e263a7cb750b7cfb725364001b85767ec668f6b2 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 16 Jan 2022 13:30:52 +0000 Subject: [PATCH 2/8] Initial state_chart changes --- include/etl/state_chart.h | 73 ++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/include/etl/state_chart.h b/include/etl/state_chart.h index e72a1fd6..5de7384e 100644 --- a/include/etl/state_chart.h +++ b/include/etl/state_chart.h @@ -40,10 +40,21 @@ SOFTWARE. namespace etl { - namespace private_state_chart + //*************************************************************************** + /// Simple Finite State Machine Types + //*************************************************************************** + class istate_chart { + public: + typedef uint_least8_t state_id_t; typedef uint_least8_t event_id_t; + }; + + namespace private_state_chart + { + typedef istate_chart::state_id_t state_id_t; + typedef istate_chart::event_id_t event_id_t; //************************************************************************* /// Transition definition @@ -148,35 +159,6 @@ namespace etl }; } - //************************************************************************* - /// istate_chart - //************************************************************************* - class istate_chart - { - public: - - typedef private_state_chart::state_id_t state_id_t; - typedef private_state_chart::event_id_t event_id_t; - - //************************************************************************* - /// Gets the current state id. - /// \return The current state id. - //************************************************************************* - state_id_t get_state_id() const - { - return current_state_id; - } - - protected: - - istate_chart(state_id_t current_state_id_) - : current_state_id(current_state_id_) - { - } - - state_id_t current_state_id; ///< The current state id. - }; - //*************************************************************************** /// Simple Finite State Machine /// Data parameter for events. @@ -186,7 +168,8 @@ namespace etl { public: - typedef TParameter parameter_t; + typedef TParameter parameter_t; + typedef etl::delegate delegate_t; typedef private_state_chart::transition transition; typedef private_state_chart::state state; @@ -202,7 +185,7 @@ namespace etl const transition* const transition_table_begin_, const transition* const transition_table_end_, const state_id_t state_id_) - : istate_chart(state_id_), + : current_state_id(state_id_), object(object_), transition_table_begin(transition_table_begin_), state_table_begin(ETL_NULLPTR), @@ -227,7 +210,7 @@ namespace etl const state* const state_table_begin_, const state* const state_table_end_, const state_id_t state_id_) - : istate_chart(state_id_), + : current_state_id(state_id_), object(object_), transition_table_begin(transition_table_begin_), state_table_begin(state_table_begin_), @@ -406,6 +389,15 @@ namespace etl } } + //************************************************************************* + /// Gets the current state id. + /// \return The current state id. + //************************************************************************* + state_id_t get_state_id() const + { + return current_state_id; + } + //************************************************************************* /// Get a delegate to the process_event function. //************************************************************************* @@ -471,6 +463,7 @@ namespace etl const state* state_table_begin; ///< The start of the table of states. uint_least8_t transition_table_size; ///< The size of the table of transitions. uint_least8_t state_table_size; ///< The size of the table of states. + state_id_t current_state_id; ///< The current state id. bool started; ///< Set if the state chart has been started. }; @@ -497,7 +490,7 @@ namespace etl const transition* transition_table_begin_, const transition* transition_table_end_, const state_id_t state_id_) - : istate_chart(state_id_), + : current_state_id(state_id_), object(object_), transition_table_begin(transition_table_begin_), state_table_begin(ETL_NULLPTR), @@ -522,7 +515,7 @@ namespace etl const state* state_table_begin_, const state* state_table_end_, const state_id_t state_id_) - : istate_chart(state_id_), + : current_state_id(state_id_), object(object_), transition_table_begin(transition_table_begin_), state_table_begin(state_table_begin_), @@ -685,6 +678,15 @@ namespace etl } } + //************************************************************************* + /// Gets the current state id. + /// \return The current state id. + //************************************************************************* + state_id_t get_state_id() const + { + return current_state_id; + } + //************************************************************************* /// Get a delegate to the process_event function. //************************************************************************* @@ -750,6 +752,7 @@ namespace etl const state* state_table_begin; ///< The start of the table of states. uint_least8_t transition_table_size; ///< The size of the table of transitions. uint_least8_t state_table_size; ///< The size of the table of states. + state_id_t current_state_id; ///< The current state id. bool started; ///< Set if the state chart has been started. }; } From 8337c87f1631f7b35ce29cb63d8920d98d4acac6 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 17 Jan 2022 11:19:03 +0000 Subject: [PATCH 3/8] Initial state_chart changes --- include/etl/state_chart.h | 300 +++++++++++- test/test_state_chart_compile_time.cpp | 612 +++++++++++++++++++++++++ 2 files changed, 887 insertions(+), 25 deletions(-) create mode 100644 test/test_state_chart_compile_time.cpp diff --git a/include/etl/state_chart.h b/include/etl/state_chart.h index 5de7384e..bd519f05 100644 --- a/include/etl/state_chart.h +++ b/include/etl/state_chart.h @@ -51,7 +51,7 @@ namespace etl typedef uint_least8_t event_id_t; }; - namespace private_state_chart + namespace state_chart_types { typedef istate_chart::state_id_t state_id_t; typedef istate_chart::event_id_t event_id_t; @@ -163,7 +163,14 @@ namespace etl /// Simple Finite State Machine /// Data parameter for events. //*************************************************************************** - template + template class state_chart : public istate_chart { public: @@ -171,8 +178,8 @@ namespace etl typedef TParameter parameter_t; typedef etl::delegate delegate_t; - typedef private_state_chart::transition transition; - typedef private_state_chart::state state; + typedef state_chart_types::transition transition; + typedef state_chart_types::state state; //************************************************************************* /// Constructor. @@ -424,8 +431,8 @@ namespace etl struct is_transition { is_transition(event_id_t event_id_, state_id_t state_id_) - : event_id(event_id_), - state_id(state_id_) + : event_id(event_id_) + , state_id(state_id_) { } @@ -471,13 +478,13 @@ namespace etl /// Simple Finite State Machine //*************************************************************************** template - class state_chart : public istate_chart + class state_chart : public istate_chart { public: typedef etl::delegate delegate_t; - typedef private_state_chart::transition transition; - typedef private_state_chart::state state; + typedef state_chart_types::transition transition; + typedef state_chart_types::state state; //************************************************************************* /// Constructor. @@ -490,13 +497,13 @@ namespace etl const transition* transition_table_begin_, const transition* transition_table_end_, const state_id_t state_id_) - : current_state_id(state_id_), - object(object_), - transition_table_begin(transition_table_begin_), - state_table_begin(ETL_NULLPTR), - transition_table_size(transition_table_end_ - transition_table_begin_), - state_table_size(0U), - started(false) + : current_state_id(state_id_) + , object(object_) + , transition_table_begin(transition_table_begin_) + , state_table_begin(ETL_NULLPTR) + , transition_table_size(transition_table_end_ - transition_table_begin_) + , state_table_size(0U) + , started(false) { } @@ -515,13 +522,13 @@ namespace etl const state* state_table_begin_, const state* state_table_end_, const state_id_t state_id_) - : current_state_id(state_id_), - object(object_), - transition_table_begin(transition_table_begin_), - state_table_begin(state_table_begin_), - transition_table_size(transition_table_end_ - transition_table_begin_), - state_table_size(state_table_end_ - state_table_begin_), - started(false) + : current_state_id(state_id_) + , object(object_) + , transition_table_begin(transition_table_begin_) + , state_table_begin(state_table_begin_) + , transition_table_size(transition_table_end_ - transition_table_begin_) + , state_table_size(state_table_end_ - state_table_begin_) + , started(false) { } @@ -713,8 +720,8 @@ namespace etl struct is_transition { is_transition(event_id_t event_id_, state_id_t state_id_) - : event_id(event_id_), - state_id(state_id_) + : event_id(event_id_) + , state_id(state_id_) { } @@ -755,6 +762,249 @@ namespace etl state_id_t current_state_id; ///< The current state id. bool started; ///< Set if the state chart has been started. }; + + //*************************************************************************** + /// Simple Finite State Machine + //*************************************************************************** + template + class state_chart : public istate_chart + { + public: + + typedef etl::delegate delegate_t; + typedef state_chart_types::transition transition; + typedef state_chart_types::state state; + + //************************************************************************* + /// Constructor. + //************************************************************************* + ETL_CONSTEXPR state_chart() + : current_state_id(InitialState) + , started(false) + { + } + + //************************************************************************* + /// Gets a const reference to the implementation object. + /// \return Const reference to the implementation object. + //************************************************************************* + TObject& get_object() + { + return *reinterpret_cast(TObjectPtr); + } + + //************************************************************************* + /// Gets a const reference to the implementation object. + /// \return Const reference to the implementation object. + //************************************************************************* + const TObject& get_object() const + { + return *reinterpret_cast(TObjectPtr); + } + + //************************************************************************* + /// Gets the current state id. + /// \return The current state id. + //************************************************************************* + const state* find_state(state_id_t state_id) + { + if (StateListBegin == ETL_NULLPTR) + { + return state_table_end(); + } + else + { + return etl::find_if(state_table_begin(), + state_table_end(), + is_state(state_id)); + } + } + + //************************************************************************* + /// Start the state chart. + //************************************************************************* + void start(const bool on_entry_initial = true) + { + if (!started) + { + if (on_entry_initial) + { + // See if we have a state item for the initial state. + const state* s = find_state(current_state_id); + + // If the initial state has an 'on_entry' then call it. + if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR)) + { + (get_object().*(s->on_entry))(); + } + } + + started = true; + } + } + + //************************************************************************* + /// Processes the specified event. + /// The state machine will action the first item in the transition table + /// that satisfies the conditions for executing the action. + /// \param event_id The id of the event to process. + //************************************************************************* + void process_event(const event_id_t event_id) + { + if (started) + { + const transition* t = transition_table_begin(); + + // Keep looping until we execute a transition or reach the end of the table. + while (t != transition_table_end()) + { + // Scan the transition table from the latest position. + t = etl::find_if(t, + transition_table_end(), + is_transition(event_id, current_state_id)); + + // Found an entry? + if (t != transition_table_end()) + { + TObject& object = get_object(); + + // Shall we execute the transition? + if ((t->guard == ETL_NULLPTR) || ((object.*t->guard)())) + { + // Shall we execute the action? + if (t->action != ETL_NULLPTR) + { + (object.*t->action)(); + } + + // Changing state? + if (current_state_id != t->next_state_id) + { + const state* s; + + // See if we have a state item for the current state. + s = find_state(current_state_id); + + // If the current state has an 'on_exit' then call it. + if ((s != state_table_end()) && (s->on_exit != ETL_NULLPTR)) + { + (object.*(s->on_exit))(); + } + + current_state_id = t->next_state_id; + + // See if we have a state item for the new state. + s = find_state(current_state_id); + + // If the new state has an 'on_entry' then call it. + if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR)) + { + (object.*(s->on_entry))(); + } + } + + t = transition_table_end(); + } + else + { + // Start the search from the next item in the table. + ++t; + } + } + } + } + } + + //************************************************************************* + /// Gets the current state id. + /// \return The current state id. + //************************************************************************* + state_id_t get_state_id() const + { + return current_state_id; + } + + //************************************************************************* + /// Get a delegate to the process_event function. + //************************************************************************* + delegate_t get_process_event_delegate() + { + return delegate_t::template create, &state_chart::process_event>(*this); + } + + private: + + //************************************************************************* + const transition* const transition_table_begin() const + { + return reinterpret_cast(TransitionListBegin); + } + + //************************************************************************* + const transition* const transition_table_end() const + { + return reinterpret_cast(TransitionListBegin) + TransitionListSize; + } + + //************************************************************************* + const state* const state_table_begin() const + { + return reinterpret_cast(StateListBegin); + } + + //************************************************************************* + const state* const state_table_end() const + { + return reinterpret_cast(StateListBegin) + StateListSize; + } + + //************************************************************************* + struct is_transition + { + is_transition(event_id_t event_id_, state_id_t state_id_) + : event_id(event_id_) + , state_id(state_id_) + { + } + + bool operator()(const transition& t) const + { + return (t.event_id == event_id) && (t.from_any_state || (t.current_state_id == state_id)); + } + + const event_id_t event_id; + const state_id_t state_id; + }; + + //************************************************************************* + struct is_state + { + is_state(state_id_t state_id_) + : state_id(state_id_) + { + } + + bool operator()(const state& s) const + { + return (s.state_id == state_id); + } + + const state_id_t state_id; + }; + + // Disabled + state_chart(const state_chart&) ETL_DELETE; + state_chart& operator =(const state_chart&) ETL_DELETE; + + state_id_t current_state_id; ///< The current state id. + bool started; ///< Set if the state chart has been started. + }; } #endif diff --git a/test/test_state_chart_compile_time.cpp b/test/test_state_chart_compile_time.cpp new file mode 100644 index 00000000..d7f4ec51 --- /dev/null +++ b/test/test_state_chart_compile_time.cpp @@ -0,0 +1,612 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2018 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. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/state_chart.h" +#include "etl/enum_type.h" +#include "etl/queue.h" +#include "etl/array.h" + +#include + +namespace +{ + //*************************************************************************** + // Events + struct EventId + { + enum enum_type + { + START, + STOP, + EMERGENCY_STOP, + STOPPED, + SET_SPEED, + ABORT + }; + + ETL_DECLARE_ENUM_TYPE(EventId, etl::istate_chart::event_id_t) + ETL_ENUM_TYPE(START, "Start") + ETL_ENUM_TYPE(STOP, "Stop") + ETL_ENUM_TYPE(EMERGENCY_STOP, "Emergency Stop") + ETL_ENUM_TYPE(STOPPED, "Stopped") + ETL_ENUM_TYPE(SET_SPEED, "Set Speed") + ETL_ENUM_TYPE(ABORT, "Abort") + ETL_END_ENUM_TYPE + }; + + //*************************************************************************** + // States + struct StateId + { + enum enum_type + { + IDLE, + RUNNING, + WINDING_DOWN, + NUMBER_OF_STATES + }; + + ETL_DECLARE_ENUM_TYPE(StateId, etl::istate_chart::state_id_t) + ETL_ENUM_TYPE(IDLE, "Idle") + ETL_ENUM_TYPE(RUNNING, "Running") + ETL_ENUM_TYPE(WINDING_DOWN, "Winding Down") + ETL_END_ENUM_TYPE + }; + + //*********************************** + // The motor control FSM. + //*********************************** + class MotorControl + { + public: + + MotorControl() + { + ClearStatistics(); + } + + //*********************************** + void ClearStatistics() + { + startCount = 0; + stopCount = 0; + setSpeedCount = 0; + stoppedCount = 0; + isLampOn = false; + speed = 0; + windingDown = 0; + entered_idle = false; + null = 0; + } + + //*********************************** + void OnStart() + { + ++startCount; + } + + //*********************************** + void OnStop() + { + ++stopCount; + } + + //*********************************** + void OnStopped() + { + ++stoppedCount; + } + + //*********************************** + void OnSetSpeed() + { + ++setSpeedCount; + SetSpeedValue(100); + } + + //*********************************** + void OnEnterIdle() + { + TurnRunningLampOff(); + entered_idle = true; + } + + //*********************************** + void OnEnterRunning() + { + TurnRunningLampOn(); + } + + //*********************************** + void OnEnterWindingDown() + { + ++windingDown; + } + + //*********************************** + void OnExitWindingDown() + { + --windingDown; + } + + //*********************************** + void SetSpeedValue(int speed_) + { + speed = speed_; + } + + //*********************************** + bool Guard() + { + return guard; + } + + //*********************************** + bool NotGuard() + { + return !guard; + } + + //*********************************** + void TurnRunningLampOn() + { + isLampOn = true; + } + + //*********************************** + void TurnRunningLampOff() + { + isLampOn = false; + } + + //*********************************** + void Null() + { + ++null; + } + + int startCount; + int stopCount; + int setSpeedCount; + int stoppedCount; + bool isLampOn; + int speed; + int windingDown; + bool entered_idle; + int null; + + bool guard; + }; + + //*************************************************************************** + using transition = etl::state_chart_types::transition; + + constexpr transition transitionTable[7] = + { + etl::state_chart_types::transition::transition(StateId::IDLE, EventId::START, StateId::RUNNING, &MotorControl::OnStart, &MotorControl::Guard), + etl::state_chart_types::transition::transition(StateId::IDLE, EventId::START, StateId::IDLE, &MotorControl::Null, &MotorControl::NotGuard), + etl::state_chart_types::transition::transition(StateId::RUNNING, EventId::STOP, StateId::WINDING_DOWN, &MotorControl::OnStop), + etl::state_chart_types::transition::transition(StateId::RUNNING, EventId::EMERGENCY_STOP, StateId::IDLE, &MotorControl::OnStop), + etl::state_chart_types::transition::transition(StateId::RUNNING, EventId::SET_SPEED, StateId::RUNNING, &MotorControl::OnSetSpeed), + etl::state_chart_types::transition::transition(StateId::WINDING_DOWN, EventId::STOPPED, StateId::IDLE, &MotorControl::OnStopped), + etl::state_chart_types::transition::transition( EventId::ABORT, StateId::IDLE) + }; + + //*************************************************************************** + using state = etl::state_chart_types::state; + + constexpr state stateTable[3] = + { + state(StateId::IDLE, &MotorControl::OnEnterIdle, nullptr), + state(StateId::RUNNING, &MotorControl::OnEnterRunning, nullptr), + state(StateId::WINDING_DOWN, &MotorControl::OnEnterWindingDown, &MotorControl::OnExitWindingDown) + }; + + MotorControl motorControl; + + etl::state_chart motorControlStateChart; + + SUITE(test_state_chart_class) + { + //************************************************************************* + TEST(test_state_chart) + { + motorControl.ClearStatistics(); + + // In Idle state. + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(false, motorControl.entered_idle); + + // Send Start event (state chart not started). + motorControl.guard = true; + motorControlStateChart.process_event(EventId::START); + + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(false, motorControl.entered_idle); + + // Start the state chart + motorControl.guard = true; + motorControlStateChart.start(); + + CHECK_EQUAL(true, motorControl.entered_idle); + + // Send unhandled events. + motorControlStateChart.process_event(EventId::STOP); + motorControlStateChart.process_event(EventId::STOPPED); + + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + + // Send Start event. + motorControl.guard = false; + motorControlStateChart.process_event(EventId::START); + + // Still in Idle state. + + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Start event. + motorControl.guard = true; + motorControlStateChart.process_event(EventId::START); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send unhandled events. + motorControlStateChart.process_event(EventId::START); + motorControlStateChart.process_event(EventId::STOPPED); + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send SetSpeed event. + motorControlStateChart.process_event(EventId::SET_SPEED); + + // Still in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Stop event. + motorControlStateChart.process_event(EventId::STOP); + + // Now in WindingDown state. + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(1, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send unhandled events. + motorControlStateChart.process_event(EventId::START); + motorControlStateChart.process_event(EventId::STOP); + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(1, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Stopped event. + motorControlStateChart.process_event(EventId::STOPPED); + + // Now in Idle state. + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(1, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + } + + //************************************************************************* + TEST(test_state_chart_with_delegate) + { + motorControl.ClearStatistics(); + + auto process_event = motorControlStateChart.get_process_event_delegate(); + + // Start the state chart + motorControl.guard = true; + motorControlStateChart.start(); + + // Send unhandled events. + process_event(EventId::STOP); + process_event(EventId::STOPPED); + + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + + // Send Start event. + motorControl.guard = false; + process_event(EventId::START); + + // Still in Idle state. + + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Start event. + motorControl.guard = true; + process_event(EventId::START); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send unhandled events. + process_event(EventId::START); + process_event(EventId::STOPPED); + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send SetSpeed event. + process_event(EventId::SET_SPEED); + + // Still in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Stop event. + process_event(EventId::STOP); + + // Now in WindingDown state. + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(1, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send unhandled events. + process_event(EventId::START); + process_event(EventId::STOP); + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(1, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Stopped event. + process_event(EventId::STOPPED); + + // Now in Idle state. + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(1, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + } + + //************************************************************************* + TEST(test_fsm_emergency_stop) + { + motorControl.ClearStatistics(); + + // Now in Idle state. + + // Send Start event. + motorControlStateChart.process_event(EventId::START); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + + // Send emergency Stop event. + motorControlStateChart.process_event(EventId::EMERGENCY_STOP); + + // Now in Idle state. + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + } + + //************************************************************************* + TEST(test_fsm_abort) + { + motorControl.ClearStatistics(); + + // Now in Idle state. + + // Send Start event. + motorControlStateChart.process_event(EventId::START); + + // Now in Running state. + + // Send abort event. + motorControlStateChart.process_event(EventId::ABORT); + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + // Send Start event. + motorControlStateChart.process_event(EventId::START); + + // Now in Running state. + + // Send Stop event. + motorControlStateChart.process_event(EventId::STOP); + + // Now in WindingDown state. + motorControlStateChart.process_event(EventId::ABORT); + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + } + }; +} From 7c3c7ea05e8330773aab67fb0eebb9a37392b007 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 18 Jan 2022 20:14:55 +0000 Subject: [PATCH 4/8] Removal of redundant code --- include/etl/bit.h | 4 ---- include/etl/callback_timer_atomic.h | 2 -- include/etl/callback_timer_locked.h | 5 +---- include/etl/endianness.h | 6 +++++- include/etl/numeric.h | 5 ++--- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/include/etl/bit.h b/include/etl/bit.h index b8e57f06..e22de9eb 100644 --- a/include/etl/bit.h +++ b/include/etl/bit.h @@ -195,8 +195,6 @@ namespace etl typename etl::enable_if::value, T>::type rotl(T value, int n) ETL_NOEXCEPT { - ETL_CONSTANT size_t N = etl::integral_limits::bits; - if (n < 0) { return etl::rotate_right(value, -n); @@ -215,8 +213,6 @@ namespace etl typename etl::enable_if::value, T>::type rotr(T value, int n) ETL_NOEXCEPT { - ETL_CONSTANT size_t N = etl::integral_limits::bits; - if (n < 0) { return etl::rotate_left(value, -n); diff --git a/include/etl/callback_timer_atomic.h b/include/etl/callback_timer_atomic.h index 9df96bb6..6e04a032 100644 --- a/include/etl/callback_timer_atomic.h +++ b/include/etl/callback_timer_atomic.h @@ -168,8 +168,6 @@ namespace etl // We have something to do? bool has_active = !active_list.empty(); - timer_data* ptimer = &active_list.front(); - if (has_active) { while (has_active && (count >= active_list.front().delta)) diff --git a/include/etl/callback_timer_locked.h b/include/etl/callback_timer_locked.h index c3b2abda..3cae867e 100644 --- a/include/etl/callback_timer_locked.h +++ b/include/etl/callback_timer_locked.h @@ -164,9 +164,7 @@ namespace etl if (try_lock()) { // We have something to do? - bool has_active = !active_list.empty(); - - timer_data* ptimer = &active_list.front(); + bool has_active = !active_list.empty(); if (has_active) { @@ -177,7 +175,6 @@ namespace etl count -= timer.delta; active_list.remove(timer.id, true); - ptimer = &active_list.front(); if (timer.repeating) { diff --git a/include/etl/endianness.h b/include/etl/endianness.h index fabaf259..b53ca51d 100644 --- a/include/etl/endianness.h +++ b/include/etl/endianness.h @@ -75,7 +75,11 @@ SOFTWARE. #endif // If true, then the endianness of the platform can be constexpr. -#define ETL_ENDIANNESS_IS_CONSTEXPR (ETL_CPP11_SUPPORTED && defined(ETL_ENDIAN_NATIVE)) +#if (ETL_CPP11_SUPPORTED && defined(ETL_ENDIAN_NATIVE)) + #define ETL_ENDIANNESS_IS_CONSTEXPR 1 +#else + #define ETL_ENDIANNESS_IS_CONSTEXPR 0 +#endif namespace etl { diff --git a/include/etl/numeric.h b/include/etl/numeric.h index f274635c..8bc135cf 100644 --- a/include/etl/numeric.h +++ b/include/etl/numeric.h @@ -177,9 +177,8 @@ namespace etl ETL_CONSTEXPR T midpoint(T a, T b, typename etl::enable_if<(!etl::is_pointer::value && !etl::is_integral::value && !etl::is_floating_point::value && - etl::is_same::iterator_category, ETL_OR_STD::forward_iterator_tag>::value || - etl::is_same::iterator_category, ETL_OR_STD::bidirectional_iterator_tag>::value) - , int>::type = 0) + (etl::is_same::iterator_category, ETL_OR_STD::forward_iterator_tag>::value || + etl::is_same::iterator_category, ETL_OR_STD::bidirectional_iterator_tag>::value)), int>::type = 0) { etl::advance(a, etl::distance(a, b) / 2U); return a; From f3973e4935e6c6f804b73f0317d2d0bad4f9ff7e Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 18 Jan 2022 20:15:56 +0000 Subject: [PATCH 5/8] Latest state chart code Reinstated virtual process_event() --- include/etl/state_chart.h | 865 ++++++++++-------- test/test_state_chart.cpp | 217 +++-- test/test_state_chart_compile_time.cpp | 306 +++---- ...chart_compile_time_with_data_parameter.cpp | 508 ++++++++++ test/test_state_chart_with_data_parameter.cpp | 9 +- ...state_chart_with_rvalue_data_parameter.cpp | 9 +- test/test_unaligned_type.cpp | 100 +- test/vs2019/etl.vcxproj | 2 + test/vs2019/etl.vcxproj.filters | 6 + 9 files changed, 1325 insertions(+), 697 deletions(-) create mode 100644 test/test_state_chart_compile_time_with_data_parameter.cpp diff --git a/include/etl/state_chart.h b/include/etl/state_chart.h index bd519f05..92899c3b 100644 --- a/include/etl/state_chart.h +++ b/include/etl/state_chart.h @@ -36,25 +36,17 @@ SOFTWARE. #include "array.h" #include "array_view.h" #include "utility.h" -#include "delegate.h" namespace etl { //*************************************************************************** /// Simple Finite State Machine Types //*************************************************************************** - class istate_chart + + namespace state_chart_traits { - public: - typedef uint_least8_t state_id_t; typedef uint_least8_t event_id_t; - }; - - namespace state_chart_types - { - typedef istate_chart::state_id_t state_id_t; - typedef istate_chart::event_id_t event_id_t; //************************************************************************* /// Transition definition @@ -63,7 +55,7 @@ namespace etl struct transition { ETL_CONSTEXPR transition(const state_id_t current_state_id_, - const event_id_t event_id_, + event_id_t event_id_, const state_id_t next_state_id_, void (TObject::* const action_)(TParameter) = ETL_NULLPTR, bool (TObject::* const guard_)() = ETL_NULLPTR) @@ -76,7 +68,7 @@ namespace etl { } - ETL_CONSTEXPR transition(const event_id_t event_id_, + ETL_CONSTEXPR transition(event_id_t event_id_, const state_id_t next_state_id_, void (TObject::* const action_)(TParameter) = ETL_NULLPTR, bool (TObject::* const guard_)() = ETL_NULLPTR) @@ -99,12 +91,13 @@ namespace etl //************************************************************************* /// Transition definition + /// Specialisation for void parameter //************************************************************************* template struct transition { ETL_CONSTEXPR transition(const state_id_t current_state_id_, - const event_id_t event_id_, + event_id_t event_id_, const state_id_t next_state_id_, void (TObject::* const action_)() = ETL_NULLPTR, bool (TObject::* const guard_)() = ETL_NULLPTR) @@ -117,7 +110,7 @@ namespace etl { } - ETL_CONSTEXPR transition(const event_id_t event_id_, + ETL_CONSTEXPR transition(event_id_t event_id_, const state_id_t next_state_id_, void (TObject::* const action_)() = ETL_NULLPTR, bool (TObject::* const guard_)() = ETL_NULLPTR) @@ -160,48 +153,465 @@ namespace etl } //*************************************************************************** - /// Simple Finite State Machine - /// Data parameter for events. + /// For non-void parameter types //*************************************************************************** - template - class state_chart : public istate_chart + template + class istate_chart { public: typedef TParameter parameter_t; + typedef state_chart_traits::state_id_t state_id_t; + typedef state_chart_traits::event_id_t event_id_t; - typedef etl::delegate delegate_t; - typedef state_chart_types::transition transition; - typedef state_chart_types::state state; + virtual void process_event(event_id_t, parameter_t) = 0; + }; + + //*************************************************************************** + /// For void parameter types + //*************************************************************************** + template <> + class istate_chart + { + public: + + typedef void parameter_t; + typedef state_chart_traits::state_id_t state_id_t; + typedef state_chart_traits::event_id_t event_id_t; + + virtual void process_event(event_id_t) = 0; + }; + + //*************************************************************************** + /// Simple Finite State Machine + /// Compile time tables. + /// Event has no parameter. + //*************************************************************************** + template * Transition_Table_Begin, + size_t Transition_Table_Size, + const etl::state_chart_traits::state* State_Table_Begin, + size_t State_Table_Size, + etl::state_chart_traits::state_id_t Initial_State> + class state_chart_ctv : public istate_chart + { + public: + + using parameter_t = typename istate_chart::parameter_t; + using state_id_t = typename istate_chart::state_id_t; + using event_id_t = typename istate_chart::event_id_t; + + typedef state_chart_traits::transition transition; + + typedef state_chart_traits::state state; //************************************************************************* /// Constructor. - /// \param object_ A reference to the implementation object. - /// \param transition_table_begin_ The start of the table of transitions. - /// \param transition_table_end_ The end of the table of transitions. - /// \param state_id_ The initial state id. //************************************************************************* - ETL_CONSTEXPR state_chart(TObject& object_, - const transition* const transition_table_begin_, - const transition* const transition_table_end_, - const state_id_t state_id_) - : current_state_id(state_id_), - object(object_), - transition_table_begin(transition_table_begin_), - state_table_begin(ETL_NULLPTR), - transition_table_size(transition_table_end_ - transition_table_begin_), - state_table_size(0U), - started(false) + ETL_CONSTEXPR state_chart_ctv() + : current_state_id(Initial_State) + , started(false) { } + //************************************************************************* + /// Gets a const reference to the implementation object. + /// \return Const reference to the implementation object. + //************************************************************************* + TObject& get_object() + { + return TObject_Ref; + } + + //************************************************************************* + /// Gets a const reference to the implementation object. + /// \return Const reference to the implementation object. + //************************************************************************* + const TObject& get_object() const + { + return TObject_Ref; + } + + //************************************************************************* + /// Gets the current state id. + /// \return The current state id. + //************************************************************************* + const state* find_state(state_id_t state_id) + { + return etl::find_if(State_Table_Begin, State_Table_Begin + State_Table_Size, is_state(state_id)); + } + + //************************************************************************* + /// Start the state chart. + //************************************************************************* + void start(const bool on_entry_initial = true) + { + if (!started) + { + if (on_entry_initial) + { + // See if we have a state item for the initial state. + const state* s = find_state(current_state_id); + + // If the initial state has an 'on_entry' then call it. + if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_entry != ETL_NULLPTR)) + { + (TObject_Ref.*(s->on_entry))(); + } + } + + started = true; + } + } + + //************************************************************************* + /// Processes the specified event. + /// The state machine will action the first item in the transition table + /// that satisfies the conditions for executing the action. + /// \param event_id The id of the event to process. + //************************************************************************* + virtual void process_event(event_id_t event_id/*, parameter_t data*/) ETL_OVERRIDE + { + if (started) + { + const transition* t = Transition_Table_Begin; + + // Keep looping until we execute a transition or reach the end of the table. + while (t != (Transition_Table_Begin + Transition_Table_Size)) + { + // Scan the transition table from the latest position. + t = etl::find_if(t, (Transition_Table_Begin + Transition_Table_Size), is_transition(event_id, current_state_id)); + + // Found an entry? + if (t != (Transition_Table_Begin + Transition_Table_Size)) + { + // Shall we execute the transition? + if ((t->guard == ETL_NULLPTR) || ((TObject_Ref.*t->guard)())) + { + // Shall we execute the action? + if (t->action != ETL_NULLPTR) + { + (TObject_Ref.*t->action)(); + } + + // Changing state? + if (current_state_id != t->next_state_id) + { + const state* s; + + // See if we have a state item for the current state. + s = find_state(current_state_id); + + // If the current state has an 'on_exit' then call it. + if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_exit != ETL_NULLPTR)) + { + (TObject_Ref.*(s->on_exit))(); + } + + current_state_id = t->next_state_id; + + // See if we have a state item for the new state. + s = find_state(current_state_id); + + // If the new state has an 'on_entry' then call it. + if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_entry != ETL_NULLPTR)) + { + (TObject_Ref.*(s->on_entry))(); + } + } + + t = (Transition_Table_Begin + Transition_Table_Size); + } + else + { + // Start the search from the next item in the table. + ++t; + } + } + } + } + } + + //************************************************************************* + /// Gets the current state id. + /// \return The current state id. + //************************************************************************* + state_id_t get_state_id() const + { + return current_state_id; + } + + private: + + //************************************************************************* + struct is_transition + { + is_transition(event_id_t event_id_, state_id_t state_id_) + : event_id(event_id_) + , state_id(state_id_) + { + } + + bool operator()(const transition& t) const + { + return (t.event_id == event_id) && (t.from_any_state || (t.current_state_id == state_id)); + } + + const event_id_t event_id; + const state_id_t state_id; + }; + + //************************************************************************* + struct is_state + { + is_state(state_id_t state_id_) + : state_id(state_id_) + { + } + + bool operator()(const state& s) const + { + return (s.state_id == state_id); + } + + const state_id_t state_id; + }; + + // Disabled + state_chart_ctv(const state_chart_ctv&) ETL_DELETE; + state_chart_ctv& operator =(const state_chart_ctv&) ETL_DELETE; + + state_id_t current_state_id; ///< The current state id. + bool started; ///< Set if the state chart has been started. + }; + + //*************************************************************************** + /// Simple Finite State Machine + /// Compile time tables. + /// Event has parameter. + //*************************************************************************** + template * Transition_Table_Begin, + size_t Transition_Table_Size, + const etl::state_chart_traits::state* State_Table_Begin, + size_t State_Table_Size, + etl::state_chart_traits::state_id_t Initial_State> + class state_chart_ctp : public istate_chart + { + public: + + using parameter_t = typename istate_chart::parameter_t; + using state_id_t = typename istate_chart::state_id_t; + using event_id_t = typename istate_chart::event_id_t; + + typedef state_chart_traits::transition transition; + + typedef state_chart_traits::state state; + + //************************************************************************* + /// Constructor. + //************************************************************************* + ETL_CONSTEXPR state_chart_ctp() + : current_state_id(Initial_State) + , started(false) + { + } + + //************************************************************************* + /// Gets a const reference to the implementation object. + /// \return Const reference to the implementation object. + //************************************************************************* + TObject& get_object() + { + return TObject_Ref; + } + + //************************************************************************* + /// Gets a const reference to the implementation object. + /// \return Const reference to the implementation object. + //************************************************************************* + const TObject& get_object() const + { + return TObject_Ref; + } + + //************************************************************************* + /// Gets the current state id. + /// \return The current state id. + //************************************************************************* + const state* find_state(state_id_t state_id) + { + return etl::find_if(State_Table_Begin, State_Table_Begin + State_Table_Size, is_state(state_id)); + } + + //************************************************************************* + /// Start the state chart. + //************************************************************************* + void start(const bool on_entry_initial = true) + { + if (!started) + { + if (on_entry_initial) + { + // See if we have a state item for the initial state. + const state* s = find_state(current_state_id); + + // If the initial state has an 'on_entry' then call it. + if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_entry != ETL_NULLPTR)) + { + (TObject_Ref.*(s->on_entry))(); + } + } + + started = true; + } + } + + //************************************************************************* + /// Processes the specified event. + /// The state machine will action the first item in the transition table + /// that satisfies the conditions for executing the action. + /// \param event_id The id of the event to process. + //************************************************************************* + virtual void process_event(event_id_t event_id, parameter_t data) ETL_OVERRIDE + { + if (started) + { + const transition* t = Transition_Table_Begin; + + // Keep looping until we execute a transition or reach the end of the table. + while (t != (Transition_Table_Begin + Transition_Table_Size)) + { + // Scan the transition table from the latest position. + t = etl::find_if(t, (Transition_Table_Begin + Transition_Table_Size), is_transition(event_id, current_state_id)); + + // Found an entry? + if (t != (Transition_Table_Begin + Transition_Table_Size)) + { + // Shall we execute the transition? + if ((t->guard == ETL_NULLPTR) || ((TObject_Ref.*t->guard)())) + { + // Shall we execute the action? + if (t->action != ETL_NULLPTR) + { +#if ETL_CPP11_SUPPORTED + (TObject_Ref.*t->action)(etl::forward(data)); +#else + (TObject_Ref.*t->action)(data); +#endif + } + + // Changing state? + if (current_state_id != t->next_state_id) + { + const state* s; + + // See if we have a state item for the current state. + s = find_state(current_state_id); + + // If the current state has an 'on_exit' then call it. + if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_exit != ETL_NULLPTR)) + { + (TObject_Ref.*(s->on_exit))(); + } + + current_state_id = t->next_state_id; + + // See if we have a state item for the new state. + s = find_state(current_state_id); + + // If the new state has an 'on_entry' then call it. + if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_entry != ETL_NULLPTR)) + { + (TObject_Ref.*(s->on_entry))(); + } + } + + t = (Transition_Table_Begin + Transition_Table_Size); + } + else + { + // Start the search from the next item in the table. + ++t; + } + } + } + } + } + + //************************************************************************* + /// Gets the current state id. + /// \return The current state id. + //************************************************************************* + state_id_t get_state_id() const + { + return current_state_id; + } + + private: + + //************************************************************************* + struct is_transition + { + is_transition(event_id_t event_id_, state_id_t state_id_) + : event_id(event_id_) + , state_id(state_id_) + { + } + + bool operator()(const transition& t) const + { + return (t.event_id == event_id) && (t.from_any_state || (t.current_state_id == state_id)); + } + + const event_id_t event_id; + const state_id_t state_id; + }; + + //************************************************************************* + struct is_state + { + is_state(state_id_t state_id_) + : state_id(state_id_) + { + } + + bool operator()(const state& s) const + { + return (s.state_id == state_id); + } + + const state_id_t state_id; + }; + + // Disabled + state_chart_ctp(const state_chart_ctp&) ETL_DELETE; + state_chart_ctp& operator =(const state_chart_ctp&) ETL_DELETE; + + state_id_t current_state_id; ///< The current state id. + bool started; ///< Set if the state chart has been started. + }; + + //*************************************************************************** + /// Simple Finite State Machine + /// Runtime tables. + /// Event has a parameter. + //*************************************************************************** + template + class state_chart : public istate_chart + { + public: + + using parameter_t = typename istate_chart::parameter_t; + using state_id_t = typename istate_chart::state_id_t; + using event_id_t = typename istate_chart::event_id_t; + + typedef state_chart_traits::transition transition; + typedef state_chart_traits::state state; + //************************************************************************* /// Constructor. /// \param object_ A reference to the implementation object. @@ -211,19 +621,19 @@ namespace etl /// \param state_table_end_ The end of the state table. /// \param state_id_ The initial state id. //************************************************************************* - ETL_CONSTEXPR state_chart(TObject& object_, - const transition* const transition_table_begin_, - const transition* const transition_table_end_, - const state* const state_table_begin_, - const state* const state_table_end_, - const state_id_t state_id_) - : current_state_id(state_id_), - object(object_), - transition_table_begin(transition_table_begin_), - state_table_begin(state_table_begin_), - transition_table_size(transition_table_end_ - transition_table_begin_), - state_table_size(state_table_end_ - state_table_begin_), - started(false) + ETL_CONSTEXPR state_chart(TObject& object_, + const transition* transition_table_begin_, + const transition* transition_table_end_, + const state* state_table_begin_, + const state* state_table_end_, + const state_id_t state_id_) + : object(object_) + , transition_table_begin(transition_table_begin_) + , state_table_begin(state_table_begin_) + , transition_table_size(transition_table_end_ - transition_table_begin_) + , state_table_size(state_table_end_ - state_table_begin_) + , current_state_id(state_id_) + , started(false) { } @@ -233,10 +643,10 @@ namespace etl /// \param state_table_end_ The end of the state table. //************************************************************************* void set_transition_table(const transition* transition_table_begin_, - const transition* transition_table_end_) + const transition* transition_table_end_) { transition_table_begin = transition_table_begin_; - transition_table_size = transition_table_end_ - transition_table_begin_; + transition_table_size = transition_table_end_ - transition_table_begin_; } //************************************************************************* @@ -245,10 +655,10 @@ namespace etl /// \param state_table_end_ The end of the state table. //************************************************************************* void set_state_table(const state* state_table_begin_, - const state* state_table_end_) + const state* state_table_end_) { state_table_begin = state_table_begin_; - state_table_size = state_table_end_ - state_table_begin_; + state_table_size = state_table_end_ - state_table_begin_; } //************************************************************************* @@ -281,9 +691,7 @@ namespace etl } else { - return etl::find_if(state_table_begin, - state_table_end(), - is_state(state_id)); + return etl::find_if(state_table_begin, state_table_end(), is_state(state_id)); } } @@ -316,19 +724,7 @@ namespace etl /// that satisfies the conditions for executing the action. /// \param event_id The id of the event to process. //************************************************************************* - void process_event(const event_id_t event_id) - { - process_event(event_id, typename etl::types::type()); - } - - //************************************************************************* - /// Processes the specified event. - /// The state machine will action the first item in the transition table - /// that satisfies the conditions for executing the action. - /// \param event_id The id of the event to process. - /// \param data The data to pass to the action. - //************************************************************************* - void process_event(const event_id_t event_id, parameter_t data) + void process_event(event_id_t event_id, parameter_t data) { if (started) { @@ -338,9 +734,7 @@ namespace etl while (t != transition_table_end()) { // Scan the transition table from the latest position. - t = etl::find_if(t, - transition_table_end(), - is_transition(event_id, current_state_id)); + t = etl::find_if(t, transition_table_end(), is_transition(event_id, current_state_id)); // Found an entry? if (t != transition_table_end()) @@ -405,14 +799,6 @@ namespace etl return current_state_id; } - //************************************************************************* - /// Get a delegate to the process_event function. - //************************************************************************* - delegate_t get_process_event_delegate() - { - return delegate_t::template create, &state_chart::process_event>(*this); - } - private: //************************************************************************* @@ -476,36 +862,20 @@ namespace etl //*************************************************************************** /// Simple Finite State Machine + /// Runtime tables. + /// Event has no parameter. //*************************************************************************** template - class state_chart : public istate_chart + class state_chart : public istate_chart { public: - typedef etl::delegate delegate_t; - typedef state_chart_types::transition transition; - typedef state_chart_types::state state; + using parameter_t = typename istate_chart::parameter_t; + using state_id_t = typename istate_chart::state_id_t; + using event_id_t = typename istate_chart::event_id_t; - //************************************************************************* - /// Constructor. - /// \param object_ A reference to the implementation object. - /// \param transition_table_begin_ The start of the table of transitions. - /// \param transition_table_end_ The end of the table of transitions. - /// \param state_id_ The initial state id. - //************************************************************************* - ETL_CONSTEXPR state_chart(TObject& object_, - const transition* transition_table_begin_, - const transition* transition_table_end_, - const state_id_t state_id_) - : current_state_id(state_id_) - , object(object_) - , transition_table_begin(transition_table_begin_) - , state_table_begin(ETL_NULLPTR) - , transition_table_size(transition_table_end_ - transition_table_begin_) - , state_table_size(0U) - , started(false) - { - } + typedef state_chart_traits::transition transition; + typedef state_chart_traits::state state; //************************************************************************* /// Constructor. @@ -516,18 +886,18 @@ namespace etl /// \param state_table_end_ The end of the state table. /// \param state_id_ The initial state id. //************************************************************************* - ETL_CONSTEXPR state_chart(TObject& object_, + ETL_CONSTEXPR state_chart(TObject& object_, const transition* transition_table_begin_, const transition* transition_table_end_, - const state* state_table_begin_, - const state* state_table_end_, - const state_id_t state_id_) - : current_state_id(state_id_) - , object(object_) + const state* state_table_begin_, + const state* state_table_end_, + const state_id_t state_id_) + : object(object_) , transition_table_begin(transition_table_begin_) , state_table_begin(state_table_begin_) , transition_table_size(transition_table_end_ - transition_table_begin_) , state_table_size(state_table_end_ - state_table_begin_) + , current_state_id(state_id_) , started(false) { } @@ -586,9 +956,7 @@ namespace etl } else { - return etl::find_if(state_table_begin, - state_table_end(), - is_state(state_id)); + return etl::find_if(state_table_begin, state_table_end(), is_state(state_id)); } } @@ -621,7 +989,7 @@ namespace etl /// that satisfies the conditions for executing the action. /// \param event_id The id of the event to process. //************************************************************************* - void process_event(const event_id_t event_id) + void process_event(event_id_t event_id) { if (started) { @@ -631,9 +999,7 @@ namespace etl while (t != transition_table_end()) { // Scan the transition table from the latest position. - t = etl::find_if(t, - transition_table_end(), - is_transition(event_id, current_state_id)); + t = etl::find_if(t, transition_table_end(), is_transition(event_id, current_state_id)); // Found an entry? if (t != transition_table_end()) @@ -694,14 +1060,6 @@ namespace etl return current_state_id; } - //************************************************************************* - /// Get a delegate to the process_event function. - //************************************************************************* - delegate_t get_process_event_delegate() - { - return delegate_t::template create, &state_chart::process_event>(*this); - } - private: //************************************************************************* @@ -762,249 +1120,6 @@ namespace etl state_id_t current_state_id; ///< The current state id. bool started; ///< Set if the state chart has been started. }; - - //*************************************************************************** - /// Simple Finite State Machine - //*************************************************************************** - template - class state_chart : public istate_chart - { - public: - - typedef etl::delegate delegate_t; - typedef state_chart_types::transition transition; - typedef state_chart_types::state state; - - //************************************************************************* - /// Constructor. - //************************************************************************* - ETL_CONSTEXPR state_chart() - : current_state_id(InitialState) - , started(false) - { - } - - //************************************************************************* - /// Gets a const reference to the implementation object. - /// \return Const reference to the implementation object. - //************************************************************************* - TObject& get_object() - { - return *reinterpret_cast(TObjectPtr); - } - - //************************************************************************* - /// Gets a const reference to the implementation object. - /// \return Const reference to the implementation object. - //************************************************************************* - const TObject& get_object() const - { - return *reinterpret_cast(TObjectPtr); - } - - //************************************************************************* - /// Gets the current state id. - /// \return The current state id. - //************************************************************************* - const state* find_state(state_id_t state_id) - { - if (StateListBegin == ETL_NULLPTR) - { - return state_table_end(); - } - else - { - return etl::find_if(state_table_begin(), - state_table_end(), - is_state(state_id)); - } - } - - //************************************************************************* - /// Start the state chart. - //************************************************************************* - void start(const bool on_entry_initial = true) - { - if (!started) - { - if (on_entry_initial) - { - // See if we have a state item for the initial state. - const state* s = find_state(current_state_id); - - // If the initial state has an 'on_entry' then call it. - if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR)) - { - (get_object().*(s->on_entry))(); - } - } - - started = true; - } - } - - //************************************************************************* - /// Processes the specified event. - /// The state machine will action the first item in the transition table - /// that satisfies the conditions for executing the action. - /// \param event_id The id of the event to process. - //************************************************************************* - void process_event(const event_id_t event_id) - { - if (started) - { - const transition* t = transition_table_begin(); - - // Keep looping until we execute a transition or reach the end of the table. - while (t != transition_table_end()) - { - // Scan the transition table from the latest position. - t = etl::find_if(t, - transition_table_end(), - is_transition(event_id, current_state_id)); - - // Found an entry? - if (t != transition_table_end()) - { - TObject& object = get_object(); - - // Shall we execute the transition? - if ((t->guard == ETL_NULLPTR) || ((object.*t->guard)())) - { - // Shall we execute the action? - if (t->action != ETL_NULLPTR) - { - (object.*t->action)(); - } - - // Changing state? - if (current_state_id != t->next_state_id) - { - const state* s; - - // See if we have a state item for the current state. - s = find_state(current_state_id); - - // If the current state has an 'on_exit' then call it. - if ((s != state_table_end()) && (s->on_exit != ETL_NULLPTR)) - { - (object.*(s->on_exit))(); - } - - current_state_id = t->next_state_id; - - // See if we have a state item for the new state. - s = find_state(current_state_id); - - // If the new state has an 'on_entry' then call it. - if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR)) - { - (object.*(s->on_entry))(); - } - } - - t = transition_table_end(); - } - else - { - // Start the search from the next item in the table. - ++t; - } - } - } - } - } - - //************************************************************************* - /// Gets the current state id. - /// \return The current state id. - //************************************************************************* - state_id_t get_state_id() const - { - return current_state_id; - } - - //************************************************************************* - /// Get a delegate to the process_event function. - //************************************************************************* - delegate_t get_process_event_delegate() - { - return delegate_t::template create, &state_chart::process_event>(*this); - } - - private: - - //************************************************************************* - const transition* const transition_table_begin() const - { - return reinterpret_cast(TransitionListBegin); - } - - //************************************************************************* - const transition* const transition_table_end() const - { - return reinterpret_cast(TransitionListBegin) + TransitionListSize; - } - - //************************************************************************* - const state* const state_table_begin() const - { - return reinterpret_cast(StateListBegin); - } - - //************************************************************************* - const state* const state_table_end() const - { - return reinterpret_cast(StateListBegin) + StateListSize; - } - - //************************************************************************* - struct is_transition - { - is_transition(event_id_t event_id_, state_id_t state_id_) - : event_id(event_id_) - , state_id(state_id_) - { - } - - bool operator()(const transition& t) const - { - return (t.event_id == event_id) && (t.from_any_state || (t.current_state_id == state_id)); - } - - const event_id_t event_id; - const state_id_t state_id; - }; - - //************************************************************************* - struct is_state - { - is_state(state_id_t state_id_) - : state_id(state_id_) - { - } - - bool operator()(const state& s) const - { - return (s.state_id == state_id); - } - - const state_id_t state_id; - }; - - // Disabled - state_chart(const state_chart&) ETL_DELETE; - state_chart& operator =(const state_chart&) ETL_DELETE; - - state_id_t current_state_id; ///< The current state id. - bool started; ///< Set if the state chart has been started. - }; } #endif diff --git a/test/test_state_chart.cpp b/test/test_state_chart.cpp index b8286b5d..80a9c21a 100644 --- a/test/test_state_chart.cpp +++ b/test/test_state_chart.cpp @@ -51,7 +51,7 @@ namespace ABORT }; - ETL_DECLARE_ENUM_TYPE(EventId, etl::istate_chart::event_id_t) + ETL_DECLARE_ENUM_TYPE(EventId, etl::state_chart_traits::event_id_t) ETL_ENUM_TYPE(START, "Start") ETL_ENUM_TYPE(STOP, "Stop") ETL_ENUM_TYPE(EMERGENCY_STOP, "Emergency Stop") @@ -73,7 +73,7 @@ namespace NUMBER_OF_STATES }; - ETL_DECLARE_ENUM_TYPE(StateId, etl::istate_chart::state_id_t) + ETL_DECLARE_ENUM_TYPE(StateId, etl::state_chart_traits::state_id_t) ETL_ENUM_TYPE(IDLE, "Idle") ETL_ENUM_TYPE(RUNNING, "Running") ETL_ENUM_TYPE(WINDING_DOWN, "Winding Down") @@ -88,9 +88,8 @@ namespace public: MotorControl() - : state_chart(*this, transitionTable.begin(), transitionTable.end(), StateId::IDLE) + : etl::state_chart(*this, transitionTable.begin(), transitionTable.end(), stateTable.begin(), stateTable.end(), StateId::IDLE) { - this->set_state_table(stateTable.begin(), stateTable.end()); ClearStatistics(); } @@ -399,141 +398,141 @@ namespace } //************************************************************************* - TEST(test_state_chart_with_delegate) - { - motorControl.ClearStatistics(); + //TEST(test_state_chart_with_delegate) + //{ + // motorControl.ClearStatistics(); - auto process_event = motorControl.get_process_event_delegate(); + // auto process_event = motorControl.get_process_event_delegate(); - // Start the state chart - motorControl.guard = true; - motorControl.start(); + // // Start the state chart + // motorControl.guard = true; + // motorControl.start(); - // Send unhandled events. - process_event(EventId::STOP); - process_event(EventId::STOPPED); + // // Send unhandled events. + // process_event(EventId::STOP); + // process_event(EventId::STOPPED); - CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + // CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); - CHECK_EQUAL(false, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(0, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(false, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(0, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); - // Send Start event. - motorControl.guard = false; - process_event(EventId::START); + // // Send Start event. + // motorControl.guard = false; + // process_event(EventId::START); - // Still in Idle state. + // // Still in Idle state. - CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + // CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); - CHECK_EQUAL(false, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(0, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(false, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(0, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send Start event. - motorControl.guard = true; - process_event(EventId::START); + // // Send Start event. + // motorControl.guard = true; + // process_event(EventId::START); - // Now in Running state. + // // Now in Running state. - CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + // CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send unhandled events. - process_event(EventId::START); - process_event(EventId::STOPPED); + // // Send unhandled events. + // process_event(EventId::START); + // process_event(EventId::STOPPED); - CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + // CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send SetSpeed event. - process_event(EventId::SET_SPEED); + // // Send SetSpeed event. + // process_event(EventId::SET_SPEED); - // Still in Running state. + // // Still in Running state. - CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + // CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(1, motorControl.setSpeedCount); - CHECK_EQUAL(100, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(1, motorControl.setSpeedCount); + // CHECK_EQUAL(100, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send Stop event. - process_event(EventId::STOP); + // // Send Stop event. + // process_event(EventId::STOP); - // Now in WindingDown state. + // // Now in WindingDown state. - CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); + // CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(1, motorControl.setSpeedCount); - CHECK_EQUAL(100, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(1, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(1, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(1, motorControl.setSpeedCount); + // CHECK_EQUAL(100, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(1, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(1, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send unhandled events. - process_event(EventId::START); - process_event(EventId::STOP); + // // Send unhandled events. + // process_event(EventId::START); + // process_event(EventId::STOP); - CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); + // CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(1, motorControl.setSpeedCount); - CHECK_EQUAL(100, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(1, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(1, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(1, motorControl.setSpeedCount); + // CHECK_EQUAL(100, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(1, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(1, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send Stopped event. - process_event(EventId::STOPPED); + // // Send Stopped event. + // process_event(EventId::STOPPED); - // Now in Idle state. - CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + // // Now in Idle state. + // CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); - CHECK_EQUAL(false, motorControl.isLampOn); - CHECK_EQUAL(1, motorControl.setSpeedCount); - CHECK_EQUAL(100, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(1, motorControl.stopCount); - CHECK_EQUAL(1, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); - } + // CHECK_EQUAL(false, motorControl.isLampOn); + // CHECK_EQUAL(1, motorControl.setSpeedCount); + // CHECK_EQUAL(100, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(1, motorControl.stopCount); + // CHECK_EQUAL(1, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); + //} //************************************************************************* TEST(test_fsm_emergency_stop) diff --git a/test/test_state_chart_compile_time.cpp b/test/test_state_chart_compile_time.cpp index d7f4ec51..7ef25e30 100644 --- a/test/test_state_chart_compile_time.cpp +++ b/test/test_state_chart_compile_time.cpp @@ -33,6 +33,7 @@ SOFTWARE. #include "etl/queue.h" #include "etl/array.h" +#include #include namespace @@ -51,7 +52,7 @@ namespace ABORT }; - ETL_DECLARE_ENUM_TYPE(EventId, etl::istate_chart::event_id_t) + ETL_DECLARE_ENUM_TYPE(EventId, etl::state_chart_traits::event_id_t) ETL_ENUM_TYPE(START, "Start") ETL_ENUM_TYPE(STOP, "Stop") ETL_ENUM_TYPE(EMERGENCY_STOP, "Emergency Stop") @@ -73,7 +74,7 @@ namespace NUMBER_OF_STATES }; - ETL_DECLARE_ENUM_TYPE(StateId, etl::istate_chart::state_id_t) + ETL_DECLARE_ENUM_TYPE(StateId, etl::state_chart_traits::state_id_t) ETL_ENUM_TYPE(IDLE, "Idle") ETL_ENUM_TYPE(RUNNING, "Running") ETL_ENUM_TYPE(WINDING_DOWN, "Winding Down") @@ -206,21 +207,21 @@ namespace }; //*************************************************************************** - using transition = etl::state_chart_types::transition; + using transition = etl::state_chart_traits::transition; constexpr transition transitionTable[7] = { - etl::state_chart_types::transition::transition(StateId::IDLE, EventId::START, StateId::RUNNING, &MotorControl::OnStart, &MotorControl::Guard), - etl::state_chart_types::transition::transition(StateId::IDLE, EventId::START, StateId::IDLE, &MotorControl::Null, &MotorControl::NotGuard), - etl::state_chart_types::transition::transition(StateId::RUNNING, EventId::STOP, StateId::WINDING_DOWN, &MotorControl::OnStop), - etl::state_chart_types::transition::transition(StateId::RUNNING, EventId::EMERGENCY_STOP, StateId::IDLE, &MotorControl::OnStop), - etl::state_chart_types::transition::transition(StateId::RUNNING, EventId::SET_SPEED, StateId::RUNNING, &MotorControl::OnSetSpeed), - etl::state_chart_types::transition::transition(StateId::WINDING_DOWN, EventId::STOPPED, StateId::IDLE, &MotorControl::OnStopped), - etl::state_chart_types::transition::transition( EventId::ABORT, StateId::IDLE) + transition(StateId::IDLE, EventId::START, StateId::RUNNING, &MotorControl::OnStart, &MotorControl::Guard), + transition(StateId::IDLE, EventId::START, StateId::IDLE, &MotorControl::Null, &MotorControl::NotGuard), + transition(StateId::RUNNING, EventId::STOP, StateId::WINDING_DOWN, &MotorControl::OnStop), + transition(StateId::RUNNING, EventId::EMERGENCY_STOP, StateId::IDLE, &MotorControl::OnStop), + transition(StateId::RUNNING, EventId::SET_SPEED, StateId::RUNNING, &MotorControl::OnSetSpeed), + transition(StateId::WINDING_DOWN, EventId::STOPPED, StateId::IDLE, &MotorControl::OnStopped), + transition( EventId::ABORT, StateId::IDLE) }; //*************************************************************************** - using state = etl::state_chart_types::state; + using state = etl::state_chart_traits::state; constexpr state stateTable[3] = { @@ -231,16 +232,15 @@ namespace MotorControl motorControl; - etl::state_chart motorControlStateChart; + etl::state_chart_ctv motorControlStateChart; - SUITE(test_state_chart_class) + SUITE(test_state_chart_compile_time) { //************************************************************************* TEST(test_state_chart) @@ -407,178 +407,178 @@ namespace } //************************************************************************* - TEST(test_state_chart_with_delegate) - { - motorControl.ClearStatistics(); + //TEST(test_state_chart_with_delegate) + //{ + // motorControl.ClearStatistics(); - auto process_event = motorControlStateChart.get_process_event_delegate(); + // auto process_event = motorControlStateChart.get_process_event_delegate(); - // Start the state chart - motorControl.guard = true; - motorControlStateChart.start(); + // // Start the state chart + // motorControl.guard = true; + // motorControlStateChart.start(); - // Send unhandled events. - process_event(EventId::STOP); - process_event(EventId::STOPPED); + // // Send unhandled events. + // process_event(EventId::STOP); + // process_event(EventId::STOPPED); - CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + // CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(false, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(0, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(false, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(0, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); - // Send Start event. - motorControl.guard = false; - process_event(EventId::START); + // // Send Start event. + // motorControl.guard = false; + // process_event(EventId::START); - // Still in Idle state. + // // Still in Idle state. - CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + // CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(false, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(0, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(false, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(0, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send Start event. - motorControl.guard = true; - process_event(EventId::START); + // // Send Start event. + // motorControl.guard = true; + // process_event(EventId::START); - // Now in Running state. + // // Now in Running state. - CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + // CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send unhandled events. - process_event(EventId::START); - process_event(EventId::STOPPED); + // // Send unhandled events. + // process_event(EventId::START); + // process_event(EventId::STOPPED); - CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + // CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send SetSpeed event. - process_event(EventId::SET_SPEED); + // // Send SetSpeed event. + // process_event(EventId::SET_SPEED); - // Still in Running state. + // // Still in Running state. - CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + // CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(1, motorControl.setSpeedCount); - CHECK_EQUAL(100, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(1, motorControl.setSpeedCount); + // CHECK_EQUAL(100, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send Stop event. - process_event(EventId::STOP); + // // Send Stop event. + // process_event(EventId::STOP); - // Now in WindingDown state. + // // Now in WindingDown state. - CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); + // CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(1, motorControl.setSpeedCount); - CHECK_EQUAL(100, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(1, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(1, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(1, motorControl.setSpeedCount); + // CHECK_EQUAL(100, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(1, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(1, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send unhandled events. - process_event(EventId::START); - process_event(EventId::STOP); + // // Send unhandled events. + // process_event(EventId::START); + // process_event(EventId::STOP); - CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); + // CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(1, motorControl.setSpeedCount); - CHECK_EQUAL(100, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(1, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(1, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(1, motorControl.setSpeedCount); + // CHECK_EQUAL(100, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(1, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(1, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); - // Send Stopped event. - process_event(EventId::STOPPED); + // // Send Stopped event. + // process_event(EventId::STOPPED); - // Now in Idle state. - CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + // // Now in Idle state. + // CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(false, motorControl.isLampOn); - CHECK_EQUAL(1, motorControl.setSpeedCount); - CHECK_EQUAL(100, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(1, motorControl.stopCount); - CHECK_EQUAL(1, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - CHECK_EQUAL(1, motorControl.null); - } + // CHECK_EQUAL(false, motorControl.isLampOn); + // CHECK_EQUAL(1, motorControl.setSpeedCount); + // CHECK_EQUAL(100, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(1, motorControl.stopCount); + // CHECK_EQUAL(1, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(1, motorControl.null); + //} - //************************************************************************* - TEST(test_fsm_emergency_stop) - { - motorControl.ClearStatistics(); + ////************************************************************************* + //TEST(test_fsm_emergency_stop) + //{ + // motorControl.ClearStatistics(); - // Now in Idle state. + // // Now in Idle state. - // Send Start event. - motorControlStateChart.process_event(EventId::START); + // // Send Start event. + // motorControlStateChart.process_event(EventId::START); - // Now in Running state. + // // Now in Running state. - CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + // CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(true, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(0, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); + // CHECK_EQUAL(true, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(0, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); - // Send emergency Stop event. - motorControlStateChart.process_event(EventId::EMERGENCY_STOP); + // // Send emergency Stop event. + // motorControlStateChart.process_event(EventId::EMERGENCY_STOP); - // Now in Idle state. - CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + // // Now in Idle state. + // CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); - CHECK_EQUAL(false, motorControl.isLampOn); - CHECK_EQUAL(0, motorControl.setSpeedCount); - CHECK_EQUAL(0, motorControl.speed); - CHECK_EQUAL(1, motorControl.startCount); - CHECK_EQUAL(1, motorControl.stopCount); - CHECK_EQUAL(0, motorControl.stoppedCount); - CHECK_EQUAL(0, motorControl.windingDown); - } + // CHECK_EQUAL(false, motorControl.isLampOn); + // CHECK_EQUAL(0, motorControl.setSpeedCount); + // CHECK_EQUAL(0, motorControl.speed); + // CHECK_EQUAL(1, motorControl.startCount); + // CHECK_EQUAL(1, motorControl.stopCount); + // CHECK_EQUAL(0, motorControl.stoppedCount); + // CHECK_EQUAL(0, motorControl.windingDown); + //} //************************************************************************* TEST(test_fsm_abort) diff --git a/test/test_state_chart_compile_time_with_data_parameter.cpp b/test/test_state_chart_compile_time_with_data_parameter.cpp new file mode 100644 index 00000000..b993d615 --- /dev/null +++ b/test/test_state_chart_compile_time_with_data_parameter.cpp @@ -0,0 +1,508 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2018 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. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/state_chart.h" +#include "etl/enum_type.h" +#include "etl/queue.h" +#include "etl/array.h" + +#include + +namespace +{ + //*************************************************************************** + // Events + struct EventId + { + enum enum_type + { + START, + STOP, + EMERGENCY_STOP, + STOPPED, + SET_SPEED, + ABORT + }; + + ETL_DECLARE_ENUM_TYPE(EventId, etl::state_chart_traits::event_id_t) + ETL_ENUM_TYPE(START, "Start") + ETL_ENUM_TYPE(STOP, "Stop") + ETL_ENUM_TYPE(EMERGENCY_STOP, "Emergency Stop") + ETL_ENUM_TYPE(STOPPED, "Stopped") + ETL_ENUM_TYPE(SET_SPEED, "Set Speed") + ETL_ENUM_TYPE(ABORT, "Abort") + ETL_END_ENUM_TYPE + }; + + //*************************************************************************** + // States + struct StateId + { + enum enum_type + { + IDLE, + RUNNING, + WINDING_DOWN, + NUMBER_OF_STATES + }; + + ETL_DECLARE_ENUM_TYPE(StateId, etl::state_chart_traits::state_id_t) + ETL_ENUM_TYPE(IDLE, "Idle") + ETL_ENUM_TYPE(RUNNING, "Running") + ETL_ENUM_TYPE(WINDING_DOWN, "Winding Down") + ETL_END_ENUM_TYPE + }; + + //*********************************** + // The motor control FSM. + //*********************************** + class MotorControl + { + public: + + MotorControl() + { + ClearStatistics(); + } + + //*********************************** + void ClearStatistics() + { + startCount = 0; + stopCount = 0; + setSpeedCount = 0; + stoppedCount = 0; + isLampOn = false; + speed = 0; + windingDown = 0; + entered_idle = false; + null = 0; + data = 0; + } + + //*********************************** + void OnStart(int d) + { + data = d; + ++startCount; + } + + //*********************************** + void OnStop(int d) + { + data = d; + ++stopCount; + } + + //*********************************** + void OnStopped(int d) + { + data = d; + ++stoppedCount; + } + + //*********************************** + void OnSetSpeed(int d) + { + data = d; + ++setSpeedCount; + SetSpeedValue(100); + } + + //*********************************** + void OnEnterIdle() + { + TurnRunningLampOff(); + entered_idle = true; + } + + //*********************************** + void OnEnterRunning() + { + TurnRunningLampOn(); + } + + //*********************************** + void OnEnterWindingDown() + { + ++windingDown; + } + + //*********************************** + void OnExitWindingDown() + { + --windingDown; + } + + //*********************************** + void SetSpeedValue(int speed_) + { + speed = speed_; + } + + //*********************************** + bool Guard() + { + return guard; + } + + //*********************************** + bool NotGuard() + { + return !guard; + } + + //*********************************** + void TurnRunningLampOn() + { + isLampOn = true; + } + + //*********************************** + void TurnRunningLampOff() + { + isLampOn = false; + } + + //*********************************** + void Null(int d) + { + data = d; + ++null; + } + + int startCount; + int stopCount; + int setSpeedCount; + int stoppedCount; + bool isLampOn; + int speed; + int windingDown; + bool entered_idle; + int null; + int data; + + bool guard; + }; + + //*************************************************************************** + using transition = etl::state_chart_traits::transition; + + constexpr transition transitionTable[7] = + { + transition(StateId::IDLE, EventId::START, StateId::RUNNING, &MotorControl::OnStart, &MotorControl::Guard), + transition(StateId::IDLE, EventId::START, StateId::IDLE, &MotorControl::Null, &MotorControl::NotGuard), + transition(StateId::RUNNING, EventId::STOP, StateId::WINDING_DOWN, &MotorControl::OnStop), + transition(StateId::RUNNING, EventId::EMERGENCY_STOP, StateId::IDLE, &MotorControl::OnStop), + transition(StateId::RUNNING, EventId::SET_SPEED, StateId::RUNNING, &MotorControl::OnSetSpeed), + transition(StateId::WINDING_DOWN, EventId::STOPPED, StateId::IDLE, &MotorControl::OnStopped), + transition(EventId::ABORT, StateId::IDLE) + }; + + //*************************************************************************** + using state = etl::state_chart_traits::state; + + constexpr state stateTable[3] = + { + state(StateId::IDLE, &MotorControl::OnEnterIdle, nullptr), + state(StateId::RUNNING, &MotorControl::OnEnterRunning, nullptr), + state(StateId::WINDING_DOWN, &MotorControl::OnEnterWindingDown, &MotorControl::OnExitWindingDown) + }; + + MotorControl motorControl; + + etl::state_chart_ctp motorControlStateChart; + + SUITE(test_state_chart_compile_time_with_data_parameter) + { + //************************************************************************* + TEST(test_state_chart) + { + motorControl.ClearStatistics(); + + // In Idle state. + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(false, motorControl.entered_idle); + + // Send Start event (state chart not started). + motorControl.guard = true; + motorControlStateChart.process_event(EventId::START, 1); + + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(0, motorControl.data); + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(false, motorControl.entered_idle); + + // Start the state chart + motorControl.guard = true; + motorControlStateChart.start(); + + CHECK_EQUAL(true, motorControl.entered_idle); + + // Send unhandled events. + motorControlStateChart.process_event(EventId::STOP, 2); + motorControlStateChart.process_event(EventId::STOPPED, 3); + + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(0, motorControl.data); + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + + // Send Start event. + motorControl.guard = false; + motorControlStateChart.process_event(EventId::START, 4); + + // Still in Idle state. + + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(4, motorControl.data); + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Start event. + motorControl.guard = true; + motorControlStateChart.process_event(EventId::START, 5); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(5, motorControl.data); + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send unhandled events. + motorControlStateChart.process_event(EventId::START, 6); + motorControlStateChart.process_event(EventId::STOPPED, 7); + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(5, motorControl.data); + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send SetSpeed event. + motorControlStateChart.process_event(EventId::SET_SPEED, 8); + + // Still in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(8, motorControl.data); + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Stop event. + motorControlStateChart.process_event(EventId::STOP, 9); + + // Now in WindingDown state. + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(9, motorControl.data); + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(1, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send unhandled events. + motorControlStateChart.process_event(EventId::START, 10); + motorControlStateChart.process_event(EventId::STOP, 11); + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(9, motorControl.data); + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(1, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + + // Send Stopped event. + motorControlStateChart.process_event(EventId::STOPPED, 12); + + // Now in Idle state. + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(12, motorControl.data); + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(1, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(1, motorControl.null); + } + + //************************************************************************* + TEST(test_fsm_emergency_stop) + { + motorControl.ClearStatistics(); + + // Now in Idle state. + + // Send Start event. + motorControlStateChart.process_event(EventId::START, 1); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(1, motorControl.data); + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + + // Send emergency Stop event. + motorControlStateChart.process_event(EventId::EMERGENCY_STOP, 2); + + // Now in Idle state. + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + + CHECK_EQUAL(2, motorControl.data); + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.windingDown); + } + + //************************************************************************* + TEST(test_fsm_abort) + { + motorControl.ClearStatistics(); + + // Now in Idle state. + + // Send Start event. + motorControlStateChart.process_event(EventId::START, 1); + + int state = int(motorControlStateChart.get_state_id()); + int check = StateId::RUNNING; + + // Now in Running state. + + // Send abort event. + motorControlStateChart.process_event(EventId::ABORT, 2); + + state = int(motorControlStateChart.get_state_id()); + check = StateId::IDLE; + + CHECK_EQUAL(check, state); + //CHECK_EQUAL(StateId::IDLE, state); + //CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + + // Send Start event. + motorControlStateChart.process_event(EventId::START, 3); + + // Now in Running state. + + state = int(motorControlStateChart.get_state_id()); + check = StateId::RUNNING; + + // Send Stop event. + motorControlStateChart.process_event(EventId::STOP, 4); + + state = int(motorControlStateChart.get_state_id()); + check = StateId::WINDING_DOWN; + + // Now in WindingDown state. + motorControlStateChart.process_event(EventId::ABORT, 5); + CHECK_EQUAL(StateId::IDLE, int(motorControlStateChart.get_state_id())); + } + }; +} diff --git a/test/test_state_chart_with_data_parameter.cpp b/test/test_state_chart_with_data_parameter.cpp index ddfbe6f8..9d8963ca 100644 --- a/test/test_state_chart_with_data_parameter.cpp +++ b/test/test_state_chart_with_data_parameter.cpp @@ -51,7 +51,7 @@ namespace ABORT }; - ETL_DECLARE_ENUM_TYPE(EventId, etl::istate_chart::event_id_t) + ETL_DECLARE_ENUM_TYPE(EventId, etl::state_chart_traits::event_id_t) ETL_ENUM_TYPE(START, "Start") ETL_ENUM_TYPE(STOP, "Stop") ETL_ENUM_TYPE(EMERGENCY_STOP, "Emergency Stop") @@ -73,7 +73,7 @@ namespace NUMBER_OF_STATES }; - ETL_DECLARE_ENUM_TYPE(StateId, etl::istate_chart::state_id_t) + ETL_DECLARE_ENUM_TYPE(StateId, etl::state_chart_traits::state_id_t) ETL_ENUM_TYPE(IDLE, "Idle") ETL_ENUM_TYPE(RUNNING, "Running") ETL_ENUM_TYPE(WINDING_DOWN, "Winding Down") @@ -88,9 +88,8 @@ namespace public: MotorControl() - : state_chart(*this, transitionTable.begin(), transitionTable.end(), StateId::IDLE) + : etl::state_chart(*this, transitionTable.begin(), transitionTable.end(), stateTable.begin(), stateTable.end(), StateId::IDLE) { - this->set_state_table(stateTable.begin(), stateTable.end()); ClearStatistics(); } @@ -239,7 +238,7 @@ namespace MotorControl motorControl; - SUITE(test_state_chart_class) + SUITE(test_state_chart_with_data_parameter) { //************************************************************************* TEST(test_state_chart) diff --git a/test/test_state_chart_with_rvalue_data_parameter.cpp b/test/test_state_chart_with_rvalue_data_parameter.cpp index 4c6e2223..4b73e3a8 100644 --- a/test/test_state_chart_with_rvalue_data_parameter.cpp +++ b/test/test_state_chart_with_rvalue_data_parameter.cpp @@ -51,7 +51,7 @@ namespace ABORT }; - ETL_DECLARE_ENUM_TYPE(EventId, etl::istate_chart::event_id_t) + ETL_DECLARE_ENUM_TYPE(EventId, etl::state_chart_traits::event_id_t) ETL_ENUM_TYPE(START, "Start") ETL_ENUM_TYPE(STOP, "Stop") ETL_ENUM_TYPE(EMERGENCY_STOP, "Emergency Stop") @@ -73,7 +73,7 @@ namespace NUMBER_OF_STATES }; - ETL_DECLARE_ENUM_TYPE(StateId, etl::istate_chart::state_id_t) + ETL_DECLARE_ENUM_TYPE(StateId, etl::state_chart_traits::state_id_t) ETL_ENUM_TYPE(IDLE, "Idle") ETL_ENUM_TYPE(RUNNING, "Running") ETL_ENUM_TYPE(WINDING_DOWN, "Winding Down") @@ -119,9 +119,8 @@ namespace public: MotorControl() - : state_chart(*this, transitionTable.begin(), transitionTable.end(), StateId::IDLE) + : state_chart(*this, transitionTable.begin(), transitionTable.end(), stateTable.begin(), stateTable.end(), StateId::IDLE) { - this->set_state_table(stateTable.begin(), stateTable.end()); ClearStatistics(); } @@ -273,7 +272,7 @@ namespace SUITE(test_state_chart_class) { //************************************************************************* - TEST(test_state_chart) + TEST(test_state_chart_with_rvalue_data_parameter) { motorControl.ClearStatistics(); diff --git a/test/test_unaligned_type.cpp b/test/test_unaligned_type.cpp index 413a4a62..a5464779 100644 --- a/test/test_unaligned_type.cpp +++ b/test/test_unaligned_type.cpp @@ -150,7 +150,7 @@ namespace CHECK_EQUAL(sizeof(signed char), etl::host_schar_t::Size); CHECK_EQUAL(sizeof(unsigned char), etl::host_uchar_t::Size); CHECK_EQUAL(sizeof(short), etl::host_short_t::Size); - CHECK_EQUAL(sizeof(unsigned short), etl::host_uint_t::Size); + CHECK_EQUAL(sizeof(unsigned short), etl::host_ushort_t::Size); CHECK_EQUAL(sizeof(int), etl::host_int_t::Size); CHECK_EQUAL(sizeof(unsigned int), etl::host_uint_t::Size); CHECK_EQUAL(sizeof(long), etl::host_long_t::Size); @@ -181,12 +181,12 @@ namespace CHECK(etl::le_char_t(0x01) == char(0x01)); CHECK(etl::le_schar_t(0x01) == etl::le_schar_t(0x01)); - CHECK(signed char(0x01) == etl::le_schar_t(0x01)); - CHECK(etl::le_schar_t(0x01) == signed char(0x01)); + CHECK((signed char)(0x01) == etl::le_schar_t(0x01)); + CHECK(etl::le_schar_t(0x01) == (signed char)(0x01)); CHECK(etl::le_uchar_t(0x01U) == etl::le_uchar_t(0x01U)); - CHECK(unsigned char(0x01U) == etl::le_uchar_t(0x01U)); - CHECK(etl::le_uchar_t(0x01U) == unsigned char(0x01U)); + CHECK((unsigned char)(0x01U) == etl::le_uchar_t(0x01U)); + CHECK(etl::le_uchar_t(0x01U) == (unsigned char)(0x01U)); // short CHECK(etl::le_short_t(0x0123) == etl::le_short_t(0x0123)); @@ -194,8 +194,8 @@ namespace CHECK(etl::le_short_t(0x0123) == short(0x0123)); CHECK(etl::le_ushort_t(0x0123) == etl::le_ushort_t(0x0123)); - CHECK(unsigned short(0x0123) == etl::le_ushort_t(0x0123)); - CHECK(etl::le_ushort_t(0x0123) == unsigned short(0x0123)); + CHECK((unsigned short)(0x0123) == etl::le_ushort_t(0x0123)); + CHECK(etl::le_ushort_t(0x0123) == (unsigned short)(0x0123)); // int CHECK(etl::le_int_t(0x012345678) == etl::le_int_t(0x012345678)); @@ -203,8 +203,8 @@ namespace CHECK(etl::le_int_t(0x012345678) == int(0x012345678)); CHECK(etl::le_uint_t(0x012345678U) == etl::le_uint_t(0x012345678U)); - CHECK(unsigned int(0x012345678U) == etl::le_uint_t(0x012345678U)); - CHECK(etl::le_uint_t(0x012345678U) == unsigned int(0x012345678U)); + CHECK((unsigned int)(0x012345678U) == etl::le_uint_t(0x012345678U)); + CHECK(etl::le_uint_t(0x012345678U) == (unsigned int)(0x012345678U)); if (sizeof(long) == 4U) { @@ -214,20 +214,20 @@ namespace CHECK(etl::le_long_t(0x012345678) == long(0x012345678)); CHECK(etl::le_ulong_t(0x012345678U) == etl::le_ulong_t(0x012345678U)); - CHECK(unsigned long(0x012345678U) == etl::le_ulong_t(0x012345678U)); - CHECK(etl::le_ulong_t(0x012345678U) == unsigned long(0x012345678U)); + CHECK((unsigned long)(0x012345678U) == etl::le_ulong_t(0x012345678U)); + CHECK(etl::le_ulong_t(0x012345678U) == (unsigned long)(0x012345678U)); } if (sizeof(long long) == 8U) { // long long CHECK(etl::le_long_long_t(0x0123456789ABCDEF) == etl::le_long_long_t(0x0123456789ABCDEF)); - CHECK(long long(0x0123456789ABCDEF) == etl::le_long_long_t(0x0123456789ABCDEF)); + CHECK((long long)(0x0123456789ABCDEF) == etl::le_long_long_t(0x0123456789ABCDEF)); CHECK(etl::le_long_long_t(0x0123456789ABCDEF) == long long(0x0123456789ABCDEF)); CHECK(etl::le_ulong_long_t(0x0123456789ABCDEFU) == etl::le_ulong_long_t(0x0123456789ABCDEFU)); - CHECK(unsigned long long(0x0123456789ABCDEFU) == etl::le_ulong_long_t(0x0123456789ABCDEFU)); - CHECK(etl::le_ulong_long_t(0x0123456789ABCDEFU) == unsigned long long(0x0123456789ABCDEFU)); + CHECK((unsigned long long)(0x0123456789ABCDEFU) == etl::le_ulong_long_t(0x0123456789ABCDEFU)); + CHECK(etl::le_ulong_long_t(0x0123456789ABCDEFU) == (unsigned long long)(0x0123456789ABCDEFU)); } } @@ -240,12 +240,12 @@ namespace CHECK(etl::le_char_t(0x01) != char(0x02)); CHECK(etl::le_schar_t(0x01) != etl::le_schar_t(0x02)); - CHECK(signed char(0x01) != etl::le_schar_t(0x02)); - CHECK(etl::le_schar_t(0x01) != signed char(0x02)); + CHECK((signed char)(0x01) != etl::le_schar_t(0x02)); + CHECK(etl::le_schar_t(0x01) != (signed char)(0x02)); CHECK(etl::le_uchar_t(0x01U) != etl::le_uchar_t(0x02U)); - CHECK(unsigned char(0x01U) != etl::le_uchar_t(0x02U)); - CHECK(etl::le_uchar_t(0x01U) != unsigned char(0x02U)); + CHECK((unsigned char)(0x01U) != etl::le_uchar_t(0x02U)); + CHECK(etl::le_uchar_t(0x01U) != (unsigned char)(0x02U)); // short CHECK(etl::le_short_t(0x0123) != etl::le_short_t(0x0223)); @@ -253,8 +253,8 @@ namespace CHECK(etl::le_short_t(0x0123) != short(0x0223)); CHECK(etl::le_ushort_t(0x0123) != etl::le_ushort_t(0x0223)); - CHECK(unsigned short(0x0123) != etl::le_ushort_t(0x0223)); - CHECK(etl::le_ushort_t(0x0123) != unsigned short(0x0223)); + CHECK((unsigned short)(0x0123) != etl::le_ushort_t(0x0223)); + CHECK(etl::le_ushort_t(0x0123) != (unsigned short)(0x0223)); // int CHECK(etl::le_int_t(0x012345678) != etl::le_int_t(0x022345678)); @@ -262,8 +262,8 @@ namespace CHECK(etl::le_int_t(0x012345678) != int(0x022345678)); CHECK(etl::le_uint_t(0x012345678U) != etl::le_uint_t(0x022345678U)); - CHECK(unsigned int(0x012345678U) != etl::le_uint_t(0x022345678U)); - CHECK(etl::le_uint_t(0x012345678U) != unsigned int(0x022345678U)); + CHECK((unsigned int)(0x012345678U) != etl::le_uint_t(0x022345678U)); + CHECK(etl::le_uint_t(0x012345678U) != (unsigned int)(0x022345678U)); if (sizeof(long) == 4U) { @@ -273,8 +273,8 @@ namespace CHECK(etl::le_long_t(0x012345678) != long(0x022345678)); CHECK(etl::le_ulong_t(0x012345678U) != etl::le_ulong_t(0x022345678U)); - CHECK(unsigned long(0x012345678U) != etl::le_ulong_t(0x022345678U)); - CHECK(etl::le_ulong_t(0x012345678U) != unsigned long(0x022345678U)); + CHECK((unsigned long)(0x012345678U) != etl::le_ulong_t(0x022345678U)); + CHECK(etl::le_ulong_t(0x012345678U) != (unsigned long)(0x022345678U)); } if (sizeof(long long) == 8U) @@ -285,8 +285,8 @@ namespace CHECK(etl::le_long_long_t(0x0123456789ABCDEF) != long long(0x0223456789ABCDEF)); CHECK(etl::le_ulong_long_t(0x0123456789ABCDEFU) != etl::le_ulong_long_t(0x0223456789ABCDEFU)); - CHECK(unsigned long long(0x0123456789ABCDEFU) != etl::le_ulong_long_t(0x0223456789ABCDEFU)); - CHECK(etl::le_ulong_long_t(0x0123456789ABCDEFU) != unsigned long long(0x0223456789ABCDEFU)); + CHECK((unsigned long long)(0x0123456789ABCDEFU) != etl::le_ulong_long_t(0x0223456789ABCDEFU)); + CHECK(etl::le_ulong_long_t(0x0123456789ABCDEFU) != (unsigned long long)(0x0223456789ABCDEFU)); } } @@ -299,12 +299,12 @@ namespace CHECK(etl::be_char_t(0x01) == char(0x01)); CHECK(etl::be_schar_t(0x01) == etl::be_schar_t(0x01)); - CHECK(signed char(0x01) == etl::be_schar_t(0x01)); - CHECK(etl::be_schar_t(0x01) == signed char(0x01)); + CHECK((signed char)(0x01) == etl::be_schar_t(0x01)); + CHECK(etl::be_schar_t(0x01) == (signed char)(0x01)); CHECK(etl::be_uchar_t(0x01U) == etl::be_uchar_t(0x01U)); - CHECK(unsigned char(0x01U) == etl::be_uchar_t(0x01U)); - CHECK(etl::be_uchar_t(0x01U) == unsigned char(0x01U)); + CHECK((unsigned char)(0x01U) == etl::be_uchar_t(0x01U)); + CHECK(etl::be_uchar_t(0x01U) == (unsigned char)(0x01U)); // short CHECK(etl::be_short_t(0x0123) == etl::be_short_t(0x0123)); @@ -312,8 +312,8 @@ namespace CHECK(etl::be_short_t(0x0123) == short(0x0123)); CHECK(etl::be_ushort_t(0x0123) == etl::be_ushort_t(0x0123)); - CHECK(unsigned short(0x0123) == etl::be_ushort_t(0x0123)); - CHECK(etl::be_ushort_t(0x0123) == unsigned short(0x0123)); + CHECK((unsigned short)(0x0123) == etl::be_ushort_t(0x0123)); + CHECK(etl::be_ushort_t(0x0123) == (unsigned short)(0x0123)); // int CHECK(etl::be_int_t(0x012345678) == etl::be_int_t(0x012345678)); @@ -321,8 +321,8 @@ namespace CHECK(etl::be_int_t(0x012345678) == int(0x012345678)); CHECK(etl::be_uint_t(0x012345678U) == etl::be_uint_t(0x012345678U)); - CHECK(unsigned int(0x012345678U) == etl::be_uint_t(0x012345678U)); - CHECK(etl::be_uint_t(0x012345678U) == unsigned int(0x012345678U)); + CHECK((unsigned int)(0x012345678U) == etl::be_uint_t(0x012345678U)); + CHECK(etl::be_uint_t(0x012345678U) == (unsigned int)(0x012345678U)); if (sizeof(long) == 4U) { @@ -332,8 +332,8 @@ namespace CHECK(etl::be_long_t(0x012345678) == long(0x012345678)); CHECK(etl::be_ulong_t(0x012345678U) == etl::be_ulong_t(0x012345678U)); - CHECK(unsigned long(0x012345678U) == etl::be_ulong_t(0x012345678U)); - CHECK(etl::be_ulong_t(0x012345678U) == unsigned long(0x012345678U)); + CHECK((unsigned long)(0x012345678U) == etl::be_ulong_t(0x012345678U)); + CHECK(etl::be_ulong_t(0x012345678U) == (unsigned long)(0x012345678U)); } if (sizeof(long long) == 8U) @@ -344,8 +344,8 @@ namespace CHECK(etl::be_long_long_t(0x0123456789ABCDEF) == long long(0x0123456789ABCDEF)); CHECK(etl::be_ulong_long_t(0x0123456789ABCDEFU) == etl::be_ulong_long_t(0x0123456789ABCDEFU)); - CHECK(unsigned long long(0x0123456789ABCDEFU) == etl::be_ulong_long_t(0x0123456789ABCDEFU)); - CHECK(etl::be_ulong_long_t(0x0123456789ABCDEFU) == unsigned long long(0x0123456789ABCDEFU)); + CHECK((unsigned long long)(0x0123456789ABCDEFU) == etl::be_ulong_long_t(0x0123456789ABCDEFU)); + CHECK(etl::be_ulong_long_t(0x0123456789ABCDEFU) == (unsigned long long)(0x0123456789ABCDEFU)); } } @@ -358,12 +358,12 @@ namespace CHECK(etl::be_char_t(0x01) != char(0x02)); CHECK(etl::be_schar_t(0x01) != etl::be_schar_t(0x02)); - CHECK(signed char(0x01) != etl::be_schar_t(0x02)); - CHECK(etl::be_schar_t(0x01) != signed char(0x02)); + CHECK((signed char)(0x01) != etl::be_schar_t(0x02)); + CHECK(etl::be_schar_t(0x01) != (signed char)(0x02)); CHECK(etl::be_uchar_t(0x01U) != etl::be_uchar_t(0x02U)); - CHECK(unsigned char(0x01U) != etl::be_uchar_t(0x02U)); - CHECK(etl::be_uchar_t(0x01U) != unsigned char(0x02U)); + CHECK((unsigned char)(0x01U) != etl::be_uchar_t(0x02U)); + CHECK(etl::be_uchar_t(0x01U) != (unsigned char)(0x02U)); // short CHECK(etl::be_short_t(0x0123) != etl::be_short_t(0x0223)); @@ -371,8 +371,8 @@ namespace CHECK(etl::be_short_t(0x0123) != short(0x0223)); CHECK(etl::be_ushort_t(0x0123) != etl::be_ushort_t(0x0223)); - CHECK(unsigned short(0x0123) != etl::be_ushort_t(0x0223)); - CHECK(etl::be_ushort_t(0x0123) != unsigned short(0x0223)); + CHECK((unsigned short)(0x0123) != etl::be_ushort_t(0x0223)); + CHECK(etl::be_ushort_t(0x0123) != (unsigned short)(0x0223)); // int CHECK(etl::be_int_t(0x012345678) != etl::be_int_t(0x022345678)); @@ -380,8 +380,8 @@ namespace CHECK(etl::be_int_t(0x012345678) != int(0x022345678)); CHECK(etl::be_uint_t(0x012345678U) != etl::be_uint_t(0x022345678U)); - CHECK(unsigned int(0x012345678U) != etl::be_uint_t(0x022345678U)); - CHECK(etl::be_uint_t(0x012345678U) != unsigned int(0x022345678U)); + CHECK((unsigned int)(0x012345678U) != etl::be_uint_t(0x022345678U)); + CHECK(etl::be_uint_t(0x012345678U) != (unsigned int)(0x022345678U)); if (sizeof(long) == 4U) { @@ -391,8 +391,8 @@ namespace CHECK(etl::be_long_t(0x012345678) != long(0x022345678)); CHECK(etl::be_ulong_t(0x012345678U) != etl::be_ulong_t(0x022345678U)); - CHECK(unsigned long(0x012345678U) != etl::be_ulong_t(0x022345678U)); - CHECK(etl::be_ulong_t(0x012345678U) != unsigned long(0x022345678U)); + CHECK((unsigned long)(0x012345678U) != etl::be_ulong_t(0x022345678U)); + CHECK(etl::be_ulong_t(0x012345678U) != (unsigned long)(0x022345678U)); } if (sizeof(long long) == 8U) @@ -403,8 +403,8 @@ namespace CHECK(etl::be_long_long_t(0x0123456789ABCDEF) != long long(0x0223456789ABCDEF)); CHECK(etl::be_ulong_long_t(0x0123456789ABCDEFU) != etl::be_ulong_long_t(0x0223456789ABCDEFU)); - CHECK(unsigned long long(0x0123456789ABCDEFU) != etl::be_ulong_long_t(0x0223456789ABCDEFU)); - CHECK(etl::be_ulong_long_t(0x0123456789ABCDEFU) != unsigned long long(0x0223456789ABCDEFU)); + CHECK((unsigned long long)(0x0123456789ABCDEFU) != etl::be_ulong_long_t(0x0223456789ABCDEFU)); + CHECK(etl::be_ulong_long_t(0x0123456789ABCDEFU) != (unsigned long long)(0x0223456789ABCDEFU)); } } diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 08689ef4..4e11555c 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -9457,6 +9457,8 @@ + + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index d2667243..f0ceaa54 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -3101,6 +3101,12 @@ Tests + + Tests + + + Tests + From 9a03489c4cb7a102505bacced5647e62ae1b1f6f Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 20 Jan 2022 11:05:21 +0000 Subject: [PATCH 6/8] Fixed casting --- test/test_unaligned_type.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/test_unaligned_type.cpp b/test/test_unaligned_type.cpp index a5464779..2c0e4213 100644 --- a/test/test_unaligned_type.cpp +++ b/test/test_unaligned_type.cpp @@ -223,7 +223,7 @@ namespace // long long CHECK(etl::le_long_long_t(0x0123456789ABCDEF) == etl::le_long_long_t(0x0123456789ABCDEF)); CHECK((long long)(0x0123456789ABCDEF) == etl::le_long_long_t(0x0123456789ABCDEF)); - CHECK(etl::le_long_long_t(0x0123456789ABCDEF) == long long(0x0123456789ABCDEF)); + CHECK(etl::le_long_long_t(0x0123456789ABCDEF) == (long long)(0x0123456789ABCDEF)); CHECK(etl::le_ulong_long_t(0x0123456789ABCDEFU) == etl::le_ulong_long_t(0x0123456789ABCDEFU)); CHECK((unsigned long long)(0x0123456789ABCDEFU) == etl::le_ulong_long_t(0x0123456789ABCDEFU)); @@ -281,8 +281,8 @@ namespace { // long long CHECK(etl::le_long_long_t(0x0123456789ABCDEF) != etl::le_long_long_t(0x0223456789ABCDEF)); - CHECK(long long(0x0123456789ABCDEF) != etl::le_long_long_t(0x0223456789ABCDEF)); - CHECK(etl::le_long_long_t(0x0123456789ABCDEF) != long long(0x0223456789ABCDEF)); + CHECK((long long)(0x0123456789ABCDEF) != etl::le_long_long_t(0x0223456789ABCDEF)); + CHECK(etl::le_long_long_t(0x0123456789ABCDEF) != (long long)(0x0223456789ABCDEF)); CHECK(etl::le_ulong_long_t(0x0123456789ABCDEFU) != etl::le_ulong_long_t(0x0223456789ABCDEFU)); CHECK((unsigned long long)(0x0123456789ABCDEFU) != etl::le_ulong_long_t(0x0223456789ABCDEFU)); @@ -340,8 +340,8 @@ namespace { // long long CHECK(etl::be_long_long_t(0x0123456789ABCDEF) == etl::be_long_long_t(0x0123456789ABCDEF)); - CHECK(long long(0x0123456789ABCDEF) == etl::be_long_long_t(0x0123456789ABCDEF)); - CHECK(etl::be_long_long_t(0x0123456789ABCDEF) == long long(0x0123456789ABCDEF)); + CHECK((long long)(0x0123456789ABCDEF) == etl::be_long_long_t(0x0123456789ABCDEF)); + CHECK(etl::be_long_long_t(0x0123456789ABCDEF) == (long long)(0x0123456789ABCDEF)); CHECK(etl::be_ulong_long_t(0x0123456789ABCDEFU) == etl::be_ulong_long_t(0x0123456789ABCDEFU)); CHECK((unsigned long long)(0x0123456789ABCDEFU) == etl::be_ulong_long_t(0x0123456789ABCDEFU)); @@ -399,8 +399,8 @@ namespace { // long long CHECK(etl::be_long_long_t(0x0123456789ABCDEF) != etl::be_long_long_t(0x0223456789ABCDEF)); - CHECK(long long(0x0123456789ABCDEF) != etl::be_long_long_t(0x0223456789ABCDEF)); - CHECK(etl::be_long_long_t(0x0123456789ABCDEF) != long long(0x0223456789ABCDEF)); + CHECK((long long)(0x0123456789ABCDEF) != etl::be_long_long_t(0x0223456789ABCDEF)); + CHECK(etl::be_long_long_t(0x0123456789ABCDEF) != (long long)(0x0223456789ABCDEF)); CHECK(etl::be_ulong_long_t(0x0123456789ABCDEFU) != etl::be_ulong_long_t(0x0223456789ABCDEFU)); CHECK((unsigned long long)(0x0123456789ABCDEFU) != etl::be_ulong_long_t(0x0223456789ABCDEFU)); From fc59b4e34e2b048568ff580c6d48b4c6e8fa60f0 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 20 Jan 2022 11:05:37 +0000 Subject: [PATCH 7/8] Latest state chart code Reinstated virtual process_event() --- include/etl/state_chart.h | 66 +++++++++---------- ...chart_compile_time_with_data_parameter.cpp | 2 +- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/include/etl/state_chart.h b/include/etl/state_chart.h index 92899c3b..d3c4b8f8 100644 --- a/include/etl/state_chart.h +++ b/include/etl/state_chart.h @@ -165,6 +165,7 @@ namespace etl typedef state_chart_traits::event_id_t event_id_t; virtual void process_event(event_id_t, parameter_t) = 0; + virtual ~istate_chart() {} }; //*************************************************************************** @@ -180,6 +181,7 @@ namespace etl typedef state_chart_traits::event_id_t event_id_t; virtual void process_event(event_id_t) = 0; + virtual ~istate_chart() {} }; //*************************************************************************** @@ -187,23 +189,21 @@ namespace etl /// Compile time tables. /// Event has no parameter. //*************************************************************************** - template * Transition_Table_Begin, - size_t Transition_Table_Size, - const etl::state_chart_traits::state* State_Table_Begin, - size_t State_Table_Size, - etl::state_chart_traits::state_id_t Initial_State> + size_t Transition_Table_Size, + const etl::state_chart_traits::state* State_Table_Begin, + size_t State_Table_Size, + etl::state_chart_traits::state_id_t Initial_State> class state_chart_ctv : public istate_chart { public: - using parameter_t = typename istate_chart::parameter_t; - using state_id_t = typename istate_chart::state_id_t; - using event_id_t = typename istate_chart::event_id_t; - + typedef void parameter_t; + typedef state_chart_traits::state_id_t state_id_t; + typedef state_chart_traits::event_id_t event_id_t; typedef state_chart_traits::transition transition; - typedef state_chart_traits::state state; //************************************************************************* @@ -391,30 +391,28 @@ namespace etl /// Compile time tables. /// Event has parameter. //*************************************************************************** - template * Transition_Table_Begin, - size_t Transition_Table_Size, - const etl::state_chart_traits::state* State_Table_Begin, - size_t State_Table_Size, - etl::state_chart_traits::state_id_t Initial_State> - class state_chart_ctp : public istate_chart + size_t Transition_Table_Size, + const etl::state_chart_traits::state* State_Table_Begin, + size_t State_Table_Size, + etl::state_chart_traits::state_id_t Initial_State> + class state_chart_ct : public istate_chart { public: - using parameter_t = typename istate_chart::parameter_t; - using state_id_t = typename istate_chart::state_id_t; - using event_id_t = typename istate_chart::event_id_t; - + typedef TParameter parameter_t; + typedef state_chart_traits::state_id_t state_id_t; + typedef state_chart_traits::event_id_t event_id_t; typedef state_chart_traits::transition transition; - typedef state_chart_traits::state state; //************************************************************************* /// Constructor. //************************************************************************* - ETL_CONSTEXPR state_chart_ctp() + ETL_CONSTEXPR state_chart_ct() : current_state_id(Initial_State) , started(false) { @@ -588,8 +586,8 @@ namespace etl }; // Disabled - state_chart_ctp(const state_chart_ctp&) ETL_DELETE; - state_chart_ctp& operator =(const state_chart_ctp&) ETL_DELETE; + state_chart_ct(const state_chart_ct&) ETL_DELETE; + state_chart_ct& operator =(const state_chart_ct&) ETL_DELETE; state_id_t current_state_id; ///< The current state id. bool started; ///< Set if the state chart has been started. @@ -605,10 +603,9 @@ namespace etl { public: - using parameter_t = typename istate_chart::parameter_t; - using state_id_t = typename istate_chart::state_id_t; - using event_id_t = typename istate_chart::event_id_t; - + typedef TParameter parameter_t; + typedef state_chart_traits::state_id_t state_id_t; + typedef state_chart_traits::event_id_t event_id_t; typedef state_chart_traits::transition transition; typedef state_chart_traits::state state; @@ -870,10 +867,9 @@ namespace etl { public: - using parameter_t = typename istate_chart::parameter_t; - using state_id_t = typename istate_chart::state_id_t; - using event_id_t = typename istate_chart::event_id_t; - + typedef void parameter_t; + typedef state_chart_traits::state_id_t state_id_t; + typedef state_chart_traits::event_id_t event_id_t; typedef state_chart_traits::transition transition; typedef state_chart_traits::state state; diff --git a/test/test_state_chart_compile_time_with_data_parameter.cpp b/test/test_state_chart_compile_time_with_data_parameter.cpp index b993d615..f0eb1da9 100644 --- a/test/test_state_chart_compile_time_with_data_parameter.cpp +++ b/test/test_state_chart_compile_time_with_data_parameter.cpp @@ -238,7 +238,7 @@ namespace MotorControl motorControl; - etl::state_chart_ctp Date: Sat, 22 Jan 2022 21:11:18 +0000 Subject: [PATCH 8/8] Renamed compile time state machine classes --- include/etl/state_chart.h | 18 +- test/CMakeLists.txt | 4 +- test/test_state_chart_compile_time.cpp | 14 +- ...chart_compile_time_with_data_parameter.cpp | 2 +- test/vs2019/etl.vcxproj.filters | 1682 +++++++++-------- 5 files changed, 885 insertions(+), 835 deletions(-) diff --git a/include/etl/state_chart.h b/include/etl/state_chart.h index d3c4b8f8..7907a545 100644 --- a/include/etl/state_chart.h +++ b/include/etl/state_chart.h @@ -196,7 +196,7 @@ namespace etl const etl::state_chart_traits::state* State_Table_Begin, size_t State_Table_Size, etl::state_chart_traits::state_id_t Initial_State> - class state_chart_ctv : public istate_chart + class state_chart_ct : public istate_chart { public: @@ -209,7 +209,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - ETL_CONSTEXPR state_chart_ctv() + ETL_CONSTEXPR state_chart_ct() : current_state_id(Initial_State) , started(false) { @@ -271,7 +271,7 @@ namespace etl /// that satisfies the conditions for executing the action. /// \param event_id The id of the event to process. //************************************************************************* - virtual void process_event(event_id_t event_id/*, parameter_t data*/) ETL_OVERRIDE + virtual void process_event(event_id_t event_id) ETL_OVERRIDE { if (started) { @@ -379,8 +379,8 @@ namespace etl }; // Disabled - state_chart_ctv(const state_chart_ctv&) ETL_DELETE; - state_chart_ctv& operator =(const state_chart_ctv&) ETL_DELETE; + state_chart_ct(const state_chart_ct&) ETL_DELETE; + state_chart_ct& operator =(const state_chart_ct&) ETL_DELETE; state_id_t current_state_id; ///< The current state id. bool started; ///< Set if the state chart has been started. @@ -399,7 +399,7 @@ namespace etl const etl::state_chart_traits::state* State_Table_Begin, size_t State_Table_Size, etl::state_chart_traits::state_id_t Initial_State> - class state_chart_ct : public istate_chart + class state_chart_ctp : public istate_chart { public: @@ -412,7 +412,7 @@ namespace etl //************************************************************************* /// Constructor. //************************************************************************* - ETL_CONSTEXPR state_chart_ct() + ETL_CONSTEXPR state_chart_ctp() : current_state_id(Initial_State) , started(false) { @@ -586,8 +586,8 @@ namespace etl }; // Disabled - state_chart_ct(const state_chart_ct&) ETL_DELETE; - state_chart_ct& operator =(const state_chart_ct&) ETL_DELETE; + state_chart_ctp(const state_chart_ctp&) ETL_DELETE; + state_chart_ctp& operator =(const state_chart_ctp&) ETL_DELETE; state_id_t current_state_id; ///< The current state id. bool started; ///< Set if the state chart has been started. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f8a755c8..ca5cc316 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -224,6 +224,8 @@ set(TEST_SOURCE_FILES test_state_chart.cpp test_state_chart_with_data_parameter.cpp test_state_chart_with_rvalue_data_parameter.cpp + test_state_chart_compile_time.cpp + test_state_chart_compile_time_with_data_parameter.cpp test_string_char.cpp test_string_char_external_buffer.cpp test_string_stream.cpp @@ -255,7 +257,7 @@ set(TEST_SOURCE_FILES test_type_lookup.cpp test_type_select.cpp test_type_traits.cpp -# test_unaligned_type.cpp + test_unaligned_type.cpp test_unordered_map.cpp test_unordered_multimap.cpp test_unordered_multiset.cpp diff --git a/test/test_state_chart_compile_time.cpp b/test/test_state_chart_compile_time.cpp index 7ef25e30..10010efd 100644 --- a/test/test_state_chart_compile_time.cpp +++ b/test/test_state_chart_compile_time.cpp @@ -232,13 +232,13 @@ namespace MotorControl motorControl; - etl::state_chart_ctv motorControlStateChart; + etl::state_chart_ct motorControlStateChart; SUITE(test_state_chart_compile_time) { diff --git a/test/test_state_chart_compile_time_with_data_parameter.cpp b/test/test_state_chart_compile_time_with_data_parameter.cpp index f0eb1da9..b993d615 100644 --- a/test/test_state_chart_compile_time_with_data_parameter.cpp +++ b/test/test_state_chart_compile_time_with_data_parameter.cpp @@ -238,7 +238,7 @@ namespace MotorControl motorControl; - etl::state_chart_ct {562466b5-677d-4448-9e9e-f70805cd71ad} + + {66b8d39a-b610-4d5e-925a-4995f2ac74b2} + + + {a1af709b-90d3-4506-b742-3231d0fff1f5} + + + {43578ed8-b61d-4210-b5d4-bb4a26351934} + + + {c75cedd3-8b6c-4662-b965-aecbe7fd5d1c} + + + {da470864-7708-4e89-a24c-93a9ca2c4856} + + + {0873470d-a6d9-445c-bbc0-33252978ecff} + + + {b42bb316-6e55-4336-a72a-fc5f28d82ea5} + + + {a300635d-25da-4af6-b7e7-1e27ec9df921} + + + {dc898ba2-50f4-4c3d-abee-039670df8582} + + + {e260d680-649f-41b5-844d-c736a252dcb5} + + + {21e56de9-b458-4395-9949-3abfb1f5723b} + + + {d115746e-4d33-41b4-b88f-9fb2ca225286} + + + {a1417994-24a2-40ae-a934-ea318299f91c} + + + {126a3068-3048-4210-8cdf-41ec9e2e1436} + + + {a8738fb5-ff9c-40c2-b3c0-4843ca55097c} + + + {89fc701f-b9ea-4ff3-beac-199c003c4b3e} + @@ -222,15 +270,6 @@ ETL\Utilities - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - ETL\Maths @@ -246,9 +285,6 @@ ETL\Containers - - ETL\Maths - ETL\Containers @@ -273,18 +309,6 @@ ETL\Containers - - ETL\Maths - - - ETL\Maths - - - Tests - - - ETL\Maths - ETL\Containers @@ -429,9 +453,6 @@ ETL\Profiles - - Tests - ETL\Profiles @@ -654,9 +675,6 @@ ETL\Frameworks - - ETL\Maths - ETL\Containers @@ -753,9 +771,6 @@ ETL\Utilities - - Tests - ETL\Utilities\Mutex @@ -909,9 +924,6 @@ ETL\Frameworks - - Tests - Tests\Sanity Checks\C++03 @@ -924,150 +936,12 @@ Tests\Sanity Checks\C++17 - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - ETL\Private ETL\Private - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - - - ETL\Maths - ETL\Maths @@ -1179,77 +1053,188 @@ ETL\Utilities + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\CRC + + + ETL\Maths\Hash + + + ETL\Maths\Hash + + + ETL\Maths\Hash + + + ETL\Maths\Hash + + + ETL\Maths\Hash + + + ETL\Maths\Hash + + + ETL\Maths\Hash + + + ETL\Maths\Hash + + + Tests\Test Support + + + Tests\Test Support + + + Tests\Test Support + + + Tests\Test Support + - - Tests - - - Tests - - - Tests - Tests - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests @@ -1259,228 +1244,45 @@ Tests - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - Tests - - Tests - - - Tests - - - Tests - - - Tests - Tests Tests - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - Tests - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - - - Tests - Tests Tests - - Tests - Tests - - Tests - - - Tests - Source Files - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - - - Tests - - - Tests - - - Tests - UnitTest++ @@ -1544,159 +1346,12 @@ UnitTest++\Win32 - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests @@ -1706,216 +1361,12 @@ Tests - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests - - Tests - - - Tests - Tests @@ -1931,9 +1382,6 @@ Tests - - Tests - Tests\Sanity Checks @@ -2981,9 +2429,6 @@ Source Files - - Tests - Source Files\Sanity Checks @@ -3032,9 +2477,6 @@ Source Files - - Tests - Tests\Sanity Checks @@ -3044,68 +2486,674 @@ Tests - - Tests - - - Tests - - - Tests - - - Tests - Tests\Sanity Checks Tests\Sanity Checks - - Tests - Tests\Sanity Checks Tests\Sanity Checks - - Tests - Tests\Sanity Checks - - Tests - - - Tests - - - Tests - - - Tests - - - Tests - Tests\Sanity Checks Tests\Sanity Checks - - Tests + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Strings + + + Tests\Messaging + + + Tests\Messaging + + + Tests\Messaging + + + Tests\Messaging + + + Tests\Messaging + + + Tests\Messaging + + + Tests\Messaging + + + Tests\Messaging + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\CRC + + + Tests\Hashes + + + Tests\Hashes + + + Tests\Hashes + + + Tests\Hashes + + + Tests\Hashes + + + Tests\Hashes + + + Tests\Hashes + + + Tests\Hashes + + + Tests\Hashes + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Queues + + + Tests\Callbacks & Delegates + + + Tests\Callbacks & Delegates + + + Tests\Callbacks & Delegates + + + Tests\Callbacks & Delegates + + + Tests\Callbacks & Delegates + + + Tests\Callbacks & Delegates + + + Tests\Callbacks & Delegates + + + Tests\Timers + + + Tests\Timers + + + Tests\Timers + + + Tests\Strings + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Queues + + + Tests\State Machines - Tests + Tests\State Machines - Tests + Tests\State Machines + + + Tests\State Machines + + + Tests\State Machines + + + Tests\State Machines + + + Tests\State Machines + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Algorithms + + + Tests\Binary + + + Tests\Binary + + + Tests\Binary + + + Tests\Binary + + + Tests\Binary + + + Tests\Hashes + + + Tests\Containers + + + Tests\Containers + + + Tests\Containers + + + Tests\Test Support + + + Tests\Test Support + + + Tests\Strings + + + Tests\Containers + + + Tests\Algorithms + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Types + + + Tests\Algorithms + + + Tests\Types + + + Tests\Types + + + Tests\Patterns + + + Tests\Patterns