Skip to content

Commit

Permalink
Zenoh Pico hello-world (space-ros#43)
Browse files Browse the repository at this point in the history
* Initial commit of Zynq RTEMS hello-world

Signed-off-by: Morgan Quigley <[email protected]>

* a bit of cleanup

Signed-off-by: Morgan Quigley <[email protected]>

* cross-compile Zenoh-Pico static library

Signed-off-by: Morgan Quigley <[email protected]>

* add application skeleton for a zenoh pick client

Signed-off-by: Morgan Quigley <[email protected]>

* WIP fix build

Signed-off-by: Morgan Quigley <[email protected]>

* fix echo flag

Signed-off-by: Morgan Quigley <[email protected]>

* fix toolchain file to declare FreeBSD explicitly

Signed-off-by: Morgan Quigley <[email protected]>

* iterate toolchain

Signed-off-by: Morgan Quigley <[email protected]>

* create zenoh session seems to work

Signed-off-by: Morgan Quigley <[email protected]>

* a bit of cleanup and documentation

Signed-off-by: Morgan Quigley <[email protected]>

* doc

Signed-off-by: Morgan Quigley <[email protected]>

* doc

Signed-off-by: Morgan Quigley <[email protected]>

* rename script to agree with doc

Signed-off-by: Morgan Quigley <[email protected]>

* fix warning

Signed-off-by: Morgan Quigley <[email protected]>

* doc

Signed-off-by: Morgan Quigley <[email protected]>

* send hello-world data through zenoh

Signed-off-by: Morgan Quigley <[email protected]>

* doc

Signed-off-by: Morgan Quigley <[email protected]>

Signed-off-by: Morgan Quigley <[email protected]>
  • Loading branch information
codebot authored Dec 16, 2022
1 parent 5de29c3 commit 386fc69
Show file tree
Hide file tree
Showing 21 changed files with 2,741 additions and 35 deletions.
20 changes: 20 additions & 0 deletions zynq_rtems/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,23 @@ WORKDIR /root/rtems/rtems-libbsd
RUN ./waf configure --prefix=$PREFIX --rtems-archs=aarch64 --rtems-bsps=aarch64/xilinx_zynqmp_lp64_qemu --buildset=buildset/default.ini
RUN ./waf
RUN ./waf install

# build Zenoh Pico, using a CMake toolchain file to cross-compile
WORKDIR /root
RUN git clone https://github.com/eclipse-zenoh/zenoh-pico
RUN mkdir /root/zenoh-pico/build
RUN wget -q https://raw.githubusercontent.com/space-ros/docker/zynq_rtems_zenoh_pico/zynq_rtems/toolchain.cmake -O /root/toolchain.cmake
WORKDIR /root/zenoh-pico/build
RUN cmake -DCMAKE_TOOLCHAIN_FILE=/root/toolchain.cmake -DBUILD_SHARED_LIBS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TOOLS=OFF -DBUILD_TESTING=OFF ..
RUN make

# install Rust and Cargo, and add to the Docker build path
WORKDIR /root
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"

# build "normal" (non-Pico) Zenoh
WORKDIR /root
RUN git clone https://github.com/eclipse-zenoh/zenoh
WORKDIR /root/zenoh
RUN cargo build
119 changes: 88 additions & 31 deletions zynq_rtems/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,128 @@

(Please note, this demonstration is a work in progress)

The goal is to create an hard real-time embedded application that runs on a
Xilinx Zynq SoC FPGA which will communicate with Space-ROS.
The goal is to create an hard real-time embedded application that runs on a Xilinx Zynq SoC FPGA which will communicate with Space-ROS.

This demonstration will be on [QEMU](https://www.qemu.org), the open-source CPU
and system emulator. This is for several reasons. First, development cycles in
QEMU are much faster and less painful than using real hardware. Second, given
the state of the semiconductor industry at time of writing (late 2022), it is
nearly impossible to obtain Zynq development boards. Third, a QEMU-based
demonstration requires no upfront costs or delays.
This demonstration will be on [QEMU](https://www.qemu.org), the open-source CPU and system emulator. This is for several reasons:
* Development cycles in QEMU are much faster and less painful than hardware.
* Given the state of the semiconductor industry at time of writing (late 2022), it is nearly impossible to obtain Zynq development boards.
* QEMU-based work requires no upfront hardware costs or purchasing delays

There are a number of reasonable choices available when selecting a real-time
OS (RTOS). We selected [RTEMS](https://www.rtems.org/) because it is fully
open-source and has a long history of successful deployments in space
applications.
There are a number of reasonable choices available when selecting a real-time OS (RTOS).
We selected [RTEMS](https://www.rtems.org/) because it is fully open-source and has a long history of successful deployments in space applications.

# Build

To simplify collecting and compiling dependencies on a wide range of systems,
we have created a Docker container that contains everything. You will need
to install Docker on your system first. Then, run this [script](https://github.com/space-ros/docker/blob/zynq_rtems/zynq_rtems/build_dependencies.sh):
To simplify collecting and compiling dependencies on a wide range of systems, we have created a Docker container that contains everything.
You will need to install Docker on your system first, for example, using `sudo apt install docker.io`
Then, run this [script](https://github.com/space-ros/docker/blob/zynq_rtems/zynq_rtems/build_dependencies.sh):

```
cd /path/to/zynq_rtems
./build_dependencies.sh
```

This will use the [zynq_rtems Dockerfile](https://github.com/space-ros/docker/blob/zynq_rtems/zynq_rtems/Dockerfile), which builds QEMU, a cross-compile toolchain for the ARMv8 processor inside the Zynq SoC, and RTEMS from source in the container. This will typically take at least 10 minutes, and can take much longer if either your network connection or compute resources is limited.
This will build the [zynq_rtems Dockerfile](https://github.com/space-ros/docker/blob/zynq_rtems_zenoh_pico/zynq_rtems/Dockerfile), which builds QEMU, a cross-compile toolchain for the ARMv8 processor inside the Zynq SoC, and RTEMS from source in the container.
This will typically take at least 10 minutes, and can take much longer if either your network connection or compute resources is limited.

Next, we will use this "container full of dependencies" to compile a sample "Hello, World" application which will just ping the host from within the container:
Next, we will use this "container full of dependencies" to compile a sample application.

```
cd /path/to/zynq_rtems
./compile_demos.sh
```

The demo application and its cross-compiled RTEMS kernel will live "outside" the container for ease of source control, editing cycles, and debugging. The build products will land in `zynq_rtems/hello_network/build`.
The demo application and its cross-compiled RTEMS kernel will be accessible both "inside" and "outside" the container for ease of source control, editing cycles, and debugging.
The build products will land in `zynq_rtems/hello_zenoh/build`.

# Run

The emulated system that will run inside QEMU needs to have a way to talk to a virtual network segment on the host machine. We'll create a TAP device for this. The following script will set this up, creating a virtual `10.0.42.x` subnet for a device named `tap0`:
The emulated system that will run inside QEMU needs to have a way to talk to a virtual network segment on the host machine.
We'll create a TAP device for this.
The following script will set this up, creating a virtual `10.0.42.x` subnet for a device named `tap0`:
```
zynq_rtems/start_network_tap.sh
./start_network_tap.sh
```

Now we can run the RTEMS-based application built in the previous step. The following script will run QEMU inside the container, with a volume-mount of the `hello_network` demo application so that the build products from the previous step are made available to the QEMU that was built inside the container.
We will need three terminals for this demo:
* Zenoh router
* Zenoh subscriber
* Zenoh-Pico publisher (in RTEMS in QEMU)

First, we will start a Zenoh router:
```
cd /path/to/zynq_rtems
cd hello_zenoh
./run_zenoh_router
```
This will print a bunch of startup information and then continue running silently, waiting for inbound Zenoh traffic. Leave this terminal running.

In the second terminal, we'll run the Zenoh subscriber example:
```
cd /path/to/zynq_rtems
cd hello_zenoh
./run_zenoh_subscriber
```

In the third terminal, we will run the RTEMS-based application, which will communicate with the Zenoh router and thence to the Zenoh subscriber.
The following script will run QEMU inside the container, with a volume-mount of the `hello_zenoh` demo application so that the build products from the previous step are made available to the QEMU that was built inside the container.
```
cd /path/to/zynq_rtems
cd hello_network
./run_qemu.sh
cd hello_zenoh
./run_rtems.sh
```

You should see the following output, which shows that an emulated network interface on the emulated Zynq SoC is able to `ping` the virtual network segment provided by the host machine's Linux kernel:
The terminal should print a bunch of information about the various emulated Zynq network interfaces and their routing information.
After that, it should contact the `zenohd` instance running in the other terminal. It should print something like this:
```
Opening zenoh session...
Zenoh session opened.
Own ID: 0000000000000000F45E7E462568C23B
Routers IDs:
B2FE444C3B454E27BCB11DF83120D927
Peers IDs:
Stopping read and lease tasks...
sending a few messages...
publishing: Hello, world! 0
publishing: Hello, world! 1
publishing: Hello, world! 2
publishing: Hello, world! 3
publishing: Hello, world! 4
publishing: Hello, world! 5
publishing: Hello, world! 6
publishing: Hello, world! 7
publishing: Hello, world! 8
publishing: Hello, world! 9
Closing zenoh session...
Done. Goodbye.
```
PING 10.0.42.1 (10.0.42.1): 56 data bytes
64 bytes from 10.0.42.1: icmp_seq=0 ttl=64 time=5.846 ms
64 bytes from 10.0.42.1: icmp_seq=1 ttl=64 time=0.598 ms
64 bytes from 10.0.42.1: icmp_seq=2 ttl=64 time=0.484 ms

--- 10.0.42.1 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.484/2.309/5.846/2.501 ms
The second terminal, running a Zenoh example subscriber, should print something like this:
```
Declaring Subscriber on 'example'...
[2022-12-06T21:41:11Z DEBUG zenoh::net::routing::resource] Register resource example
[2022-12-06T21:41:11Z DEBUG zenoh::net::routing::pubsub] Register client subscription
[2022-12-06T21:41:11Z DEBUG zenoh::net::routing::pubsub] Register client subscription example
[2022-12-06T21:41:11Z DEBUG zenoh::net::routing::pubsub] Register subscription example for Face{0, 5F6D54C4366D42EDB367F17A5A2CACCD}
Enter 'q' to quit...
>> [Subscriber] Received PUT ('example': 'Hello, world! 0')
>> [Subscriber] Received PUT ('example': 'Hello, world! 1')
>> [Subscriber] Received PUT ('example': 'Hello, world! 2')
>> [Subscriber] Received PUT ('example': 'Hello, world! 3')
>> [Subscriber] Received PUT ('example': 'Hello, world! 4')
>> [Subscriber] Received PUT ('example': 'Hello, world! 5')
>> [Subscriber] Received PUT ('example': 'Hello, world! 6')
>> [Subscriber] Received PUT ('example': 'Hello, world! 7')
>> [Subscriber] Received PUT ('example': 'Hello, world! 8')
>> [Subscriber] Received PUT ('example': 'Hello, world! 9')
```

After that output, the RTEMS shutdown will display the various RTEMS threads running and their memory usage.

This showed that the Zenoh Pico client running in RTEMS successfully reached the Zenoh router running natively on the host.
Success!
This is a good thing.

# Clean up

If you would like, you can now remove the network tap device that we created in the previous step:
Expand Down
6 changes: 3 additions & 3 deletions zynq_rtems/compile_demos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -o verbose
docker run --rm --net=host -e DISPLAY=$DISPLAY \
--device=/dev/dri:/dev/dri \
--volume="$HOME/.Xauthority:/root/.Xauthority:rw" \
--volume="$PWD/hello_network:/root/hello_network" \
-w /root/hello_network \
--volume="$PWD/hello_zenoh:/root/hello_zenoh" \
-w /root/hello_zenoh \
openrobotics/zynq_rtems:latest \
/root/hello_network/compile.sh
/root/hello_zenoh/compile.sh
2 changes: 1 addition & 1 deletion zynq_rtems/enter_container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
docker run --rm -e DISPLAY=$DISPLAY \
--device=/dev/dri:/dev/dri \
--device=/dev/net/tun --cap-add=NET_ADMIN \
--volume="$HOME/.Xauthority:/root/.Xauthority:rw" \
--volume="$PWD/hello_network:/root/hello_network" \
--volume="$PWD/hello_zenoh:/root/hello_zenoh" \
--network=host \
-w /root \
-it \
Expand Down
21 changes: 21 additions & 0 deletions zynq_rtems/hello_zenoh/compile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash
APP_NAME=hello_zenoh
if [ $(basename $PWD) != $APP_NAME ]; then
echo "This script must be run in the '$APP_NAME' directory."
exit
fi
if [ $(id -u) -ne 0 ]; then
echo "Non-root user detected. Re-running myself inside docker..."
set -o verbose
docker run --rm --net=host -e DISPLAY=$DISPLAY \
--device=/dev/dri:/dev/dri \
--volume=$PWD:/root/$APP_NAME \
-w /root/$APP_NAME \
openrobotics/zynq_rtems:latest \
/root/$APP_NAME/compile.sh
exit
fi
set -o errexit
set -o verbose
./waf configure --rtems=/root/rtems/6 --rtems-archs=aarch64 --rtems-version=6 --show-commands
./waf
Loading

0 comments on commit 386fc69

Please sign in to comment.