Commit Graph

394 Commits

Author SHA1 Message Date
sjg 6c213369da [fix](trx-ft8): fix const qualifier warning in ft8_lib C code
Fix compiler warning about discarded const qualifier in strchr() call.
The result of strchr(const char*, ...) should be assigned to const char*,
not char*.

This resolves:
  warning: initialization discards 'const' qualifier from pointer target type

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-27 00:42:29 +01:00
sjg bc270834e0 [chore](trx-rs): enable CPU optimizations for better performance
Add .cargo/config.toml to enable native CPU features (AVX2, SSE4.2, etc.)
for maximum performance during compilation. This allows rustc and
dependencies to use SIMD instructions and other CPU optimizations.

This should reduce CPU usage of the DSP backend by allowing:
- Vectorized floating-point operations
- Better compiler optimizations for complex number math
- SIMD acceleration in dependencies like num-complex

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-27 00:36:37 +01:00
sjg 2bdc23400a [fix](trx-frontend-http): hide rig picker when auth is required
Hide the header rig picker when showing the authentication gate,
since no rigs are accessible until the user authenticates.
Show the picker again when auth gate is hidden (after login).

This improves UX by not showing an empty picker to unauthenticated users.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-27 00:26:57 +01:00
sjg efd2c53754 [fix](trx-server): auto-generate rig IDs when not specified in config
When rigs are configured without explicit IDs in TOML, they now
receive auto-generated IDs based on model name and index (e.g.,
"ft817_0", "soapysdr_1"). Previously, the default empty ID prevented
auto-generation from triggering.

Changes:
- Set RigInstanceConfig default id to empty string (was "default")
- This allows resolved_rigs() auto-generation to trigger for all rigs
- Legacy single-rig path still gets explicit "default" ID
- Auto-generated IDs now appear in HTTP API /rigs endpoint
- Rig picker now displays auto-IDs correctly

The fix ensures that rigs without explicit ids get proper identifiers
that appear in the protocol and frontend selectors.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-27 00:24:15 +01:00
sjg a370742d2b [chore](trx-rs): remove test config file
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-27 00:19:05 +01:00
sjg 12d967154c [fix](trx-backend-soapysdr): improve device initialization diagnostics
Enhance error handling and messaging for SoapySDR device initialization:
- Add fallback logic to try empty args if device-specific args fail
- Provide detailed multi-line error messages with troubleshooting guidance
- Include suggestions to check SoapySDR plugins and run SoapySDRUtil --probe
- Clarify device lifetime management in struct
- Document why actual streaming not yet implemented (soapysdr 0.3 limitations)
- Note that sdr 0.3 requires FFI or upgrade for streaming support

This helps users diagnose device initialization failures and understand
the current architectural limitations.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-27 00:18:07 +01:00
sjg 6ed3f96155 [refactor](trx-server): access soapysdr through trx-backend facade
Remove direct dependency on trx-backend-soapysdr from server Cargo.toml.
Re-export SoapySdrRig from trx-backend instead so server accesses it
through the proper facade. This keeps sub-backends internal to trx-backend
and maintains proper module organization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:12:38 +01:00
sjg c3ea605924 [refactor](trx-backend-soapysdr): remove feature gating, require real hardware
Drop optional feature gating - SoapySDR hardware support is now required.
Make soapysdr a required dependency in Cargo.toml instead of optional.
Update server to always enable soapysdr backend and its dependencies.
Simplify initialization to always use RealIqSource instead of conditional
fallback to MockIqSource.

This assumes SoapySDR library is installed on the system.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:09:10 +01:00
sjg 1de15cba7e [feat](trx-server): auto-generate rig IDs from model name if not specified
Allow rigs to have empty IDs in config; auto-generate from backend model
name with numeric suffix (e.g., 'ft817_0', 'ft817_1', 'soapysdr_0').
This makes config more concise when using multiple instances of the same
model without explicit ID assignment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:59:49 +01:00
sjg 5a6cac470a [feat](trx-backend-soapysdr): implement real hardware IQ source with feature gating
Add RealIqSource that connects to actual SoapySDR devices when soapysdr-sys
feature is enabled. Implements proper device initialization, frequency/bandwidth
configuration, gain control, and RX stream management.

When soapysdr-sys feature is disabled (default), falls back to MockIqSource
for testing. Update feature flags in Cargo.toml dependencies to support both
real hardware and mock operation.

