diff --git a/08-interop/README.md b/08-interop/README.md index 1fb2cc0..4d5fd69 100644 --- a/08-interop/README.md +++ b/08-interop/README.md @@ -14,103 +14,134 @@ Task #02 - ICMPv6 echo between iotlab-m3 and Linux with 6LowPAN ICMPv6 echo request/reply exchange between an iotlab-m3 node running RIOT and a Raspberry Pi running Linux with 6LoWPAN support. -Task #03 - UDP exchange between iotlab-m3 and Contiki +Task #03 - ICMPv6 echo between RIOT and Contiki-NG ===================================================== ### Description -UDP packet exchange between an iotlab-m3 node running RIOT and a Contiki node. +ICMPv6 echo request/reply exchange between a node running RIOT and a Contiki node. ### Testing procedure -1. Get your hands on a [CC2538DK evaluation board][cc2538dk] -1. Clone the Contiki repository to your machine - ```sh - git clone http://github.com/contiki-os/contiki.git && cd contiki/ - ``` -2. Go to the `udp-ipv6-echo-server` for the CC2538DK: - ```sh - cd examples/cc2538dk/udp-ipv6-echo-server - ``` -3. Apply the following patch - ```sh - echo 'diff --git a/examples/cc2538dk/udp-ipv6-echo-server/Makefile b/examples/cc2538dk/udp-ipv6-echo-server/Makefile - index 5bbbdd6..92ec1c5 100644 - --- a/examples/cc2538dk/udp-ipv6-echo-server/Makefile - +++ b/examples/cc2538dk/udp-ipv6-echo-server/Makefile - @@ -1,8 +1,12 @@ - +DEFINES+=PROJECT_CONF_H=\"project-conf.h\" - CONTIKI_PROJECT = udp-echo-server - - all: $(CONTIKI_PROJECT) - - CONTIKI = ../../.. - +CONTIKI_WITH_RIME = 0 - CONTIKI_WITH_IPV6 = 1 - CFLAGS += -DUIP_CONF_ND6_SEND_NS=1 - +CFLAGS += -DRF_CHANNEL=26 - +CFLAGS += -DIEEE802154_CONF_PANID=0x23 - include $(CONTIKI)/Makefile.include - diff --git a/examples/cc2538dk/udp-ipv6-echo-server/project-conf.h b/examples/cc2538dk/udp-ipv6-echo-server/project-conf.h - new file mode 100644 - index 0000000..1718ded - --- /dev/null - +++ b/examples/cc2538dk/udp-ipv6-echo-server/project-conf.h - @@ -0,0 +1,4 @@ - +#ifndef PROJECT_CONF_H_ - +#define PROJECT_CONF_H_ - +#define NETSTACK_CONF_RDC nullrdc_driver - +#endif /* PROJECT_CONF_H_ */' | git apply - ``` -4. Build the application with - ``` - make - ``` -5. **Switch to your RIOT repository** -6. Switch the CC2538DK into bootloader mode by holding SELECT, then pressing - EM RESET, and then releasing SELECT (there should be no LED blinking when - you release RESET) -7. Use `dist/tools/cc2538-bsl/cc2538-bsl.py` to flash the *Contiki* application - to the CC2538DK. - You first need to fetch it from upstream. - ```sh - make -C examples/hello-world/ ${PWD}/dist/tools/cc2538-bsl/cc2538-bsl.py - dist/tools/cc2538-bsl/cc2538-bsl.py -e -w -v -p /dev/ttyUSB1 \ - ""/examples/cc2538dk/udp-ipv6-echo-server/udp-echo-server.bin - ``` - *Note:* If you encounter any problems the [cc2538dk] documentation might help - you. -8. Use either `pyterm` or a sniffer to find out the Contiki node's link local - address. With the sniffer just copy the source address of the first RPL - package you see (assuming there are no other IEEE 802.15.4 nodes around you - 😉). With `pyterm` you will see something like +This assummes Docker is installed and configured. The steps for configuring +Contiki-NG are based on the [official documentation](https://docs.contiki-ng.org/en/master/doc/getting-started/index.html) + +1. Clone Contiki-NG + +```bash +git clone https://github.com/contiki-ng/contiki-ng.git +cd contiki-ng +git submodule update --init --recursive + +``` + +2. Pull the Contiki-NG Docker image + +```bash +docker pull contiker/contiki-ng +``` + +3. Create a `contiker` alias to start the Contiki-NG environment +```bash + +export CNG_PATH= +alias contiker="docker run --privileged --sysctl net.ipv6.conf.all.disable_ipv6=0 --mount type=bind,source=$CNG_PATH,destination=/home/user/contiki-ng -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix -v /dev/bus/usb:/dev/bus/usb -ti contiker/contiki-ng" - Rime configured with address 00:12:34:56:78:9a:bc:de +``` - in the output. +4. Add the `shell` service to the `examples/hello-world` application. +```diff +diff --git a/examples/hello-world/Makefile b/examples/hello-world/Makefile +index 0a79167ae..710496368 100644 +--- a/examples/hello-world/Makefile ++++ b/examples/hello-world/Makefile +@@ -1,5 +1,7 @@ + CONTIKI_PROJECT = hello-world + all: $(CONTIKI_PROJECT) + ++MODULES += os/services/shell ++ + CONTIKI = ../.. + include $(CONTIKI)/Makefile.include +``` - You might have seen this address also during flashing +5. Run the Contiki-NG environment using the `contiker` alias. - Primary IEEE Address: 00:12:34:56:78:9A:BC:DE +```bash +contiker +``` +6. Compile the `hello-world` application for your target platform. Check the +[platform documentation](https://docs.contiki-ng.org/en/master/doc/platforms/index.html) +for board specific steps. E.g for `nrf52840dk`: +``` +make -C examples/hello-world TARGET=nrf52840 hello-world +make -C examples/hello-world TARGET=nrf52840 hello-world.upload +``` - You can get the IPv6 link local address of the node by toggling the second - bit of the MSB of the address and prepending `fe80::`. So for the example - above that would be `fe80::0212:3456:789a:bcde`. -7. For the `iotlab-m3` side just use [gnrc_networking] or the [gnrc_udp] test - application, whichever you prefer. There start a UDP server on port 3000 with +7. Use any serial terminal (e.g `pyterm`) to get the link-local IP address of +the Contiki-NG node: +``` +ip-addr +2023-04-14 15:23:36,732 # #f4ce.36c6.d8d1.e340> Node IPv6 addresses: +2023-04-14 15:23:36,735 # -- fe80::f6ce:36c6:d8d1:e340 +``` - > udp server start 3000 +8. For the RIOT side just use [gnrc_networking](https://github.com/RIOT-OS/RIOT/tree/master/examples/gnrc_networking). Get the link-local IP address with `ifconfig`: - and send a UDP packet to port 3000 of the CC2538DK/Contiki node: +``` +2023-04-14 15:11:12,614 # ifconfig +2023-04-14 15:11:12,620 # Iface 6 HWaddr: 06:EE Channel: 26 NID: 0xabcd PHY: O-QPSK +2023-04-14 15:11:12,622 # +2023-04-14 15:11:12,626 # Long HWaddr: 00:04:25:19:18:01:86:EE +2023-04-14 15:11:12,633 # TX-Power: 0dBm State: IDLE max. Retrans.: 3 CSMA Retries: 4 +2023-04-14 15:11:12,640 # AUTOACK ACK_REQ CSMA L2-PDU:102 MTU:1280 HL:64 RTR +2023-04-14 15:11:12,643 # RTR_ADV 6LO IPHC +2023-04-14 15:11:12,646 # Source address length: 8 +2023-04-14 15:11:12,649 # Link type: wireless +2023-04-14 15:11:12,655 # inet6 addr: fe80::204:2519:1801:86ee scope: link VAL +2023-04-14 15:11:12,665 # inet6 group: ff02::2 +2023-04-14 15:11:12,668 # inet6 group: ff02::1 +2023-04-14 15:11:12,672 # inet6 group: ff02::1:ff01:86ee +2023-04-14 15:11:12,674 # inet6 group: ff02::1a +2023-04-14 15:11:12,675 # +2023-04-14 15:11:12,678 # Statistics for Layer 2 +2023-04-14 15:11:12,682 # RX packets 16174 bytes 1812690 +2023-04-14 15:11:12,688 # TX packets 14824 (Multicast: 82) bytes 1715052 +2023-04-14 15:11:12,692 # TX succeeded 14694 errors 130 +2023-04-14 15:11:12,694 # Statistics for IPv6 +2023-04-14 15:11:12,698 # RX packets 3194 bytes 1453638 +2023-04-14 15:11:12,704 # TX packets 2545 (Multicast: 82) bytes 1430068 +2023-04-14 15:11:12,707 # TX succeeded 2545 errors 0 +2023-04-14 15:11:12,707 # +``` - > udp send 3000 +9. Set the PAN ID of the RIOT node to `abcd` (default PAN ID of Contiki) - Every packet you send should be echoed by the CC2538DK/Contiki node and - printed to the console (you might need to send more than once since the - neighbor discovery of Contiki is not queueing packets for unknown - destinations). +``` +ifconfig 6 set pan_id abcd +``` + +10. Run the `ping` command on both the RIOT and the Contiki-NG node: + +Contiki-NG: +``` +ping fe80::204:2519:1801:86ee +2023-04-14 15:23:29,960 # #f4ce.36c6.d8d1.e340> Pinging fe80::204:2519:1801:86ee +2023-04-14 15:23:29,974 # Received ping reply from fe80::204:2519:1801:86ee, len 4, ttl 64, delay 15 ms +``` + +RIOT +``` +ping fe80::f6ce:36c6:d8d1:e340 +2023-04-14 15:30:20,415 # ping fe80::f6ce:36c6:d8d1:e340 +2023-04-14 15:30:20,449 # 12 bytes from fe80::f6ce:36c6:d8d1:e340%6: icmp_seq=0 ttl=64 rssi=-46 dBm time=24.320 ms +2023-04-14 15:30:21,441 # 12 bytes from fe80::f6ce:36c6:d8d1:e340%6: icmp_seq=1 ttl=64 rssi=-46 dBm time=6.031 ms +2023-04-14 15:30:22,455 # 12 bytes from fe80::f6ce:36c6:d8d1:e340%6: icmp_seq=2 ttl=64 rssi=-46 dBm time=8.237 ms +2023-04-14 15:30:22,455 # +2023-04-14 15:30:22,460 # --- fe80::f6ce:36c6:d8d1:e340 PING statistics --- +2023-04-14 15:30:22,465 # 3 packets transmitted, 3 packets received, 0% packet loss +2023-04-14 15:30:22,469 # round-trip min/avg/max = 6.031/12.862/24.320 ms +``` -[cc2538dk]: http://doc.riot-os.org/group__boards__cc2538dk.html -[gnrc_networking]: https://github.com/RIOT-OS/RIOT/tree/master/examples/gnrc_networking -[gnrc_udp]: https://github.com/RIOT-OS/RIOT/tree/master/examples/gnrc_networking +Every packet should be echoed by the target node and printed to the console. Task #04 - ICMPv6 echo between iotlab-m3 and Internet host through Linux with 6LowPAN ===================================================================================== diff --git a/08-interop/compile_contiki.sh b/08-interop/compile_contiki.sh new file mode 100755 index 0000000..db020eb --- /dev/null +++ b/08-interop/compile_contiki.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +cd /tmp + +# Clone Contiki-NG +git clone https://github.com/contiki-ng/contiki-ng.git; cd contiki-ng || \ +cd contiki-ng; git pull +git submodule update --init --recursive + +# Pull the Contiki-NG Docker image +docker pull contiker/contiki-ng + +# Add the `shell` service to the `examples/hello-world` application. +if ! grep -q "MODULES += os/services/shell" examples/hello-world/Makefile; then + sed -i '/all: $(CONTIKI_PROJECT)/a\\nMODULES += os/services/shell\n' examples/hello-world/Makefile +fi + + +# Compile the `examples/hello-world` application for the nRF52840 platform. +export CNG_PATH=/tmp/contiki-ng +docker run \ + --sysctl net.ipv6.conf.all.disable_ipv6=0 \ + --mount type=bind,source=$CNG_PATH,destination=/home/user/contiki-ng \ + contiker/contiki-ng \ + make -C examples/hello-world TARGET=nrf52840 hello-world diff --git a/08-interop/test_spec08.py b/08-interop/test_spec08.py old mode 100644 new mode 100755 index dae060e..8538a78 --- a/08-interop/test_spec08.py +++ b/08-interop/test_spec08.py @@ -1,5 +1,8 @@ +import os import re import sys +import subprocess + import pexpect.replwrap import pytest @@ -49,6 +52,49 @@ def test_task01(riot_ctrl, log_nodes): assert res["stats"]["packet_loss"] < 1 +@pytest.mark.flaky(reruns=1, reruns_delay=30) +@pytest.mark.iotlab_creds +# nodes passed to riot_ctrl fixture +@pytest.mark.parametrize( + 'nodes', [pytest.param(['nrf52840dk', 'nrf52840dk'])], indirect=['nodes'] +) +def test_task03(riot_ctrl): + # run `./compile_contiki.sh` relative to this file + subprocess.check_call( + ["./compile_contiki.sh"], + cwd=os.path.dirname(os.path.realpath(__file__)), + ) + + build_path = "build/nrf52840/dk/hello-world.nrf52840" + flashfile = f"/tmp/contiki-ng/examples/hello-world/{build_path}" + + gnrc_node, contiki_node = ( + riot_ctrl(0, GNRC_APP, Shell), + riot_ctrl( + 1, + 'examples/hello-world', + riotctrl.shell.ShellInteraction, + extras={"BINFILE": flashfile}, + ), + ) + + gnrc_netif, gnrc_addr = lladdr(gnrc_node.ifconfig_list()) + + # get the address of the contiki node, ie a substring after "-- " + res = contiki_node.cmd("ip-addr") + match = re.search("-- (.+)", res) + assert match + contiki_addr = match[1] + + gnrc_node.ifconfig_set(gnrc_netif, "pan_id", "abcd") + + res = contiki_node.cmd(f"ping {gnrc_addr}") + assert f"Received ping reply from {gnrc_addr}" in res + + res = ping6(gnrc_node, contiki_addr, 3, 12, 1) + assert res['stats']['packet_loss'] < 10 + + @pytest.mark.flaky(reruns=3, reruns_delay=30) @pytest.mark.iotlab_creds # nodes passed to riot_ctrl fixture diff --git a/conftest.py b/conftest.py index a3bc5e8..62b7545 100644 --- a/conftest.py +++ b/conftest.py @@ -303,7 +303,8 @@ def nodes(local, request, boards, iotlab_site): RUNNING_EXPERIMENTS.remove(exp) -def update_env(node, modules=None, cflags=None, port=None, termflags=None): +def update_env(node, modules=None, cflags=None, port=None, termflags=None, extras=None): + # pylint: disable=too-many-arguments node.env['QUIETER'] = '1' if not isinstance(modules, str) and isinstance(modules, Iterable): node.env['USEMODULE'] = ' '.join(str(m) for m in modules) @@ -322,6 +323,8 @@ def update_env(node, modules=None, cflags=None, port=None, termflags=None): node.env['PORT'] = port if termflags is not None: node.env['TERMFLAGS'] = termflags + if extras is not None: + node.env.update(extras) @pytest.fixture @@ -333,6 +336,7 @@ def riot_ctrl(log_nodes, log_file_fmt, nodes, riotbase, request): factory_ctrls = [] # pylint: disable=R0913 + # flake8: noqa: C901 def ctrl( nodes_idx, application_dir, @@ -342,12 +346,13 @@ def ctrl( cflags=None, port=None, termflags=None, + extras=None, ): if board_type is not None: node = next(n for n in nodes if n.board() == board_type) else: node = nodes[nodes_idx] - update_env(node, modules, cflags, port, termflags) + update_env(node, modules, cflags, port, termflags, extras) # if the nodes are not logged, there is no sense in logging to a file # so check if nodes are logged as well as if they should be logged to a # file @@ -366,8 +371,11 @@ def ctrl( # need to access private member here isn't possible otherwise sadly :( # pylint: disable=W0212 node._application_directory = os.path.join(riotbase, application_dir) + flash_cmd = "flash" + if "BINFILE" in node.env: + flash_cmd = "flash-only" node.make_run( - ['flash'], + [flash_cmd], check=True, stdout=None if log_nodes else subprocess.DEVNULL, stderr=None if log_nodes else subprocess.DEVNULL,