The RiotOS operating system is an Open Source operating system that targets different embedded platforms while allowing to use the same code base for some aspects of IoT development: Connectivity, protocols and security. It also supports other key aspects such as threads, Inter process communication, synchronization support on the kernel side. It also supports several communications protocols, suche BLE, 6LoWPAN, Lorawan, and so on.
At the target level for the RiotOS operating system, RiotOS supports a wide scope of different platforms, including a special native platform. What does this means? It means that within certain limitations, it is entirely possible to develop an IoT application that runs where the code is developed, this includes our PC and any SBC such as the RaspberryPI. This support opens a new window of opportunities where it is possible to integrate different classes of devices, such as Arduino, STM32 and RPI while leveraging the knowledge on the same supporting code base.
How to start:
This is a very quick start instructions for building a native demo application with network support. As usual all the instructions apply to a Linux Operating system, in my case Arch Linux.
Clone the RiotOS repository:
Just run:
cd /opt
git clone https://github.com/RIOT-OS/RIOT.git
I’ve chosen the /opt directory for the sake of example.
Compile one the example application:
All example applications are under the example applications.
In each directory, there is a Makefile file with a specific content.
For example on the examples/default there is Makefile that targets the native environment.
Of key interest is the line in this file that defines the target board:
BOARD ?= native
If the BOARD variable is not defined on the running environment it will use the native board.
We just need now to run the make command:
[pcortex@pcortex:default|master]$ make
Building application "default" for "native" with MCU "native".
"make" -C /opt/RIOT/boards/native
"make" -C /opt/RIOT/boards/native/drivers
"make" -C /opt/RIOT/core
"make" -C /opt/RIOT/cpu/native
...
...
...
"make" -C /opt/RIOT/sys/shell
"make" -C /opt/RIOT/sys/shell/commands
text data bss dec hex filename
88189 1104 72088 161381 27665 /opt/RIOT/examples/default/bin/native/default.elf
We can see that the compilation output was placed at /opt/RIOT/examples/default/bin/native/default.elf.
But if we ran the default.elf executable, we get:
[pcortex@pcortex:default|master]$ bin/native/default.elf
usage: bin/native/default.elf [-i ] [-d] [-e|-E] [-o] [-c ]
help: bin/native/default.elf -h
Options:
-h, --help
print this help message
-i , --id=
specify instance id (set by config module)
-s , --seed=
specify srandom(3) seed (/dev/random is used instead of random(3) if
the option is omitted)
-d, --daemonize
daemonize native instance
-e, --stderr-pipe
redirect stderr to file
-E, --stderr-noredirect
do not redirect stderr (i.e. leave sterr unchanged despite
daemon/socket io)
-o, --stdout-pipe
redirect stdout to file (/tmp/riot.stdout.PID) when not attached
to socket
-c , --uart-tty=
specify TTY device for UART. This argument can be used multiple
times (up to UART_NUMOF)
A little side note, under bin there is a native directory but if we target the compilation to a different platform, a new directory under bin will be created to that platform.
Returning to result to the above command, we notice that the command requires a TAP (terminal interface point) interface. The fact is that the RiotOS code to access the network resources of the hosting operating system doesn’t access the network interface directly, but does it through the TAP interface. We can create only one TAP interface, or several TAP interfaces, which in such case, means that we can have several RiotOS applications using an TAP based network to communicate between themselves and also with the external network. Neat!
RiotOS offers a script to the TAP intefaces, but before running the script, just make sure if any Linux operating system Kernel was done recently, a reboot migh be needed to the interfaces be successfully created.
So:
[pcortex@pcortex:RIOT|master]$ ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp6s0: mtu 4000 qdisc fq_codel state UP group default qlen 1000
link/ether 00:24:8c:02:dd:7e brd ff:ff:ff:ff:ff:ff
inet 192.168.1.68/24 brd 192.168.1.255 scope global noprefixroute enp6s0
valid_lft forever preferred_lft forever
inet6 fe80::224:8cff:fe02:dd7e/64 scope link
valid_lft forever preferred_lft forever
Now we run the tapsetup script that creates the TAP interfaces. This script when called without any parameters, it creates two TAP interfaces. If we pass the -c argument with a number, for example -c 4, it will create 4 TAP interfaces. The -d parameter deletes all interface that where created.
[pcortex@pcortex:tapsetup|master]$ pwd
/opt/RIOT/dist/tools/tapsetup
[pcortex@pcortex:tapsetup|master]$ sudo ./tapsetup
creating tapbr0
creating tap0
creating tap1
[pcortex@pcortex:tapsetup|master]$ ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp6s0: mtu 4000 qdisc fq_codel state UP group default qlen 1000
link/ether 00:24:8c:02:dd:7e brd ff:ff:ff:ff:ff:ff
inet 192.168.1.68/24 brd 192.168.1.255 scope global noprefixroute enp6s0
valid_lft forever preferred_lft forever
inet6 fe80::224:8cff:fe02:dd7e/64 scope link
valid_lft forever preferred_lft forever
8: tapbr0: mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 2e:bd:d8:88:64:55 brd ff:ff:ff:ff:ff:ff
inet6 fe80::2cbd:d8ff:fe88:6455/64 scope link
valid_lft forever preferred_lft forever
9: tap0: mtu 1500 qdisc fq_codel master tapbr0 state DOWN group default qlen 1000
link/ether 9a:a0:bc:fa:c7:61 brd ff:ff:ff:ff:ff:ff
10: tap1: mtu 1500 qdisc fq_codel master tapbr0 state DOWN group default qlen 1000
link/ether 2e:bd:d8:88:64:55 brd ff:ff:ff:ff:ff:ff
We can see that both tap0 and tap1 where created and are down.
Within two different windows we can run the default.elf with each interface now:
Window one: > sudo ./default.elf tap0
Window two: > sudo ./default.elf tap1
The two instances will start communicate and the tap interface have addresses and are up now.
11: tapbr0: mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 0e:db:a6:77:3b:e5 brd ff:ff:ff:ff:ff:ff
inet6 fe80::cdb:a6ff:fe77:3be5/64 scope link
valid_lft forever preferred_lft forever
12: tap0: mtu 1500 qdisc fq_codel master tapbr0 state UP group default qlen 1000
link/ether 0e:db:a6:77:3b:e5 brd ff:ff:ff:ff:ff:ff
inet6 fe80::cdb:a6ff:fe77:3be5/64 scope link
valid_lft forever preferred_lft forever
13: tap1: mtu 1500 qdisc fq_codel master tapbr0 state UP group default qlen 1000
link/ether be:65:4f:4d:a0:ed brd ff:ff:ff:ff:ff:ff
inet6 fe80::bc65:4fff:fe4d:a0ed/64 scope link
valid_lft forever preferred_lft forever
Conclusion:
The above is a simple example, but RiotOS offers several examples including COAP, MQTT-SN and OpenThread examples.
The next step is to test RiotOS on ESP8266 and ESP32.