- Device initialization with proper error handling
- RX frequency, bandwidth, and gain configuration
- IQ sample streaming via broadcast channel
- Proper resource cleanup via Drop trait
- Throttled MockIqSource to prevent 100% CPU

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:58:12 +01:00
sjg a337c0ccea [fix](trx-backend-soapysdr): throttle MockIqSource to avoid 100% CPU load
Add sleep proportional to block duration in iq_read_loop to simulate
real hardware timing. MockIqSource immediately returns samples without
any delay, causing busy-looping. Throttling prevents excessive CPU usage
when using the mock source.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:48:41 +01:00
sjg 2fe3ee6fc1 [feat](trx-frontend-http): remove rig selector from about page
Use header rig selector as the single point for rig switching. Remove
redundant about page rig selector controls and associated JavaScript
event listeners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:46:12 +01:00
sjg f716e7ec47 [feat](trx-client): support rig display names in frontend layer
Add display_name field to RemoteRigEntry and propagate from GetRigs
response. Update http-json frontend to include display_name in rig
entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:46:08 +01:00
sjg 283c9b049e [feat](trx-protocol): add display_name to RigEntry
Include optional display_name field in GetRigs response to allow clients
to show friendly rig names instead of just identifiers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:46:05 +01:00
sjg 8297af8302 [feat](trx-server): add configurable display name for rigs
Add optional `name` field to RigInstanceConfig to allow long-form rig names
(e.g., "HF Transceiver"). The name defaults to rig id if not configured.
Add display_name() method to get display name with fallback to id.
Propagate display_name through RigHandle to listener for GetRigs response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:46:02 +01:00
sjg 68944f7d78 [fix](trx-backend): fix clippy warnings and improve code style
Fix useless vec! allocation in demod tests, improve loop iterator usage,
and reformat code for better readability across dummy and soapysdr
backends.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:33:40 +01:00
sjg f8a683b312 [style](trx-server): improve code formatting and remove unused imports
Reformat assertions, multi-line function calls, and error handling for
better readability. Remove unused soapysdr feature import in main.rs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:33:37 +01:00
sjg 30ac7aab1e [feat](trx-server): add soapysdr as default feature
Enable SoapySDR backend by default to make multi-device setups work out
of the box without requiring explicit feature flags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:33:34 +01:00
sjg 68ca798b47 [style](trx-client): improve audio and HTTP frontend code formatting
Reformat multi-line statements and function calls for better readability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:33:30 +01:00
sjg e3626eafd4 [style](trx-core): improve code formatting and trait readability
Reformat filter state methods and error handling for better consistency.
Improve readability of complex return type expressions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:33:27 +01:00
sjg 3cd614e6a2 [style](trx-protocol): reformat codec tests for readability
Improve assertion and struct literal formatting across test cases
for better code clarity and consistency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:33:24 +01:00
sjg b7073e9104 fix(trx-client): increase command timeouts for slow CAT responses 2026-02-25 23:40:56 +01:00
sjg 47cff3f927 feat(multi-rig): auto-discover per-rig audio ports via GetRigs 2026-02-25 23:31:38 +01:00
sjg b1c232f388 fix(trx-client): route audio by selected rig with per-rig port map 2026-02-25 23:23:48 +01:00
sjg 8ffeba47df fix(http-ui): avoid blocking controls on slow rig initialization 2026-02-25 23:20:21 +01:00
sjg a052c8a33d fix(trx-client): populate rig picker eagerly and via /rigs refresh 2026-02-25 23:17:05 +01:00
sjg bd80ffa870 fix(trx-client): prefer TX rig default and add header rig picker 2026-02-25 23:14:05 +01:00
sjg 6f836a93e9 feat(trx-client): add runtime multi-rig discovery and switching 2026-02-25 22:39:02 +01:00
sjg 30ad6d1bb4 feat(trx-client): add remote rig_id selection via config and CLI 2026-02-25 22:31:59 +01:00
sjg 49118b65a1 [chore](trx-rs): remove implementation stub files
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 21:36:34 +01:00
sjg 93536ed45e [docs](trx-rs): add SKILLS.md documenting project slash commands
Documents the /frontend-design skill (project-scoped, in
.claude/commands/frontend-design.md) and explains how to add new
skills. Lists global skills available across all projects.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 20:33:51 +01:00
sjg 08acbeecad [chore](trx-rs): add .claude/ to .gitignore
Prevent Claude Code session files, worktrees, and settings from
being accidentally committed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 20:25:52 +01:00
sjg 66163c7e7d [feat](trx-client): capability-gated UI controls and filter panel (UC-05..07)
Add /set_bandwidth and /set_fir_taps HTTP endpoints to api.rs.

Add applyCapabilities(caps) function to app.js that shows/hides:
- PTT button and TX meters: capabilities.tx
- TX limit row: capabilities.tx_limit
- VFO row: capabilities.vfo_switch
- Signal meter row: capabilities.signal_meter
- Filters panel: capabilities.filter_controls

Called from render() whenever capabilities are present; runs on both
initial /status response and every SSE event.

