[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>
This commit is contained in:
2026-02-12 22:27:36 +01:00
parent 144afbae8e
commit 4b34a39745
27 changed files with 684 additions and 210 deletions
+46 -12
View File
@@ -38,15 +38,51 @@ impl DummyRig {
revision: "1.0".to_string(),
capabilities: RigCapabilities {
supported_bands: vec![
Band { low_hz: 1_800_000, high_hz: 2_000_000, tx_allowed: true },
Band { low_hz: 3_500_000, high_hz: 4_000_000, tx_allowed: true },
Band { low_hz: 7_000_000, high_hz: 7_300_000, tx_allowed: true },
Band { low_hz: 14_000_000, high_hz: 14_350_000, tx_allowed: true },
Band { low_hz: 21_000_000, high_hz: 21_450_000, tx_allowed: true },
Band { low_hz: 28_000_000, high_hz: 29_700_000, tx_allowed: true },
Band { low_hz: 50_000_000, high_hz: 54_000_000, tx_allowed: true },
Band { low_hz: 144_000_000, high_hz: 148_000_000, tx_allowed: true },
Band { low_hz: 430_000_000, high_hz: 440_000_000, tx_allowed: true },
Band {
low_hz: 1_800_000,
high_hz: 2_000_000,
tx_allowed: true,
},
Band {
low_hz: 3_500_000,
high_hz: 4_000_000,
tx_allowed: true,
},
Band {
low_hz: 7_000_000,
high_hz: 7_300_000,
tx_allowed: true,
},
Band {
low_hz: 14_000_000,
high_hz: 14_350_000,
tx_allowed: true,
},
Band {
low_hz: 21_000_000,
high_hz: 21_450_000,
tx_allowed: true,
},
Band {
low_hz: 28_000_000,
high_hz: 29_700_000,
tx_allowed: true,
},
Band {
low_hz: 50_000_000,
high_hz: 54_000_000,
tx_allowed: true,
},
Band {
low_hz: 144_000_000,
high_hz: 148_000_000,
tx_allowed: true,
},
Band {
low_hz: 430_000_000,
high_hz: 440_000_000,
tx_allowed: true,
},
],
supported_modes: vec![
RigMode::LSB,
@@ -112,9 +148,7 @@ impl Rig for DummyRig {
impl RigCat for DummyRig {
fn get_status<'a>(&'a mut self) -> RigStatusFuture<'a> {
Box::pin(async move {
Ok((self.freq, self.mode.clone(), Some(self.build_vfo())))
})
Box::pin(async move { Ok((self.freq, self.mode.clone(), Some(self.build_vfo()))) })
}
fn set_freq<'a>(
+2 -54
View File
@@ -3,17 +3,16 @@
// SPDX-License-Identifier: BSD-2-Clause
use std::collections::HashMap;
use std::sync::{Arc, Mutex, OnceLock};
use trx_core::rig::RigCat;
use trx_core::DynResult;
mod dummy;
#[cfg(feature = "ft817")]
use trx_backend_ft817::Ft817;
#[cfg(feature = "ft450d")]
use trx_backend_ft450d::Ft450d;
#[cfg(feature = "ft817")]
use trx_backend_ft817::Ft817;
/// Connection details for instantiating a rig backend.
#[derive(Debug, Clone)]
@@ -88,27 +87,6 @@ fn normalize_name(name: &str) -> String {
.collect()
}
/// Phase 3D: Plugin compatibility adapter - delegates to bootstrap context.
fn bootstrap_context() -> &'static Arc<Mutex<RegistrationContext>> {
static BOOTSTRAP_CONTEXT: OnceLock<Arc<Mutex<RegistrationContext>>> = OnceLock::new();
BOOTSTRAP_CONTEXT.get_or_init(|| Arc::new(Mutex::new(RegistrationContext::new())))
}
/// Snapshot current plugin/bootstrap registrations into an owned context.
pub fn snapshot_bootstrap_context() -> RegistrationContext {
let ctx = bootstrap_context()
.lock()
.expect("backend context mutex poisoned");
ctx.clone()
}
/// Register a backend factory under a stable name (e.g. "ft817").
/// Plugin compatibility: delegates to bootstrap context.
pub fn register_backend(name: &str, factory: BackendFactory) {
let mut ctx = bootstrap_context().lock().expect("backend context mutex poisoned");
ctx.register_backend(name, factory);
}
/// Register all built-in backends enabled by features on a context.
pub fn register_builtin_backends_on(context: &mut RegistrationContext) {
context.register_backend("dummy", dummy_factory);
@@ -118,40 +96,10 @@ pub fn register_builtin_backends_on(context: &mut RegistrationContext) {
context.register_backend("ft450d", ft450d_factory);
}
/// Register all built-in backends enabled by features (global, for plugin compatibility).
pub fn register_builtin_backends() {
register_backend("dummy", dummy_factory);
#[cfg(feature = "ft817")]
register_backend("ft817", ft817_factory);
#[cfg(feature = "ft450d")]
register_backend("ft450d", ft450d_factory);
}
fn dummy_factory(_access: RigAccess) -> DynResult<Box<dyn RigCat>> {
Ok(Box::new(dummy::DummyRig::new()))
}
/// Check whether a backend name is registered.
/// Plugin compatibility: reads from bootstrap context.
pub fn is_backend_registered(name: &str) -> bool {
let ctx = bootstrap_context().lock().expect("backend context mutex poisoned");
ctx.is_backend_registered(name)
}
/// List registered backend names.
/// Plugin compatibility: reads from bootstrap context.
pub fn registered_backends() -> Vec<String> {
let ctx = bootstrap_context().lock().expect("backend context mutex poisoned");
ctx.registered_backends()
}
/// Instantiate a rig backend based on the selected name and access method.
/// Plugin compatibility: reads from bootstrap context.
pub fn build_rig(name: &str, access: RigAccess) -> DynResult<Box<dyn RigCat>> {
let ctx = bootstrap_context().lock().expect("backend context mutex poisoned");
ctx.build_rig(name, access)
}
#[cfg(feature = "ft817")]
fn ft817_factory(access: RigAccess) -> DynResult<Box<dyn RigCat>> {
match access {
@@ -325,7 +325,9 @@ impl Ft450d {
async fn read_freq(&mut self) -> DynResult<u64> {
let resp = self.query("FA;").await?;
let data = resp.strip_prefix("FA").ok_or("CAT freq response missing FA")?;
let data = resp
.strip_prefix("FA")
.ok_or("CAT freq response missing FA")?;
let digits: String = data.chars().filter(|c| c.is_ascii_digit()).collect();
let freq: u64 = digits.parse().map_err(|_| "CAT freq parse failed")?;
Ok(freq)
@@ -333,7 +335,9 @@ impl Ft450d {
async fn read_mode(&mut self) -> DynResult<RigMode> {
let resp = self.query("MD0;").await?;
let data = resp.strip_prefix("MD").ok_or("CAT mode response missing MD")?;
let data = resp
.strip_prefix("MD")
.ok_or("CAT mode response missing MD")?;
let code = data.chars().last().ok_or("CAT mode parse failed")?;
Ok(decode_mode(code))
}