docs: update overview and sample config
This commit is contained in:
+334
@@ -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 <path>` (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<u64> },
|
||||||
|
Initializing { rig_info: Option<RigInfo> },
|
||||||
|
PoweredOff { rig_info: RigInfo },
|
||||||
|
Ready(ReadyStateData),
|
||||||
|
Transmitting(TransmittingStateData),
|
||||||
|
Error { error: RigStateError, previous_state: Box<RigMachineState> },
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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<Box<dyn Future<Output = DynResult<CommandResult>> + 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<Freq>, 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
|
||||||
|
```
|
||||||
@@ -4,13 +4,40 @@
|
|||||||
|
|
||||||
# trx-rs (work in progress)
|
# 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
|
## Supported backends
|
||||||
|
|
||||||
- Yaesu FT-817 (feature-gated crate `trx-backend-ft817`)
|
- Yaesu FT-817 (feature-gated crate `trx-backend-ft817`)
|
||||||
- Planned: other rigs I own; contributions and reports are welcome.
|
- 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
|
## License
|
||||||
|
|
||||||
This project is licensed under the BSD-2-Clause license. See `LICENSES/` for bundled third-party license files.
|
This project is licensed under the BSD-2-Clause license. See `LICENSES/` for bundled third-party license files.
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user