Contiki NG, Linux WPAN and 6LoWPAN

mk16.de

Recently I came across a list of operating systems in Wikipedia and there I rediscovered Contiki NG. I had seen before that Contiki NG is an operating system for small embedded systems, but I never had any hardware to try it out with. Contiki NG has a very nice documentation and in it I saw that it supports 6LoWPAN - an IPv6-only low-rate low-power 2.4 GHz network standard - as an IPv6 fan this of course sounded great. 6LoWPAN was actually designed for IoT devices, but who says I can’t try it out for fun?

Hardware

I then looked at which hardware Contiki NG works on and came across NRF chips, which I already knew from Meshtastic. They were also the only inexpensive, easily available ones. I opted for the fairly compact nRF52840 MDK USB dongle, which was even available online with a protective case.

You can see a kind of USB stick lying on a wooden surface. It has an "M" logo printed on it. There is also a small cut-out for a key fob. You can also see a small button and an LED (or that there is a gray dot that can light up). The USB dongle is white.

Of course I also checked whether Linux supports 6LoWPAN and lo and behold - it is even in the mainline kernel. The Linux implementation is driven by the Linux WPAN project. All Linux needs is supported hardware. The project’s website has a list of these with links to online stores (many of which lead to 404 pages). My next step was to see which one was available in USB format and as cheaply as possible. I then decided on the ATUSB dongle - unfortunately there was no protective case available.

You can see a circuit board. There is a USB port on the right side. On the left side you can see an antenna built into the circuit board. Two distinctive black chips can be seen on the circuit board. The board itself is green.

Linux WPAN

The first thing I received was the ATUSB dongle. A wpan0 interface with an MTU of 123 (and therefore not IPv6-capable) appears automatically. There are instructions on the website on how to derive a lowpan0 interface from this, which also supports IPv6 with an MTU of 1280. In order to keep the packets as small as possible, header compression is used. In addition, the packets are fragmented at MAC level if necessary. In order to achieve the best possible performance, it is still recommended to keep the packets as small as possible. The following are the commands I used for configuration:

sudo ip link set dev wpan0 down
sudo iwpan dev wpan0 set pan_id 0xbada
sudo iwpan phy phy0 set channel 0 26
sudo ip link set dev wpan0 up
sudo ip link add link wpan0 name lowpan0 type lowpan
sudo ip link set dev lowpan0 up

Here, 0xbada is the PAN ID (comparable to an SSID for WLAN) and 0 26 is the channel (standard channel in Contiki NG).

Firmware

The nRF52840 MDK USB dongle arrived one day after the ATUSB dongle. This comes with the UF2 bootloader, which I already knew from Meshtastic. This is quite easy to use and protects (at least partially) against a briek of the device. To flash a firmware, use the button to switch the device to bootloader mode and mount it as a file system. You can then simply copy the firmware (supplied as an .uf2 file) to the device and the firmware will be installed automatically.

So I tried to compile Contiki NG as described in the documentation - but without success: My GCC version was too new. Contiki NG currently requires a GCC version of 10 (the current one is 13). There is already an Issue. Fortunately, it was possible to install GCC version 10. After I had compiled the program with GCC 10, I received an .nrf file. The Makefile of Contiki NG actually also supports the upload of the firmware via USB, but no UF2 bootloader is expected, but the device as a serial interface. As this was not the case for me, I had to convert the .nrf file into an .uf2 file. When trying to upload it, I noticed that Contiki NG creates a .hex file in the build folder. This in turn can be easily converted into an .uf2 file using a Python tool. I executed the following commands to create the .uf2 file:

make TARGET=nrf BOARD=nrf52840/dongle node.upload
uf2conv build/nrf/nrf52840/dongle/node.hex --family 0xADA52840 --convert --output node.uf2

I have named my program ‘node’.

Source code

Contiki-NG provides some examples. However, I just wanted a program with which I could ping other nodes - so I used the following from the examples: node.c:

#include "contiki.h"
#include "sys/log.h"

#define LOG_MODULE "Contiki-NG node"
#define LOG_LEVEL LOG_LEVEL_INFO

#include <stdbool.h>

