Commit Graph

378 Commits

Author SHA1 Message Date
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 47cff3f927 feat(multi-rig): auto-discover per-rig audio ports via GetRigs 2026-02-25 23:31:38 +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 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 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 2ee217a1a1 [feat](trx-backend-soapysdr): add crate scaffold with RigCat stub
Introduces the trx-backend-soapysdr crate with a compilable SoapySdrRig
struct that satisfies the Rig + RigCat trait bounds.  RX methods
(get_status, set_freq, set_mode, get_signal_strength) are implemented;
TX-only methods return RigError::not_supported.  as_audio_source returns
None for now (overridden in SDR-07).  Wires the crate into the workspace
and trx-backend (feature "soapysdr"), and fixes the non-exhaustive match
on RigAccess::Sdr in trx-server main.rs and rig_task.rs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 19:51:52 +01:00
sjg b00f054bd4 [feat](trx-server): add SdrConfig structs and SDR access config validation
Add SdrConfig, SdrGainConfig, and SdrChannelConfig structs to config.rs,
extend AccessConfig with an args field for the "sdr" access type, wire
SdrConfig into ServerConfig, and implement validate_sdr() with all
startup validation rules from SDR.md §11. Marks SDR-03 complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 19:16:27 +01:00
sjg bf19ffb38d [feat](trx-backend): add RigAccess::Sdr variant and soapysdr feature stub
Add `RigAccess::Sdr { args: String }` to the backend access enum, register
a feature-gated `soapysdr` factory stub in `register_builtin_backends_on`,
handle the new variant in all existing `match` arms, and add the `soapysdr`
feature flag (no dep yet; implementation lands in SDR-04). Mark SDR-02 done.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-02-24 19:07:00 +01:00
sjg b9005acffd [refactor](decoders): extract decoder logging into trx-decode-log crate
Move DecoderLoggers and DecodeLogsConfig out of trx-server into a
dedicated src/decoders/trx-decode-log crate, giving file logging the
same standalone crate treatment as the four decoder crates.

- src/decoders/trx-decode-log/ (new — DecodeLogsConfig + DecoderLoggers)
- trx-server/config.rs: re-exports DecodeLogsConfig from trx-decode-log
  so ServerConfig field references and all tests compile unchanged
- trx-server: drop decode_logs module, use trx_decode_log directly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 18:36:04 +01:00
sjg f4b92a0f20 [refactor](decoders): extract CW decoder into trx-cw crate
Move the Goertzel-based CW decoder out of trx-server::decode::cw into
a dedicated src/decoders/trx-cw crate, matching the layout of trx-aprs,
trx-ft8, and trx-wspr. The decode module is now empty and removed.

- src/decoders/trx-cw/ (new — Goertzel + Morse decoder)
- trx-server: drop decode module entirely, use trx_cw::CwDecoder
- CwEvent stays in trx-core (mirrors AprsPacket / Ft8Message / WsprMessage)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 18:33:02 +01:00
sjg 3ebd185a7e [refactor](decoders): consolidate decoder crates under src/decoders/
Move trx-ft8 and trx-wspr into src/decoders/ alongside a new trx-aprs
crate that extracts the Bell 202/AX.25 decoder from trx-server, giving
all three modems a consistent crate-per-decoder layout.

- src/decoders/trx-ft8/  (moved from src/trx-ft8/)
- src/decoders/trx-wspr/ (moved from src/trx-wspr/)
- src/decoders/trx-aprs/ (new — Bell 202 AFSK + AX.25/APRS decoder)
- trx-ft8/build.rs: fix external/ft8_lib relative path after move
- trx-server: drop decode::aprs module, use trx_aprs::AprsDecoder
- AprsPacket stays in trx-core (mirrors Ft8Message / WsprMessage)
- Workspace Cargo.toml updated with new member paths

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 18:30:04 +01:00
sjg 0d6a35a933 [feat](trx-server): add APRS-IS IGate uplink (aprs.fi integration)
Forwards CRC-valid RF APRS packets to APRS-IS via plain TCP using the
TNC2 line format, making them visible on aprs.fi and other APRS-IS
consumers. Mirrors the pskreporter module in structure.

