Declarative programming with MansOS
Contents
Quick Start
Go to mansos/apps/sadlang/Blink and type
make <architecture>
in command line.
If you haven't used MansOS before, the tutorial will be helpful.
mansos/apps/sadlang/ contains Blink and other SeAdScript example applications. The file main.sl in every subfolder contains SeAdScript source code for the particular application.
Overview
SeAdScript (Sensor Application Development Script) is a declarative application specification language.
SeAdScript code is stored in files with the extension .sl.
Source file can contain the following kind of statements:
- statements describing systems parameters (
parameter
), such as the routing protocol used or system's energy budget - statements describing actuators and other active agents (
use
), such as LEDs or debug output agents (use Print
) - statements describing sensors (
read
), such as temperature, voltage or light sensors when
statements - code block that start with a conditional expressions and in turn can contain blocks of other statements- statements describing where the output of the system should go (
output
), such as serial port, radio, or network protocols
Each of the use
, read
, and output
statements has the following syntax:
<statement> <name>, <parameterN> [<parameter1 value>], <parameter2> [<parameter2 value>], ..., <parameterN> [<parameterN value>];
For output
statements, a list of packet fields can also be specified. This list can contain:
- <fieldName> -- a field which correspond to a sensor in the system;
- <fieldName> <number> -- the same, but included in the packet not once, but a number of times;
- const<FieldName> <value> - fields with constant values (for example, some ID of the mote). The names of these fields must start with "const", and they shouldn't correspond to any sensor names;
If the list is omitted, all active sensors are included in the packet.
SeAdScript supports C-style comments. Comments start with double slash ("//") and last until the end of the line.
The language at the moment is case partially-sensitive - i.e. all keywords must be in small case, while identifiers are not case sensitive.
Actuators
Specified with the use
keyword.
Examples:
- Led
- RedLed
- GreenLed
- BlueLed
- Print (NOT SUPPORTED YET!)
Parameters:
- period - toggle period
- on_time - time when turned on, seconds after system's start
- off_time - time when turned off, seconds after system's start
- blink, blinkTwice, blinkTimes <n> - for LEDs
Sensors
Specified with the read
keyword.
Examples:
- Light
- Humidity
- Temperature (NOT SUPPORTED YET!)
- InternalVoltage (NOT SUPPORTED YET!)
- InternalTemperature (NOT SUPPORTED YET!)
- ADC channels (NOT SUPPORTED YET!)
Parameters:
- period - read period
Outputs
Specified with the output
keyword.
Examples:
- Serial port (USB)
- Radio
- MAC protocol
- Network socket
Parameters:
- aggregate - whether to send all in one packet or each value individually
- baudrate - serial port baudrate, by default 38400
- crc - whether to add checksum for packets, by default on for radio
Specifying individual fields
The following syntax is supported:
output <name> {field1, field2, ..., fieldN <timesToInclude>, ... , constField1 value1, constaField2 value2, ...}, <parameter1> [<parameter1 value>], ..., <parameterN> [<parameterN value>];
The field list is optional, but if present, it must be non-empty.
Constants (NOT SUPPORTED YET!)
A boolean or integer constant can be declared by using this syntax:
const <name> <value>;
Afterwards, it can be used everywhere when and scalar value is required.
States (NOT SUPPORTED YET!)
The language is not fully declarative, it has some statements with side effects. In particular, finite-state machine abstractions are built in the language.
A state of the system can be specified by state keyword. The syntax is:
state <name> [<initial value>];
States can take boolean or integer values, including symbolic constants.
Once declared, the state can be
Code example:
state temperatureCritical false; when Sensors.Temperature > 50: set temperatureCritical true; when Sensors.Temperature < 40: set temperatureCritical false; when temperatureCritical: use RedLed, period 100ms;
Conditions (NOT SUPPORTED YET!)
Syntax:
when <condition>: statement1; statement2; else when <condition>: statement1; statement2; end
Conditions:
- System.time - time elapsed
- System.RTC - clock time, requires real time clock present on the mote
- System.isDaytime - whether the current time is in day, real time clock present on the mote
- MAC.isBaseStationNearby - whether as base station is reachable via radio
Using sensors in conditions
Each sensor present in the system can also be used in a condition:
when Voltage.value < 1234: use RedLed, turn_on;
A condition can also be made on sensor failing or working correctly:
when Light.failed: use RedLed, turn_on; when not Light.failed: use GreenLed, period 1s;
Combining conditions
Two or more conditions can be combined together with logical connectives and
, and or
. If multiple are specified, and
has higher priority. Unary not
can also be used to invert a value of an condtion.
when <condition1> and not <condition>2: statement1;
Code inclusion (NOT SUPPORTED YET!)
Both C code and configuration file fragments can be included in a SeAdScript program.
...
Code examples
Blink with some extras:
use RedLed, period 1s, on_time 1500ms, off_time 4500ms;
Conditional blink of all three leds:
// blink red led periodically use RedLed, period 1000ms; // blink green led; faster at the start when System.time < 5s: use GreenLed, period 100ms; else: use GreenLed, period 1000ms; // turn on blue led once the program has started use BlueLed, on_time 2000ms;
Light sensor reading:
read Light, period 2s; output Serial, baudrate 38400;
Examples for syntactic sugar for conditions. Base case syntax:
when System.time < 5s: use BlueLed, period 100ms; end
One-liner:
when System.time < 5s: use BlueLed, period 100ms;
Another one-liner:
use BlueLed, period 100ms, when System.time < 5s;
Else-when syntax:
when System.time < 2s: use BlueLed, period 100ms; use RedLed, period 200ms; elsewhen System.time < 6s: use BlueLed, period 500ms; use RedLed, period 1000ms; else: use BlueLed, period 2000ms; use RedLed, period 3000ms; end
Just turn on a led when a constant condition is true:
when 1 < 2 use BlueLed, turn_on;
A larger example:
// do nothing, just declare that red LED will be used in the program use RedLed; // red led is on when system starts use RedLed, turn_on; // red led is turned off when a condition is fullfilled // (conditions are checked in the main loop at least once per minute) use RedLed, turn_off, when 1 < 2; // blue led is always on in daytime when System.isDaytime: use BlueLed, turn_on; // blue led blinks periodically in night when System.isDaytime = false: use BlueLed, period 1000; // alternatively: when System.isDaytime: use BlueLed, turn_on; else: use BlueLed, period 1000; end // compilation error // when System.isDaytime = false use BlueLed, period 2000; // blink one time on radio rx use GreenLed, blinkOnce, when System.radioRx; // blink two times on radio rx error use GreenLed, blinkTwice, when System.radioRxError; // blink three times on radio tx use GreenLed, blinkTimes 3, when System.radioTx; // during daytime also read sensors when System.isDaytime read Light, period 2s; read Humidity, period 2s; end // send data to serial output Serial; // also send data to radio output Radio;
Another larger example:
// define system parameters parameter battery 2700mAh; parameter routingProtocol GPSR; // blink red led periodically use RedLed, period 1000ms; // turn green led on once the program has started use GreenLed, on_time 2000ms; // blink blue led; faster at the start when System.time < 5s: use BlueLed, period 100ms; else: use BlueLed, period 1000ms; end // read onboard light sensor once every 10 seconds read Light, period 10s; // read a specific sensor once every 10 seconds read APDS9300, period 10s; // define a constant time value const PERIOD 10s; read Humidity, period PERIOD; // by default, output all data read to serial port; the baudrate is 38400 by default, but specify it explicitly output Serial, baudrate 38400; // also output to radio (aggregate=yes means put all data in one packet; by default on for radio, off for serial port) output Radio, aggregate yes; // also output to MAC protocol, but only when a base station is detected nearby output Network, protocol CSMA_MAC, when MAC.baseStationIsReachable; // also output to higher level network-stack output Network, protocol Socket, port 100; // save light sensor values (but not humidity sensor!) to flash in case battery voltage is above 2.7V output Flash {Light, APDS9300}, when System.voltage > 2.7V;