Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce transition predicates #42

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
98 changes: 50 additions & 48 deletions Fsm.cpp
Expand Up @@ -17,24 +17,24 @@


State::State(void (*on_enter)(), void (*on_state)(), void (*on_exit)())
: on_enter(on_enter),
on_state(on_state),
on_exit(on_exit)
: on_enter(on_enter),
on_state(on_state),
on_exit(on_exit)
{
}


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)
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)
{
}


Fsm::~Fsm()
Fsm::~Fsm()
{
free(m_transitions);
free(m_timed_transitions);
Expand All @@ -43,85 +43,86 @@ Fsm::~Fsm()
}


void Fsm::add_transition(State* state_from, State* state_to, int event,
void (*on_transition)())
{
void Fsm::add_transition(State *state_from, State *state_to, int event,
void (*on_transition)(), predicate precondition) {
if (state_from == NULL || state_to == NULL)
return;

Transition transition = Fsm::create_transition(state_from, state_to, event,
on_transition);
on_transition, precondition);
m_transitions = (Transition*) realloc(m_transitions, (m_num_transitions + 1)
* sizeof(Transition));
* 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)())
{
void Fsm::add_timed_transition(State *state_from, State *state_to,
unsigned long interval, void (*on_transition)(),
predicate precondition) {
if (state_from == NULL || state_to == NULL)
return;

Transition transition = Fsm::create_transition(state_from, state_to, 0,
on_transition);
on_transition, precondition);

TimedTransition timed_transition;
timed_transition.transition = transition;
timed_transition.start = 0;
timed_transition.interval = interval;

m_timed_transitions = (TimedTransition*) realloc(
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)())
{
Fsm::Transition Fsm::create_transition(State *state_from, State *state_to,
int event, void (*on_transition)(),
predicate precondition) {
Transition t;
t.state_from = state_from;
t.state_to = state_to;
t.event = event;
t.on_transition = on_transition;
t.precondition = precondition;

return t;
}

void Fsm::trigger(int event)
{
if (m_initialized)
if (m_initialized)
{
// Find the transition with the current state and given event.
for (int i = 0; i < m_num_transitions; ++i)
for (int i = 0; i < m_num_transitions; ++i)
{
if (m_transitions[i].state_from == m_current_state &&
m_transitions[i].event == event)
{
m_transitions[i].event == event &&
m_transitions[i].precondition(m_current_state,
m_transitions[i].state_to)) {
Fsm::make_transition(&(m_transitions[i]));
return;
}
}
}
}

void Fsm::check_timed_transitions()
void Fsm::check_timed_transitions()
{
for (int i = 0; i < m_num_timed_transitions; ++i)
for (int i = 0; i < m_num_timed_transitions; ++i)
{
TimedTransition* transition = &m_timed_transitions[i];
if (transition->transition.state_from == m_current_state)
TimedTransition *transition = &m_timed_transitions[i];
if (transition->transition.state_from == m_current_state)
{
if (transition->start == 0)
if (transition->start == 0)
{
transition->start = millis();
}
else{
}
else {
unsigned long now = millis();
if (now - transition->start >= transition->interval)
if ((now - transition->start >= transition->interval) &&
transition->transition.precondition(
m_current_state, transition->transition.state_to))
{
Fsm::make_transition(&(transition->transition));
transition->start = 0;
Expand All @@ -131,25 +132,25 @@ void Fsm::check_timed_transitions()
}
}

void Fsm::run_machine()
void Fsm::run_machine()
{
// first run must exec first state "on_enter"
if (!m_initialized)
if (!m_initialized)
{
m_initialized = true;
if (m_current_state->on_enter != NULL)
m_current_state->on_enter();
}

if (m_current_state->on_state != NULL)
m_current_state->on_state();

Fsm::check_timed_transitions();
}

void Fsm::make_transition(Transition* transition)
void Fsm::make_transition(Transition *transition)
{

// Execute the handlers in the correct order.
if (transition->state_from->on_exit != NULL)
transition->state_from->on_exit();
Expand All @@ -159,16 +160,17 @@ void Fsm::make_transition(Transition* transition)

if (transition->state_to->on_enter != NULL)
transition->state_to->on_enter();

m_current_state = transition->state_to;

//Initialice all timed transitions from m_current_state
// Initialice all timed transitions from m_current_state
unsigned long now = millis();
for (int i = 0; i < m_num_timed_transitions; ++i)
for (int i = 0; i < m_num_timed_transitions; ++i)
{
TimedTransition* ttransition = &m_timed_transitions[i];
TimedTransition *ttransition = &m_timed_transitions[i];
if (ttransition->transition.state_from == m_current_state)
ttransition->start = now;
}

}

bool _enabled(const State *from, const State *to) { return true; };
46 changes: 26 additions & 20 deletions Fsm.h
Expand Up @@ -18,65 +18,71 @@


#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#include <Arduino.h>
#else
#include <WProgram.h>
#include <WProgram.h>
#endif


struct State
struct State
{
State(void (*on_enter)(), void (*on_state)(), void (*on_exit)());
void (*on_enter)();
void (*on_state)();
void (*on_exit)();
};

bool _enabled(const State *from, const State *to);

class Fsm
typedef bool (*predicate)(const State *, const State *);

class Fsm
{
public:
Fsm(State* initial_state);
Fsm(State *initial_state);
~Fsm();

void add_transition(State* state_from, State* state_to, int event,
void (*on_transition)());
void add_transition(State *state_from, State *state_to, int event,
void (*on_transition)(),
predicate precondition = _enabled);

void add_timed_transition(State* state_from, State* state_to,
unsigned long interval, void (*on_transition)());
void add_timed_transition(State *state_from, State *state_to,
unsigned long interval, void (*on_transition)(),
predicate precondition = _enabled);

void check_timed_transitions();

void trigger(int event);
void run_machine();

private:
struct Transition
struct Transition
{
State* state_from;
State* state_to;
State *state_from;
State *state_to;
int event;
void (*on_transition)();

predicate precondition;
};
struct TimedTransition
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)());
static Transition create_transition(State *state_from, State *state_to,
int event, void (*on_transition)(),
predicate precondition);

void make_transition(Transition* transition);
void make_transition(Transition *transition);

private:
State* m_current_state;
Transition* m_transitions;
State *m_current_state;
Transition *m_transitions;
int m_num_transitions;

TimedTransition* m_timed_transitions;
TimedTransition *m_timed_transitions;
int m_num_timed_transitions;
bool m_initialized;
};
Expand Down
67 changes: 67 additions & 0 deletions examples/using_predicates/light_switch_with_predicate.ino
@@ -0,0 +1,67 @@
#include "Fsm.h"

// State machine variables
#define FLIP_LIGHT_SWITCH 1

State state_light_on(on_light_on_enter, NULL, &on_light_on_exit);
State state_light_off(on_light_off_enter, NULL, &on_light_off_exit);
Fsm fsm(&state_light_off);

bool transition_enabled(const State *, const State *)
{
return millis() > 5000;
}

// Transition callback functions
void on_light_on_enter()
{
Serial.println("Entering LIGHT_ON");
}

void on_light_on_exit()
{
Serial.println("Exiting LIGHT_ON");
}

void on_light_off_enter()
{
Serial.println("Entering LIGHT_OFF");
}

void on_light_off_exit()
{
Serial.println("Exiting LIGHT_OFF");
}

void on_trans_light_on_light_off()
{
Serial.println("Transitioning from LIGHT_ON to LIGHT_OFF");
}

void on_trans_light_off_light_on()
{
Serial.println("Transitioning from LIGHT_OFF to LIGHT_ON");
}

// standard arduino functions
void setup()
{
Serial.begin(9600);

fsm.add_transition(&state_light_on, &state_light_off,
FLIP_LIGHT_SWITCH,
&on_trans_light_on_light_off);
fsm.add_transition(&state_light_off, &state_light_on,
FLIP_LIGHT_SWITCH,
&on_trans_light_off_light_on,
transition_enabled);
}

void loop()
{
// No "fsm.run_machine()" call needed as no "on_state" funcions or timmed transitions exists
delay(2000);
fsm.trigger(FLIP_LIGHT_SWITCH);
delay(2000);
fsm.trigger(FLIP_LIGHT_SWITCH);
}