diff --git a/src/decoders/trx-aprs/src/lib.rs b/src/decoders/trx-aprs/src/lib.rs index 7cad161..03f7003 100644 --- a/src/decoders/trx-aprs/src/lib.rs +++ b/src/decoders/trx-aprs/src/lib.rs @@ -416,6 +416,7 @@ fn parse_aprs(ax25: &Ax25Frame) -> AprsPacket { } AprsPacket { + ts_ms: None, src_call, dest_call, path, diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js index 77dcaba..999eec0 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js @@ -4,6 +4,7 @@ const aprsPacketsEl = document.getElementById("aprs-packets"); const aprsFilterInput = document.getElementById("aprs-filter"); const aprsBarOverlay = document.getElementById("aprs-bar-overlay"); const APRS_MAX_PACKETS = 100; +const APRS_BAR_WINDOW_MS = 60 * 60 * 1000; let aprsFilterText = ""; let aprsPacketHistory = []; @@ -105,7 +106,8 @@ function applyAprsFilterToAll() { function updateAprsBar() { if (!aprsBarOverlay) return; const isPkt = (document.getElementById("mode")?.value || "").toUpperCase() === "PKT"; - const okFrames = aprsPacketHistory.filter((p) => p.crcOk); + const cutoffMs = Date.now() - APRS_BAR_WINDOW_MS; + const okFrames = aprsPacketHistory.filter((p) => p.crcOk && p._tsMs >= cutoffMs); if (!isPkt || okFrames.length === 0) { aprsBarOverlay.style.display = "none"; return; @@ -143,8 +145,9 @@ function addAprsPacket(pkt) { console.log(tag, `${pkt.srcCall}>${pkt.destCall}${pkt.path ? "," + pkt.path : ""}: ${pkt.info}`, pkt); // Stamp timestamp for persistence - pkt._ts = new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }); - pkt._tsMs = Date.now(); + const tsMs = Number.isFinite(pkt.ts_ms) ? Number(pkt.ts_ms) : Date.now(); + pkt._tsMs = tsMs; + pkt._ts = new Date(tsMs).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }); aprsPacketHistory.unshift(pkt); if (aprsPacketHistory.length > APRS_MAX_PACKETS) aprsPacketHistory.length = APRS_MAX_PACKETS; diff --git a/src/trx-client/trx-frontend/trx-frontend-http/src/audio.rs b/src/trx-client/trx-frontend/trx-frontend-http/src/audio.rs index 93e490d..e5c2743 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/src/audio.rs +++ b/src/trx-client/trx-frontend/trx-frontend-http/src/audio.rs @@ -12,7 +12,7 @@ use std::collections::VecDeque; use std::sync::atomic::Ordering; use std::sync::Arc; -use std::time::{Duration, Instant}; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use actix_web::{get, web, Error, HttpRequest, HttpResponse}; use actix_ws::Message; @@ -103,7 +103,14 @@ pub fn snapshot_aprs_history(context: &FrontendRuntimeContext) -> Vec Vec { @@ -141,6 +148,17 @@ pub fn clear_aprs_history(context: &FrontendRuntimeContext) { history.clear(); } +fn timestamp_ms_for_elapsed(elapsed: Duration) -> i64 { + let wall_clock = SystemTime::now() + .checked_sub(elapsed) + .unwrap_or(UNIX_EPOCH); + let millis = wall_clock + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis(); + i64::try_from(millis).unwrap_or(i64::MAX) +} + pub fn clear_cw_history(context: &FrontendRuntimeContext) { let mut history = context .cw_history diff --git a/src/trx-core/src/decode.rs b/src/trx-core/src/decode.rs index 30caa64..088af1e 100644 --- a/src/trx-core/src/decode.rs +++ b/src/trx-core/src/decode.rs @@ -22,6 +22,8 @@ pub enum DecodedMessage { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AprsPacket { + #[serde(skip_serializing_if = "Option::is_none")] + pub ts_ms: Option, pub src_call: String, pub dest_call: String, pub path: String, diff --git a/src/trx-server/src/aprsfi.rs b/src/trx-server/src/aprsfi.rs index 2dac952..5bd234d 100644 --- a/src/trx-server/src/aprsfi.rs +++ b/src/trx-server/src/aprsfi.rs @@ -250,6 +250,7 @@ mod tests { fn make_pkt(src: &str, dest: &str, path: &str, info: &str, crc_ok: bool) -> AprsPacket { AprsPacket { + ts_ms: None, src_call: src.to_string(), dest_call: dest.to_string(), path: path.to_string(),