Index

Introduction

Classes and objects

Output file declaration (FILE)

Pin/value declarations and types (DECLARE)

Expressions

digitalRead(p)

analogRead(p)

Class definition (CLASS, STATE)

Ports (PORT IN, PORT OUT)

ON EVENT

SET STATE

DIGITAL WRITE

Send events (SEND)

Timers (TIMER, SET TIMER, CLEAR TIMER)

Start transition (START)

Object parameters (REQUIRES)

Class attributes and assignment (ATTRIBUTE)

Object instancing (OBJECT)

IF/ELSIF/ELSE/ENDIF

Continuous events (WHEN)

Connections (CONNECT)

Queue length (QUEUE LENGTH)

Integration with Arduino libraries and C++

Tracing and debugging

Introduction

The Generino language is an explicit implementation of message-based finite-state machines (FSM).

Complete and formal definitions of FSMs can be find on the internet (see for example Wikipedia, so we shall give a short and down-to-earth definition of it.

Finite-State Machines are a programming paradigm where the involved objects simply sit there waiting for something to happen. When something interesting happens, they receive a notification called event. When an object receives an event, it is allowed to execute commands but using a negligible amount of time.

When such objects receive an event, they can generate events directed to other objects, change bits in the processor registry and doing any other thing. This sequence of actions is called transition.

When they are done processing, they move into a state which can be the same as before or a new one.

Every state has a list of events it reacts to with their related transition code: in this way, the same object can react to the same event in different way according to its state. For example, a simple light controller could have the state ON and OFF: when it receives the "toggle" event, could react turning on the light if in state OFF or turning it on if in the ON state.

In the Generino implementation, only one transaction is executed at a given time: events sent to other objects will be queued until the target object reaches its execution slot.

The Generino implementation is very simple: all objects are called in turn continuosly. At each call, every object checks its own queue: if it has some events waiting, it will process them; then, it will return control.

Classes and objects

The entire Generino FSM implementation is contained by classes; a class is a logical container that lists the valid states the FSM, what events it expects and sends and how it should react, state by state, when an event is received.

In order to be operative, a class is to be instanced into an object. This allow reusing the same concepts for multiple similar instances. For example, we can have a class LedBlinker describing a blinking led: then we can create many objects, instances of LedBlinker, each one controlling a different led.

If a class is designed to handle a single problem that can not be replicated, it will have one class and one object instanced.

Output file declaration

Generino creates a .ino file that can be compiled with the normal Arduino IDE.

Name and location of the generated file must declared in the Generino source file using the FILE keyword:

FILE "prog1\\prog1.ino"

In the example above the generated file will be prog1.ino, that will be created under a directory named prog1.

Since the path specified is relative, the directory will be created below the directory where the .fct target project has been saved.

Note the double backslash (\\): this is required because quoted strings supports the same escape characters of C and C++. Note also that you can use as well the slash (/) symbol: both work automatically on Windows and Unix environments.

No matter how manu .gino files your project includes, there must be one and only one FILE declaration.

Important: the Arduino compiler requires the main .ino file to be in a directory with the same name. So, if you create abc.ino, this file must be in a directory named abc.

Pin/value declarations and types

Pin declaration is used to define which Arduino pins are being used, how (digital input, digital output or analog input) and their name. The Generino code generator will automatically generate the appropriate pinMode function.

The pin declaration can be done using the given form:

DECLARE type name = value

The supported types are:

Type Description
DIGITAL INPUT

Arduino digital input pin; value must be a valid digital pin number. For example:

DECLARE DIGITAL INPUT PIN_ENC_A = 8
DIGITAL OUTPUT

Arduino digital output pin; value must be a valid digital pin number. For example:

DECLARE DIGITAL OUTPUT PIN_LED_YELLOW = 13
ANALOG INPUT

Arduino digital output pin; value must be a valid analog pin number; strings like A0 are admitted. For example:

DECLARE ANALOG INPUT PIN_SENSOR = A0
NUMBER

this is a special case where a generic number can be defined; it can be used wherever a number is required, like for example when setting a timer timeout. It supports expressions:

DECLARE NUMBER Period1 = 100+Period2
DECLARE NUMBER Period2 = 320

Predefined values

Generino supports some predefined values that can be used without any definition:

Name Type Description
nowMs NUMBER Current reference time in milliseconds, used by timers. Set once at the beginning of every cycle.
HIGH NUMBER Same as Arduino's HIGH macro, used for digital pins.
LOW NUMBER Same as Arduino's LOW macro, used for digital pins.

Expressions

The Generino language supports expressions formed by the usual C operators. The Generino expressions accept and return values of the NUMBER type. For example:

DECLARE NUMBER Period1 = 2*(100+Period2)+10*HIGH
DECLARE NUMBER Period2 = 320

Class definition

In Generino a class is defined with the CLASS/END CLASS statements. This is a minimal class definition:

CLASS BlinkingLed
  STATE ledOff
  END STATE

  STATE ledOn
  END STATE
END CLASS

The class above has two states and reacts to no events at all.

Ports

Ports define the channels that allow an object to receive or send events:

CLASS BlinkingLed
  PORT IN commandsToMe RECEIVES enable, disable, faster, slower
  PORT OUT notifications SENDS ledIsOn, ledIsOff

  STATE ledOff
  END STATE

  STATE ledOn
  END STATE
END CLASS

The code above declares two ports. The port named commandsToMe is an incoming port and it is enabled to receive messages. The port The port named notifications is an outgoing port and it is enabled to send messages.

Each port contains a list of events that can be sent or received by the port.

Transitions (ON EVENT)

Transitions are sequences of instructions that are triggered by the reception of an event in a given state.

CLASS BlinkingLed
  PORT IN commandsToMe RECEIVES enable, disable, faster, slower
  PORT OUT notifications SENDS ledIsOn, ledIsOff

  STATE ledOff
    ON EVENT enable
      transition 1...
    END

    ON EVENT disable
      transition 2...
    END
  END STATE

  STATE ledOn
  END STATE
END CLASS

The above code contains two transitions: transition 1 is the code executed when, in the ledOff state, the object receives an enable event. Transition transition 2, instead, is executed when in the same state it receives a disable event.

In the following chapters we shall see the instructions supported by the transition code.

SET STATE

SET STATE newState

Sets the next state to newState. The next transition will start from state newState.

If multiple SET STATE are specified, only the last one will be taken in accound. If no SET STATE are specified, the next state will be the same as the previous one.

The state specified in SET STATE must be a valid state declared with STATE x in the same class.

CLASS BlinkingLed
  PORT IN commandsToMe RECEIVES enable, disable, faster, slower
  PORT OUT notifications SENDS ledIsOn, ledIsOff

  STATE ledOff
    ON EVENT enable
      SET STATE ledOn
    END
    ON EVENT disable
    END
  END STATE

  STATE ledOn
  END STATE

END CLASS

DIGITAL WRITE

DIGITAL WRITE value TO PIN digOut

Sets the digital output to value. For example:

DIGITAL WRITE HIGH TO PIN LED_PIN

Parameter value must be of type DIGITAL OUTPUT.

Send event

The SEND statement is used within a transition to send an event to another object. The event is to be routed through one of the output ports that support the event being sent:

SEND event TO PORT portName

Parameter event is one of the events listed after the PORT OUT declaration whose name matches portName.

The event being sent will be queued in all objects connected to the given output port.

The "TO PORT portName" part can be omitted if this class has only one output port defined.

Timers

TIMER timerName
SET TIMER timerName TO ms
CLEAR TIMER timerName

A timer is an internal reasource that sends an event after a given number of milliseconds to the object that activated it.

Parameter ms must be of type NUMBER.

The timer event appears like normal event but it does not come from a port. For this reason, the timer can not have a

Command SET TIMER sets the timer timerName to expire after ms milliseconds from now. For example:

SET TIMER tim TO 100

If the timer was already set, it will be set to the new timeout value. The timer

Command CLEAR TIMER clears the timer timerName so it does not expire anymore. If the timer was already off, nothing happens. For example:

CLEAR TIMER tim

This is a timer example: the led is turned off after 3s from start unless a stopOperations event is received:

// Turn on a led after 3s unless the "stopOperations" event is received
CLASS Led
  PORT IN inChannel RECEIVES stopOperations

  TIMER blinkPeriod

  START
    SET TIMER blinkPeriod TO 3000
  END START

  STATE blinkedOff
    ON EVENT blinkPeriod
      DIGITAL WRITE HIGH TO PIN ledPin
    END
    ON EVENT stopOperations
      CLEAR TIMER blinkPeriod
    END
  END STATE
END CLASS

Start transition

The start transition is a transition that is automatically executed when the object is instanced:

CLASS myClass
  START
    start transition code
  END START
  ...
END CLASS

The start transition can contain any code that can normally go within a transition. It can be used, for example, to set an initial state, to set initial timers, set pin outputs and so on.

Object parameters

In order to use the same implementation for multiple objects, classes support object parameters. Object parameters are some configuration data that must be specified every time an object of that class is being created. For example, a BlinkingLed class could have two object parameters, pinNumber and blinkMillisecs: in this way, multiple BlikingLed objects could be instanced on different leds and different blinking ratios.

Object parameters are declared within the class with the REQUIRES keyword:

REQUIRES type name

The available parameter types are the same as those alreay exposed in the declaration types section.

Example:

CLASS BlinkingLed
  REQUIRES DIGITAL OUTPUT ledPin
  REQUIRES NUMBER blinkMs
  ...
END CLASS

Once declared, these parameters can be used inside a class in their appropriate position. For example, a DIGITAL OUTPUT parameter can be used in a DIGITAL WRITE statement:

DIGITAL WRITE HIGH TO PIN ledPin

Class attributes and assignment

Class attributes are values that maintained by each object of the class for internal use. They are declared inside a class with the following syntax:

ATTRIBUTE type name

Although type can be any valid type, the most used one will be NUMBER.

Attributes can be used within expressions and assigned using the = symbol inside the transition code:

ATTRIBUTE NUMBER blinkDelay

ON EVENT myEvent
  blinkDelay = blinkDelay + 100
  SET TIMER tim TO blinkDelay
END

Object instancing

Once a class has been defined, objects of that class must be instanced in order to be used. Each object has a unique name and it must supply the object parameters requested by its class.

OBJECT className objectName par1=value1 par2=value2 ... parN=valueN

For example:

OBJECT BlinkingLed led2 ledPin=PIN_LED_YELLOW blinkMs=100

IF/ELSIF/ELSE/ENDIF

The IF statement allows to control the execution flow within a transition.

Its general form is:

IF expr1 THEN
  statements1
ELSIF expr2 THEN
  statements2
...
ELSIF exprN THEN
  statements2
ELSE
  statementsElse
END IF

digitalRead

The digitalRead(pin) is an expression that reads the status of a digital pin, with the same rules of the digitalRead() Arduino function. The pin parameter must be an expression of type DIGITAL INPUT.

analogRead

The analogRead(pin) is an expression that reads the status of a analog pin, with the same rules of the analogRead() Arduino function. The pin parameter must be an expression of type ANALOG INPUT.

Continuous event

A continuous event consists in a repeated monitoring of a resource looking for a change. For example, when waiting for an hardware button to be pressed, the system has to continously read its pin waiting for its value to go high.

In Generino, this is obtained by the WHEN keyword:

WHEN expression
  statements
END WHEN

The NUMBER expression is evaluated at every cycle. If it returns other than zero, it will execute the statements.

In the example below, the machine state changes its state when a button is pressed or released. Every time a button is pressed, a trigger event is emitted:

CLASS SimpleButton
  REQUIRES DIGITAL INPUT buttonPin
  PORT OUT action SENDS trigger
  
  STATE depressed
    WHEN digitalRead(buttonPin)
      SET STATE pressed
      SEND trigger TO PORT action
    END WHEN
  END STATE
  
  STATE pressed
    WHEN !digitalRead(buttonPin)
      SET STATE depressed
    END WHEN
  END STATE

END CLASS

Connections

Connections are to be used to connect input and output ports of various objects:

CONNECT portOut@objectOut TO portIn1@objectIn1, portIn2@objectIn2, ..., portInN@objectInN

For example:

CONNECT out1@logic TO commands@led1
CONNECT out2@logic TO commands@led2
CONNECT action@btn1 TO inCommand1@logic, commands@bouncer
CONNECT action@btn2 TO inCommand1@logic
CONNECT action@btn2 TO clear@displ
CONNECT action@rot TO rotary@displ

The connected input and output ports must hold at least one event in common. Otherwise an error will occur because communication among those ports would be impossibile.

Queue length

Events sent from one object to another are queued up until the receiving object is able to process them. In theory, an object could receive any number of events before being able to process them. However, maintaining a long queue is expensive in terms of memory: for this reason, the length of the queue can be finely tuned.

The default queue length is 4 items but it can be programmed using the QUEUE LENGTH keyword:

CLASS MyClass QUEUE LENGTH 1
	...
END CLASS

Classes without input port have always queue length of 0. For all the other classes, the queue length can range from 1 to 255.