2020-10-31: reel board; Zephyr and Gemini

reel board

I've been experimenting recently on incorporating SPDX bill-of-material generation into CMake builds, in particular for use in projects like Zephyr.

cmake-spdx

Zephyr

My friend and colleague @kestewart sent me a couple of Phytec reel boards to play around with, to get more familiar with Zephyr. I figured I would document some of the things I'm trying out here.

https://github.com/kestewart

reel board

The reel board has an nRF52840 processor, which is a 32-bit ARM Cortex-M4 processor, appears to have 1MB flash memory and 256kB RAM.

nRF52840 summary PDF

Zephyr is an open source operating system particularly intended for embedded and IoT devices. I've heard it described informally as Linux's little sister. It kind of fits the niche for applications that are too small for a full Linux install but too big to handle with Arduino and similar 8-bit microcontroller setups. It supports a ton of different development boards, as well as emulation in QEMU.

Supported boards

Zephyr support for the reel board

Getting started with Zephyr is pretty straightforward. The tool chain is relatively easy to set up. The project website has a good "blink an LED" guide for getting started, and Adafruit also has a similar tutorial for using it with one of their Feather boards.

Getting Started Guide

Adafruit tutorial

The Zephyr page on the reel board (linked above) has details about specific setup requirements, including an additional udev rule to install for use with the board.

Blinking an LED

Based on the label from the display ribbon cable, the boards I've got are the "reel_board_v2" type.

With that info, it was pretty straightforward to build the "blink an LED" sample program that comes with Zephyr:

west build -b reel_board_v2 samples/basic/blinky
west flash

The only point of confusion I ran into is that there are two Micro USB ports on the reel board. One is labeled "Debug USB" and the other "nRF USB". It seems that flashing the board requires plugging the cable into the "Debug USB" port, and also sliding the power switch to the USB setting.

So there you go. *stares into the blinkenlights*

Weirdly, connecting the debug port to my computer via USB results in the board mounting as a read-only USB drive, with a text file containing firmware details, unique ID, etc. Wasn't expecting that, but pretty useful. EDIT: actually it turns out that it isn't read-only, but apparently a 64MB read-write drive. Not sure what to do with that yet or whether it's accessible from within the Zephyr application...

Other samples

Blinking an LED is fun and all, I guess, but there's a lot of processing power here that isn't being used. Let's see what else we can do!

basic/blinky_pwm

basic/blinky_pwm code

Pretty straightforward too, just build and flash. Increases and decreases the frequency of the LED. Also includes system log debug output, accessible via UART with a tool like minicom while still connected through the Debug USB port.

display/cfb

display/cfb code

cfb == Character frame buffer. This one looks interesting, and calls out reel board as one that should work.

Notes from looking at the source code, before running:

device_get_binding() API reference

The sample program works. Can't say the reel board has the highest quality display. Here's what the output looks like:

reel board display in use

The blurriness and weird edges aren't from artifacts in the photo. If anything, they're worse in real life. But that's fine, this is all just for fun so I don't mind. :)

Zephyr and Gemini

Okay, let's be honest: the goal here is to turn this into a Gemini server.

The reel board on its own only has Bluetooth support. Phytec sells a base platform and an Ethernet shield that can be used to provide actual hardware networking, and it looks like Zephyr will support that. Looks like I need to obtain one of those.

Phytec reel board page

I reached out to their sales contact address, since it looks like North American customers can't order directly through their website.

In the meantime, even if I can't actually connect it to the Internet yet, it's probably worth thinking through some pieces of how this might work. It's been a long time since I've written C code for anything meaningful, but this sounds fun.

Assumptions for first version

Ignore threading. Any reasonable server should probably spin off requests into threads, so as to handle multiple requests with some semblance of responsiveness. And the Zephyr kernel actually does provide threading support. But... that sounds hard, and sounds like premature optimization for these purposes.

Ignore client certificates. Definitely a "not v1" sort of feature.

Provide very limited flexibility for paths / content. I assume most Gemini servers allow users to serve up a filesystem tree as a set of URLs. This will be far more limited, and probably require all content to be compiled directly into the application at build time. Adding new URLs / content would require recompiling and reflashing. That can likely be improved over time, but for v1 I'm fine with this approach.

Provide no support for dynamic content in the first instance, although (with the chip's built-in Bluetooth support) it actually might not be too hard to come up with some interesting dynamic content without too much difficulty.

TLS and certificate management will probably be one of the hardest part of this. Zephyr does appear to provide TLS support, but only for TLS 1.2, not 1.3. Looks like 1.2 does work for Zephyr under the spec, but is discouraged and clients might not support it.

Zephyr TLS constants

Gemini spec (see section 4.1 re: TLS requirements)

Just for extra fun, I'm going to take a shot at writing this without diving into code from the plethora of other Zephyr servers out there. That might be a dumb idea, but I'm interested to see what I can figure out from just the spec.

First steps

To pick a random starting point, one of the things the server will need to do is to take a request and process it:

I'll want to have some basic testing infrastructure around this, to be able to pass it a variety of requests and confirm it processes them correctly.

To get my head around this, I'm taking a look at the Zephyr documentation guide to application development.

Zephyr docs: Application Development

Will configure with kernel log / shell support for testing purposes. This could probably be done even more easily with QEMU emulation, since there's nothing network-related yet. But hey, I've got this actual hardware processor sitting right here, I may as well use it.