All docsStellar LinkRF bench · by Stellar Systems v0.1.0

Deployment

Releases and Deployment

Traceable release bundles: the release identifier, building a bundle, writing it to the SD card, verifying what the board runs, and quick iterations.

What runs on the board comes from two repositories (satlink-sdr for the bitstream and the daemon, stellar-fw for the firmware) and three build flows. A release ties them together: one bundle, one identifier, and a refusal whenever the pieces do not match.

The release identifier#

text
r<YYYYMMDD>-<first 12 hex of sha256(commits + diffs of both repos + md5 of the .bit)>[-dirty]
  • It is derived from the inputs (both repositories' commits and uncommitted diffs, and the bitstream's md5), not from the outputs. That is what allows it to be burnt into satlinkd, which is itself one of the outputs.
  • It is deterministic: the same sources give the same identifier, so rebuilding a deployed release produces a bundle that compares equal.
  • -dirty marks a bundle built from trees with uncommitted changes.

The running board reports it:

Shell
curl -s http://192.168.2.1:8080/api/v1/version
JSON
{"firmware": "0.1.0", "api": "v1", "fpga": "0xDEADBEEF", "release": "r20260911-829886a51ba2-dirty"}
FieldMeaning
releaseThe identifier burnt into the running satlinkd; "unreleased" for a build that did not go through the release script
fpgaThe PL's BUILD_ID register, read live. Today every build carries the default 0xDEADBEEF, so it tells a loaded bitstream from none, not one bitstream from another

The bundle#

A bundle lives in release/<id>/:

FileContent
system_top.binThe bitstream, converted by bootgen
satlink.xsaThe hardware description exported with it
BOOT.bin, u-boot.img, uEnv.txtBoot loader and environment
uImage, devicetree.dtbKernel and device tree
uramdisk.image.gzRoot filesystem, including satlinkd and the DSL files
satlinkdThe daemon binary, for reference and checks
manifest.json, MANIFEST.txtmd5 of every file, provenance of both trees

Building a release#

The bitstream must already exist in pl/top/build/ (see Building the Bitstream).

Shell
tools/make-release.sh                                   # 1. computes the id, builds satlinkd with it,
                                                        #    then REFUSES: the ramdisk does not carry it yet
(cd ~/Code/stellar-fw && ./build.sh build fishball7020) # 2. firmware build, burns satlinkd into the ramdisk
tools/make-release.sh                                   # 3. same id, coherent bundle

make-release.sh options: --force (build from trees with uncommitted changes), --no-satlinkd (skip the cross-compilation; such a bundle cannot be deployed).

The checks, each of which refuses:

CheckCatches
Modified tree without --forceA bundle nobody could rebuild
satlinkd does not contain its idA recycled build artefact reporting a previous id
uramdisk.image.gz does not contain the idA new daemon beside an old ramdisk: both files exist and look fine, but the board would run the old daemon
Bundle differs from its manifestA file changed after the build
Incomplete bundleHalf a release
The target is not the real SD cardThe board's own USB storage has the same label SATLINK; writing to it succeeds and changes nothing

Deploying#

Shell
tools/deploy-release.sh                         # newest bundle under release/, to a mounted SD card
tools/deploy-release.sh release/r2026...        # a specific bundle
tools/deploy-release.sh --over-ssh              # to the SD card inside the running board

With --over-ssh, the bundle is written to the card while it stays in the board (the FAT partition is mounted on the board), md5 sums are computed on the board, and files are written under a temporary name and renamed at the end, so an interrupted transfer never leaves a truncated system_top.bin. The board is found with pl/top/bringup/resolve-board.sh.

Then reboot and verify:

Shell
tools/deploy-release.sh --verify <id>

--verify asks the running board for its release id and compares. It is the only check that proves a deployment took: writing files and running them are two different things.

Quick iterations#

For a daemon change, rebuilding the firmware is slow. The RAM-disk root filesystem is writable, so a new satlinkd can be copied in for the current boot:

Shell
fw/make-satlinkd.sh                          # cross-build into fw/out/ (wraps stellar-fw's script)
scp -O fw/out/satlinkd root@192.168.2.1:/tmp/
ssh root@192.168.2.1 '/etc/init.d/S99satlinkd stop && mv /tmp/satlinkd /usr/bin/satlinkd && /etc/init.d/S99satlinkd start'
  • A running executable cannot be overwritten: copy to /tmp, stop, move, start.
  • Burn a marker into the id (SATLINK_RELEASE_ID=<id>+scp-<sha>) so /api/v1/version says the binary was hand-deployed.
  • It disappears at the next reboot, by construction. Never leave a campaign running across a reboot on a hand-deployed binary: it will measure the SD card's daemon without saying so.

For a bitstream-only iteration, pl/top/deploy-sd.sh converts the .bit to system_top.bin and copies it to the SD card with md5 verification. It leaves the daemon, kernel and device tree as they were, which is right for a PL experiment and wrong for a release.

Known limits#

  • The manifest vouches for itself. It lists the md5 of every file except itself; editing it by hand goes unnoticed. It protects against drift, not tampering.
  • The PL's BUILD_ID does not identify builds. Nothing at runtime can tell two bitstreams apart; the release id is the only link between a board and the sources of its bitstream.

Stellar Link · v0.1.0

↑↓ to moveEnter to open