How to run real multi-node Zephyr setups without physical hardware with Renode (pt. 1)

Published:

If you’re working with multi-node IoT systems, you probably know all the problems related to testing, security, interoperability, reuse, lifecycle management and code quality involved in building real-life networks.

To address these problems, we need new tools and workflows that allow developers to collaborate around code more effectively and increase the test coverage and understanding of the software and protocols running on the devices that form - or will soon form - the backbone of our homes, offices, factories and cities.

Renode & Zephyr

The open source Renode framework from Antmicro, which started a collaboration with the Zephyr project in 2017, is aimed at doing exactly that: it lets you simulate complex wireless (and wired) setups running real binaries so that you can do testing, continuous integration and debugging to an extent that wasn’t imaginable before.

Sounds promising? We hope it does. And it’s not as complex as it sounds. In this blog note we will explain how Renode can help you in your daily development without forcing you to rewrite your software or abandon your familiar toolset.

Renode can simulate physical hardware systems - including both the CPU, peripherals, sensors, environment and wireless medium between nodes. Just develop your IoT software (including that based on the Zephyr RTOS) as normal and then use Renode to debug and test it in various circumstances. This includes protocols and applications that span multiple nodes - run them in a joint virtual environment with full determinism and control over the parameters of execution.

For example, at this year’s Embedded Linux Conference (ELC) EU, the Renode and Zephyr teams have been jointly showcasing a fairly complex simulated wireless setup. With nodes based on two architectures - x86 and ARM, and running two different RTOS - Zephyr and Contiki, the demo also showed how easy it is to perform interoperability testing with Renode.