/*---------------------------------------------------------------------------*/
PROCESS(node_process, "Contiki-NG node");
AUTOSTART_PROCESSES(&node_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(node_process, ev, data)
{
    PROCESS_BEGIN();

    LOG_INFO("Contiki-NG node Started\n");

    while (true) {
        PROCESS_WAIT_EVENT();
    }

    PROCESS_END();
}
/*---------------------------------------------------------------------------*/

This program only starts the operating system and displays ‘Contiki-NG node Started’ once at startup.

project-conf.h:

#ifndef PROJECT_CONF_H
#define PROJECT_CONF_H

#define IEEE802154_CONF_PANID 0xbada

#define UIP_CONF_ND6_SEND_RA 0

#endif

The project settings are made in this file. In this case, I wanted Contiki NG to act neither as a radv client nor as a radv server and set the PANID accordingly.

Makefile:

CONTIKI_PROJECT = node
all: $(CONTIKI_PROJECT)
CONTIKI=../..

include $(CONTIKI)/Makefile.dir-variables

MAKE_MAC = MAKE_MAC_CSMA
MAKE_ROUTING = MAKE_ROUTING_NULLROUTING

MODULES += $(CONTIKI_NG_SERVICES_DIR)/shell

include $(CONTIKI)/Makefile.include

Makefiles actually play a more important role in Contiki NG, as various project settings are also made in them. In this case, I have set that only the basic MAC level should be used and no extension such as TSCH, 6TiSCH or 6top, as Linux WPAN does not (yet) support this. In addition, these extensions appear very centralized, which creates a single point of failure (see here). I then set that no routing protocol is used. For 6LoWPAN normally RPL is used as routing protocol (also supported by Linux), but the routing protocol seems to be very centralized. Furthermore, Contiki NG offers a shell module. This later provides a serial console where I can perform various actions.

Ping

After I had configured both the Linux 6LoWPAN interface and flashed Contiki NG, I opened a serial console to Contiki NG:

#f4ce.369a.e71b.e9cf> hrelp
Available commands:
'> help': Shows this help
'> reboot': Reboot the board by watchdog_reboot()
ng.
'> mac-addr': Shows the node's MAC address
'> ip-addr': Shows all IPv6 addresses
'> ip-nbr': Shows all IPv6 neighbors
'> ping addr': Pings the IPv6 address 'addr'
'> routes': Shows the route entries
#f4ce.369a.e71b.e9cf> mac-addr
Node MAC address: f4ce.369a.e71b.e9cf
#f4ce.369a.e71b.e9cf> ip-addr
Node IPv6 addresses:
-- fe80::f6ce:369a:e71b:e9cf
#f4ce.369a.e71b.e9cf> ip-nbr
Node IPv6 neighbors: none

I then tried to ping my Linux device via Contiki NG:

#f4ce.369a.e71b.e9cf> ping fe80::12e2:d5ff:ff00:463
Pinging fe80::12e2:d5ff:ff00:463
Timeout
#f4ce.369a.e71b.e9cf> ping fe80::12e2:d5ff:ff00:463
Pinging fe80::12e2:d5ff:ff00:463
Received ping reply from fe80::12e2:d5ff:ff00:463, len 4, ttl 64, delay 39 ms
#f4ce.369a.e71b.e9cf> ping fe80::12e2:d5ff:ff00:463
Pinging fe80::12e2:d5ff:ff00:463
Received ping reply from fe80::12e2:d5ff:ff00:463, len 4, ttl 64, delay 46 ms
#f4ce.369a.e71b.e9cf> ping fe80::12e2:d5ff:ff00:463
Pinging fe80::12e2:d5ff:ff00:463
Received ping reply from fe80::12e2:d5ff:ff00:463, len 4, ttl 64, delay 15 ms
#f4ce.369a.e71b.e9cf> ping fe80::12e2:d5ff:ff00:463
Pinging fe80::12e2:d5ff:ff00:463
Received ping reply from fe80::12e2:d5ff:ff00:463, len 4, ttl 64, delay 23 ms
#f4ce.369a.e71b.e9cf> ip-nbr
Node IPv6 neighbors:
-- fe80::12e2:d5ff:ff00:463 <-> 10e2.d5ff.ff00.0463, router 128, state Reachable 

During my tests, a timeout always appeared the first time (perhaps due to Neighbor Discovery?!). After that, however, the ping worked without any problems.

The other way round - from Linux to Contiki NG the ping also works without any problems:

$ ping -c 4 fe80::f6ce:369a:e71b:e9cf%lowpan0
PING fe80::f6ce:369a:e71b:e9cf%lowpan0 (fe80::f6ce:369a:e71b:e9cf%lowpan0) 56 data bytes
64 bytes from fe80::f6ce:369a:e71b:e9cf%lowpan0: icmp_seq=1 ttl=64 time=14.1 ms
64 bytes from fe80::f6ce:369a:e71b:e9cf%lowpan0: icmp_seq=2 ttl=64 time=11.2 ms
64 bytes from fe80::f6ce:369a:e71b:e9cf%lowpan0: icmp_seq=3 ttl=64 time=58.2 ms
64 bytes from fe80::f6ce:369a:e71b:e9cf%lowpan0: icmp_seq=4 ttl=64 time=17.0 ms

--- fe80::f6ce:369a:e71b:e9cf%lowpan0 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 11.226/25.143/58.241/19.218 ms