mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-29 22:08:45 +08:00
Merge remote-tracking branch 'origin/feature/light_weight_fsm' into development
This commit is contained in:
commit
7175653c36
@ -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.
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user