mirror of
https://github.com/ETLCPP/etl.git
synced 2026-11-09 14:49:53 +08:00
Merge branch 'pull-request/#672-Added-HFSM-specific-start()-and-reset()' into development
This commit is contained in:
commit
c5432e42ff
@ -346,7 +346,7 @@ namespace etl
|
||||
/// Subsequent calls will do nothing.
|
||||
///\param call_on_enter_state If true will call on_enter_state() for the first state. Default = true.
|
||||
//*******************************************
|
||||
void start(bool call_on_enter_state = true)
|
||||
virtual void start(bool call_on_enter_state = true)
|
||||
{
|
||||
// Can only be started once.
|
||||
if (p_state == ETL_NULLPTR)
|
||||
@ -451,7 +451,7 @@ namespace etl
|
||||
/// Reset the FSM to pre-started state.
|
||||
///\param call_on_exit_state If true will call on_exit_state() for the current state. Default = false.
|
||||
//*******************************************
|
||||
void reset(bool call_on_exit_state = false)
|
||||
virtual void reset(bool call_on_exit_state = false)
|
||||
{
|
||||
if ((p_state != ETL_NULLPTR) && call_on_exit_state)
|
||||
{
|
||||
|
||||
@ -372,7 +372,7 @@ namespace etl
|
||||
/// Subsequent calls will do nothing.
|
||||
///\param call_on_enter_state If true will call on_enter_state() for the first state. Default = true.
|
||||
//*******************************************
|
||||
void start(bool call_on_enter_state = true)
|
||||
virtual void start(bool call_on_enter_state = true)
|
||||
{
|
||||
// Can only be started once.
|
||||
if (p_state == ETL_NULLPTR)
|
||||
@ -477,7 +477,7 @@ namespace etl
|
||||
/// Reset the FSM to pre-started state.
|
||||
///\param call_on_exit_state If true will call on_exit_state() for the current state. Default = false.
|
||||
//*******************************************
|
||||
void reset(bool call_on_exit_state = false)
|
||||
virtual void reset(bool call_on_exit_state = false)
|
||||
{
|
||||
if ((p_state != ETL_NULLPTR) && call_on_exit_state)
|
||||
{
|
||||
|
||||
@ -50,6 +50,41 @@ namespace etl
|
||||
{
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Starts the HFSM.
|
||||
/// Can only be called once.
|
||||
/// Subsequent calls will do nothing.
|
||||
///\param call_on_enter_state If true will call on_enter_state() for the first state. Default = true.
|
||||
//*******************************************
|
||||
void start(bool call_on_enter_state = true) ETL_OVERRIDE
|
||||
{
|
||||
// Can only be started once.
|
||||
if (p_state == ETL_NULLPTR)
|
||||
{
|
||||
p_state = state_list[0];
|
||||
ETL_ASSERT(p_state != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
|
||||
|
||||
if (call_on_enter_state)
|
||||
{
|
||||
do_enters(ETL_NULLPTR, p_state, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Reset the HFSM to pre-started state.
|
||||
///\param call_on_exit_state If true will call on_exit_state() for the current state. Default = false.
|
||||
//*******************************************
|
||||
virtual void reset(bool call_on_exit_state = false) ETL_OVERRIDE
|
||||
{
|
||||
if ((p_state != ETL_NULLPTR) && call_on_exit_state)
|
||||
{
|
||||
do_exits(ETL_NULLPTR, p_state);
|
||||
}
|
||||
|
||||
p_state = ETL_NULLPTR;
|
||||
}
|
||||
|
||||
using fsm::receive;
|
||||
|
||||
//*******************************************
|
||||
|
||||
@ -33,6 +33,7 @@ SOFTWARE.
|
||||
#include "etl/container.h"
|
||||
#include "etl/packet.h"
|
||||
#include "etl/queue.h"
|
||||
#include "etl/circular_buffer.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@ -196,6 +197,9 @@ namespace
|
||||
stoppedCount = 0;
|
||||
isLampOn = false;
|
||||
speed = 0;
|
||||
|
||||
stateEnterHistory.clear();
|
||||
stateExitHistory.clear();
|
||||
}
|
||||
|
||||
//***********************************
|
||||
@ -238,6 +242,10 @@ namespace
|
||||
int stoppedCount;
|
||||
bool isLampOn;
|
||||
int speed;
|
||||
|
||||
// A circular buffer is used so that data overflows won't assert in tests which don't use this data
|
||||
etl::circular_buffer<StateId::enum_type, 10UL> stateEnterHistory{};
|
||||
etl::circular_buffer<StateId::enum_type, 10UL> stateExitHistory{};
|
||||
};
|
||||
|
||||
//***********************************
|
||||
@ -271,9 +279,19 @@ namespace
|
||||
//***********************************
|
||||
etl::fsm_state_id_t on_enter_state()
|
||||
{
|
||||
get_fsm_context().TurnRunningLampOff();
|
||||
auto& context = get_fsm_context();
|
||||
context.stateEnterHistory.push(static_cast<StateId::enum_type>(get_state_id()));
|
||||
context.TurnRunningLampOff();
|
||||
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
//***********************************
|
||||
void on_exit_state()
|
||||
{
|
||||
auto& context = get_fsm_context();
|
||||
context.stateExitHistory.push(static_cast<StateId::enum_type>(get_state_id()));
|
||||
}
|
||||
};
|
||||
|
||||
//***********************************
|
||||
@ -301,10 +319,19 @@ namespace
|
||||
//***********************************
|
||||
etl::fsm_state_id_t on_enter_state()
|
||||
{
|
||||
get_fsm_context().TurnRunningLampOn();
|
||||
auto& context = get_fsm_context();
|
||||
context.stateEnterHistory.push(static_cast<StateId::enum_type>(get_state_id()));
|
||||
context.TurnRunningLampOn();
|
||||
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
//***********************************
|
||||
void on_exit_state()
|
||||
{
|
||||
auto& context = get_fsm_context();
|
||||
context.stateExitHistory.push(static_cast<StateId::enum_type>(get_state_id()));
|
||||
}
|
||||
};
|
||||
|
||||
//***********************************
|
||||
@ -336,11 +363,21 @@ namespace
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
//***********************************
|
||||
etl::fsm_state_id_t on_enter_state()
|
||||
{
|
||||
++get_fsm_context().windUpStartCount;
|
||||
auto& context = get_fsm_context();
|
||||
context.stateEnterHistory.push(static_cast<StateId::enum_type>(get_state_id()));
|
||||
++context.windUpStartCount;
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
//***********************************
|
||||
void on_exit_state()
|
||||
{
|
||||
auto& context = get_fsm_context();
|
||||
context.stateExitHistory.push(static_cast<StateId::enum_type>(get_state_id()));
|
||||
}
|
||||
};
|
||||
|
||||
//***********************************
|
||||
@ -371,6 +408,13 @@ namespace
|
||||
++get_fsm_context().unknownCount;
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
//***********************************
|
||||
void on_exit_state()
|
||||
{
|
||||
auto& context = get_fsm_context();
|
||||
context.stateExitHistory.push(static_cast<StateId::enum_type>(get_state_id()));
|
||||
}
|
||||
};
|
||||
|
||||
//***********************************
|
||||
@ -852,5 +896,87 @@ namespace
|
||||
|
||||
CHECK_THROW(mc.set_states(stateList, StateId::Number_Of_States), etl::fsm_state_list_order_exception);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_hfsm_start_enters)
|
||||
{
|
||||
MotorControl mc;
|
||||
|
||||
motorControl.Initialise(stateList, std::size(stateList));
|
||||
motorControl.reset();
|
||||
motorControl.ClearStatistics();
|
||||
|
||||
CHECK(!motorControl.is_started());
|
||||
|
||||
// Start the HFSM (with enters)
|
||||
motorControl.start(true);
|
||||
CHECK(motorControl.is_started());
|
||||
|
||||
// Now in Idle state.
|
||||
|
||||
CHECK_EQUAL(StateId::Idle, int(motorControl.get_state_id()));
|
||||
CHECK_EQUAL(StateId::Idle, int(motorControl.get_state().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.windUpCompleteCount);
|
||||
CHECK_EQUAL(0, motorControl.windUpStartCount);
|
||||
CHECK_EQUAL(0, motorControl.stoppedCount);
|
||||
CHECK_EQUAL(0, motorControl.unknownCount);
|
||||
|
||||
etl::array<StateId::enum_type, 1UL> expectedEnters{StateId::Idle};
|
||||
CHECK_EQUAL(expectedEnters.size(), motorControl.stateEnterHistory.size());
|
||||
// No enters should have been performed
|
||||
CHECK(motorControl.stateExitHistory.empty());
|
||||
|
||||
bool entersCorrect = std::equal(motorControl.stateEnterHistory.begin(), motorControl.stateEnterHistory.end(), expectedEnters.begin());
|
||||
CHECK(entersCorrect);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_hfsm_reset_exits)
|
||||
{
|
||||
MotorControl mc;
|
||||
|
||||
motorControl.Initialise(stateList, std::size(stateList));
|
||||
motorControl.reset();
|
||||
motorControl.ClearStatistics();
|
||||
|
||||
CHECK(!motorControl.is_started());
|
||||
|
||||
// Start the HFSM (with enters)
|
||||
motorControl.start(false);
|
||||
CHECK(motorControl.is_started());
|
||||
|
||||
// Now in Idle state.
|
||||
|
||||
// Send Start event.
|
||||
motorControl.receive(Start());
|
||||
|
||||
// Send Timeout event
|
||||
motorControl.receive(Timeout());
|
||||
|
||||
// Send SetSpeed event.
|
||||
motorControl.receive(SetSpeed(100));
|
||||
CHECK_EQUAL(StateId::At_Speed, int(motorControl.get_state_id()));
|
||||
CHECK_EQUAL(StateId::At_Speed, int(motorControl.get_state().get_state_id()));
|
||||
|
||||
// Clean statistics before reset for clean results
|
||||
motorControl.ClearStatistics();
|
||||
|
||||
// Reset HFSM (with exits)
|
||||
motorControl.reset(true);
|
||||
|
||||
etl::array<StateId::enum_type, 2UL> expectedExits{StateId::At_Speed, StateId::Running};
|
||||
CHECK_EQUAL(expectedExits.size(), motorControl.stateExitHistory.size());
|
||||
// No enters should have been performed
|
||||
CHECK(motorControl.stateEnterHistory.empty());
|
||||
|
||||
bool exitsCorrect = std::equal(motorControl.stateExitHistory.begin(), motorControl.stateExitHistory.end(), expectedExits.begin());
|
||||
CHECK(exitsCorrect);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user