All docsStellar LinkRF bench · by Stellar Systems v0.1.0

Deployment

Daemon Configuration

satlinkd's command line and every section of satlinkd.toml, with the shipped values, the defaults, and how to change the configuration on a board.

satlinkd is configured by one TOML file. On the board it is /etc/satlinkd/satlinkd.toml, installed by the firmware build from stellar-fw/overlay/etc/satlinkd/satlinkd.toml.

Command line#

text
satlinkd [-c|--config <FILE>] [-l|--log-level <FILTER>] [--dry-run]
OptionEnvironmentMeaning
-c, --configSATLINKD_CONFIGThe configuration file. Without it, ./satlinkd.toml then /etc/satlinkd/satlinkd.toml are searched
-l, --log-levelSATLINKD_LOG_LEVELA log filter (info, debug, satlink_api=debug,info, …). When given, it overrides [observability] log_filter
--dry-run—Load and validate the configuration, then exit without starting any service

If the configured filter would silence the daemon's own info messages, the daemon says so on standard error: a filter string that parses but matches nothing is otherwise indistinguishable from a quiet daemon.

On the board the daemon is started at boot by /etc/init.d/S99satlinkd {start|stop|restart} and logs to /var/log/satlinkd.log.

Changing the configuration on a board#

/etc is on the RAM disk. An edit there works until the next reboot:

Shell
ssh root@192.168.2.1
vi /etc/satlinkd/satlinkd.toml
satlinkd --config /etc/satlinkd/satlinkd.toml --dry-run    # check it
/etc/init.d/S99satlinkd restart

A permanent change goes into stellar-fw/overlay/etc/satlinkd/satlinkd.toml and a new release.

[daemon]#

KeyBoardDefaultMeaning
profiles_dir/opt/satlink/dsl/profilesdsl/profilesProfiles, *.yaml directly in the directory
scenarios_dir/opt/satlink/dsl/scenariosdsl/scenariosScenarios, loaded recursively; POST /api/v1/scenarios writes here
campaigns_dir/opt/satlink/dsl/campaignsdsl/campaignsCampaigns
campaign_state_dir/mnt/jffs2/satlink-campaignsthe sameCampaign cursors. Must survive a reboot: keep it on /mnt/jffs2

[api]#

KeyBoardDefaultMeaning
bind0.0.0.0:80800.0.0.0:8080REST and WebSocket listener
cors_origins["*"]["http://localhost:5173"]Allowed browser origins; "*" allows any
auth_required—falseRequire a JWT on mutating requests (needs the auth build feature)
auth_secret—emptyHS256 secret for those tokens
max_body_bytes—20 MiBLargest request body. Hex payloads double in size, and a transmit request costs about 11× its useful bytes in memory while it is processed. Use /ws/tx for large transfers

[pl_driver]#

KeyBoardMeaning
uio_device/dev/uio0The UIO node mapping the PL's 1 MiB window
map_index0UIO map index
mockfalseRequired, no default. true uses an in-memory stub instead of the hardware. It is mandatory on purpose: a board whose configuration lost this key refuses to start rather than serving invented register values
trace_writestrueLog every PL register write by name
trace_to_kmsgtrueSend those lines to /dev/kmsg, so they reach dmesg and the serial console, and survive in the kernel log when the RAM-disk log file is lost to a freeze

[telemetry]#

KeyBoardMeaning
poll_interval_ms200Telemetry cadence (5 Hz on the board)
watch_registersabout 30 namesPL registers sampled on every tick by catalogued name; assertable as reg.<name>. Unknown names are reported at startup and dropped. Default: none. See Telemetry and Metrics

[store]#

KeyBoardMeaning
sqlite_path/var/lib/satlink/satlink.dbThe run store (reports, run history, profile revisions). On the RAM disk: lost at reboot
disabled—true opens no store

[observability]#

KeyBoardDefaultMeaning
metrics_bind0.0.0.0:90900.0.0.0:9090Prometheus exporter
log_filterinfoinfoLog filter (overridden by --log-level)
json_logs—falseJSON log lines
journald—falseLog to journald

[datapath]#

KeyBoardDefaultMeaning
autostartfalsefalseClaim the modem's IIO devices at startup. Leave it off on a bench: holding them makes every other tool fail with EBUSY, which looks like a dead modem. The daemon claims them on demand
buffer_length40964096IIO buffer length in samples; a block is buffer_length × 4 bytes and carries buffer_length useful bytes

[radio]#

KeyDefaultMeaning
condition_at_startfalseRun the AD9361 calibration and interface tuning once at startup. Off because a conditioning from a power-cycled part has taken a board off the network; turn it on only after measuring it on your board
boot_profilenoneThe profile whose rate the startup tuning targets
condition_timeout_s180Give up on the startup conditioning after this long (the API comes up regardless)
settle_after_calibrate_ms2000Wait between calibration and tuning

[monitor] and [iq]#

KeyDefaultMeaning
[monitor] synthetic_fftfalseManufacture a spectrum when no samples are available (UI work without a board). Responses are then marked synthetic: true
[iq] allow_syntheticfalseAllow IQ captures to fall back to a synthesised tone, marked synthetic: true
KeyBoardDefaultMeaning
enabledtruefalseRun the ZeroMQ bridge
kindzmqzmqTransport; only zmq is implemented, anything else is refused
bind_address0.0.0.00.0.0.0Listen address
tx_port55555555PULL: frames in
rx_port55565556PUB: frames received
telemetry_port55575557PUB: telemetry; 0 disables it
frame_slot_bytes000 publishes whole blocks; N parses N-byte slots. Must match the profile's mtu_bytes and divide 4096

See ZeroMQ Link Service.

A minimal host configuration#

For UI or API work on a host without a board (ps/config/satlinkd.default.toml):

TOML
[daemon]
profiles_dir  = "dsl/profiles"
scenarios_dir = "dsl/scenarios"

[api]
bind         = "0.0.0.0:8080"
cors_origins = ["http://localhost:5173"]

[pl_driver]
uio_device = "/dev/uio0"
map_index  = 0
mock       = true

[telemetry]
poll_interval_ms = 200

Stellar Link · v0.1.0

↑↓ to moveEnter to open