diff --git a/Fsm.cpp b/Fsm.cpp index 2b83a3b..8a73782 100644 --- a/Fsm.cpp +++ b/Fsm.cpp @@ -34,7 +34,9 @@ Fsm::Fsm(State* initial_state) Fsm::~Fsm() { free(m_transitions); + free(m_timed_transitions); m_transitions = NULL; + m_timed_transitions = NULL; } @@ -44,12 +46,8 @@ void Fsm::add_transition(State* state_from, State* state_to, int event, if (state_from == NULL || state_to == NULL) return; - Transition transition; - transition.state_from = state_from; - transition.state_to = state_to; - transition.event = event; - transition.on_transition = on_transition; - + Transition transition = Fsm::create_transition(state_from, state_to, event, + on_transition); m_transitions = (Transition*) realloc(m_transitions, (m_num_transitions + 1) * sizeof(Transition)); m_transitions[m_num_transitions] = transition; @@ -57,34 +55,91 @@ void Fsm::add_transition(State* state_from, State* state_to, int event, } +void Fsm::add_timed_transition(State* state_from, State* state_to, + unsigned long interval, void (*on_transition)()) +{ + if (state_from == NULL || state_to == NULL) + return; + + Transition transition = Fsm::create_transition(state_from, state_to, 0, + on_transition); + + TimedTransition timed_transition; + timed_transition.transition = transition; + timed_transition.start = 0; + timed_transition.interval = interval; + + m_timed_transitions = (TimedTransition*) realloc( + m_timed_transitions, (m_num_timed_transitions + 1) * sizeof(TimedTransition)); + m_timed_transitions[m_num_timed_transitions] = timed_transition; + m_num_timed_transitions++; +} + + +Fsm::Transition Fsm::create_transition(State* state_from, State* state_to, + int event, void (*on_transition)()) +{ + Transition t; + t.state_from = state_from; + t.state_to = state_to; + t.event = event; + t.on_transition = on_transition; + + return t; +} + void Fsm::trigger(int event) { // Find the transition with the current state and given event. - Transition transition; - bool found = false; for (int i = 0; i < m_num_transitions; ++i) { - transition = m_transitions[i]; - if (transition.state_from == m_current_state && - transition.event == event) + if (m_transitions[i].state_from == m_current_state && + m_transitions[i].event == event) { - found = true; - break; + m_current_state = m_transitions[i].make_transition(); + return; } } +} - // Execute the handlers in the correct order. - if (found) + +void Fsm::check_timer() +{ + for (int i = 0; i < m_num_timed_transitions; ++i) { - if (transition.state_from->on_exit != NULL) - transition.state_from->on_exit(); + TimedTransition* transition = &m_timed_transitions[i]; + if (transition->transition.state_from == m_current_state) + { + if (transition->start == 0) + { + transition->start = millis(); + } + else + { + unsigned long now = millis(); + Serial.println(now); + if (now - transition->start >= transition->interval) + { + m_current_state = transition->transition.make_transition(); + transition->start = 0; + } + } + } + } +} + + +State* Fsm::Transition::make_transition() +{ + // Execute the handlers in the correct order. + if (state_from->on_exit != NULL) + state_from->on_exit(); - if (transition.on_transition != NULL) - transition.on_transition(); + if (on_transition != NULL) + on_transition(); - m_current_state = transition.state_to; + if (state_to->on_enter != NULL) + state_to->on_enter(); - if (transition.state_to->on_enter != NULL) - transition.state_to->on_enter(); - } + return state_to; } diff --git a/Fsm.h b/Fsm.h index 2c23a88..f58757f 100644 --- a/Fsm.h +++ b/Fsm.h @@ -41,7 +41,12 @@ class Fsm void add_transition(State* state_from, State* state_to, int event, void (*on_transition)()); + + void add_timed_transition(State* state_from, State* state_to, + unsigned long interval, void (*on_transition)()); + void trigger(int event); + void check_timer(); private: struct Transition @@ -50,12 +55,26 @@ class Fsm State* state_to; int event; void (*on_transition)(); + + State* make_transition(); }; + struct TimedTransition + { + Transition transition; + unsigned long start; + unsigned long interval; + }; + + static Transition create_transition(State* state_from, State* state_to, + int event, void (*on_transition)()); private: State* m_current_state; Transition* m_transitions; int m_num_transitions; + + TimedTransition* m_timed_transitions; + int m_num_timed_transitions; }; diff --git a/README.md b/README.md index f464fda..4ffa89a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,11 @@ An arduino library for implementing a finite state machine. Other than the examples included in the library, the following pages might be useful to you: -* [Humble Coder](http://www.humblecoder.com/arduino-finite-state-machine-library/) +* [Humble Coder: Arduino finite state machine library][1] +* [Humble Coder: Arduino multitasking using a finite state machine][2] + +[1]: http://www.humblecoder.com/arduino-finite-state-machine-library/ +[2]: http://www.humblecoder.com/arduino-multitasking-using-finite-state-machines/ # Contribution @@ -14,6 +18,10 @@ feature branch. # Changelog +**2.1.0 - 21/11/2015** + +* Add timed transitions + **2.0.0 - 03/09/2015** * Remove AUTHORS files: too much hassle to maintain diff --git a/examples/multitasking/multitasking.ino b/examples/multitasking/multitasking.ino new file mode 100644 index 0000000..11cc94d --- /dev/null +++ b/examples/multitasking/multitasking.ino @@ -0,0 +1,57 @@ +// This example shows how two finite state machines can be used to simulate +// multitasking on an arduino. Two LED's are turned on and off at irregular +// intervals; the finite state machines take care of the transitions. + +#include + +#define LED1_PIN 10 +#define LED2_PIN 11 + +void on_led1_on_enter() { + Serial.println("on_led1_on_enter"); + digitalWrite(LED1_PIN, HIGH); +} + +void on_led1_off_enter() { + Serial.println("on_led1_off_enter"); + digitalWrite(LED1_PIN, LOW); +} + +void on_led2_on_enter() { + Serial.println("on_led2_on_enter"); + digitalWrite(LED2_PIN, HIGH); +} + +void on_led2_off_enter() { + Serial.println("on_led2_off_enter"); + digitalWrite(LED2_PIN, LOW); +} + +State state_led1_on(&on_led1_on_enter, NULL); +State state_led1_off(&on_led1_off_enter, NULL); + +State state_led2_on(&on_led2_on_enter, NULL); +State state_led2_off(&on_led2_off_enter, NULL); + +Fsm fsm_led1(&state_led1_off); +Fsm fsm_led2(&state_led2_off); + +void setup() { + Serial.begin(9600); + + pinMode(LED1_PIN, OUTPUT); + pinMode(LED2_PIN, OUTPUT); + + fsm_led1.add_timed_transition(&state_led1_off, &state_led1_on, 1000, NULL); + fsm_led1.add_timed_transition(&state_led1_on, &state_led1_off, 3000, NULL); + fsm_led2.add_timed_transition(&state_led2_off, &state_led2_on, 1000, NULL); + fsm_led2.add_timed_transition(&state_led2_on, &state_led2_off, 2000, NULL); +} + + +void loop() { + fsm_led1.check_timer(); + fsm_led2.check_timer(); + + delay(100); +}