[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>
This commit is contained in:
2026-02-13 00:05:54 +01:00
parent d085f96838
commit a1d56dc1d0
3 changed files with 58 additions and 5 deletions
+25
View File
@@ -296,6 +296,15 @@ impl ServerConfig {
if self.pskreporter.port == 0 {
return Err("[pskreporter].port must be > 0".to_string());
}
if self.pskreporter.receiver_locator.is_none()
&& (self.general.latitude.is_none() || self.general.longitude.is_none())
{
return Err(
"[pskreporter] enabled requires either [pskreporter].receiver_locator \
or [general].latitude and [general].longitude"
.to_string(),
);
}
}
Ok(())
@@ -560,6 +569,22 @@ tokens = ["secret123"]
assert!(config.validate().is_err());
}
#[test]
fn test_validate_pskreporter_requires_locator_source() {
let mut config = ServerConfig::default();
config.rig.access.port = Some("/dev/ttyUSB0".to_string());
config.rig.access.baud = Some(9600);
config.pskreporter.enabled = true;
config.pskreporter.receiver_locator = None;
config.general.latitude = None;
config.general.longitude = None;
assert!(config.validate().is_err());
config.general.latitude = Some(52.0);
config.general.longitude = Some(21.0);
assert!(config.validate().is_ok());
}
#[test]
fn test_default_search_paths_include_legacy_home_file() {
let paths = ServerConfig::default_search_paths();
+13 -4
View File
@@ -188,10 +188,19 @@ fn build_rig_task_config(
registry: std::sync::Arc<RegistrationContext>,
) -> rig_task::RigTaskConfig {
let pskreporter_status = if cfg.pskreporter.enabled {
Some(format!(
"Enabled ({}:{})",
cfg.pskreporter.host, cfg.pskreporter.port
))
let has_locator = cfg.pskreporter.receiver_locator.is_some()
|| (resolved.latitude.is_some() && resolved.longitude.is_some());
if has_locator {
Some(format!(
"Enabled ({}:{})",
cfg.pskreporter.host, cfg.pskreporter.port
))
} else {
Some(format!(
"Enabled but inactive (missing locator source) ({}:{})",
cfg.pskreporter.host, cfg.pskreporter.port
))
}
} else {
Some("Disabled".to_string())
};
+20 -1
View File
@@ -6,6 +6,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use tokio::net::UdpSocket;
use tokio::sync::{broadcast, watch};
use tokio::time::{self, Duration};
use tracing::{info, warn};
use trx_core::decode::DecodedMessage;
@@ -81,9 +82,20 @@ pub async fn run_pskreporter_uplink(
);
let mut current_freq_hz = state_rx.borrow().status.freq.hz;
let mut stats_received: u64 = 0;
let mut stats_sent: u64 = 0;
let mut stats_skipped: u64 = 0;
let mut stats_send_err: u64 = 0;
let mut stats_tick = time::interval(Duration::from_secs(60));
loop {
tokio::select! {
_ = stats_tick.tick() => {
info!(
"PSK Reporter stats: received={}, sent={}, skipped={}, send_errors={}",
stats_received, stats_sent, stats_skipped, stats_send_err
);
}
changed = state_rx.changed() => {
if changed.is_err() {
break;
@@ -99,13 +111,20 @@ pub async fn run_pskreporter_uplink(
}
Err(broadcast::error::RecvError::Closed) => break,
};
stats_received += 1;
let spot = match decoded_to_spot(decoded, current_freq_hz) {
Some(spot) => spot,
None => continue,
None => {
stats_skipped += 1;
continue;
}
};
if let Err(err) = client.send_spot(&spot).await {
warn!("PSK Reporter send failed: {}", err);
stats_send_err += 1;
} else {
stats_sent += 1;
}
}
}