- Setting up OpenThread Border Router
- Setting up OpenThread End Node
- Joining the network
As a continuation of the last post, today we are going to build our OpenThread network with the help of Zephyr OS.
When preparing resources for the needs of this article, we wanted to build as big OpenThread network as possible. That’s why we tried to grab as many OpenThread capable (with 802.15.4 support) platforms as possible. We came up with the following:
EM Adapter Booster Pack+
EM Adapter Booster Pack+
Unfortunately, we were only able to run OpenThread + Zephyr on
CC2650 SensorTag‘s RAM memory size turned out to be too small to hold both Zephyr OS and OpenThread. Even turning off components such as CLI and logging didn’t help:
Memory region Used Size Region Size %age Used FLASH: 74596 B 130984 B 56.95% FLASH_CCFG: 88 B 88 B 100.00% SRAM: 56544 B 20 KB 276.09%
- Even though
CC3200 LaunchXLboard is supported in Zephyr, using it together with
CC2500EM(802.15.4 transceiver) would require a specially designed device tree. And as every developer knows – implementing new things often gives birth to bugs which then need to be fixed. Since we’ve aimed only to do a fast evaluation, we’ve decided to put away this board.
- It turned out that
MSP430F5529 LaunchPadis currently not supported in Zephyr.
Setting up OpenThread Border Router
Before setting up the Border Router, we have to flash an OpenThread NCP (Network Co-Processor) firmware image to some OpenThread-capable board. Our Border Router needs it to be able to connect to the OpenThread network. It’s really simple, in our case we’ve used one of the
nRF52840_PCA10056. You need to:
# clone OpenThread repository git clone https://github.com/openthread/openthread cd openthread # set up the environment using provided script ./bootstrap # build the OpenThread firmware using Makefile for your board, # and proper flags make -f examples/Makefile-nrf52840 BORDER_AGENT=1 BORDER_ROUTER=1 COMMISSIONER=1 UDP_FORWARD=1 # build .bin file from .hex file arm-none-eabi-objcopy -O binary output/nrf52840/bin/ot-ncp-ftd ot-ncp-ftd.bin
Afterward, we can flash the binary as we would normally flash the firmware for our chosen board. In the case of
nRF52840_PCA10056, we simply drag&dropped the binary to the board, utilizing the board’s SEGGER J-Link interface (which makes it possible for the board to turn up as a normal storage device in the host PC filesystem).
To quickly set up the Border Router itself, we have several options to choose from:
- build and configure the OpenThread Border Router on our own, using the tutorial available here. Supported platforms are Raspberry Pi 3B and BeagleBone Black.
- run OpenThread Border Router Docker image, as described here. The tutorial says that it can be run on
the Raspberry Pi 3B (RPi3B) or any Linux-based machinebut we’ve only tested it on Raspberry.
- use the ready-to-go Raspberry Pi system image –
RaspPIoT Border Router Demofrom Nordic Semiconductor’s
nRF5 SDK for Thread.
We advise you to use the third option because it involves the smallest workload. Simply download the image, flash it on a microSD card (using e.g. Etcher), plug it into your Raspberry and power it up.
The used Raspberry should:
- be connected to the Internet through the Ethernet cable
- have an ability to set up the WiFi hotspot (so WiFi dongle might be necessary).
- have the previously prepared NCP plugged into one of Raspberry’s USB ports.
The Border Router can either join one of the existing OpenThread networks or form the new one. Here, we will form a new network, leaving the default configuration as it is. Later, we will join this network from the end nodes.
To form a network, we can:
- use the Border Router’s web GUI,
- log in to the Border Router and set up the network through the command line, using
To use the first option, log in to the Border Router’s WiFi Access Point. The login credentials are:
SSID: BorderRouter-AP Password: 12345678
After logging in, you can access Web GUI by entering
10.42.0.1 address in your web browser.
To form a network, click on the
Form button on the right. Leave the default network parameters and click the
Form button. After several seconds, you should see a prompt message informing you that the network was successfully formed.
If you prefer the command line, log in to the Raspberry using
ssh or a Serial-USB converter. You can configure and start the network using the following commands:
# First, leave the current network (the Border Router could form it # automatically on power-up) to be able to change the network's configuration sudo wpanctl leave # set the channel used by the network to 15 sudo wpanctl setprop NCP:Channel 15 # Set the network's PANID sudo wpanctl setprop Network:PANID 0x1234 # Set the network's Extended PANID sudo wpanctl setprop Network:XPANID 1111111122222222 # Set the network's Master KEy sudo wpanctl setprop Network:Key 00112233445566778899aabbccddeeff # Set the on-mesh prefix sudo wpanctl config-gateway -d "fd11:22::" # Form the network using "OpenThreadDemo" name sudo wpanctl form "OpenThreadDemo"
We can verify that the operation was successful by using the
sudo wpanctl status command. The output should look similar to this:
wpan0 => [ "NCP:State" => "associated" "Daemon:Enabled" => true "NCP:Version" => "OPENTHREAD/20180926-00639-gfb11d96e; NRF52840; May 27 2019 15:22:52" "Daemon:Version" => "0.08.00d (; Apr 5 2019 13:05:28)" "Config:NCP:DriverName" => "spinel" "NCP:HardwareAddress" => [F4CE368B2528BBCF] "NCP:Channel" => 15 "Network:NodeType" => "leader" "Network:Name" => "OpenThreadDemo" "Network:XPANID" => 0x1111111122222222 "Network:PANID" => 0x1234 "IPv6:LinkLocalAddress" => "fe80::2cdf:7e62:a7c1:8138" "IPv6:MeshLocalAddress" => "fd11:1111:1122:0:e7a6:b7bd:63e4:d87f" "IPv6:MeshLocalPrefix" => "fd11:1111:1122::/64" "com.nestlabs.internal:Network:AllowingJoin" => false ]
Setting up OpenThread End Node
In order to set up OpenThread end nodes with Zephyr OS, we will use the sample code provided by Zephyr in the form of
echo_server example. It’s a simple application that waits for incoming TCP/UDP packets on some pre-defined port and simply sends it back.
Thread protocol has been designed with low-power devices in mind, so TCP is heavily discouraged if we want to achieve long battery life (it introduces a lot of communication overhead and 802.15.4 radio is very power-hungry). That’s why by default, TCP is disabled in this sample’s code
when using OpenThread overlay.
After downloading the Zephyr repository and setting the environment up, simply go to
samples/net/sockets/echo_server directory and build the application as described in the
README, using OpenThread overlay configuration file. Don’t forget to use the proper
Before that, let’s do one little modification to the
overlay-ot.conf file. We’ll add an additional configuration parameter:
This line makes it possible to join the OpenThread network using CLI of the end nodes. After that, you can use the following commands to build the application:
$ cd $ZEPHYR_BASE/samples/net/sockets/echo_server $ mkdir build && cd build $ cmake -GNinja -DBOARD=nrf52840pca10056 -DCONF_FILE="prj.conf overlay-ot.conf" .. $ ninja run
$ cd $ZEPHYR_BASE/samples/net/sockets/echo_server $ mkdir build && cd build $ cmake -GNinja -DBOARD=frdm_kw41z -DCONF_FILE="prj.conf overlay-ot.conf" .. $ ninja run
Joining the network
Normally, when building Zephyr application with OpenThread enabled, the interface will get initialized, before calling our application’s
main() function, using network configuration provided in the used
.conf file. For example, if we would like to connect to the network that we’ve configured on the Border Router, we’d have to add the following lines to our
CONFIG_OPENTHREAD_CHANNEL=15 CONFIG_OPENTHREAD_NETWORK_NAME="OpenThreadDemo" CONFIG_OPENTHREAD_XPANID="1111111122222222" CONFIG_OPENTHREAD_PANID=4660 # 0x1234 in decimal form
But hardcoding the network’s credentials is not always convenient. We will try to join the Border Router’s network using the Thread Commissioning, and that’s also why we’ve set
CONFIG_OPENTHREAD_JOINER=y in the
overlay-ot.conf file in the previous chapter. More information about the Thread Commissioning can be found here and here
To join the network, first, we have to use the following commands in the end node’s CLI:
uart:~$ ot thread stop Done uart:~$ ot panid 0xffff Done uart:~$ ot eui64 257073449c617a0d Done
Before we start joining the network, we have to turn on the commissioner service on the Border Router and tell it that the new device with the
eui64 obtained above and the
JOINER1 will try to join the network:
pi@raspberrypi:~ $ sudo wpanctl commissioner start Commissioner started pi@raspberrypi:~ $ sudo wpanctl commissioner joiner-add 257073449c617a0d 300 JOINER1 Added Joiner 25:70:73:44:9C:61:7A:0D, timeout:300, PSKd:"JOINER1"
Then, we can use the following commands back in the end node’s CLI to join the network:
uart:~$ ot joiner start JOINER1 Done Join success uart:~$ ot thread start Done
Remember that every device that joins the network has a unique
eui64 and should use a unique
PSKd. We could always tell the commissioner to ignore the device’s
eui64 when it tries to join the network, by using
* wildcard character:
pi@raspberrypi:~ $ sudo wpanctl commissioner joiner-add * 300 JOINER1
But I think we can agree that it brings a big security hole to our network, doesn’t it?
After establishing the OpenThread connection from our two end nodes to our Border Router, we have a great sea of possibilities. Our MCUs have access to the Internet, which we can demonstrate by pinging the public Google DNS server.
OpenThread nodes use the IPv6 addresses, but the Border Router runs a
NAT64 service which can translate proper
IPv6 addresses to
IPv4 when the
IPv6 address use a
64:ff9b::/96 prefix. The Google DNS server as we know has an
IPv4 address of
188.8.131.52, so we should translate that to
IPv6 using for example this webpage. Then we can use the obtained
IPv6 adress and combine it with the
64:ff9b::/96 prefix. So, the full
IPv6 address that we will use is
64:ff9b::808:808. We can use it in the end node’s CLI to ping it:
uart:~$ ot ping 64:ff9b::808:808 16 bytes from 64:ff9b:0:0:0:0:808:808: icmp_seq=1 hlim=48 time=70ms
Obviously we can also ping from one node to the other, but we first need to obtain the address of the node we want to ping, so in the first one’s CLI. The OpenThread interface uses a lot of addresses but we have to look for the one with the network’s on-mesh prefix of
uart:~$ ot ipaddr fdbb:23e2:daeb:0:0:ff:fe00:8c00 fd11:22:0:0:189b:7a27:cdb9:f589 # this is the one fdbb:23e2:daeb:0:db49:22e3:220f:d0c1 fe80:0:0:0:b460:1548:f83c:10e9 fdde:ad00:beef:0:0:0:0:2 Done
After that, we can ping this node from the other one by executing:
uart:~$ ot ping fd11:22:0:0:189b:7a27:cdb9:f589 16 bytes from fd11:22:0:0:189b:7a27:cdb9:f589: icmp_seq=2 hlim=64 time=90ms
As we remember, the basic purpose of the
echo_server sample is to echo UDP packets received by the end node. We can find the port the application uses for UDP packet reception by inspecting
#define MY_PORT 4242
This can be verified by executing the following command on the Border Router:
pi@raspberrypi:~ $ echo -n "hello" | nc -6u -w1 fd11:22:0:0:189b:7a27:cdb9:f589 4242 hello
We can see that the end node in fact responded with
hello message. We should also see the following message in the end node’s CLI:
[01:51:46.646,362] <dbg> net_echo_server_sample.process_udp: (0x20007c24): UDP (IPv6): Received and replied with 5 bytes
As we can see, OpenThread can be very easily integrated with Zephyr OS allowing us to achieve the Internet connectivity on small, low-power IoT devices. That opens a lot of opportunities – we can send MQTT messages or query SNTP servers among other things.
In LPN Plant we connect consulting, technical expertise and financial effectiveness to design and implement low power wireless solutions for industry. If you are looking for product developers or just need support in a piece of your system feel free to contact us. If you enjoying this type of content feel free to share content on social media.