This walk-through takes a freshly booted board to a first verified scenario run. It assumes the board is powered, booted from a SatLink SD card and reachable (see Hardware Setup).
1. Build the CLI#
satlinkctl is part of the Rust workspace under ps/:
cd ps
cargo build --release -p satlinkctl
export PATH="$PWD/target/release:$PATH"Every command that talks to the board reads the daemon's address from --api or from the
SATLINK_API environment variable (default http://localhost:8080). Add --json to any command
for machine-readable output.
export SATLINK_API=http://192.168.2.1:80802. Check the board#
satlinkctl status # daemon version, uptime, services
satlinkctl doctor # bring-up health check, every verdict by register namedoctor exits with 0 only when nothing failed. It also re-reads the same PL register several
times, because a class of AXI fault only shows on repetition.
Check which release is running:
curl -s $SATLINK_API/api/v1/version{"firmware":"0.1.0","api":"v1","fpga":"0xDEADBEEF","release":"r20260911-829886a51ba2-dirty"}release is the identifier burnt into the running satlinkd ("unreleased" for a hand-made
build); fpga is read live from the PL's BUILD_ID register. See
Releases and Deployment.
3. Prove the modem with a PL loopback#
Before trusting any measurement on a boot, prove that the modem transmits and receives its own
loopback byte for byte. The pl_loopback profile routes the transmitter straight back into the
receiver inside the FPGA, through the channel emulator, with no RF involved.
satlinkctl chain up --target pl --profile pl_loopback
satlinkctl datapath disable # `loopback` claims the modem itself
head -c 65536 /dev/urandom > p.bin
satlinkctl loopback --payload p.bin --blocks 4 --warmup 1chain up brings every prerequisite into place in the one order that works and prints what it
did. loopback feeds the payload while capturing, then compares: expect a verdict of
BytePerfect, or better than 99 % with errors confined to the first 16 bytes of a block (a
known DMA block-boundary artefact).
4. Run a scenario#
Scenarios are YAML timelines that the daemon executes and judges. hc_qpsk is the reference
health check: QPSK, uncoded, PL loopback, 22 seconds of generated traffic, five assertions on
measured telemetry.
satlinkctl scenario list
satlinkctl scenario run hc_qpsk # prints the run id
satlinkctl runs --limit 5 # verdicts of the latest runsA scenario run first conditions the chain for its target and refuses to start when that is not
possible. Conditioning can take tens of seconds when the AD9361 needs tuning, and the CLI's
request may time out before it finishes. Running satlinkctl chain up first, for the same target
and profile, makes the run start at once.
Read the full report, with every event, assertion and telemetry sample:
curl -s $SATLINK_API/api/v1/reports/<run-id> | jq '.assertions'or open it in the Web Console under Library → Reports. See Assertions and Reports for how to read it.
5. Push your own bytes#
With the chain up on the PL loopback, send a CSP packet and watch it come back on the ZeroMQ bridge:
satlinkctl datapath enable
satlinkctl tx send --protocol csp --src 10 --dst 1 --hex 01020304tx send always flushes two DMA blocks, so the packet is actually transmitted and a full block
comes back on the receive side. To receive it programmatically, subscribe to
tcp://<board>:5556 (see ZeroMQ Link Service), or try the
interactive chat example in Example Clients.
6. Go on air#
On-air work needs the AD9361 tuned, calibrated and routed, and a profile whose
radio.loopback is false:
satlinkctl chain status --target air # what is missing for an on-air emission
satlinkctl chain up --target air --profile rf_loopbackBefore doing this, read Chain Conditioning and the cabling rules in Hardware Setup.
Next steps#
- RF Profiles: write a profile for your radio.
- Scenarios: script traffic, impairments and measurements.
- CLI Reference: every
satlinkctlcommand.