[fix](trx-rs): fix LRPT pass detection status never updating during active decoding

The #sat-status element was stuck on "Waiting for satellite pass" because:

1. The client audio handler (audio_client.rs) did not include AUDIO_MSG_LRPT_IMAGE
   in its message type match, so LRPT image messages from the server were silently
   dropped and never reached the frontend.

2. No progress was reported during active LRPT decoding — the only status update
   happened when a complete image was finalized, which could take the entire pass.

3. The sat-status text was never updated when the decoder was enabled/disabled,
   leaving it permanently at the HTML default text.

Changes:
- Add DecodedMessage::LrptProgress variant for live MCU progress reporting
- Send LRPT progress updates from the decoder task when new MCUs are decoded
- Add AUDIO_MSG_LRPT_IMAGE and AUDIO_MSG_LRPT_PROGRESS to client audio handler
- Update sat-status text when decoder state changes (enabled/disabled)
- Handle lrpt_progress messages in the frontend to show "Receiving — N MCU rows"

https://claude.ai/code/session_017knbD7dr6hJGAWR6pModL7
Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
Claude
2026-03-31 14:17:56 +00:00
committed by Stan Grams
parent f2469fee12
commit 1fe0b75e20
8 changed files with 50 additions and 7 deletions
+5 -3
View File
@@ -29,8 +29,8 @@ use trx_core::audio::{
AUDIO_MSG_HF_APRS_DECODE, AUDIO_MSG_HISTORY_COMPRESSED, AUDIO_MSG_RX_FRAME,
AUDIO_MSG_RX_FRAME_CH, AUDIO_MSG_STREAM_INFO, AUDIO_MSG_TX_FRAME, AUDIO_MSG_VCHAN_ALLOCATED,
AUDIO_MSG_VCHAN_BW, AUDIO_MSG_VCHAN_DESTROYED, AUDIO_MSG_VCHAN_FREQ, AUDIO_MSG_VCHAN_MODE,
AUDIO_MSG_VCHAN_REMOVE, AUDIO_MSG_VCHAN_SUB, AUDIO_MSG_VCHAN_UNSUB, AUDIO_MSG_VDES_DECODE,
AUDIO_MSG_WSPR_DECODE,
AUDIO_MSG_LRPT_IMAGE, AUDIO_MSG_LRPT_PROGRESS, AUDIO_MSG_VCHAN_REMOVE, AUDIO_MSG_VCHAN_SUB,
AUDIO_MSG_VCHAN_UNSUB, AUDIO_MSG_VDES_DECODE, AUDIO_MSG_WSPR_DECODE,
};
use trx_core::decode::DecodedMessage;
use trx_frontend::VChanAudioCmd;
@@ -567,7 +567,9 @@ async fn handle_single_rig_connection(
| AUDIO_MSG_FT8_DECODE
| AUDIO_MSG_FT4_DECODE
| AUDIO_MSG_FT2_DECODE
| AUDIO_MSG_WSPR_DECODE,
| AUDIO_MSG_WSPR_DECODE
| AUDIO_MSG_LRPT_IMAGE
| AUDIO_MSG_LRPT_PROGRESS,
payload,
)) => {
if let Ok(mut msg) = serde_json::from_slice::<DecodedMessage>(&payload) {
+1
View File
@@ -523,6 +523,7 @@ async fn async_init() -> DynResult<AppState> {
}
}
DecodedMessage::LrptImage(_) => {}
DecodedMessage::LrptProgress(_) => {}
}
});
@@ -9134,7 +9134,8 @@ function dispatchDecodeMessage(msg, skipStats) {
if (msg.type === "ft2" && window.onServerFt2) window.onServerFt2(msg);
if (msg.type === "wspr" && window.onServerWspr) window.onServerWspr(msg);
if (msg.type === "lrpt_image" && window.onServerLrptImage) window.onServerLrptImage(msg);
if (!skipStats && msg.type && msg.type !== "lrpt_image") {
if (msg.type === "lrpt_progress" && window.onServerLrptProgress) window.onServerLrptProgress(msg);
if (!skipStats && msg.type && msg.type !== "lrpt_image" && msg.type !== "lrpt_progress") {
statsRecordDecode(msg.type, msg.rig_id || msg.remote || null);
scheduleStatsRender();
}
@@ -9144,7 +9145,7 @@ function dispatchDecodeBatch(batch) {
if (!Array.isArray(batch) || batch.length === 0) return;
// Record statistics for every message in the batch regardless of dispatch path.
for (const msg of batch) {
if (msg.type && msg.type !== "lrpt_image") {
if (msg.type && msg.type !== "lrpt_image" && msg.type !== "lrpt_progress") {
statsRecordDecode(msg.type, msg.rig_id || msg.remote || null);
}
}
@@ -9231,7 +9232,7 @@ function loadDecodeHistoryOnMainThread(onReady, onError) {
function restoreDecodeHistoryGroup(kind, messages) {
if (!Array.isArray(messages) || messages.length === 0) return;
// Record statistics for restored history messages.
if (kind !== "lrpt_image") {
if (kind !== "lrpt_image" && kind !== "lrpt_progress") {
for (const msg of messages) {
statsRecordDecode(kind, msg.rig_id || msg.remote || null, msg.ts_ms || undefined);
}
@@ -91,6 +91,13 @@ window.updateSatLiveState = function (update) {
_lastSatLrptOn = lrptOn;
satDom.lrptState.textContent = lrptOn ? "Listening" : "Idle";
satDom.lrptState.className = "sat-live-value " + (lrptOn ? "sat-state-listening" : "sat-state-idle");
if (satDom.status) {
if (lrptOn) {
satDom.status.textContent = "Decoder active \u2014 waiting for signal";
} else {
satDom.status.textContent = "Decoder idle";
}
}
}
};
@@ -233,6 +240,12 @@ function addSatImage(img, decoder) {
}
// ── Server callbacks ────────────────────────────────────────────────
window.onServerLrptProgress = function (msg) {
if (satDom.status && msg.mcu_count > 0) {
satDom.status.textContent = "Receiving \u2014 " + msg.mcu_count + " MCU rows decoded";
}
};
window.onServerLrptImage = function (msg) {
if (satDom.status) satDom.status.textContent = "Image received (Meteor LRPT)";
addSatImage(msg, "lrpt");
@@ -585,6 +585,7 @@ pub fn start_decode_history_collector(context: Arc<FrontendRuntimeContext>) {
DecodedMessage::Ft2(msg) => record_ft2(&context, msg),
DecodedMessage::Wspr(msg) => record_wspr(&context, msg),
DecodedMessage::LrptImage(_) => {}
DecodedMessage::LrptProgress(_) => {}
},
Err(broadcast::error::RecvError::Lagged(_)) => continue,
Err(broadcast::error::RecvError::Closed) => break,