Merge remote-tracking branch 'origin/feature/light_weight_fsm' into development

This commit is contained in:
John Wellbelove 2018-09-10 20:42:58 +01:00
commit 7175653c36
2 changed files with 94 additions and 44 deletions

View File

@ -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 <b>first</b> 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<const transition> transition_table; ///< The table of transitions.
etl::array_view<const state> state_table; ///< The table of states.
bool started; ///< Set if the state chart has been started.
};
}

View File

@ -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);