- New aprsfi.rs: IGate task with reconnect loop (exponential backoff
  1s→60s), login/logresp, 60s keepalive, 60s stats, passcode
  auto-computation from callsign (standard APRS hash algorithm)
- config.rs: AprsFiConfig struct with enabled/host/port/passcode fields
  and validation; default host rotate.aprs.net:14580
- main.rs: mod aprsfi; spawn task inside audio block when aprsfi.enabled
- trx-server.toml.example, CONFIGURATION.md: document [aprsfi] section
- Remove APRSFI_IMPLEMENTATION.rs planning artifact

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 18:23:35 +01:00
sjg e12a3dfa4f [fix](trx-server): re-enumerate audio device on each stream recovery cycle
After ALSA POLLERR the existing cpal Device handle can be stale, causing
repeated stream build failures with no path to recovery. Re-acquire host
and device inside the outer recreation loop so each attempt gets a fresh
handle. Device-not-found is now a warn+retry rather than a fatal error,
allowing recovery from transient USB audio device disappearances.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 15:59:29 +01:00
sjg 1a282f5ec6 [fix](trx-server): prevent audio thread crash on ALSA EPIPE
CPAL error callbacks can fire millions of times per second on ALSA
EPIPE (errno -32). Previously each invocation did a string allocation
and mutex lock, saturating CPU and eventually crashing the server.

- Use atomic swap in both input and output error callbacks so only the
  first error fires the expensive log+notify path; all subsequent hits
  cost a single atomic op and return immediately.
- Replace stream.play()? with explicit error handling in run_playback
  so a play failure triggers stream recreation instead of permanently
  terminating the playback thread.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <stanislawgrams@gmail.com>
2026-02-23 13:24:55 +01:00
sjg 66baa73fa9 [test](trx-server): update port assertions for 4530/4531 defaults
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <stanislawgrams@gmail.com>
2026-02-23 12:39:49 +01:00
sjg 5dc2b923d1 [chore](trx-server): update default ports to 4530/4531
Change JSON TCP listener default from 4532 to 4530 and audio
streaming default from 4533 to 4531.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <stanislawgrams@gmail.com>
2026-02-23 12:12:04 +01:00
sjg 1d0db79ca3 [feat](trx-rs): show server/client build info in HTTP footer
Add compile-time build dates for trx-server and trx-frontend-http, propagate server build metadata through rig state/snapshot, and render both versions + build dates in the HTTP footer.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-13 11:06:13 +01:00
sjg 8a4e9f5ed3 [feat](trx-server): add optional per-decoder log files
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-13 10:43:52 +01:00
sjg 86ca1a60fb [fix](trx-rs): harden hamlib rigctl compatibility
Improve rigctl interoperability with hamlib/WSJT-X and stabilize FT-817 PTT handling.\n\n- support extended '+' command replies\n- accept decimal and MHz-style frequency inputs\n- retry set_freq rounded to 10 Hz on CAT alignment errors\n- add compatibility handling for get_level probes\n- broaden PTT command parsing and aliases\n- derive PTT capability dynamically from snapshot data\n- improve dump_state/dump_caps compatibility behavior\n- move temporary rigctl diagnostics to debug level\n- make FT-817 set_ptt more reliable with unlock/clear and double-send\n\nCo-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-13 01:30:04 +01:00
sjg 81890b15a8 [fix](trx-core): expose rig min tuning step and align UI tuning
Add min_freq_step_hz to RigCapabilities, set backend values, and make HTTP frontend parse suffix-less frequency input using the selected unit while snapping set/jog frequencies to rig step granularity.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-13 00:17:16 +01:00
sjg a7719bd7a9 [fix](trx-server): make ALSA stream recovery reliable
Signal backend stream callback failures directly to capture/playback loops and strengthen cross-thread failure flag visibility so recurring POLLERR conditions consistently trigger stream recreation.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-13 00:12:12 +01:00
sjg a1d56dc1d0 [fix](trx-server): make PSK Reporter activation diagnosable
Require a receiver locator source when PSK Reporter is enabled,
show inactive reason in status text, and add periodic uplink runtime
counters (received/sent/skipped/errors).

