From 9becaefdd8416978ecfd1b7853185bc2246f5c20 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 10 Sep 2018 20:42:32 +0100 Subject: [PATCH] Added start() and changed order of execution. --- include/etl/state_chart.h | 102 +++++++++++++++++++++++--------------- test/test_state_chart.cpp | 36 ++++++++++++-- 2 files changed, 94 insertions(+), 44 deletions(-) diff --git a/include/etl/state_chart.h b/include/etl/state_chart.h index 1657e174..b37f6578 100644 --- a/include/etl/state_chart.h +++ b/include/etl/state_chart.h @@ -138,7 +138,8 @@ namespace etl const state_id_t state_id_) : istate_chart(state_id_), object(object_), - transition_table(transition_table_.begin(), transition_table_.end()) + transition_table(transition_table_.begin(), transition_table_.end()), + started(false) { } @@ -189,6 +190,29 @@ namespace etl } } + //************************************************************************* + /// + //************************************************************************* + 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 != nullptr)) + { + (object.*(s->on_entry))(); + } + } + + started = true; + } + } + //************************************************************************* /// Processes the specified event. /// The state machine will action the first item in the transition table @@ -197,52 +221,51 @@ namespace etl //************************************************************************* void process_event(const event_id_t event_id) { - // Scan the transition table. - const transition* t = std::find_if(transition_table.begin(), - transition_table.end(), - is_transition(event_id, current_state_id)); - - // Found an entry? - if (t != transition_table.end()) + if (started) { - // Shall we execute the transition? - if ((t->guard == nullptr) || ((object.*t->guard)())) + // Scan the transition table. + const transition* t = std::find_if(transition_table.begin(), + transition_table.end(), + is_transition(event_id, current_state_id)); + + // Found an entry? + if (t != transition_table.end()) { - const bool to_new_state = (current_state_id != t->next_state_id); - - // Execute the state exit if necessary. - if (to_new_state) + // Shall we execute the transition? + if ((t->guard == nullptr) || ((object.*t->guard)())) { - // See if we have a state item for the current state. - const 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 != nullptr)) + // Shall we execute the action? + if (t->action != nullptr) { - (object.*(s->on_exit))(); + (object.*t->action)(); } - } - // Shall we execute the action? - if (t->action != nullptr) - { - (object.*t->action)(); - } - - // Execute the state entry if necessary. - if (to_new_state) - { - // See if we have a state item for the next state. - const state* s = find_state(t->next_state_id); - - // If the new state has an 'on_entry' then call it. - if ((s != state_table.end()) && (s->on_entry != nullptr)) + // Changing state? + if (current_state_id != t->next_state_id) { - (object.*(s->on_entry))(); - } - } + const state* s; - current_state_id = t->next_state_id; + // 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 != nullptr)) + { + (object.*(s->on_exit))(); + } + + // See if we have a state item for the next state. + s = find_state(t->next_state_id); + + // If the new state has an 'on_entry' then call it. + if ((s != state_table.end()) && (s->on_entry != nullptr)) + { + (object.*(s->on_entry))(); + } + } + + current_state_id = t->next_state_id; + } } } } @@ -290,6 +313,7 @@ namespace etl 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. }; } diff --git a/test/test_state_chart.cpp b/test/test_state_chart.cpp index a7730ce8..61f4bf07 100644 --- a/test/test_state_chart.cpp +++ b/test/test_state_chart.cpp @@ -102,6 +102,7 @@ namespace isLampOn = false; speed = 0; windingDown = 0; + entered_idle = false; } //*********************************** @@ -133,6 +134,7 @@ namespace void OnEnterIdle() { TurnRunningLampOff(); + entered_idle = true; } //*********************************** @@ -184,6 +186,7 @@ namespace bool isLampOn; int speed; int windingDown; + bool entered_idle; bool guard; @@ -218,7 +221,7 @@ namespace { motorControl.ClearStatistics(); - // Now in Idle state. + // In Idle state. CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); CHECK_EQUAL(false, motorControl.isLampOn); @@ -228,12 +231,13 @@ namespace CHECK_EQUAL(0, motorControl.stopCount); CHECK_EQUAL(0, motorControl.stoppedCount); CHECK_EQUAL(0, motorControl.windingDown); + CHECK_EQUAL(false, motorControl.entered_idle); - // Send unhandled events. - motorControl.process_event(EventId::STOP); - motorControl.process_event(EventId::STOPPED); + // Send Start event (state chart not started). + motorControl.guard = true; + motorControl.process_event(EventId::START); - CHECK_EQUAL(StateId::IDLE, motorControl.get_state_id()); + CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); CHECK_EQUAL(false, motorControl.isLampOn); CHECK_EQUAL(0, motorControl.setSpeedCount); @@ -241,7 +245,29 @@ namespace 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; + motorControl.start(); + + CHECK_EQUAL(true, motorControl.entered_idle); + + // Send unhandled events. + motorControl.process_event(EventId::STOP); + motorControl.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; motorControl.process_event(EventId::START);