Skip to content

lf-lang/reactor-uc-tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

69 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

micro-LF tutorial on RIOT-OS

banner


This is a tutorial for Lingua Franca applications running on RIOT OS with the Adafruit Feather Sense board. It uses reactor-uc, the "micro C" target for Lingua Franca.


Part 1: Environment Setup

1.1. Supported Operating Systems

OS Support Level
Linux (Ubuntu/Debian) Fully supported (recommended)
NixOS / Nix Fully supported
macOS Supported with caveats

Note: For detailed RIOT OS setup instructions, see the official RIOT Getting Started Guide.

1.2. Clone reactor-uc and this tutorial

clone

# Clone via HTTPS
git clone https://github.com/lf-lang/reactor-uc.git --recurse-submodules

# Or clone via SSH
git clone git@github.com:lf-lang/reactor-uc.git --recurse-submodules

# Set the environment variable (add to ~/.bashrc for persistence)
export REACTOR_UC_PATH=$(pwd)/reactor-uc

1.3. Install Dependencies

Choose the setup method for your operating system:

1.3.1. Linux (Ubuntu / Debian)

Most RIOT OS developers use Linux, providing the most streamlined experience. Ubuntu is recommended for newcomers.

Install required packages:

sudo apt update
sudo apt install git openjdk-17-jdk openjdk-17-jre cmake build-essential \
    python3 python3-serial gcc-arm-none-eabi gdb-multiarch openocd

1.3.2. NixOS / Nix Package Manager

This is the easiest setup method. The repository includes a shell.nix / flake.nix that provisions all dependencies automatically.

If you don't have Nix installed:

curl -L https://nixos.org/nix/install | sh

Otherwise use your package manager to install it.

Enter the development environment:

nix develop

This creates a shell with all dependencies (cross-compiler, Java, etc.) pre-installed. No manual package installation required.

Important: Run nix develop each time you open a new terminal session for this project.

1.3.3. macOS

Native macOS development is supported but requires additional setup. macOS ships with an older version of make, so you must install GNU Make 4.0+.

Install required packages via Homebrew:

brew install git cmake openjdk@17 make
pip3 install pyserial

Install the ARM cross-compiler:

brew install --cask gcc-arm-embedded

Warning: Do not install the arm-none-eabi-gcc formula. If you did, uninstall it first:

brew uninstall arm-none-eabi-gcc
brew install --cask gcc-arm-embedded

Important: On macOS, make is installed as gmake. Use gmake instead of make in all commands below.

1.4. Verify Your Setup

Check that the required tools are available:

# Check cross-compiler
which arm-none-eabi-gcc

# Check Java version (should be 17+)
java -version

# Check make version (should be 4.0+)
make --version   # or gmake --version on macOS

1.5. Initialize the Repository

The RIOT OS sources are provided as a submodule of the repository. Fetch them with:

cd reactor-uc-tutorial
git submodule update --init --recursive

Part 2: Getting Started

2.1. Configure the Makefile

The repository has a Makefile that governs the build. By default, it compiles the LF program in src/HelloUc.lf. To compile a different program, edit the Makefile to set LF_MAIN to your program and BOARD to your board.

LF_MAIN ?= HelloUc
BOARD ?= adafruit-feather-nrf52840-sense

Alternatively, you can override the board on the command line. For example:

make LF_MAIN=HelloUc all

2.2. Build

make all

Or override the Makefile configuration with parameters:

make LF_MAIN=HelloUc BOARD=adafruit-feather-nrf52840-sense all

2.3. Flash the Program onto Your Board

flashing

make flash

Or override the Makefile configuration with parameters:

make LF_MAIN=HelloUc BOARD=adafruit-feather-nrf52840-sense flash

2.4. Open a Terminal

You can open a terminal that interacts with stdin and stdout of your program as follows:

make term

This will display any output your program generates using, for example, printf.

You can also get debug output from the reactor-uc runtime by changing the following line in the Makefile:

CFLAGS += -DLF_LOG_LEVEL_ALL=LF_LOG_LEVEL_ERROR

to

CFLAGS += -DLF_LOG_LEVEL_ALL=LF_LOG_LEVEL_DEBUG

debug


Part 3: Basic Tutorial

3.1. LedController Reactor

Modify src/LedController.lf — a reactor that controls the on-board LED.

Lingua Franca docs: lf-lang.org/docs

Task: Add an input port named toggle.

Task: Implement a reaction that reacts on the toggle input port. This reaction should check the state variable self->num to toggle either LED 0 or LED 1.

Use the RIOT macros from led.h: LED0_TOGGLE and LED1_TOGGLE

3.2. HelloUc: Using the LedController

Edit src/HelloUc.lf to use your LedController with a periodic timer.

You can import reactor from other files like this:

import LedController from "./LedController.lf"

The file already imports and instantiates the LedController as led, and includes a startup reaction that sets the LED on initially.

Task: Add a timer.