This makes missing-spot issues visible instead of silently dropping
all decode events.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-13 00:05:54 +01:00
sjg d085f96838 [fix](trx-server): auto-recover audio streams and harden frontend reconnect
Implement ALSA/CPAL stream auto-recovery by recreating input/output
streams after backend callback failures with bounded retry delay.

Also improve HTTP frontend resilience by polling /status on reconnect
and after SSE errors to refresh snapshot state after broken pipes.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 23:59:39 +01:00
sjg 273283708e [fix](trx-server): preserve PSK Reporter status in snapshots
Pass pskreporter_status through RigTaskConfig and apply it to rig_task
state initialization so snapshot updates keep the About-tab value.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 23:50:41 +01:00
sjg e243f0e4cc [fix](trx-server): include legacy home config path and coords in print-config
Fix server config discovery to include ~/.trx-server.toml and update
example/print-config output to explicitly include general latitude and
longitude fields.

Also update config docs and add a test for the legacy search path.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 23:47:36 +01:00
sjg 28dab2d00f [feat](trx-server): expose PSK Reporter status in About
Add pskreporter_status to shared rig snapshots and display it in the
HTTP frontend About tab.

Also include audio stream error log throttling to avoid repetitive ALSA
error flooding in backend logs.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 23:37:15 +01:00
sjg db792cc9d8 [feat](trx-server): add PSK Reporter uplink for FT8/WSPR
Add a PSK Reporter uploader task that subscribes to decoded FT8/WSPR
messages and sends spots over UDP when [pskreporter].enabled is true.

Include new [pskreporter] server config options and example config docs,
and hardcode software identification as 'trx-server v<version> by SP2SJG'.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 23:31:04 +01:00
sjg 091810c6cb [feat](trx-server): integrate wsprd-based WSPR decoding
Add a new trx-wspr crate that wraps wsprd slot decoding and parsed
results, wire it into the server audio pipeline, and emit WSPR decode
events to clients.

Also add frontend event routing for WSPR decode messages and temporary
rendering in the FT8 table until a dedicated WSPR panel is introduced.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 22:47:37 +01:00
sjg 63ba6882cd [feat](trx-core): add WSPR decode plumbing across stack
Introduce WSPR command/state/protocol/transport wiring and integrate lifecycle, history, and frontend API paths mirroring the FT8 architecture.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 22:38:05 +01:00
sjg 4b34a39745 [refactor](workspace): complete remaining architecture phases
Bundle all pending repository updates, including plugin context de-globalization, runtime hardening, config validation, boundary tests, and supporting docs/scripts.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 22:27:36 +01:00
sjg 144afbae8e [fix](trx-server): validate config semantics at startup
Add semantic validate() checks for server/client config models and fail fast on invalid ranges, field combinations, and auth token values before runtime startup.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 22:05:54 +01:00
sjg 3cc36d9c24 [fix](trx-client): harden json tcp parsing and io limits
Add typed remote endpoint parsing (including bracketed IPv6), bounded JSON line reads, and read/write/request timeouts across client/server JSON-TCP paths.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 21:57:24 +01:00
sjg cadb60f99d [refactor](trx-server): supervise runtime tasks and shutdown
Add coordinated shutdown signaling and task supervision for long-running server and client tasks to avoid detached runtimes on Ctrl+C.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 21:49:39 +01:00
sjg 0aa2fcbbbb [refactor](trx-protocol): move transport dto out of core
Phase 5: relocate ClientCommand/Envelope/Response into trx-protocol and update call sites so trx-core remains domain-focused.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 21:19:42 +01:00
sjg 0d8314cab6 [refactor](trx-rs): adopt shared app infra modules
Phase 4: route config loading and plugin discovery through trx-app, remove duplicated local plugin loaders, and align binary dependencies.

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 21:19:03 +01:00
sjg b7fb9adef7 [refactor](trx-rs): inject runtime contexts for io paths
Phase 3: replace frontend/backend hot-path globals with explicit runtime/registration context wiring while keeping plugin compatibility adapters.

