Skip to content

Instantly share code, notes, and snippets.

@tinkerspy
Created July 3, 2016 11:05
Show Gist options
  • Save tinkerspy/6ca5ad01e9a3477658b32c1b36e4bad9 to your computer and use it in GitHub Desktop.
Save tinkerspy/6ca5ad01e9a3477658b32c1b36e4bad9 to your computer and use it in GitHub Desktop.
#include "Atm_trafficlight.h"
/* Add optional parameters for the state machine to begin()
* Add extra initialization code
*/
Atm_trafficlight& Atm_trafficlight::begin( int pin_g, int pin_y, int pin_r ) {
// clang-format off
const static state_t state_table[] PROGMEM = {
/* ON_ENTER ON_LOOP ON_EXIT EVT_TIMER_G EVT_TIMER_Y EVT_TIMER_R EVT_NEXT EVT_GREEN EVT_YELLOW EVT_RED ELSE */
/* GREEN */ ENT_GREEN, -1, EXT_GREEN, YELLOW, -1, -1, YELLOW, -1, YELLOW, RED, -1,
/* YELLOW */ ENT_YELLOW, -1, EXT_YELLOW, -1, RED, -1, RED, GREEN, -1, RED, -1,
/* RED */ ENT_RED, -1, EXT_RED, -1, -1, GREEN, GREEN, GREEN, YELLOW, -1, -1,
};
// clang-format on
Machine::begin( state_table, ELSE );
this->pin_g = pin_g; // Save the pins
this->pin_y = pin_y;
this->pin_r = pin_r;
pinMode( pin_g, OUTPUT ); // Set the pin modes
pinMode( pin_y, OUTPUT );
pinMode( pin_r, OUTPUT );
timer_g.set( -1 ); // Initialize the timers
timer_y.set( -1 );
timer_r.set( -1 );
return *this;
}
/* Add C++ code for each internally handled event (input)
* The code must return 1 to trigger the event
*/
int Atm_trafficlight::event( int id ) {
switch ( id ) {
case EVT_TIMER_G:
return timer_g.expired( this );
case EVT_TIMER_Y:
return timer_y.expired( this );
case EVT_TIMER_R:
return timer_r.expired( this );
}
return 0;
}
/* Add C++ code for each action
* This generates the 'output' for the state machine
*
* Available connectors:
* push( connectors, ON_CHANGE, 0, <v>, <up> );
*/
void Atm_trafficlight::action( int id ) {
switch ( id ) {
case ENT_GREEN:
digitalWrite( pin_g, HIGH );
push( connectors, ON_CHANGE, 0, 0, 0 );
return;
case EXT_GREEN:
digitalWrite( pin_g, LOW );
return;
case ENT_YELLOW:
digitalWrite( pin_y, HIGH );
push( connectors, ON_CHANGE, 0, 1, 0 );
return;
case EXT_YELLOW:
digitalWrite( pin_y, LOW );
return;
case ENT_RED:
digitalWrite( pin_r, HIGH );
push( connectors, ON_CHANGE, 0, 2, 0 );
return;
case EXT_RED:
digitalWrite( pin_r, LOW );
return;
}
}
Atm_trafficlight& Atm_trafficlight::automatic( int g, int y, int r ) {
timer_g.set( g );
timer_y.set( y );
timer_r.set( r );
return *this;
}
/* Optionally override the default trigger() method
* Control how your machine processes triggers
*/
Atm_trafficlight& Atm_trafficlight::trigger( int event ) {
Machine::trigger( event );
return *this;
}
/* Optionally override the default state() method
* Control what the machine returns when another process requests its state
*/
int Atm_trafficlight::state( void ) {
return Machine::state();
}
/* Nothing customizable below this line
************************************************************************************************
*/
/* Public event methods
*
*/
Atm_trafficlight& Atm_trafficlight::next() {
trigger( EVT_NEXT );
return *this;
}
Atm_trafficlight& Atm_trafficlight::green() {
trigger( EVT_GREEN );
return *this;
}
Atm_trafficlight& Atm_trafficlight::yellow() {
trigger( EVT_YELLOW );
return *this;
}
Atm_trafficlight& Atm_trafficlight::red() {
trigger( EVT_RED );
return *this;
}
/*
* onChange() push connector variants ( slots 1, autostore 0, broadcast 0 )
*/
Atm_trafficlight& Atm_trafficlight::onChange( Machine& machine, int event ) {
onPush( connectors, ON_CHANGE, 0, 1, 1, machine, event );
return *this;
}
Atm_trafficlight& Atm_trafficlight::onChange( atm_cb_push_t callback, int idx ) {
onPush( connectors, ON_CHANGE, 0, 1, 1, callback, idx );
return *this;
}
/* State trace method
* Sets the symbol table and the default logging method for serial monitoring
*/
Atm_trafficlight& Atm_trafficlight::trace( Stream & stream ) {
Machine::setTrace( &stream, atm_serial_debug::trace,
"TRAFFICLIGHT\0EVT_TIMER_G\0EVT_TIMER_Y\0EVT_TIMER_R\0EVT_NEXT\0EVT_GREEN\0EVT_YELLOW\0EVT_RED\0ELSE\0GREEN\0YELLOW\0RED" );
return *this;
}
#pragma once
#include <Automaton.h>
class Atm_trafficlight: public Machine {
public:
enum { GREEN, YELLOW, RED }; // STATES
enum { EVT_TIMER_G, EVT_TIMER_Y, EVT_TIMER_R, EVT_NEXT, EVT_GREEN, EVT_YELLOW, EVT_RED, ELSE }; // EVENTS
Atm_trafficlight( void ) : Machine() {};
Atm_trafficlight& begin( void );
Atm_trafficlight& trace( Stream & stream );
Atm_trafficlight& trigger( int event );
int state( void );
Atm_trafficlight& onChange( Machine& machine, int event = 0 );
Atm_trafficlight& onChange( atm_cb_push_t callback, int idx = 0 );
Atm_trafficlight& next( void );
Atm_trafficlight& green( void );
Atm_trafficlight& yellow( void );
Atm_trafficlight& red( void );
Atm_trafficlight& begin( int pin_g, int pin_y, int pin_r );
Atm_trafficlight& automatic( int g, int y, int r );
private:
enum { ENT_GREEN, EXT_GREEN, ENT_YELLOW, EXT_YELLOW, ENT_RED, EXT_RED }; // ACTIONS
enum { ON_CHANGE, CONN_MAX }; // CONNECTORS
atm_connector connectors[CONN_MAX];
int pin_g, pin_y, pin_r;
atm_timer_millis timer_g, timer_y, timer_r;
int event( int id );
void action( int id );
};
/*
Automaton::ATML::begin - Automaton Markup Language
<?xml version="1.0" encoding="UTF-8"?>
<machines>
<machine name="Atm_trafficlight">
<states>
<GREEN index="0" on_enter="ENT_GREEN" on_exit="EXT_GREEN">
<EVT_TIMER_G>YELLOW</EVT_TIMER_G>
<EVT_NEXT>YELLOW</EVT_NEXT>
<EVT_YELLOW>YELLOW</EVT_YELLOW>
<EVT_RED>RED</EVT_RED>
</GREEN>
<YELLOW index="1" on_enter="ENT_YELLOW" on_exit="EXT_YELLOW">
<EVT_TIMER_Y>RED</EVT_TIMER_Y>
<EVT_NEXT>RED</EVT_NEXT>
<EVT_GREEN>GREEN</EVT_GREEN>
<EVT_RED>RED</EVT_RED>
</YELLOW>
<RED index="2" on_enter="ENT_RED" on_exit="EXT_RED">
<EVT_TIMER_R>GREEN</EVT_TIMER_R>
<EVT_NEXT>GREEN</EVT_NEXT>
<EVT_GREEN>GREEN</EVT_GREEN>
<EVT_YELLOW>YELLOW</EVT_YELLOW>
</RED>
</states>
<events>
<EVT_TIMER_G index="0" access="PRIVATE"/>
<EVT_TIMER_Y index="1" access="PRIVATE"/>
<EVT_TIMER_R index="2" access="PRIVATE"/>
<EVT_NEXT index="3" access="PUBLIC"/>
<EVT_GREEN index="4" access="PUBLIC"/>
<EVT_YELLOW index="5" access="PUBLIC"/>
<EVT_RED index="6" access="PUBLIC"/>
</events>
<connectors>
<CHANGE autostore="0" broadcast="0" dir="PUSH" slots="1"/>
</connectors>
<methods>
</methods>
</machine>
</machines>
Automaton::ATML::end
*/
#include <Automaton.h>
#include "Atm_trafficlight.h"
Atm_trafficlight trafficlight;
void setup() {
// Serial.begin( 9600 );
// trafficlight.trace( Serial );
trafficlight.begin( 4, 5, 6 ) // Pins 4, 5 & 6
.automatic( 5000, 2000, 5000 ); // Green 5s, yellow 2s, red 5s
}
void loop() {
automaton.run();
}
@tinkerspy
Copy link
Author

This is the code from the Machine Building 2 tutorial:

https://github.com/tinkerspy/Automaton/wiki/Machine-building-tutorial-2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment