sjg 18107ce07e
CI / lint (pull_request) Successful in 2m16s
CI / frontend (pull_request) Successful in 4m12s
CI / reuse (pull_request) Successful in 2s
CI / lint (push) Successful in 2m15s
CI / test (pull_request) Successful in 9m37s
CI / test (push) Successful in 7m36s
CI / frontend (push) Failing after 31s
CI / reuse (push) Successful in 3s
[feat](trx-rs): receive SSTV pictures end to end
Wires the SSTV decoder into the stack, from the audio the server already
has to a panel in the browser that shows the picture arriving.

Server: a decoder task alongside the WEFAX one, running whenever the
decoder is enabled and the rig is in a mode SSTV is sent in.  A finished
picture is written to the cache as a PNG and sent on as a message; the
rows are sent as they decode, so a client can watch two minutes of
Martin M1 fill in rather than waiting for it.  Pictures join the decode
history, are replayed to a client that connects later, and survive a
restart.

Protocol: SetSstvDecodeEnabled and ResetSstvDecoder, a sstv_decode
_enabled flag in the rig state, two audio message types, and Sstv and
SstvProgress on DecodedMessage.  The history stores the message without
its base64 payload -- the picture is already on disk, and a megabyte per
entry is not what a history is for.

Client: pictures land in their own history, and the PNG the server sent
is written to the local cache so /sstv-images/ can serve it back.  That
endpoint and the WEFAX one now share their filename checks rather than
each carrying a copy: no separators, no parent references, .png only.

Web UI: an SSTV sub-tab beside WEFAX, with a live canvas the rows paint
into at the line number they carry, a card for the last picture, and a
filterable history with links to the files.  Rows below the one arriving
are grey rather than black -- not yet received is a different thing from
received as black.  A picture is not a spot, so neither pictures nor
their progress updates reach the decode statistics; that exclusion list
had grown by hand for LRPT and WEFAX and is now one named set.

The decoder crate gains what the server needed to hand a picture on:
to_png, to_png_base64 and save_png, with file names stamped in UTC so
they sort.

Panel behaviour is tested with the plugin runtime: rows painting at
their own line numbers rather than in arrival order, a completed picture
linked by file name alone with no server path in the page, a cut-off
picture reported as partial, clearing, and the toggle following the rig
state.

Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-06 00:14:59 +02:00
2026-05-17 23:25:14 +02:00
2026-05-17 23:25:14 +02:00
2026-05-17 23:25:14 +02:00
2026-05-17 23:25:14 +02:00
2026-05-17 23:25:14 +02:00
2026-05-17 23:25:14 +02:00
2026-05-17 23:25:14 +02:00

trx-rs logo

trx-rs

A modular amateur radio control stack written in Rust.

License

trx-rs splits radio hardware access from user-facing interfaces so you can run rig control, SDR DSP, decoding, audio streaming, and web access as separate, composable pieces.

Backends Yaesu FT-817, Yaesu FT-450D, SoapySDR
Frontends Web UI, rigctl-compatible TCP, JSON-over-TCP
Decoders AIS, APRS, CW, FT8, RDS, VDES, WSPR
Audio Opus streaming between server, client, and browser

Quick Start

1. Install dependencies

Debian / Ubuntu
sudo apt install build-essential pkg-config cmake libopus-dev libasound2-dev
# Optional — SDR support
sudo apt install libsoapysdr-dev
Fedora
sudo dnf install gcc pkg-config cmake opus-devel alsa-lib-devel
# Optional — SDR support
sudo dnf install SoapySDR-devel
Arch Linux
sudo pacman -S base-devel pkgconf cmake opus alsa-lib
# Optional — SDR support
sudo pacman -S soapysdr
macOS (Homebrew)
brew install cmake opus
# Optional — SDR support
brew install soapysdr

See Build Requirements in the wiki for details on each library.

Note: cmake is required even when a system Opus library is installed. The audiopus_sys crate probes for Opus via pkg-config; if it is not found (or pkg-config is unavailable), it falls back to compiling a vendored copy of Opus with CMake. A missing cmake therefore fails the build with is cmake not installed? rather than a missing-Opus error.

2. Build

cargo build --release

Build without SDR support: cargo build --release --no-default-features

3. Configure

Run the interactive setup wizard to generate config files for your station:

./target/release/trx-configurator

The wizard walks you through rig selection, serial port detection, audio settings, and frontend options, then writes trx-server.toml and trx-client.toml.

Alternatively, generate example configs and edit them by hand:

./target/release/trx-server --print-config > trx-server.toml
./target/release/trx-client --print-config > trx-client.toml

4. Run

./target/release/trx-server --config trx-server.toml
./target/release/trx-client --config trx-client.toml

Open the configured HTTP frontend address in a browser (default http://localhost:8080).

How It Works

graph TD
    SDR1["SDR #1"] & SDR2["SDR #2"] <-->|USB| S1["trx-server A"]
    SDR3["SDR #3"] & FT817["FT-817"] <-->|USB / serial| S2["trx-server B"]

    S1 <-->|"JSON-TCP :4530"| C1["trx-client"]
    S1 -->|"Opus-TCP per rig"| C1
    S2 <-->|"JSON-TCP :4530"| C1
    S2 -->|"Opus-TCP per rig"| C1

    C1 <-->|internal channels| F1["Web UI :8080"]
    C1 <-->|internal channels| F2["rigctl :4532"]

Each trx-server owns one or more rigs and runs DSP, decoding, and audio capture locally. A trx-client connects to any number of servers over TCP and exposes them through a unified set of frontends.

Documentation

Resource Description
User Manual Configuration, features, and usage
Architecture System design, crate layout, data flow, and internals
Optimization Guidelines Performance guidelines for the real-time DSP pipeline
Planned Features Roadmap and design notes
Contributing Commit conventions, workflow, and code style

License

GPL-2.0-or-later. See LICENSES for the full license text and bundled third-party license files. Bundled third-party components retain their original licenses: Leaflet is BSD-2-Clause, DSEG is OFL-1.1, and opus-decoder is MIT. The APRS symbol sprites come from hessu/aprs-symbols; their per-symbol copyright status is catalogued in LICENSES/LicenseRef-APRS-Symbols.txt.

S
Description
Experimental ham rig and SDR controller written in Rust
Readme
34 MiB
Languages
Rust 52.7%
JavaScript 20.7%
TypeScript 19.9%
CSS 4.1%
HTML 2.3%
Other 0.2%