RTEMS Tutorial

../_images/RTEMS_logo.png

This section serves as a comprehensive guide to assist in creating and understanding the key points of a basic Safe DDS application using RTEMS.

This project has been tested with RTEMS 6.1 and Waf 2.0.19, building for a Xilinx Zynq board, and running through QEMU emulation. Check Supported platforms for more information.

Note

This guide might require adaptations to work with a different hardware, or RTEMS version.

In order to get support please contact support@eProsima.com.

Note

It is recommended to first read the Getting Started section to gain a better understanding of the basic concepts and terminology used in this section.

Project Configuration

This section describes how to configure an RTEMS project that uses the Safe DDS library.

1. Install the required dependencies

Before starting, ensure that you have the necessary dependencies installed on your system.

To replicate this tutorial on Ubuntu 24.04, the following packages are needed:

sudo apt install apt-utils build-essential vim u-boot-tools git cmake bison flex \
    texinfo bzip2 xz-utils unzip libexpat1-dev python3-dev python3 python-is-python3 \
    zlib1g-dev libtinfo-dev pax qemu-system-arm wget curl bsdmainutils

2. Download and setup RTEMS

Start by downloading RTEMS and configuring it for the target architecture:

# Create a directory for the RTEMS installation
mkdir /rtems
cd /rtems

# Download and install RTEMS Source Builder
wget https://ftp.rtems.org/pub/rtems/releases/6/6.1/sources/rtems-source-builder-6.1.tar.xz
tar xJf rtems-source-builder-6.1.tar.xz
mv rtems-source-builder-6.1 rsb

# Download RTEMS Sources
wget https://ftp.rtems.org/pub/rtems/releases/6/6.1/sources/rtems-6.1.tar.xz
tar xJf rtems-6.1.tar.xz

# Build ARM A9 BSP
cd rsb/rtems
../source-builder/sb-set-builder --prefix=/rtems/rtems/6 --jobs=10 6/rtems-arm

# Build Kernel
../source-builder/sb-set-builder --prefix=/rtems/rtems/6 --jobs=10 \
    --target=arm-rtems6 --with-rtems-bsp=arm/xilinx_zynq_a9_qemu --with-rtems-tests=samples 6/rtems-kernel

# Build Network Stack
git clone -b 6-freebsd-14 https://github.com/RTEMS/rtems-libbsd
cd rtems-libbsd
git submodule init
git submodule update rtems_waf
./waf configure --prefix=/rtems/rtems/6 --rtems-bsps=arm/xilinx_zynq_a9_qemu --buildset=buildset/default.ini
./waf
./waf install

3. Create a project for Safe DDS

Start by creating a directory for the Safe DDS project.

mkdir Safe-DDS-RTEMS
cd Safe-DDS-RTEMS

Clone rtems_waf and download the Waf tool:

git clone -b main https://gitlab.rtems.org/rtems/tools/rtems_waf.git rtems_waf
curl https://waf.io/waf-2.0.19 > waf
chmod +x waf

4. Add Safe DDS to the project

To add the Safe DDS library to the project follow these steps:

  • Create a new directory for the Safe-DDS sources in the root of the project. Name the folder something like SafeDDS.

  • Copy the Safe-DDS src and include folders from the Safe-DDS source release to the SafeDDS folder in the project.

  • Navigate to the support packages folder and copy the rtems_transport folder to the root of the project.

Safe DDS application

With the library in place, the next step is to create the application sources:

1. Add the application files to the project

  • Navigate to the tutorial_rtems folder.

  • Add the provided HelloWorldTypeSupport.hpp file to a new include folder inside the project root.

  • Add the provided main.cc and rtems_config.c files to the project root.

2. Configure the build system

To configure the project, create a wscript file in the root of the project with the following content.

The script will build all the Safe DDS sources, the RTEMS transport, and two different applications that will communicate with each other.

from __future__ import print_function
import os

rtems_version = '6'

try:
    import rtems_waf.rtems as rtems
except BaseException:
    print('error: no rtems_waf git submodule')
    import sys
    sys.exit(1)

def init(ctx):
    rtems.init(ctx, version=rtems_version, long_commands=True)

def bsp_configure(conf, arch_bsp):
    pass

def options(opt):
    rtems.options(opt)