Add a Filters panel to index.html with bandwidth slider (1..500 kHz)
and FIR taps select (16/32/64/128/256); hidden by default, revealed by
applyCapabilities when filter_controls is set. Each control dispatches
to the corresponding HTTP endpoint on change.

Sync filter state from update.filter in render() to keep slider/select
in sync with server-side DSP state.

Fix missing struct fields in test helpers across remote_client.rs,
trx-frontend-http-json/server.rs, trx-frontend-rigctl/server.rs, and
trx-core controller tests (handlers.rs, machine.rs).

Update aidocs/UI-CAPS.md: all tasks UC-01..UC-09 marked [x].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 20:25:11 +01:00
sjg 3b98c8b7b5 [feat](trx-server): dispatch SetBandwidth and SetFirTaps in rig_task
Handle SetBandwidth(hz) and SetFirTaps(taps) in process_command:
call the RigCat methods, update filter state in-place, broadcast
the updated state, and return the new snapshot.

Fix missing capability fields in listener.rs test helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 20:25:00 +01:00
sjg dc33d1e841 [feat](trx-backend): set capability flags; add SDR filter state; add UC-08 tests
Set tx/tx_limit/vfo_switch/filter_controls/signal_meter on all backends:
- FT-817, FT-450D, dummy: tx=true, tx_limit=true, vfo_switch=true,
  filter_controls=false, signal_meter=true
- SoapySDR: tx=false, tx_limit=false, vfo_switch=false,
  filter_controls=true, signal_meter=true

SoapySDR backend now stores bandwidth_hz and fir_taps fields; overrides
set_bandwidth, set_fir_taps, and filter_state on RigCat to expose live
DSP state in the snapshot.

Add UC-08 unit tests on dummy backend asserting tx capabilities present
and filter_controls absent, and that filter_state returns None.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 20:24:55 +01:00
sjg 3335942374 [feat](trx-protocol): add SetBandwidth, SetFirTaps commands; add UC-09 tests
Add SetBandwidth { bandwidth_hz: u32 } and SetFirTaps { taps: u32 } to
ClientCommand with bidirectional mapping to RigCommand variants.

Add UC-09 protocol serialization tests confirming that RigSnapshot
serializes the filter field when Some and omits it when None.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 20:24:48 +01:00
sjg 9177206dd9 [feat](trx-core): add capability flags and filter state for UI gating
Add five new boolean fields to RigCapabilities: tx, tx_limit,
vfo_switch, filter_controls, signal_meter. These drive which controls
the HTTP frontend shows or hides per rig type.

Add RigFilterState struct (bandwidth_hz, fir_taps, cw_center_hz) and
filter: Option<RigFilterState> to both RigState (skip-serialized) and
RigSnapshot (skip_serializing_if = None).

Add SetBandwidth and SetFirTaps to RigCommand; add default not-supported
implementations of set_bandwidth, set_fir_taps, and filter_state to
the RigCat trait.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 20:24:43 +01:00
sjg 80afb928ae [chore](trx-rs): rename autogendoc/ to aidocs/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 19:21:43 +01:00
sjg eec5aaf811 [chore](trx-rs): move autogenerated spec docs into autogendoc/
Keeps README.md, CLAUDE.md, and CONTRIBUTING.md at root as standard
project files. Moves AI-generated design/specification documents
(AGENTS, AUTH, CONFIGURATION, ENHANCEMENT, MULTI, OVERVIEW, SDR,
UI-CAPS) into autogendoc/ to distinguish them from hand-maintained docs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 08:11:38 +01:00
sjg d7d2b3f790 [docs](trx-rs): add UI-CAPS.md plan for capability-gated UI controls
Specifies UC-01 through UC-09: extending RigCapabilities with tx/tx_limit/
vfo_switch/filter_controls/signal_meter flags, RigFilterState struct,
SetBandwidth/SetFirTaps protocol commands, new HTTP endpoints, and
frontend visibility gating via applyCapabilities() in app.js.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 08:11:28 +01:00
sjg 758dde97a2 [docs](trx-rs): add MULTI.md progress tracking for multi-rig support
Documents architecture, TOML format, protocol wire format, validation
rules, and task completion status (MR-01 through MR-09).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 08:04:23 +01:00
sjg 0b8c408c17 [feat](trx-server): implement multi-rig support
Enable N simultaneous rig backends in one server process:

- rig_handle.rs: new RigHandle { rig_id, rig_tx, state_rx } thin struct
- config.rs: RigInstanceConfig, rigs: Vec<RigInstanceConfig> in ServerConfig,
  resolved_rigs() (synthesises legacy flat fields as id="default"),
  validate() checks unique rig IDs and audio ports; MR-08 config tests
- audio.rs: replace four OnceLock<Mutex<VecDeque>> statics with
  DecoderHistories { aprs, ft8, wspr } Arc struct; decoder/listener
  functions now take Arc<DecoderHistories> for per-rig isolation
