The row of controls under the plot held four different control heights, units as loose text beside the field they belonged to, and a quarter of its width as a hole in the middle. Between about 1100 and 1400 px it came apart: the bandwidth cluster wrapped to two lines while the level cluster stayed on one, so the two sat at heights that matched neither each other nor anything else on the page. Every control stays, in its order, with its name and its behaviour. This is the styling and the layout. A field is now one box -- name, value and unit inside a single border -- so a number cannot be read apart from the unit it is in. Fields, buttons, the peak-hold select and the contrast slider are one height, border-box so a button's own border cannot add two pixels to it, and 2.4rem under a coarse pointer where a fingertip needs the room. The contrast readout holds a fixed, tabular slot, so the row no longer twitches between 1.0 and 0.9. The container wraps and a cluster does not: a cluster that will not fit drops whole to the next line and starts it left-aligned. The slack goes to a spacer rather than to `space-between`, which is what opened the hole. Two things this turned up. The select carries `status-input` for other layouts' sake, which drew a box inside the field's box. And the narrow -screen rules lived in a media query earlier in the file than the rules they override -- identical specificity, so the later one won and the phone layout had been overflowing sideways rather than stacking. The narrow rules now sit directly after what they override. The layout test measures the strip at three widths: one height across every control, no overflow, inside the plot, and clusters either sharing a line or each having one -- never one floating against the middle of the other. docs/Spectrum-Controls-Rework.md records what was wrong and what was deliberately left alone: the two different Autos, the settings that do not persist, the one-shot buttons, and Sweet-spot's silence while it retunes the SDR. Those are behaviour, and are for another day. Signed-off-by: Stan Grams <sjg@haxx.space>
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:
cmakeis required even when a system Opus library is installed. Theaudiopus_syscrate probes for Opus viapkg-config; if it is not found (orpkg-configis unavailable), it falls back to compiling a vendored copy of Opus with CMake. A missingcmaketherefore fails the build withis 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.
