mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-16 00:46:03 +08:00
Merge branch 'feature/state-chart-to-have-optional-data-parameter' into development
This commit is contained in:
commit
bec129a192
@ -35,6 +35,7 @@ SOFTWARE.
|
||||
#include "etl/nullptr.h"
|
||||
#include "etl/array.h"
|
||||
#include "etl/array_view.h"
|
||||
#include "etl/type_traits.h"
|
||||
|
||||
namespace etl
|
||||
{
|
||||
@ -74,11 +75,332 @@ namespace etl
|
||||
state_id_t current_state_id; ///< The current state id.
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Simple Finite State Machine
|
||||
/// Data parameter for events.
|
||||
//***************************************************************************
|
||||
template <typename TObject, typename TDataParameter = void>
|
||||
class state_chart : public istate_chart
|
||||
{
|
||||
public:
|
||||
|
||||
typedef TDataParameter data_parameter_type;
|
||||
typedef typename etl::types<data_parameter_type>::type data_type;
|
||||
|
||||
//*************************************************************************
|
||||
/// 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_)(data_parameter_type) = 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_)(data_parameter_type) = 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)(data_parameter_type);
|
||||
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)();
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
/// 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_)
|
||||
: istate_chart(state_id_),
|
||||
object(object_),
|
||||
transition_table(transition_table_begin_, transition_table_end_),
|
||||
started(false)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// 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_table_begin_ The start of the state table.
|
||||
/// \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_)
|
||||
: istate_chart(state_id_),
|
||||
object(object_),
|
||||
transition_table(transition_table_begin_, transition_table_end_),
|
||||
state_table(state_table_begin_, state_table_end_),
|
||||
started(false)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Sets the transition table.
|
||||
/// \param state_table_begin_ The start of the state table.
|
||||
/// \param state_table_end_ The end of the state table.
|
||||
//*************************************************************************
|
||||
void set_transition_table(const transition* transition_table_begin_,
|
||||
const transition* transition_table_end_)
|
||||
{
|
||||
transition_table.assign(transition_table_begin_, transition_table_end_);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Sets the state table.
|
||||
/// \param state_table_begin_ The start of the state table.
|
||||
/// \param state_table_end_ The end of the state table.
|
||||
//*************************************************************************
|
||||
void set_state_table(const state* state_table_begin_,
|
||||
const state* state_table_end_)
|
||||
{
|
||||
state_table.assign(state_table_begin_, state_table_end_);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets a reference to the implementation object.
|
||||
/// \return Reference to the implementation object.
|
||||
//*************************************************************************
|
||||
TObject& get_object()
|
||||
{
|
||||
return object;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets a const reference to the implementation object.
|
||||
/// \return Const reference to the implementation object.
|
||||
//*************************************************************************
|
||||
const TObject& get_object() const
|
||||
{
|
||||
return object;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets the current state id.
|
||||
/// \return The current state id.
|
||||
//*************************************************************************
|
||||
const state* find_state(state_id_t state_id)
|
||||
{
|
||||
if (state_table.empty())
|
||||
{
|
||||
return state_table.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
return etl::find_if(state_table.begin(),
|
||||
state_table.end(),
|
||||
is_state(state_id));
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
///
|
||||
//*************************************************************************
|
||||
virtual void start(const bool on_entry_initial = true) ETL_OVERRIDE
|
||||
{
|
||||
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))
|
||||
{
|
||||
(object.*(s->on_entry))();
|
||||
}
|
||||
}
|
||||
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Processes the specified event.
|
||||
/// The state machine will action the <b>first</b> 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(const event_id_t event_id) ETL_OVERRIDE
|
||||
{
|
||||
process_event(event_id, data_type());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Processes the specified event.
|
||||
/// The state machine will action the <b>first</b> 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, data_parameter_type data)
|
||||
{
|
||||
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())
|
||||
{
|
||||
// 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)(data);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(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<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.
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Simple Finite State Machine
|
||||
//***************************************************************************
|
||||
template <typename TObject>
|
||||
class state_chart : public istate_chart
|
||||
class state_chart<TObject, void> : public istate_chart
|
||||
{
|
||||
public:
|
||||
|
||||
@ -243,7 +565,7 @@ namespace etl
|
||||
//*************************************************************************
|
||||
///
|
||||
//*************************************************************************
|
||||
virtual void start(const bool on_entry_initial = true)
|
||||
virtual void start(const bool on_entry_initial = true) ETL_OVERRIDE
|
||||
{
|
||||
if (!started)
|
||||
{
|
||||
@ -269,7 +591,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)
|
||||
virtual void process_event(const event_id_t event_id) ETL_OVERRIDE
|
||||
{
|
||||
if (started)
|
||||
{
|
||||
|
||||
484
test/test_state_chart_with_data_parameter.cpp
Normal file
484
test/test_state_chart_with_data_parameter.cpp
Normal file
@ -0,0 +1,484 @@
|
||||
/******************************************************************************
|
||||
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 "UnitTest++/UnitTest++.h"
|
||||
|
||||
#include "etl/state_chart.h"
|
||||
#include "etl/enum_type.h"
|
||||
#include "etl/queue.h"
|
||||
#include "etl/array.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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 etl::state_chart<MotorControl, const int&>
|
||||
{
|
||||
public:
|
||||
|
||||
MotorControl()
|
||||
: state_chart<MotorControl, const int&>(*this, transitionTable.begin(), transitionTable.end(), StateId::IDLE)
|
||||
{
|
||||
this->set_state_table(stateTable.begin(), stateTable.end());
|
||||
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(data_parameter_type d)
|
||||
{
|
||||
data = d;
|
||||
++startCount;
|
||||
}
|
||||
|
||||
//***********************************
|
||||
void OnStop(data_parameter_type d)
|
||||
{
|
||||
data = d;
|
||||
++stopCount;
|
||||
}
|
||||
|
||||
//***********************************
|
||||
void OnStopped(data_parameter_type d)
|
||||
{
|
||||
data = d;
|
||||
++stoppedCount;
|
||||
}
|
||||
|
||||
//***********************************
|
||||
void OnSetSpeed(data_parameter_type 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(data_parameter_type 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;
|
||||
|
||||
static const etl::array<MotorControl::transition, 7> transitionTable;
|
||||
static const etl::array<MotorControl::state, 3> stateTable;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
constexpr etl::array<MotorControl::transition, 7> MotorControl::transitionTable =
|
||||
{
|
||||
MotorControl::transition(StateId::IDLE, EventId::START, StateId::RUNNING, &MotorControl::OnStart, &MotorControl::Guard),
|
||||
MotorControl::transition(StateId::IDLE, EventId::START, StateId::IDLE, &MotorControl::Null, &MotorControl::NotGuard),
|
||||
MotorControl::transition(StateId::RUNNING, EventId::STOP, StateId::WINDING_DOWN, &MotorControl::OnStop),
|
||||
MotorControl::transition(StateId::RUNNING, EventId::EMERGENCY_STOP, StateId::IDLE, &MotorControl::OnStop),
|
||||
MotorControl::transition(StateId::RUNNING, EventId::SET_SPEED, StateId::RUNNING, &MotorControl::OnSetSpeed),
|
||||
MotorControl::transition(StateId::WINDING_DOWN, EventId::STOPPED, StateId::IDLE, &MotorControl::OnStopped),
|
||||
MotorControl::transition( EventId::ABORT, StateId::IDLE)
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
constexpr etl::array<MotorControl::state, 3> MotorControl::stateTable =
|
||||
{
|
||||
MotorControl::state(StateId::IDLE, &MotorControl::OnEnterIdle, nullptr),
|
||||
MotorControl::state(StateId::RUNNING, &MotorControl::OnEnterRunning, nullptr),
|
||||
MotorControl::state(StateId::WINDING_DOWN, &MotorControl::OnEnterWindingDown, &MotorControl::OnExitWindingDown)
|
||||
};
|
||||
|
||||
MotorControl motorControl;
|
||||
|
||||
SUITE(test_state_chart_class)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_state_chart)
|
||||
{
|
||||
motorControl.ClearStatistics();
|
||||
|
||||
// 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(false, motorControl.entered_idle);
|
||||
|
||||
// Send Start event (state chart not started).
|
||||
motorControl.guard = true;
|
||||
motorControl.process_event(EventId::START, 1);
|
||||
|
||||
CHECK_EQUAL(StateId::IDLE, int(motorControl.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;
|
||||
motorControl.start();
|
||||
|
||||
CHECK_EQUAL(true, motorControl.entered_idle);
|
||||
|
||||
// Send unhandled events.
|
||||
motorControl.process_event(EventId::STOP, 2);
|
||||
motorControl.process_event(EventId::STOPPED, 3);
|
||||
|
||||
CHECK_EQUAL(StateId::IDLE, int(motorControl.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;
|
||||
motorControl.process_event(EventId::START, 4);
|
||||
|
||||
// Still in Idle state.
|
||||
|
||||
CHECK_EQUAL(StateId::IDLE, int(motorControl.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;
|
||||
motorControl.process_event(EventId::START, 5);
|
||||
|
||||
// Now in Running state.
|
||||
|
||||
CHECK_EQUAL(StateId::RUNNING, int(motorControl.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.
|
||||
motorControl.process_event(EventId::START, 6);
|
||||
motorControl.process_event(EventId::STOPPED, 7);
|
||||
|
||||
CHECK_EQUAL(StateId::RUNNING, int(motorControl.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.
|
||||
motorControl.process_event(EventId::SET_SPEED, 8);
|
||||
|
||||
// Still in Running state.
|
||||
|
||||
CHECK_EQUAL(StateId::RUNNING, int(motorControl.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.
|
||||
motorControl.process_event(EventId::STOP, 9);
|
||||
|
||||
// Now in WindingDown state.
|
||||
|
||||
CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.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.
|
||||
motorControl.process_event(EventId::START, 10);
|
||||
motorControl.process_event(EventId::STOP, 11);
|
||||
|
||||
CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.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.
|
||||
motorControl.process_event(EventId::STOPPED, 12);
|
||||
|
||||
// Now in Idle state.
|
||||
CHECK_EQUAL(StateId::IDLE, int(motorControl.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.
|
||||
motorControl.process_event(EventId::START, 1);
|
||||
|
||||
// Now in Running state.
|
||||
|
||||
CHECK_EQUAL(StateId::RUNNING, int(motorControl.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.
|
||||
motorControl.process_event(EventId::EMERGENCY_STOP, 2);
|
||||
|
||||
// Now in Idle state.
|
||||
CHECK_EQUAL(StateId::IDLE, int(motorControl.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.
|
||||
motorControl.process_event(EventId::START, 1);
|
||||
|
||||
// Now in Running state.
|
||||
|
||||
motorControl.process_event(EventId::ABORT, 2);
|
||||
CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id()));
|
||||
|
||||
// Send Start event.
|
||||
motorControl.process_event(EventId::START, 3);
|
||||
|
||||
// Now in Running state.
|
||||
|
||||
// Send Stop event.
|
||||
motorControl.process_event(EventId::STOP, 4);
|
||||
|
||||
// Now in WindingDown state.
|
||||
motorControl.process_event(EventId::ABORT, 5);
|
||||
CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id()));
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1950,6 +1950,7 @@
|
||||
<ClCompile Include="..\test_state_chart.cpp" />
|
||||
<ClCompile Include="..\test_smallest.cpp" />
|
||||
<ClCompile Include="..\test_stack.cpp" />
|
||||
<ClCompile Include="..\test_state_chart_with_data_parameter.cpp" />
|
||||
<ClCompile Include="..\test_string_utilities_std.cpp" />
|
||||
<ClCompile Include="..\test_string_char.cpp" />
|
||||
<ClCompile Include="..\test_string_char_external_buffer.cpp" />
|
||||
|
||||
@ -1496,6 +1496,9 @@
|
||||
<ClCompile Include="..\test_queue_lockable_small.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_state_chart_with_data_parameter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\library.properties">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user