From ee2527127532a3f6592bbf03b9199f5af6590556 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Sun, 18 Jan 2026 09:24:16 +0100 Subject: [PATCH] docs: update overview and sample config --- OVERVIEW.md | 334 ++++++++++++++++++++++++++++++++++++++++++++ README.md | 29 +++- trx-rs.toml.example | 79 +++++++++++ 3 files changed, 441 insertions(+), 1 deletion(-) create mode 100644 OVERVIEW.md create mode 100644 trx-rs.toml.example diff --git a/OVERVIEW.md b/OVERVIEW.md new file mode 100644 index 0000000..d5eba1b --- /dev/null +++ b/OVERVIEW.md @@ -0,0 +1,334 @@ +# trx-rs Project Overview + +## What is trx-rs? + +**trx-rs** is a modular transceiver (radio) control stack written in Rust. It provides a backend service for controlling amateur radio transceivers via CAT (Computer-Aided Transceiver) protocols, with multiple frontend interfaces for access and monitoring. + +### Current Capabilities + +| Feature | Status | +|---------|--------| +| Yaesu FT-817 CAT control | Implemented | +| HTTP/Web UI with SSE | Implemented | +| rigctl-compatible TCP | Implemented | +| VFO A/B switching | Implemented | +| PTT control | Implemented | +| Signal/TX power metering | Implemented | +| Front panel lock | Implemented | +| Multiple rig backends | Extensible (only FT-817) | +| Backend/frontend registry | Implemented | +| TCP CAT transport | Partial (config wiring only) | +| JSON TCP control (line-delimited) | Implemented (configurable frontend) | +| Plugin registry loading | Implemented (shared libraries) | +| Qt/QML GUI frontend | In progress (Linux only, optional) | +| Configuration file (TOML) | Implemented | +| Rig state machine | Implemented | +| Command handlers | Implemented | +| Event notifications | Implemented (rig task emits events) | +| Retry/polling policies | Implemented | +| Controller-based rig task | Implemented | + +--- + +## Current Architecture + +``` +┌──────────────────────────────────────────────────────────────────────────┐ +│ trx-bin │ +│ ┌────────────────────────────────────────────────────────────────────┐ │ +│ │ Application │ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │ │ +│ │ │ Config │ │ CLI │ │ Rig Task │ │ │ +│ │ │ (TOML file) │ │ (clap) │ │ (main loop) │ │ │ +│ │ └──────────────┘ └──────────────┘ └──────────────────────────┘ │ │ +│ └────────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌───────────────────┴───────────────────┐ │ +│ ▼ ▼ │ +│ ┌─────────────────────┐ ┌─────────────────────┐ │ +│ │ trx-core │ │ Frontend Layer │ │ +│ │ ┌───────────────┐ │ │ ┌───────────────┐ │ │ +│ │ │ controller/ │ │ │ │ HTTP │ │ │ +│ │ │ - machine │ │ │ │ (REST+SSE) │ │ │ +│ │ │ - handlers │ │ │ └───────────────┘ │ │ +│ │ │ - events │ │ │ ┌───────────────┐ │ │ +│ │ │ - policies │ │ │ │ HTTP JSON │ │ │ +│ │ └───────────────┘ │ │ │ (TCP/JSON) │ │ │ +│ └─────────────────────┘ │ └───────────────┘ │ │ +│ │ │ ┌───────────────┐ │ │ +│ │ │ │ rigctl │ │ │ +│ │ │ │ (TCP/hamlib) │ │ │ +│ │ │ └───────────────┘ │ │ +│ │ └─────────────────────┘ │ +│ ▼ │ +│ ┌─────────────────────┐ │ +│ │ trx-backend │ │ +│ │ ┌───────────────┐ │ │ +│ │ │ FT-817 Driver │ │ │ +│ │ └───────────────┘ │ │ +│ └─────────────────────┘ │ +└──────────────────────────────────────────────────────────────────────────┘ +``` + +### Key Components + +| Component | Purpose | +|-----------|---------| +| `trx-core` | Core types, traits (`Rig`, `RigCat`), state definitions, controller components | +| `trx-core/rig/controller` | State machine, command handlers, event system, policies | +| `trx-backend` | Backend factory and abstraction layer | +| `trx-backend-ft817` | FT-817 CAT protocol implementation | +| `trx-frontend` | Frontend trait (`FrontendSpawner`) | +| `trx-frontend-http` | Web UI with REST API and SSE | +| `trx-frontend-http-json` | JSON-over-TCP control frontend | +| `trx-frontend-qt` | Qt/QML GUI frontend (Linux only, optional) | +| `trx-frontend-rigctl` | Hamlib rigctl-compatible TCP interface | +| `trx-bin` | Main executable with config file support | + +--- + +## Configuration + +trx-rs supports TOML configuration files with the following search order: + +1. `--config ` (explicit CLI argument) +2. `./trx-rs.toml` (current directory) +3. `~/.config/trx-rs/config.toml` (XDG user config) +4. `/etc/trx-rs/config.toml` (system-wide) + +CLI arguments override config file values. + +Plugin discovery: +- Uses shared libraries with a `trx_register` entrypoint. +- Searches `./plugins`, `~/.config/trx-rs/plugins`, and any paths in `TRX_PLUGIN_DIRS`. + +Qt remote client: +- Uses JSON TCP (`frontends.http_json`) with optional bearer tokens. +- Configure the client with `frontends.qt.remote.enabled/url/auth.token`. + +### Example Configuration + +```toml +[general] +callsign = "N0CALL" + +[rig] +model = "ft817" +initial_freq_hz = 144300000 +initial_mode = "USB" + +[rig.access] +type = "serial" +port = "/dev/ttyUSB0" +baud = 9600 + +[frontends.http] +enabled = true +listen = "127.0.0.1" +port = 8080 + +[frontends.rigctl] +enabled = true +listen = "127.0.0.1" +port = 4532 + +[frontends.http_json] +enabled = true +listen = "127.0.0.1" +port = 9000 +auth.tokens = ["demo-token"] + +[frontends.qt] +enabled = false +remote.enabled = true +remote.url = "127.0.0.1:9000" +remote.auth.token = "demo-token" + +[behavior] +poll_interval_ms = 500 +poll_interval_tx_ms = 100 +max_retries = 3 +retry_base_delay_ms = 100 +``` + +Use `trx-bin --print-config` to generate an example configuration. + +--- + +## Rig Controller Components + +Located in `trx-core/src/rig/controller/`: + +### State Machine (`machine.rs`) + +Explicit state machine for rig lifecycle management: + +```rust +pub enum RigMachineState { + Disconnected, + Connecting { started_at: Option }, + Initializing { rig_info: Option }, + PoweredOff { rig_info: RigInfo }, + Ready(ReadyStateData), + Transmitting(TransmittingStateData), + Error { error: RigStateError, previous_state: Box }, +} +``` + +Events trigger state transitions: +- `RigEvent::Connected`, `Initialized`, `PoweredOn`, `PoweredOff` +- `RigEvent::PttOn`, `PttOff` +- `RigEvent::Error(RigStateError)`, `Recovered`, `Disconnected` + +### Command Handlers (`handlers.rs`) + +Trait-based command system with validation: + +```rust +pub trait RigCommandHandler: Debug + Send + Sync { + fn name(&self) -> &'static str; + fn can_execute(&self, ctx: &dyn CommandContext) -> ValidationResult; + fn execute<'a>(&'a self, executor: &'a mut dyn CommandExecutor) + -> Pin> + Send + 'a>>; +} +``` + +Implemented commands: +- `SetFreqCommand`, `SetModeCommand`, `SetPttCommand` +- `PowerOnCommand`, `PowerOffCommand` +- `ToggleVfoCommand`, `LockCommand`, `UnlockCommand` +- `GetTxLimitCommand`, `SetTxLimitCommand`, `GetSnapshotCommand` + +The rig task (`trx-bin/src/rig_task.rs`) now syncs the state machine to the live `RigState` +and emits events whenever rig status changes. + +### Event Notifications (`events.rs`) + +Typed event system for rig state changes: + +```rust +pub trait RigListener: Send + Sync { + fn on_frequency_change(&self, old: Option, new: Freq); + fn on_mode_change(&self, old: Option<&RigMode>, new: &RigMode); + fn on_ptt_change(&self, transmitting: bool); + fn on_state_change(&self, old: &RigMachineState, new: &RigMachineState); + fn on_meter_update(&self, rx: Option<&RigRxStatus>, tx: Option<&RigTxStatus>); + fn on_lock_change(&self, locked: bool); + fn on_power_change(&self, powered: bool); +} + +pub struct RigEventEmitter { + // Manages listeners and dispatches events +} +``` + +### Policies (`policies.rs`) + +Configurable retry and polling behavior: + +```rust +pub trait RetryPolicy: Send + Sync { + fn should_retry(&self, attempt: u32, error: &RigError) -> bool; + fn delay(&self, attempt: u32) -> Duration; + fn max_attempts(&self) -> u32; +} + +pub trait PollingPolicy: Send + Sync { + fn interval(&self, transmitting: bool) -> Duration; + fn should_poll(&self, transmitting: bool) -> bool; +} +``` + +Implementations: +- `ExponentialBackoff` - Exponential delay with max cap +- `FixedDelay` - Constant delay between retries +- `NoRetry` - Fail immediately +- `AdaptivePolling` - Faster polling during TX +- `FixedPolling` - Constant interval +- `NoPolling` - Disable automatic polling + +### Error Types + +`RigError` now includes error classification: + +```rust +pub struct RigError { + pub message: String, + pub kind: RigErrorKind, // Transient or Permanent +} + +impl RigError { + pub fn timeout() -> Self; // Transient + pub fn communication(msg) -> Self; // Transient + pub fn invalid_state(msg) -> Self; // Permanent + pub fn not_supported(op) -> Self; // Permanent + pub fn is_transient(&self) -> bool; +} +``` + +--- + +## Remaining Improvement Opportunities + +### Integration Work + +1. **Plugin UX improvements** - Add structured plugin metadata (name, version, capabilities) and surface it in CLI help. + +### Testing + +- Add integration tests with mock backends +- Add more backend/frontend unit tests + +### Features + +- Add more rig backends (IC-7300, TS-590, etc.) +- Add TX limit support for FT-817 (or document per-backend constraints in UI) +- Add WebSocket support for bidirectional communication +- Add metrics/telemetry export (Prometheus) +- Add authentication for HTTP frontend + +### Code Quality + +- Add CI/CD pipeline +- Add pre-commit hooks + +--- + +## Implementation Status + +| Component | Status | Tests | +|-----------|--------|-------| +| State Machine | Implemented | 5 tests | +| Command Handlers | Implemented | 3 tests | +| Event Notifications | Implemented | 2 tests | +| Retry/Polling Policies | Implemented | 5 tests | +| Config File Support | Implemented | 4 tests | +| rigctl Frontend | Implemented | - | +| HTTP Frontend | Implemented | - | +| FT-817 Backend | Implemented | - | + +**Total: 19 unit tests passing** + +--- + +## Building and Running + +```bash +# Build +cargo build --release + +# Run with CLI args +./target/release/trx-bin -r ft817 "/dev/ttyUSB0 9600" + +# Run with config file +./target/release/trx-bin --config /path/to/config.toml + +# Print example config +./target/release/trx-bin --print-config > trx-rs.toml + +# Run tests +cargo test + +# Run clippy +cargo clippy +``` diff --git a/README.md b/README.md index b019093..62a190c 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,40 @@ # trx-rs (work in progress) -This is an early, untested snapshot of a transceiver control stack (core + backend + HTTP frontend). Things may change quickly and APIs are not stable yet. Expect rough edges and bugs; use at your own risk and please report issues you hit. Features, tests and docs are still being written (or not). +This is an early, untested snapshot of a transceiver control stack (core + backend + frontends). Things may change quickly and APIs are not stable yet. Expect rough edges and bugs; use at your own risk and please report issues you hit. Features, tests and docs are still being written (or not). + +The rig task is now driven by the controller components (state machine, handlers, and policies). Polling and retry behavior are configurable via the `[behavior]` section in the config file. ## Supported backends - Yaesu FT-817 (feature-gated crate `trx-backend-ft817`) - Planned: other rigs I own; contributions and reports are welcome. +## Frontends + +- HTTP status/control frontend (`trx-frontend-http`) +- JSON TCP control frontend (`trx-frontend-http-json`) +- Qt/QML GUI frontend (`trx-frontend-qt`, Linux only, optional via `qt-frontend` feature) +- rigctl-compatible TCP frontend (`trx-frontend-rigctl`, listens on 127.0.0.1:4532) + +## Plugin discovery + +`trx-bin` can load shared-library plugins that register backends/frontends via a +`trx_register` entrypoint. Search paths: + +- `./plugins` +- `~/.config/trx-rs/plugins` +- `TRX_PLUGIN_DIRS` (path-separated) + +Example plugin: `examples/trx-plugin-example` + +## Qt remote client + +The Qt frontend can run as a remote client over the JSON TCP interface. +Configure the server with `frontends.http_json.auth.tokens` and the client with +`frontends.qt.remote.enabled`, `frontends.qt.remote.url`, and +`frontends.qt.remote.auth.token`. + ## License This project is licensed under the BSD-2-Clause license. See `LICENSES/` for bundled third-party license files. diff --git a/trx-rs.toml.example b/trx-rs.toml.example new file mode 100644 index 0000000..31fb9df --- /dev/null +++ b/trx-rs.toml.example @@ -0,0 +1,79 @@ +# trx-rs Configuration File +# +# Copy this file to one of: +# ./trx-rs.toml (current directory) +# ~/.config/trx-rs/config.toml (user config) +# /etc/trx-rs/config.toml (system-wide) +# +# Or specify a custom path with: trx-bin --config /path/to/config.toml +# +# CLI arguments override config file values. + +[general] +# Callsign or station identifier displayed in frontends +callsign = "N0CALL" + +# Log level: trace, debug, info, warn, error +# log_level = "info" + +[rig] +# Rig model: ft817 (more models coming) +model = "ft817" +# Initial frequency (Hz) before first CAT read +initial_freq_hz = 144300000 +# Initial mode before first CAT read (LSB, USB, CW, CWR, AM, WFM, FM, DIG, PKT) +initial_mode = "USB" + +[rig.access] +# Access type: "serial" or "tcp" +type = "serial" + +# Serial port settings (when type = "serial") +port = "/dev/ttyUSB0" +baud = 9600 + +# TCP settings (when type = "tcp") +# host = "192.168.1.100" +# tcp_port = 4532 + +[frontends.http] +# Enable HTTP/REST frontend with SSE for real-time updates +enabled = true +listen = "127.0.0.1" +port = 8080 + +[frontends.rigctl] +# Enable rigctl-compatible TCP interface (hamlib compatible) +enabled = false +listen = "127.0.0.1" +port = 4532 + +[frontends.http_json] +# Enable JSON-over-TCP control interface +enabled = true +listen = "127.0.0.1" +# Set to 0 to bind an ephemeral port +port = 0 +# List of accepted bearer tokens (empty = no auth) +# auth.tokens = ["example-token"] + +[frontends.qt] +# Enable Qt/QML GUI frontend (Linux only, requires system Qt6) +enabled = false +# Use remote JSON TCP server instead of local rig task +# remote.enabled = true +# remote.url = "127.0.0.1:9000" +# remote.auth.token = "example-token" + +[behavior] +# Polling interval when idle (milliseconds) +poll_interval_ms = 500 + +# Polling interval when transmitting (milliseconds) +poll_interval_tx_ms = 100 + +# Maximum retry attempts for transient errors +max_retries = 3 + +# Base delay for exponential backoff (milliseconds) +retry_base_delay_ms = 100