Skip to content

Commit

Permalink
Add timed transitions
Browse files Browse the repository at this point in the history
A timed transition will move from state_from to state_to after the given
interval has passed.
  • Loading branch information
jonblack committed Nov 21, 2015
1 parent 58c060a commit a68ce3a
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 24 deletions.
101 changes: 78 additions & 23 deletions Fsm.cpp
Expand Up @@ -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;
}


Expand All @@ -44,47 +46,100 @@ 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;
m_num_transitions++;
}


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;
}
19 changes: 19 additions & 0 deletions Fsm.h
Expand Up @@ -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
Expand All @@ -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;
};


Expand Down
10 changes: 9 additions & 1 deletion README.md
Expand Up @@ -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

Expand All @@ -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
Expand Down
57 changes: 57 additions & 0 deletions 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 <Fsm.h>

#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);
}

0 comments on commit a68ce3a

Please sign in to comment.