Today we’d like to focus on how a simpler multi-node setup can be reproduced from the comfort of your chair. This short tutorial can act as a starting point for your development with Renode and Zephyr.

  1. Installation

    The Renode framework is hosted on GitHub.
    You can follow the instructions in the README file to download and compile it manually, but the easiest way to start is by downloading a binary release from the releases page.
    The precompiled packages are provided as deb and rpm packages for Linux, dmg package for macOS and a zip archive for Windows.

  2. Starting Renode

    One of the many ways to interact with Renode is via its command line interface. In this post we will focus on this most basic method.
    Upon installation, you should be able to run the ‘renode’ command. Alternatively, look for the Renode.exe binary.
    Once Renode is started, you will see two windows - one for Renode’s smart logger (you can control what’s being logged with and one for the CLI called “the Monitor”.

    From this window you will be able to create and control the whole emulation environment.

  3. Scripts

    While you can type all commands interactively, it’s a good idea to group them into reusable Renode scripts, which typically have the “*.resc” extension. Their purpose is to load binaries, set starting conditions, prepare the environment, connect machines to the network etc.

    For the purpose of this article we will use scripts available in the Renode package named: scripts/many-nodes/quark-c1000-zephyr/demo.resc and scripts/many-nodes/quark-c1000-zephyr/quark_c1000.resc. The scripts are documented - for details, please inspect the files in the Renode installation directory (e.g. for Linux it is “/opt/renode/scripts”).

  4. Loading our setup

    The setup we present here consists of two Intel Quark C1000 nodes with a TI CC2520 radio connected via SPI. The nodes run applications based on Zephyr demos - an echo_server and an echo_client, compiled as normal for the target hardware (in the provided scripts, we’re using precompiled binaries hosted online, but you can provide your own binaries by changing the relevant $BIN variable in the scripts).

    In Renode, the nodes have coordinates in a virtual 3D space assigned to them, so that, by manipulating the maximum range of the wireless medium or moving the nodes around, we can put them in or out of each other’s range, and form different topologies, building routing scenarios of various complexity. In this simple example, the nodes are within each other’s range and we won’t be moving them around or making them lose packets - you will learn how to do this in the second blog note in the series.

    To run a script, use the include command (or i, for short), with a path to the script to load, prepended with the @ sign, like this:

    include @scripts/many-nodes/quark-c1000-zephyr/demo.resc
    

    After the script is loaded, you will see two new terminals - these are UART windows opened for each machine.

    The emulation is now loaded, but not started. You can control it using start and pause - and other commands, as described in the next section.

  5. Simple commands

    Execute commands by writing them into the Monitor window.

    • Start and pause

      To control whether the simulation is running, use start and pause.

    • Machines

      In the provided scripts, we use the mach create command to create new machines. This switches the context in the Monitor. All subsequent commands are executed with regard to the current machine.

      To change the machine use the mach set command. Use a number or the name of the machine, e.g. mach set 1 or mach set "server".

      All machines can be listed with the mach command. To clear the current selection use mach clear.

    • Accessing peripherals

      All peripherals are accessible in the Monitor, with most of their methods and properties exposed to the user. To list all available peripherals use the peripherals command.

    • Peripheral methods and properties

      To access a peripheral you have to provide its path. All peripherals are registered in sysbus, so use sysbus.uartB to access the second UART or sysbus.spi1.radio to access the CC2520.

      The using sysbus command is used in most of the provided demos, allowing you to drop the sysbus. prefix.

      Typing a peripheral name gives you a list of available methods, fields and properties. The list is automatically generated, so most of the accessible members are not designed for the end-user.

      The list shows examples of correct Monitor syntax for each member type.

    • Other commands

      To find information about built-in Monitor commands, type help and refer to the documentation. Running help builtin_command_name prints out the help for the given command.

  6. Debugging and inspection

    Renode offers you many ways to verify the behavior of your applications. Thanks to having full control over the environment, you can add logging, hooks on events, interactive code debugging and more in a way that is 100% transparent to the emulated application.

    Here we will present just a few of available debugging options.

    • Function name logging

      When the application is stuck or misbehaves it is always a good idea to inspect the trace of function calls. To enable logging of function names in a selected machine run cpu LogFunctionNames true (and false, respectively, to disable it).
      Since the amount of logged data may be too overwhelming to be useful, you can filter the logged functions to the ones that begin with a specified prefix. For example cpu LogFunctionNames true “uart_ qm_” will only log functions that begin with either “uart_” or “qm_” prefix.

    • Logging of peripheral accesses

      If your driver does not behave correctly, it may be beneficial to investigate communication with the device it controls. To enable logging of each interaction between the CPU and the UART peripheral, run “sysbus LogPeripheralAccess uartB”.

      This feature is available only for peripherals registered directly on the system bus.

    • Wireshark

      Network traffic analysis is a common task in every multinode system. As Wireshark is very often a tool of choice for programmers, Renode supports it both for ethernet and wireless networks.
      There are multiple options for choosing which interfaces should be logged, but the easiest way to observe all packets in IEEE802.15.4 network is to run emulation LogWirelessTraffic.

      This command opens a new Wireshark window. If you close it, you can always reopen it by running host.wireshark-allWirelessTraffic Run.

    • GDB

      A popular tool for debugging, GDB can be used to analyze applications running in Renode. It uses the same remote protocol as OpenOCD, so it can be easily integrated with most GDB-based IDEs, such as Eclipse.
      To start a GDB stub in Renode, run cpu StartGDBServer 3333 (where 3333 is a sample port number) and connect from GDB by calling (gdb) target remote :3333. To start the emulation you have to run both start in Renode and continue in GDB.

      You can use most of GDB’s regular features: breakpoints, watchpoints, stepping, reading/writing to variables, etc. You can also use the monitor command in GDB to send commands directly to Renode CLI (to avoid switching between two console windows).

We hope that this short tutorial will help you get started with Zephyr and Renode. which has recently become one of Zephyr’s recommended developer tools.

We will continue with part 2, where we will explain details about more complex wireless setups - stay tuned!

Renode™ is a software development framework from Antmicro, a technology company building software-driven IoT systems. If you need help with implementing your platforms and setups in Renode, adopting a Continuous Integration workflow inside your organization, integrating with your tools or building custom ones, or IoT system development services using the Renode methodology you can contact us at contact@renode.io.