def configure(conf):
    rtems.configure(conf, bsp_configure=bsp_configure)

def build(bld):
    rtems.build(bld)

    # Find the source files
    srcs = ['main.cc', 'rtems_config.c']
    for root, dirs, files in os.walk('SafeDDS/src'):
        if 'transport/posix' in root:
            continue
        for file in files:
            if '.cpp' in file:
                srcs.append(os.path.join(root, file))

    # Add RTEMS transport files
    srcs.append('rtems_transport/src/RTEMSUDPv4.cpp')
    srcs.append('rtems_transport/src/transport.cpp')
    srcs.append('rtems_transport/src/UDPv4.cpp')

    # Build the project for part A
    bld(features='cxx cxxprogram',
        target='safedds_rtems_poc_A',
        cflags='-g -O2',
        cxxflags='-g -O2',
        includes=[
            'SafeDDS/include',
            'rtems_transport/include',
            'include'],
        defines=[
            'PART_A',
            'SAFEDDS_LOGGING_ENABLED',
            'SAFEDDS_LOG_LEVEL=DEBUG'],
        lib=['m', 'bsd'],
        source=srcs)

    # Build the project for part B
    bld(features='cxx cxxprogram',
        target='safedds_rtems_poc_B',
        cflags='-g -O2',
        cxxflags='-g -O2',
        includes=[
            'SafeDDS/include',
            'rtems_transport/include',
            'include'],
        defines=[
            'PART_B',
            'SAFEDDS_LOGGING_ENABLED',
            'SAFEDDS_LOG_LEVEL=DEBUG'],
        lib=['m', 'bsd'],
        source=srcs)

Running the application on QEMU

Build the applications using the Waf commands.

./waf configure --rtems /rtems/rtems/6
./waf

To allow the two executables to communicate with each other while running in QEMU, tap interfaces and QEMUBridge can be set up.

# Set up tap and bridge interfaces
sudo ip link add QEMUBridge0 type bridge
sudo ip link set QEMUBridge0 up
sudo ip tuntap add dev tap0 mode tap
sudo ip link set tap0 up
sudo ip link set tap0 master QEMUBridge0
sudo ip tuntap add dev tap1 mode tap
sudo ip link set tap1 up
sudo ip link set tap1 master QEMUBridge0

Note

If developing in a Docker environment, the network commands should be run on the host system, and the Docker container should have net=host.

Run both applications in separate terminals using QEMU:

qemu-system-arm -serial null -serial mon:stdio -nographic -M xilinx-zynq-a9 -m 256M -net nic,model=cadence_gem -net tap,ifname=tap0,script=no,downscript=no -kernel build/arm-rtems6-xilinx_zynq_a9_qemu/safedds_rtems_poc_A
qemu-system-arm -serial null -serial mon:stdio -nographic -M xilinx-zynq-a9 -m 256M -net nic,model=cadence_gem -net tap,ifname=tap1,script=no,downscript=no -kernel build/arm-rtems6-xilinx_zynq_a9_qemu/safedds_rtems_poc_B

The console output should show messages similar to the following after the QEMU emulation starts:

[DW: 0] Message: HelloWorld with index: 1
[DW: 16777216] Message: HelloWorld with index: 12
[DW: 0] Message: HelloWorld with index: 2
[DW: 16777216] Message: HelloWorld with index: 13
[DW: 0] Message: HelloWorld with index: 3
[DW: 0] Message: HelloWorld with index: 4
[DW: 16777216] Message: HelloWorld with index: 14
[DW: 0] Message: HelloWorld with index: 5
[DW: 16777216] Message: HelloWorld with index: 15
[DW: 0] Message: HelloWorld with index: 6
[DW: 16777216] Message: HelloWorld with index: 16
[DW: 0] Message: HelloWorld with index: 7
[DW: 0] Message: HelloWorld with index: 8

Note

It is also possible to flash the firmware to a compatible board instead of using QEMU. If flashing the firmware to a physical device, run the Getting Started example in a local machine on the same network as the device to test the communications.

Cleanup

When finished, cleanup the TAP interfaces:

# Remove TAP interfaces
sudo ip link delete tap0
sudo ip link delete tap1
sudo ip link delete QEMUBridge0