Co-authored-by: Codex <codex@openai.com>,
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 21:18:42 +01:00
sjg d7f5dc83f8 [refactor](trx-backend): implement plugin compatibility adapter shim
Replace legacy global BackendRegistry with bootstrap context adapter that
maintains backward compatibility while delegating to explicit context.

Changes:
- Create BOOTSTRAP_CONTEXT: OnceLock<Arc<Mutex<RegistrationContext>>>
- register_backend(): delegates to bootstrap context
- is_backend_registered(): reads from bootstrap context
- registered_backends(): reads from bootstrap context
- build_rig(): reads from bootstrap context

Result: Plugins continue calling global functions, but all operations
now route through the bootstrap context instead of a separate global
registry. This completes the de-globalization while maintaining full
backward compatibility with existing plugins.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 20:56:11 +01:00
sjg 0a8a98ea54 [feat](trx-backend): add register_builtin_backends_on for context initialization
Add register_builtin_backends_on(context: &mut RegistrationContext) function
to allow explicit backend registration on a context instead of always using globals.

This enables proper initialization sequencing where backends are registered
on a specific context that can be passed through bootstrap.

The global register_builtin_backends() still works for plugin compatibility,
delegating to the new context-based approach.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 20:49:37 +01:00
sjg ef6d45b878 [feat](trx-backend): add RegistrationContext for explicit initialization
Create explicit RegistrationContext type for backend factory registration
instead of relying solely on global mutable state.

New RegistrationContext:
- register_backend(name, factory) - register a backend
- is_backend_registered(name) - check if registered
- registered_backends() -> Vec<String> - list all backends
- build_rig(name, access) -> DynResult - instantiate a rig

Maintains global API for plugin compatibility, delegates to context.
Paves way for threading context through bootstrap in Phase 3B.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 20:47:19 +01:00
sjg 5d83fba8f5 [refactor](trx-server): use trx-app for shared infrastructure
Replace server's local implementations with unified trx-app utilities.

Changes:
- Use trx_app::normalize_name() instead of local fn
- Depend on trx-app crate

This eliminates the server's copy of the normalize_name logic and ensures
both server and client use the same implementation.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 20:39:20 +01:00
sjg ab53d3ae3b [refactor](trx-server): use RigState constructors and fix config bug
Replace duplicated RigState initialization with new constructor methods.
This fixes a critical bug where rig_task was hardcoding 144.3 MHz/USB
instead of respecting config.initial_freq_hz and config.initial_mode.

Changes:
- Use RigState::new_with_metadata() in main.rs
- Use RigState::new_with_metadata() in rig_task.rs (FIX: now respects config)
- Remove 45-line build_initial_state() helper function

The rig_task bug fix ensures the configured initial frequency and mode
are applied when the rig task starts, instead of always using defaults.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 20:37:12 +01:00
sjg 8718a5d8d1 [refactor](trx-server): consolidate protocol logic with trx-protocol
Use centralized trx-protocol crate for:
- parse_mode and mode string parsing
- parse_envelope with fallback behavior
- command mapping (ClientCommand -> RigCommand)
- token validation with SimpleTokenValidator

Removes 116 lines of duplicate code. Wraps validator in Arc for
safe sharing across async tasks. No behavior changes, all tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-12 20:27:42 +01:00
sjg 2dfe4a30dc [feat](trx-backend): add ft450d cat backend
Co-authored-by: OpenAI <assistant@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-09 23:53:16 +01:00
sjg 995ddd7306 [fix](trx-ft8): align decode result layout
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
2026-02-09 21:41:08 +01:00