- rig_task.rs: add rig_id + histories: Arc<DecoderHistories> to
  RigTaskConfig; clear_*_history calls use ctx.histories instance methods
- listener.rs: run_listener takes Arc<HashMap<String, RigHandle>> +
  default_rig_id; routes envelope.rig_id to correct rig; GetRigs fast
  path aggregates all rig states; all responses include rig_id field
- main.rs: loop over resolved_rigs(); spawn_rig_audio_stack() helper;
  builds Arc<HashMap<String, RigHandle>> passed to run_listener

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 08:04:19 +01:00
sjg bb3464e32f [feat](trx-protocol): add multi-rig protocol support
Add GetRigs command, rig_id routing fields, and RigEntry type:
- ClientCommand::GetRigs (intercepted in listener before rig_task)
- rig_id: Option<String> on ClientEnvelope (absent = first rig)
- rig_id: Option<String> and rigs: Option<Vec<RigEntry>> on ClientResponse
- RigEntry { rig_id, state } for GetRigs aggregated response
- Sentinel unreachable!() arm for GetRigs in client_command_to_rig()
- MR-09 codec tests: rig_id parsing, GetRigs round-trip, serde omit-when-None

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-25 08:04:08 +01:00
sjg 319e935d97 [feat](trx-server): wire SoapySDR backend and AudioSource into server startup
- Call validate_sdr() at startup and abort on errors (SDR.md §11)
- Build SoapySdrRig with full [[sdr.channels]] config when access_type is
  "sdr"; subscribe to its primary-channel PCM sender before handing the
  pre-built rig to the rig task via RigTaskConfig.prebuilt_rig
- Skip cpal capture when an SDR audio source is available; bridge the
  SdrPipeline PCM broadcast into pcm_tx so all decoder tasks are unchanged
- Add trx-backend-soapysdr optional dep and soapysdr feature to trx-server
- Add prebuilt_rig field to RigTaskConfig so rig_task skips the registry
  factory when a pre-built rig is supplied by main

Marks SDR-08 complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 22:27:15 +01:00
sjg dc3fd63a83 [test](trx-server): add SDR config validation unit tests
Adds 12 unit tests for ServerConfig::validate_sdr() covering: minimal
valid config, non-SDR skip, empty/missing args, zero sample_rate,
channel IF out-of-range (positive, negative, exactly at Nyquist), dual
stream_opus, tx_enabled with SDR backend, duplicate decoder, and
multiple simultaneous errors. Marks SDR-11 complete in SDR.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 22:12:27 +01:00
sjg 1be5b3d4c2 [feat](trx-backend-soapysdr): implement SoapySdrRig with AudioSource and DSP wiring
Replace the stub SoapySdrRig with a full implementation: wire up SdrPipeline
from dsp.rs, implement AudioSource::subscribe_pcm on the primary channel,
add gain control (manual/auto with fallback warning), and track primary
channel freq/mode so set_freq/set_mode update the live DSP pipeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 21:57:39 +01:00
sjg 1353e2a29b [test](trx-backend-soapysdr): add demodulator unit tests
Add 9 unit tests covering all demodulators in demod.rs: USB/LSB/Passthrough
real-part extraction, AM DC removal and varying-envelope, FM tone frequency
and silence, CW peak normalisation, mode mapping, and empty-input safety.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 21:51:48 +01:00
sjg 5090ab71b3 [feat](trx-backend-soapysdr): implement IQ DSP pipeline (mixer/FIR/decimate/demod)
Add dsp.rs with IqSource trait abstraction, MockIqSource, windowed-sinc
FIR low-pass filter, ChannelDsp (mixer/decimate/demod/frame-accumulator),
and SdrPipeline which spawns a dedicated IQ read thread. No soapysdr crate
dependency; the real device will be wired in SDR-07.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 21:34:09 +01:00
sjg db6dff304e [feat](trx-backend-soapysdr): implement demodulators (USB/LSB/AM/FM/CW)
Add demod.rs with Demodulator enum and per-mode demodulate() implementations:
USB/Passthrough (real part), LSB (real part, IF negated upstream), AM
(envelope, DC removal, peak normalisation), FM/WFM (quadrature discriminator
scaled by 1/π), CW (magnitude envelope, peak normalised). Marks SDR-05 done.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 21:29:27 +01:00
sjg 04f8fd019a [docs](trx-rs): document SDR backend configuration options
Add [sdr], [sdr.gain], and [[sdr.channels]] sections to CONFIGURATION.md,
extend [rig.access] with type = "sdr" / args, add CLI override note, and
append a commented SoapySDR example block to trx-server.toml.example.
Mark SDR-09 as complete in SDR.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 21:24:41 +01:00