Task: Add a reaction that is triggered by the timer and toggles the led.toggle port.

Flashing Procedure LF Diagram
flash_and_blinking blink_diagram

Part 4: Sensor Integration

4.1. Sensor Makefile Configuration

Add the following lines to your Makefile to enable I2C support in RIOT:

# so i2c and printf support for floats is compiled into the riot kernel
USEMODULE += periph_i2c
USEMODULE += printf_float

4.2. Implementing the Sensor

The Adafruit Feather Sense includes many sensors. We'll focus on the LSM6DS33 accelerometer and gyro. See the full sensor list for details.

The file LSM6DS33.lf has a section for reading sensor values that you need to complete. Refer to the RIOT I2C documentation and read register OUTX_L_G (see the datasheet for details).

To test your sensor implementation, compile and run Sensor.lf (which includes the sensor reactor). This command compiles, flashes, and opens the serial console:

make LF_MAIN=Sensor BOARD=adafruit-feather-nrf52840-sense all flash term

4.3. Using Sensor Values

Make the LED blink faster or slower based on the device's orientation. When flat on a table (angle ≈ 0), use a 1-second LED toggle period.

uint32_t time_speed_up = MAX(ROTATION_TO_TIME * total_angle_x) + BASE_BLINKING_PERIOD, MIN_BLINKING_PERIOD);

This produces our PERIOD in milliseconds.

Task: Add a reaction that gets triggered based on the self->blinking_speed period. Use the logical action blink for this. This reaction should also toggle the LED.

sensor

Flash the program and rotate the device around its longest axis to see the LED blink rate change. See the video below.

Flashing Procedure LF Diagram
flash_and_blinking blink_diagram

Part 5: Advanced Features

5.1. Annotations

reactor-uc supports many annotations; see the full list. In this scenario, we'll add a timeout and configure a buffer size for actions.

  • Timeout: add the @timeout(<time_value>) annotation to the main reactor.
  • Action Buffer Size: add the @max_pending_event(<number>) before the action declaration.

Now recompile your program.

You can validate if the code generator correctly adjusted the action buffer size by opening src-gen/Sensor/Sensor/Sensor.h file and searching for the LF_DEFINE_ACTION_STRUCT macro.

The timeout property can be found inside the src-gen/Sensor/lf_start.c file inside the DynamicScheduler_ctor.

5.2. Delayed Connections and the Buffer Annotation

Before we go federated it is good to look into the @buffer annotation, which can be added to delayed connections to increase the associated buffer for storing the values. If you have a timer with a high frequency it is very easy to run out of space inside the connection.

Task: The DelayedConn.lf program has a high-frequency source (1ms timer) with a 500ms delayed connection. Experiment with different @buffer values to find the minimum buffer size that prevents dropped values.

Compile and Flash your program, then observe the output and adjust the @buffer annotation until no values are dropped.


Part 6: Federated Execution

6.1. Finding Your Device's IPv6 Address

Temporarily add the following to your Makefile:

USEMODULE += gnrc_netif
USEMODULE += gnrc_ipv6_default
USEMODULE += ipv6_addr
USEMODULE += netdev_default
USEMODULE += gnrc_netif_ieee802154
USEMODULE += gnrc_ipv6_default
USEMODULE += auto_init_gnrc_netif
USEMODULE += auto_init

Then compile and run the src/Ipv6LinkLocal.lf program. This program will print the IPv6 Link Local address of this board. Copy and save this address.

ipv6

6.2. Simple Federated Example

You need to tell reactor-uc to add the COAP network channel to the compilation unit:

CFLAGS += -DNETWORK_CHANNEL_COAP_RIOT

In reactor-uc, configure the network channels by adding annotations:

@interface_coap(name="if1", address="<Paste Your Link Local Address Here>")

Task: Coordinate with your neighbor, agree on which federate your board will run, and exchange the IPv6 link local addresses accordingly. Also, make sure your programs have the same structure.

This creates a CoAP network channel named if1 with the specified IPv6 address. The @link annotation specifies which network channel interface to use for a connection.

The compilation command also changes because you now need to specify which federate to compile and flash using the LF_FED variable:

make LF_MAIN=SimpleCoapFederated LF_FED=r1 BOARD=adafruit-feather-nrf52840-sense all flash term

make LF_MAIN=SimpleCoapFederated LF_FED=r2 BOARD=adafruit-feather-nrf52840-sense all flash term

If successful, you should see in the serial output that the two federates are communicating.

Flashing Procedure LF Diagram
flash_and_blinking blink_diagram

6.3. The Final Boss - Federated Blinking

drawing

You made it to the final level.

Open the the src/FederatedBlinking.lf file now we want to combine everything learned and here we want to let the local Blink faster if neighbors microcontroller is turned.

Then make sure all the necessary modules are added inside your Makefile. Additionally, make sure you flash the correct version onto the correct board (otherwise the addresses won't match).

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors