Deploying Contiki-NG firmware on multiple sensors with OpenTestbed¶
In this tutorial we will compile Contiki-NG firmware, and deploy it on multiple sensors at once with OpenTestbed.
OpenTestbed allows you to manage multiple sensors, spread over multiple devices via an MQTT-server. It was initially developed at Inria, and has subsequently been adapted for use on w-iLab.1 .
It supports:
- automatic discovery of all available sensor motes;
- flashing a firmware (from a URL or from a file);
- sending serial data to one or more motes simultaneously;
- listening to the serial data sent by the motes.
Deploy an OpenTestbed instance¶
An ESpec has been developed to deploy OpenTestbed on one or more nodes. It can be obtained from the espec_minimal branch of OpenTestbed .
To use it:
- Reserve 2 nodes on w-iLab.1 testbed
- Adapt the RSpec located in
deployment/otb.rspec
to refer to your reserved sensor nodes. Change thecomponent_id
-attributes to refer to the nodes that you reserved. - Once your reservation has started, swap in the resources with the ESpec. In jFed: click Open ESpec, select the folder with your adapted ESpec and start the experiment.
- Wait for the resources to be swapped in, and the software to be installed via Ansible.
Install Contiki-NG¶
Download and install Contiki-NG and it’s dependencies as follows on one of the sensor-nodes:
$ git clone https://github.com/contiki-ng/contiki-ng.git
Cloning into 'contiki-ng'...
remote: Enumerating objects: 15, done.
remote: Counting objects: 100% (15/15), done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 123115 (delta 2), reused 6 (delta 1), pack-reused 123100
Receiving objects: 100% (123115/123115), 74.57 MiB | 28.15 MiB/s, done.
Resolving deltas: 100% (90766/90766), done.
Checking connectivity... done.
$ cd contiki-ng
$ git checkout -b release/v4.2
On branch release/v4.2
nothing to commit, working directory clean
$ git submodule update --init --recursive
Submodule 'arch/cpu/cc26xx-cc13xx/lib/cc13xxware' (https://github.com/contiki-ng/cc13xxware.git) registered for path 'arch/cpu/cc26xx-cc13xx/lib/cc13xxware'
Submodule 'arch/cpu/cc26xx-cc13xx/lib/cc2640r2-sdk' (https://github.com/contiki-ng/cc2640r2-sdk.git) registered for path 'arch/cpu/cc26xx-cc13xx/lib/cc2640r2-sdk'
Submodule 'arch/cpu/cc26xx-cc13xx/lib/cc26xxware' (https://github.com/contiki-ng/cc26xxware.git) registered for path 'arch/cpu/cc26xx-cc13xx/lib/cc26xxware'
...
Cloning into 'tools/sensniff'...
remote: Enumerating objects: 195, done.
remote: Total 195 (delta 0), reused 0 (delta 0), pack-reused 195
Receiving objects: 100% (195/195), 38.09 KiB | 0 bytes/s, done.
Resolving deltas: 100% (101/101), done.
Checking connectivity... done.
Submodule path 'tools/sensniff': checked out '3b3ac51b0a11a234a93ca50279181c648bf07976'
$ sudo apt-get update; sudo apt-get install -y srecord gcc-arm-none-eabi
Get:1 http://security.ubuntu.com/ubuntu xenial-security InRelease [107 kB]
Hit:2 http://us.archive.ubuntu.com/ubuntu xenial InRelease
Get:3 http://security.ubuntu.com/ubuntu xenial-security/main amd64 Packages [596 kB]
...
Setting up gcc-arm-none-eabi (15:4.9.3+svn231177-1) ...
Setting up libnewlib-dev (2.2.0+git20150830.5a3d536-1) ...
Setting up libnewlib-arm-none-eabi (2.2.0+git20150830.5a3d536-1) ...
Setting up libsrecord0v5 (1.58-1.1ubuntu1) ...
Setting up libstdc++-arm-none-eabi-newlib (15:4.9.3+svn227297-1+8) ...
Setting up srecord (1.58-1.1ubuntu1) ...
Processing triggers for libc-bin (2.23-0ubuntu3) ...
Compile Contiki-NG’s firmware¶
We will use the example ‘hello-world’ firmware in this example. You can build it as follows:
$ cd examples/hello-world
$ make TARGET=zoul BOARD=remote-revb hello-world
MKDIR build/zoul/remote-revb//obj
CC ../../arch/platform/zoul/./platform.c
CC ../../arch/platform/zoul/dev/leds-arch.c
...
CC hello-world.c
LD build/zoul/remote-revb//hello-world.elf
OBJCOPY build/zoul/remote-revb//hello-world.elf --> build/zoul/remote-revb//hello-world.i16hex
SREC_CAT build/zoul/remote-revb//hello-world.i16hex --> build/zoul/remote-revb//hello-world.hex
OBJCOPY build/zoul/remote-revb//hello-world.elf --> build/zoul/remote-revb//hello-world.bin
CP build/zoul/remote-revb//hello-world.elf --> build/zoul/remote-revb//hello-world.zoul
CP build/zoul/remote-revb//hello-world.zoul --> hello-world.zoul
rm hello-world.o build/zoul/remote-revb//obj/startup-gcc.o build/zoul/remote-revb//hello-world.i16hex
Let’s verify if the HEX-file looks al-right:
$ xxd build/zoul/remote-revb/hello-world.hex | head
00000000: 3a30 3230 3030 3030 3430 3032 3044 410a :020000040020DA.
00000010: 3a32 3032 3030 3030 3036 3036 4330 3032 :20200000606C002
00000020: 3038 4432 3232 3030 3041 4241 4632 3030 08D222000ABAF200
00000030: 3041 3941 4632 3030 3041 3941 4632 3030 0A9AF2000A9AF200
00000040: 3041 3941 4632 3030 3041 3941 4632 3030 0A9AF2000A9AF200
00000050: 3030 3030 3030 3030 3041 420a 3a32 3032 000000000AB.:202
00000060: 3032 3030 3030 3030 3030 3030 3030 3030 0200000000000000
00000070: 3030 3030 3030 3030 3030 3030 3041 3941 0000000000000A9A
00000080: 4632 3030 3041 3941 4632 3030 3030 3030 F2000A9AF2000000
00000090: 3030 3030 3041 3941 4632 3030 3034 3342 00000A9AF200043B
Deploying the firmware with OpenTestbed via the CLI¶
We can now upload this hex-file with the OpenTestbed CLI. As part of the ESpec, the CLI-script was uploaded to
/opt/opentestbed/cli.py
, and the necessary environment variables were set in ~/.profile
:
$ grep OTB_ ~/.profile
export OTB_TESTBED="wilab"
export OTB_BROKER="server.otb.wall2-ilabt-iminds-be.wall2.ilabt.iminds.be"
$ python /opt/opentestbed/cli.py
Usage: cli.py [OPTIONS] COMMAND [ARGS]...
Options:
-t, --testbed [iotlab|opentestbed|wilab]
[required]
-b, --broker TEXT The MQTT broker address [required]
-v, --verbose Increase verbosity
--help Show this message and exit.
Commands:
changelocation Change location of otbox
discovermotes Discover motes connected to otboxes
echo Simple echo command
listenserial Listen to the output of mote with the given EUI64
program-from-file Flash firmware from local file
program-from-url Flash firmware from URL
status Request status of otboxes
tomoteserialbytes Send data to serial port of mote
These environment variables mean that we can omit the -t
and -b
options in the CLI.
To deploy our compiled hex-file on all the sensors, use the program-from-file
command from the CLI. By omitting the
mote identifiers that we want to deploy to, this command will default to flashing ALL motes:
$ python /opt/opentestbed/cli.py program-from-file build/zoul/remote-revb/hello-world.hex
m 00-12-4b-00-09-df-90-95: True
m 00-12-4b-00-09-df-2c-2c: True
m 00-12-4b-00-10-03-56-2f: True
m 00-12-4b-00-10-03-54-44: True
Each line represents a sensor, which is identified by it’s EUI64.
As the CLI does not know how many sensors are deployed, it will keep listening for responses. To stop the CLI press
CTRL+C
.
Let’s verify that the serial has the output that we expect. For this we use the listenserial
command of the CLI.
This command expects the EUI64-identifier of the mote we want to listen to. We copy&paste the first EUI64-identifier
from the output of the program-from-file
command.
$ python /opt/opentestbed/cli.py listenserial 00-12-4b-00-09-df-90-95
Hello, world
Hello, world
Hello, world
^C
We can also request the status of each OpenTestbed-box with the status
command:
$ python /opt/opentestbed/cli.py status
b sensor1: {u'uptime': u'0:11:57.991773', u'software_version': u'1.1.1', u'currenttime':
u'Fri Dec 21 13:11:52 2018', u'location': u'not available', u'motes': [{u'firmware_description':
u'hello-world.hex', u'EUI64': u'00-12-4b-00-10-03-54-44', u'bootload_success': True, u'serialport':
u'/dev/ttyUSB0'}, {u'firmware_description': u'hello-world.hex', u'EUI64': u'00-12-4b-00-09-df-90-95',
u'bootload_success': True, u'serialport': u'/dev/ttyUSB1'}], u'host_name': u'sensor1', u'starttime':
u'Fri Dec 21 12:59:54 2018', u'IP_address': u'10.0.3.37 2001:6a8:1d80:2011:baae:edff:fe75:ab6a',
u'threads_name': [u'MainThread', u'SerialportHandler@/dev/ttyUSB0', u'sensor1_command_status',
u'heartbeat_thread', u'mqtt_loop_thread', u'SerialRxBytePublisher@/dev/ttyUSB1',
u'SerialRxBytePublisher@/dev/ttyUSB0', u'SerialportHandler@/dev/ttyUSB1']}
b sensor2: {u'uptime': u'0:11:58.159916', u'software_version': u'1.1.1', u'currenttime':
u'Fri Dec 21 13:18:46 2018', u'location': u'not available', u'motes': [{u'firmware_description':
u'hello-world.hex', u'EUI64': u'00-12-4b-00-10-03-56-2f', u'bootload_success': True, u'serialport':
u'/dev/ttyUSB0'}, {u'firmware_description': u'hello-world.hex', u'EUI64': u'00-12-4b-00-09-df-2c-2c',
u'bootload_success': True, u'serialport': u'/dev/ttyUSB1'}], u'host_name': u'sensor2', u'starttime':
u'Fri Dec 21 13:06:48 2018', u'IP_address': u'10.0.3.38 2001:6a8:1d80:2011:baae:edff:fe75:bb20',
u'threads_name': [u'MainThread', u'SerialportHandler@/dev/ttyUSB0', u'sensor2_command_status',
u'heartbeat_thread', u'mqtt_loop_thread', u'SerialportHandler@/dev/ttyUSB1',
u'SerialRxBytePublisher@/dev/ttyUSB0', u'SerialRxBytePublisher@/dev/ttyUSB1']}