sjgandClaude Opus 5 18b2d0efe6
CI / lint (pull_request) Successful in 2m23s
CI / test (pull_request) Successful in 9m12s
CI / frontend (pull_request) Successful in 5m52s
CI / reuse (pull_request) Successful in 6s
[feat](trx-rs): keep a station log, and a layout to work the bands from
The logbook of issue #54, in the shape the proposal settled on.

A new crate, trx-logbook, holds the contact, the ADIF reader and writer, the
file, and the rules for telling one contact from two.  ADIF because it is the
only thing the ecosystem reads: LoTW, eQSL, Club Log, QRZ and every other
logger take it and nothing else, so a log that cannot write .adi cannot be
uploaded, confirmed or moved.  The reader is forgiving in the ways real files
are irregular -- lowercase tags, CRLF, missing header, unknown fields, a
declared length that is the only thing ending a value -- and carries what it
does not model through to the export, so a round trip does not strip what
another program wrote.

The file is JSON Lines, appended one line per contact.  A log is the one
thing here that cannot be regenerated, and the bookmark store's whole-file
dump would rewrite megabytes to log one contact and lose all of them if the
power went halfway; an append costs the record being written and no more,
which a test tears a line in half to prove.  Edits append revisions, deletes
append tombstones, and the file compacts when the superseded outnumber the
live.

The panel is its own tab and stands in every layout.  An entry opens with six
fields and no more -- frequency, mode, rig name, time, and the callsign and
locator of whatever decode it was started from.  A report stays empty: an FT8
SNR is not what was sent.  Times come from the server, because the browser
may be a phone in another timezone, and the panel says so when the two
disagree by more than a second.  Worked-before answers as a callsign is
typed.

A decode is not a contact, so the Log button on an FT8 or APRS row opens an
entry and logs nothing by itself.

The ham layout is the fifth operator layout, opening on the logbook with the
radio controls around it, offered only where the rig can transmit.

Two bugs found on the way, both in code written here: a frequency of a whole
number of megahertz ending in a zero rendered as a tenth of itself, in Rust
and in TypeScript alike, because trimming trailing zeros from "20.000000"
walks back through the point.  The API also sits under /api/logbook rather
than /logbook, so it cannot shadow its own page the way /bookmarks does.

Closes #54

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SyX26FCpMQxiBoC7r5K1A7
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-07 21:12:03 +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, copy trx-rs.toml.example — a commented example covering every setting — and edit it by hand:

cp trx-rs.toml.example trx-rs.toml
./target/release/trx-server --check-config --config trx-rs.toml

--check-config reports everything wrong with a config without starting anything. --print-config prints the same settings without comments.

4. Run

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

A single trx-rs.toml can configure both: the server reads its [trx-server] section and the client reads [trx-client].

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%