From ea98bc346e09019cd9c39cf2b83676692fd351f0 Mon Sep 17 00:00:00 2001 From: jfmauzey Date: Sun, 28 Feb 2016 15:24:42 -0700 Subject: [PATCH 1/4] Change behavior to force "on_enter" call on first transition. --- examples/initBugTest/initBugTest.ino | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 examples/initBugTest/initBugTest.ino diff --git a/examples/initBugTest/initBugTest.ino b/examples/initBugTest/initBugTest.ino new file mode 100644 index 0000000..ec11d84 --- /dev/null +++ b/examples/initBugTest/initBugTest.ino @@ -0,0 +1,74 @@ +/* + initBugTest -- sketch to demonstrate startup behaviour of a classic event + driven FSM and also a timed-transition FSM. + + Issue with first invokation of the trigger() function. + Issue with first invokation of the check_timer() function. + + Expect to see the "on_enterX" function called followed by + the "on_exitX" function. + + Only one state machine is needed to demonstrate the problem. + However the change I made to fix the problem requires a fresh + copy of the FSM to excercise the two code paths affected. + + John Mauzey 20160212 +*/ +#include + +#define BAUD 115200 //for console log of status messages + +//define a standard FSM that prints a text message on both enter and exit +#define TRANS_TEST 1 //for testing classic transitions (not timed) +void on_enter1(void) +{ + Serial.print(millis()); + Serial.println(" fsm1: on_enter called"); +} + +void on_exit1(void) +{ + Serial.print(millis()); + Serial.println(" fsm1: on_exit called "); +} + +State state_enter_exit1(&on_enter1,&on_exit1); +Fsm fsm1(&state_enter_exit1); + +//define a periodic FSM that prints a text message on both enter and exit +void on_enter2(void) +{ + Serial.print(millis()); + Serial.println(" fsm2: on_enter called"); +} + +void on_exit2(void) +{ + Serial.print(millis()); + Serial.println(" fsm2: on_exit called "); +} + +State state_enter_exit2(&on_enter2,&on_exit2); + +Fsm fsm2(&state_enter_exit2); + +void setup() +{ + Serial.begin(BAUD); + fsm1.add_transition(&state_enter_exit1, &state_enter_exit1, TRANS_TEST, NULL); + fsm2.add_timed_transition(&state_enter_exit2, &state_enter_exit2, 3000, NULL); + + Serial.println("Testing classic state machine -- Sending first trigger"); + fsm1.trigger(TRANS_TEST); + + Serial.println("Testing classic state machine -- Sending second trigger"); + fsm1.trigger(TRANS_TEST); + Serial.println(""); + Serial.println("Testing timed state machine -- 3 second periodic timer"); +} + +void loop(void) +{ + fsm2.check_timer(); +} + From 2c6b8f820230ba173afb80140f31dee3ee9cd2b2 Mon Sep 17 00:00:00 2001 From: jfmauzey Date: Sun, 28 Feb 2016 15:29:14 -0700 Subject: [PATCH 2/4] Change behavior to force "on_enter" call on first transition. --- Fsm.cpp | 21 +++++++++++++++++++-- Fsm.h | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Fsm.cpp b/Fsm.cpp index 8a73782..5da70fe 100644 --- a/Fsm.cpp +++ b/Fsm.cpp @@ -26,7 +26,8 @@ State::State(void (*on_enter)(), void (*on_exit)()) Fsm::Fsm(State* initial_state) : m_current_state(initial_state), m_transitions(NULL), - m_num_transitions(0) + m_num_transitions(0), + m_initialized(false) { } @@ -96,6 +97,14 @@ void Fsm::trigger(int event) if (m_transitions[i].state_from == m_current_state && m_transitions[i].event == event) { + if (! m_initialized) + { + m_initialized = true; + if (m_transitions[i].state_from->on_enter != NULL) + { + m_transitions[i].state_from->on_enter(); + } + } m_current_state = m_transitions[i].make_transition(); return; } @@ -112,12 +121,20 @@ void Fsm::check_timer() { if (transition->start == 0) { + if (! m_initialized) + { + m_initialized = true; + if (transition->transition.state_from->on_enter != NULL) + { + transition->transition.state_from->on_enter(); + } + } transition->start = millis(); } else { unsigned long now = millis(); - Serial.println(now); + //Serial.println(now); //jfm if (now - transition->start >= transition->interval) { m_current_state = transition->transition.make_transition(); diff --git a/Fsm.h b/Fsm.h index f58757f..bd03268 100644 --- a/Fsm.h +++ b/Fsm.h @@ -72,6 +72,7 @@ class Fsm State* m_current_state; Transition* m_transitions; int m_num_transitions; + boolean m_initialized; TimedTransition* m_timed_transitions; int m_num_timed_transitions; From e115a6eb9c222bc632b649f3258a1e67a4a8458a Mon Sep 17 00:00:00 2001 From: jfmauzey Date: Tue, 1 Mar 2016 14:55:06 -0700 Subject: [PATCH 3/4] Adding test case for using operator new Fsm. Uncovered a defect with original code that does not initialize the class property Fsm->m_num_timed_transtions. --- examples/fsmUnitTest1/fsmUnitTest1.ino | 40 +++++++++++++++++++++++ examples/fsmUnitTest2/fsmUnitTest2.ino | 44 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 examples/fsmUnitTest1/fsmUnitTest1.ino create mode 100644 examples/fsmUnitTest2/fsmUnitTest2.ino diff --git a/examples/fsmUnitTest1/fsmUnitTest1.ino b/examples/fsmUnitTest1/fsmUnitTest1.ino new file mode 100644 index 0000000..9e73deb --- /dev/null +++ b/examples/fsmUnitTest1/fsmUnitTest1.ino @@ -0,0 +1,40 @@ +/* + fsmUnitTest1 -- sketch to test added functionality to allow setting of state + at runtime. + + John Mauzey 20160226 +*/ +#include + +#define BAUD 115200 + +//define a periodic fsm that prints a text message on both enter and exit +void on_enter(void) +{ + Serial.print(millis()); + Serial.println(" fsm1: on_enter called"); +} + +void on_exit(void) +{ + Serial.print(millis()); + Serial.println(" fsm1: on_exit called "); +} + + +Fsm fsm1; +State state_enter_exit; + +void setup() +{ + Serial.begin(BAUD); + state_enter_exit.init(&on_enter,&on_exit); + fsm1.init(&state_enter_exit); + fsm1.add_timed_transition(&state_enter_exit, &state_enter_exit, 3000, NULL); +} + +void loop(void) +{ + fsm1.check_timer(); +} + diff --git a/examples/fsmUnitTest2/fsmUnitTest2.ino b/examples/fsmUnitTest2/fsmUnitTest2.ino new file mode 100644 index 0000000..074ca36 --- /dev/null +++ b/examples/fsmUnitTest2/fsmUnitTest2.ino @@ -0,0 +1,44 @@ +/* + fsmUnitTest2 -- sketch to test Fsm using pointers tothe state machine. + + John Mauzey 20160227 +*/ +#include + +#define BAUD 115200 + +//define a periodic fsm that prints a text message on both enter and exit +void on_enter(void) +{ + Serial.print(millis()); + Serial.println(" fsm1: on_enter called"); +} + +void on_exit(void) +{ + Serial.print(millis()); + Serial.println(" fsm1: on_exit called "); +} + + +Fsm *fsm1; +State *state_enter_exit; + +void setup() +{ + Serial.begin(BAUD); + state_enter_exit = new State(&on_enter,&on_exit); + fsm1 = new Fsm(state_enter_exit); + fsm1->add_timed_transition(state_enter_exit, state_enter_exit, 3000, NULL); +} + +uint32_t lastTime = 0; +void loop(void) +{ + if (millis() - lastTime > 2000) { + lastTime = millis(); + Serial.println("heartbeat:"); + } + fsm1->check_timer(); +} + From acc3a49113747bd18f9c2ce12258eaeecde2a144 Mon Sep 17 00:00:00 2001 From: jfmauzey Date: Tue, 1 Mar 2016 15:57:22 -0700 Subject: [PATCH 4/4] Fix constructor to initialize member data. --- Fsm.cpp | 1 + examples/fsmUnitTest1/fsmUnitTest1.ino | 16 +++++++++------- examples/fsmUnitTest2/fsmUnitTest2.ino | 12 +++++------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Fsm.cpp b/Fsm.cpp index 5da70fe..27a942a 100644 --- a/Fsm.cpp +++ b/Fsm.cpp @@ -27,6 +27,7 @@ Fsm::Fsm(State* initial_state) : m_current_state(initial_state), m_transitions(NULL), m_num_transitions(0), + m_num_timed_transitions(0), m_initialized(false) { } diff --git a/examples/fsmUnitTest1/fsmUnitTest1.ino b/examples/fsmUnitTest1/fsmUnitTest1.ino index 9e73deb..c7035a5 100644 --- a/examples/fsmUnitTest1/fsmUnitTest1.ino +++ b/examples/fsmUnitTest1/fsmUnitTest1.ino @@ -1,12 +1,14 @@ /* - fsmUnitTest1 -- sketch to test added functionality to allow setting of state - at runtime. + fsmUnitTest1 -- sketch to test basic functionality of the Fsm class. + Test runs the simplest timed transition by creating + a periodic timer that fires every three seconds. John Mauzey 20160226 */ #include #define BAUD 115200 +#define PERIOD 3000 //define a periodic fsm that prints a text message on both enter and exit void on_enter(void) @@ -22,15 +24,15 @@ void on_exit(void) } -Fsm fsm1; -State state_enter_exit; +State state_enter_exit(&on_enter, &on_exit); +Fsm fsm1(&state_enter_exit); void setup() { Serial.begin(BAUD); - state_enter_exit.init(&on_enter,&on_exit); - fsm1.init(&state_enter_exit); - fsm1.add_timed_transition(&state_enter_exit, &state_enter_exit, 3000, NULL); + //Serial.println("JFM -- Testing periodic timer"); + fsm1.add_timed_transition(&state_enter_exit, &state_enter_exit, PERIOD, NULL); + //Serial.println("Entering main loop"); } void loop(void) diff --git a/examples/fsmUnitTest2/fsmUnitTest2.ino b/examples/fsmUnitTest2/fsmUnitTest2.ino index 074ca36..bea4b18 100644 --- a/examples/fsmUnitTest2/fsmUnitTest2.ino +++ b/examples/fsmUnitTest2/fsmUnitTest2.ino @@ -1,7 +1,7 @@ /* - fsmUnitTest2 -- sketch to test Fsm using pointers tothe state machine. + fsmUnitTest2 -- sketch to test operator new for Fsm class. - John Mauzey 20160227 + John Mauzey 20160226 */ #include @@ -27,18 +27,16 @@ State *state_enter_exit; void setup() { Serial.begin(BAUD); + /* NOTE: the following println affects demostrating the defect. */ + //Serial.println("JFM -- Testing operator new"); state_enter_exit = new State(&on_enter,&on_exit); fsm1 = new Fsm(state_enter_exit); fsm1->add_timed_transition(state_enter_exit, state_enter_exit, 3000, NULL); + //Serial.println("Entering main loop"); } -uint32_t lastTime = 0; void loop(void) { - if (millis() - lastTime > 2000) { - lastTime = millis(); - Serial.println("heartbeat:"); - } fsm1->check_timer(); }