diff --git a/include/etl/fsm.h b/include/etl/fsm.h index 1e527d5d..ed1a9a7d 100644 --- a/include/etl/fsm.h +++ b/include/etl/fsm.h @@ -169,6 +169,18 @@ namespace etl } }; + //*************************************************************************** + /// Exception for message received but not started. + //*************************************************************************** + class fsm_not_started : public etl::fsm_exception + { + public: + fsm_not_started(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:not started", ETL_FSM_FILE_ID"F"), file_name_, line_number_) + { + } + }; + namespace private_fsm { template @@ -404,31 +416,38 @@ namespace etl //******************************************* void receive(const etl::imessage& message) ETL_OVERRIDE { - etl::fsm_state_id_t next_state_id = p_state->process_event(message); - - if (have_changed_state(next_state_id)) + if (is_started()) { - ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); - etl::ifsm_state* p_next_state = state_list[next_state_id]; + etl::fsm_state_id_t next_state_id = p_state->process_event(message); - do + if (have_changed_state(next_state_id)) + { + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + etl::ifsm_state* p_next_state = state_list[next_state_id]; + + do + { + p_state->on_exit_state(); + p_state = p_next_state; + + next_state_id = p_state->on_enter_state(); + + if (have_changed_state(next_state_id)) + { + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + p_next_state = state_list[next_state_id]; + } + } while (p_next_state != p_state); // Have we changed state again? + } + else if (is_self_transition(next_state_id)) { p_state->on_exit_state(); - p_state = p_next_state; - - next_state_id = p_state->on_enter_state(); - - if (have_changed_state(next_state_id)) - { - ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); - p_next_state = state_list[next_state_id]; - } - } while (p_next_state != p_state); // Have we changed state again? + p_state->on_enter_state(); + } } - else if (is_self_transition(next_state_id)) + else { - p_state->on_exit_state(); - p_state->on_enter_state(); + ETL_ASSERT_FAIL(ETL_ERROR(etl::fsm_not_started)); } } diff --git a/include/etl/hfsm.h b/include/etl/hfsm.h index c9ca12f3..47a936c5 100644 --- a/include/etl/hfsm.h +++ b/include/etl/hfsm.h @@ -98,30 +98,37 @@ namespace etl //******************************************* void receive(const etl::imessage& message) ETL_OVERRIDE { - etl::fsm_state_id_t next_state_id = p_state->process_event(message); - - if (next_state_id != ifsm_state::No_State_Change) + if (is_started()) { - ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); - etl::ifsm_state* p_next_state = state_list[next_state_id]; + etl::fsm_state_id_t next_state_id = p_state->process_event(message); - // Have we changed state? - if (p_next_state != p_state) + if (next_state_id != ifsm_state::No_State_Change) { - etl::ifsm_state* p_root = common_ancestor(p_state, p_next_state); - do_exits(p_root, p_state); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + etl::ifsm_state* p_next_state = state_list[next_state_id]; - p_state = p_next_state; - - next_state_id = do_enters(p_root, p_next_state, true); - - if (next_state_id != ifsm_state::No_State_Change) + // Have we changed state? + if (p_next_state != p_state) { - ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); - p_state = state_list[next_state_id]; + etl::ifsm_state* p_root = common_ancestor(p_state, p_next_state); + do_exits(p_root, p_state); + + p_state = p_next_state; + + next_state_id = do_enters(p_root, p_next_state, true); + + if (next_state_id != ifsm_state::No_State_Change) + { + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + p_state = state_list[next_state_id]; + } } } } + else + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::fsm_not_started)); + } } private: diff --git a/test/test_fsm.cpp b/test/test_fsm.cpp index e092f1d2..d3481dd3 100644 --- a/test/test_fsm.cpp +++ b/test/test_fsm.cpp @@ -672,5 +672,13 @@ namespace CHECK_TRUE(motorControl.exited_state); CHECK_TRUE(motorControl.entered_state); } + + //************************************************************************* + TEST(test_fsm_no_states_and_no_start) + { + MotorControl mc; + + CHECK_THROW(mc.receive(Start()), etl::fsm_not_started); + } }; } diff --git a/test/test_hfsm.cpp b/test/test_hfsm.cpp index 584c3f48..4ea762ab 100644 --- a/test/test_hfsm.cpp +++ b/test/test_hfsm.cpp @@ -978,5 +978,13 @@ namespace bool exitsCorrect = std::equal(motorControl.stateExitHistory.begin(), motorControl.stateExitHistory.end(), expectedExits.begin()); CHECK(exitsCorrect); } + + //************************************************************************* + TEST(test_fsm_no_states_and_no_start) + { + MotorControl mc; + + CHECK_THROW(mc.receive(Start()), etl::fsm_not_started); + } }; }