Close

A real release process for the firmware — and shipping the simulator as an artifact

A project log for OE5XRX — Open-Source Modular Remote Ham Station

A modular, repairable remote station for amateur radio — open hardware, built almost entirely AI-assisted.

peter-bucheggerPeter Buchegger 07/04/2026 at 18:070 Comments

Until now our Zephyr firmware repo had CI that built and tested, but produced no releases. That's fine until you need actual artifacts: the real STM32 binary to flash over DFU, and — less obvious — the native_sim binary, because the whole plan is to test the station virtually before touching hardware. So we built a proper release process from scratch.

A few decisions worth writing down:

One monorepo, many boards, artifacts named by board. All module firmware lives in one repo; the 2 m vs 70 cm variants are just a devicetree band property (SA818-V vs SA818-U). A small declarative release-targets.yaml lists what to build; the release job iterates it and emits board-named assets — fm-sa818-2m.binfm-sa818-70cm.bin, and so on. A new board later is one line in that file, not a pipeline rewrite.

The version is 26.07.04-01. Date-based (year.month.day-sequence), one repo-wide version for all boards — the same idea our Linux image uses, but with a two-digit year. That last bit is deliberate: dropping the "20" makes the whole thing fit straight into Zephyr's native app/VERSION numeric fields — VERSION_MAJOR=26, MINOR=7, PATCH=4, TWEAK=01, all inside the 0–255 byte range. So the firmware reports its own build version at runtime through the generated app_version.h, and APP_VERSION_NUMBER stays machine-comparable. No custom version header, no string hacks. The date is the version.

The simulator ships as a first-class artifact. Next to the real firmware, every release carries the native_sim build — the host-side x86-64 executable of the same firmware, statically linked so it runs in any target image without a glibc-version dance. That's what lets the Linux image pin a known, signed firmware-simulator and bring up a fully virtual station in CI. Everything is cosign-signed with a SHA256SUMS manifest so the consuming side can pin by hash.

First release out: 26.07.04-01 — both bands, real + sim, signed.

On the AI-dev side, since we build this fairly openly: the design (brainstorm → spec) and the CI plumbing came together fast and cleanly with an AI assistant in the loop — exactly the kind of pattern-heavy, well-trodden work where it shines. The honest bump: the first release run tripped over the boring real-world stuff — pushing a tag to a protected main and getting the artifacts attached correctly — and needed a follow-up fix commit. The design was right; the last 10 % was CI edge cases that only surface once you actually pull the trigger. AI for the shape, a human-in-the-loop pass for the plumbing reality.

Next up: the Linux-image side consumes these pinned artifacts to bundle image + firmware as one tested unit.

Discussions