[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>
This commit is contained in:
2026-02-25 20:24:43 +01:00
parent 80afb928ae
commit 9177206dd9
6 changed files with 69 additions and 2 deletions
+1 -1
View File
@@ -14,4 +14,4 @@ pub use rig::AudioSource;
pub use rig::command::RigCommand;
pub use rig::request::RigRequest;
pub use rig::response::{RigError, RigResult};
pub use rig::state::{RigMode, RigSnapshot, RigState};
pub use rig::state::{RigFilterState, RigMode, RigSnapshot, RigState};
+2
View File
@@ -30,4 +30,6 @@ pub enum RigCommand {
ResetCwDecoder,
ResetFt8Decoder,
ResetWsprDecoder,
SetBandwidth(u32),
SetFirTaps(u32),
}
+13 -1
View File
@@ -512,7 +512,9 @@ pub fn command_from_rig_command(cmd: RigCommand) -> Box<dyn RigCommandHandler> {
| RigCommand::ResetAprsDecoder
| RigCommand::ResetCwDecoder
| RigCommand::ResetFt8Decoder
| RigCommand::ResetWsprDecoder => Box::new(GetSnapshotCommand),
| RigCommand::ResetWsprDecoder
| RigCommand::SetBandwidth(_)
| RigCommand::SetFirTaps(_) => Box::new(GetSnapshotCommand),
}
}
@@ -553,6 +555,11 @@ mod tests {
rit: false,
rpt: false,
split: false,
tx: true,
tx_limit: true,
vfo_switch: true,
filter_controls: false,
signal_meter: true,
},
access: RigAccessMethod::Serial {
path: "/dev/test".to_string(),
@@ -607,6 +614,11 @@ mod tests {
rit: false,
rpt: false,
split: false,
tx: true,
tx_limit: true,
vfo_switch: true,
filter_controls: false,
signal_meter: true,
},
access: RigAccessMethod::Serial {
path: "/dev/test".to_string(),
@@ -450,6 +450,11 @@ mod tests {
rit: false,
rpt: false,
split: false,
tx: true,
tx_limit: true,
vfo_switch: true,
filter_controls: false,
signal_meter: true,
},
access: RigAccessMethod::Serial {
path: "/dev/test".to_string(),
+31
View File
@@ -51,6 +51,16 @@ pub struct RigCapabilities {
pub rit: bool,
pub rpt: bool,
pub split: bool,
/// Backend supports transmit: PTT, power on/off, TX meters, TX audio.
pub tx: bool,
/// Backend supports get_tx_limit / set_tx_limit.
pub tx_limit: bool,
/// Backend supports toggle_vfo.
pub vfo_switch: bool,
/// Backend supports runtime filter adjustment (bandwidth, FIR taps).
pub filter_controls: bool,
/// Backend returns a meaningful RX signal strength value.
pub signal_meter: bool,
}
fn default_min_freq_step_hz() -> u64 {
@@ -112,6 +122,27 @@ pub trait RigCat: Rig + Send {
fn unlock<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = DynResult<()>> + Send + 'a>>;
fn as_audio_source(&self) -> Option<&dyn AudioSource> { None }
fn set_bandwidth<'a>(
&'a mut self,
_bandwidth_hz: u32,
) -> Pin<Box<dyn Future<Output = DynResult<()>> + Send + 'a>> {
Box::pin(std::future::ready(Err(Box::new(
response::RigError::not_supported("set_bandwidth"),
) as Box<dyn std::error::Error + Send + Sync>)))
}
fn set_fir_taps<'a>(
&'a mut self,
_taps: u32,
) -> Pin<Box<dyn Future<Output = DynResult<()>> + Send + 'a>> {
Box::pin(std::future::ready(Err(Box::new(
response::RigError::not_supported("set_fir_taps"),
) as Box<dyn std::error::Error + Send + Sync>)))
}
/// Return the current filter state if this backend supports filter controls.
fn filter_state(&self) -> Option<state::RigFilterState> { None }
}
/// Snapshot of a rig's status that every backend can expose.
+17
View File
@@ -42,6 +42,10 @@ pub struct RigState {
pub cw_wpm: u32,
#[serde(default)]
pub cw_tone_hz: u32,
/// Filter state for backends that support runtime filter adjustment.
/// Skipped in serde; flows into RigSnapshot via snapshot().
#[serde(skip)]
pub filter: Option<RigFilterState>,
#[serde(default, skip_serializing)]
pub aprs_decode_reset_seq: u64,
#[serde(default, skip_serializing)]
@@ -127,6 +131,7 @@ impl RigState {
cw_auto: true,
cw_wpm: 15,
cw_tone_hz: 700,
filter: None,
aprs_decode_reset_seq: 0,
cw_decode_reset_seq: 0,
ft8_decode_reset_seq: 0,
@@ -186,6 +191,7 @@ impl RigState {
cw_tone_hz: snapshot.cw_tone_hz,
ft8_decode_enabled: snapshot.ft8_decode_enabled,
wspr_decode_enabled: snapshot.wspr_decode_enabled,
filter: snapshot.filter,
aprs_decode_reset_seq: 0,
cw_decode_reset_seq: 0,
ft8_decode_reset_seq: 0,
@@ -223,6 +229,7 @@ impl RigState {
cw_tone_hz: self.cw_tone_hz,
ft8_decode_enabled: self.ft8_decode_enabled,
wspr_decode_enabled: self.wspr_decode_enabled,
filter: self.filter.clone(),
})
}
@@ -249,6 +256,14 @@ impl RigState {
}
}
/// Current filter/DSP state for backends that support runtime filter adjustment.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RigFilterState {
pub bandwidth_hz: u32,
pub fir_taps: u32,
pub cw_center_hz: u32,
}
/// Read-only projection of state shared with clients.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RigSnapshot {
@@ -283,4 +298,6 @@ pub struct RigSnapshot {
pub cw_wpm: u32,
#[serde(default)]
pub cw_tone_hz: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub filter: Option<RigFilterState>,
}