[feat](trx-rs): receive SSTV pictures end to end
CI / lint (pull_request) Successful in 2m16s
CI / frontend (pull_request) Successful in 4m12s
CI / reuse (pull_request) Successful in 2s
CI / lint (push) Successful in 2m15s
CI / test (pull_request) Successful in 9m37s
CI / test (push) Successful in 7m36s
CI / frontend (push) Failing after 31s
CI / reuse (push) Successful in 3s

Wires the SSTV decoder into the stack, from the audio the server already
has to a panel in the browser that shows the picture arriving.

Server: a decoder task alongside the WEFAX one, running whenever the
decoder is enabled and the rig is in a mode SSTV is sent in.  A finished
picture is written to the cache as a PNG and sent on as a message; the
rows are sent as they decode, so a client can watch two minutes of
Martin M1 fill in rather than waiting for it.  Pictures join the decode
history, are replayed to a client that connects later, and survive a
restart.

Protocol: SetSstvDecodeEnabled and ResetSstvDecoder, a sstv_decode
_enabled flag in the rig state, two audio message types, and Sstv and
SstvProgress on DecodedMessage.  The history stores the message without
its base64 payload -- the picture is already on disk, and a megabyte per
entry is not what a history is for.

Client: pictures land in their own history, and the PNG the server sent
is written to the local cache so /sstv-images/ can serve it back.  That
endpoint and the WEFAX one now share their filename checks rather than
each carrying a copy: no separators, no parent references, .png only.

Web UI: an SSTV sub-tab beside WEFAX, with a live canvas the rows paint
into at the line number they carry, a card for the last picture, and a
filterable history with links to the files.  Rows below the one arriving
are grey rather than black -- not yet received is a different thing from
received as black.  A picture is not a spot, so neither pictures nor
their progress updates reach the decode statistics; that exclusion list
had grown by hand for LRPT and WEFAX and is now one named set.

The decoder crate gains what the server needed to hand a picture on:
to_png, to_png_base64 and save_png, with file names stamped in UTC so
they sort.

Panel behaviour is tested with the plugin runtime: rows painting at
their own line numbers rather than in arrival order, a completed picture
linked by file name alone with no server path in the page, a cut-off
picture reported as partial, clearing, and the toggle following the rig
state.

Signed-off-by: Stan Grams <sjg@haxx.space>
This commit was merged in pull request #44.
This commit is contained in:
sjg
2026-08-06 00:14:59 +02:00
parent a0b0c0ed81
commit 18107ce07e
36 changed files with 1517 additions and 38 deletions
+10
View File
@@ -139,6 +139,16 @@ pub const DECODER_REGISTRY: &[DecoderDescriptor] = &[
background_decode: false,
bookmark_selectable: true,
},
DecoderDescriptor {
id: "sstv",
label: "SSTV",
activation: DecoderActivation::Toggle,
// SSTV is sent on sideband on HF and on FM simplex on VHF, and the
// decoder cares only about the audio it is handed.
active_modes: &["USB", "LSB", "FM", "AM", "DIG"],
background_decode: false,
bookmark_selectable: true,
},
];
// ============================================================================
+3 -1
View File
@@ -122,7 +122,8 @@ define_command_mapping! {
ResetFt2Decoder <=> ResetFt2Decoder,
ResetWsprDecoder <=> ResetWsprDecoder,
ResetLrptDecoder <=> ResetLrptDecoder,
ResetWefaxDecoder <=> ResetWefaxDecoder;
ResetWefaxDecoder <=> ResetWefaxDecoder,
ResetSstvDecoder <=> ResetSstvDecoder;
// ── Single-field struct <=> tuple ────────────────────────────────
field:
@@ -140,6 +141,7 @@ define_command_mapping! {
SetWsprDecodeEnabled { enabled } <=> SetWsprDecodeEnabled,
SetLrptDecodeEnabled { enabled } <=> SetLrptDecodeEnabled,
SetWefaxDecodeEnabled { enabled } <=> SetWefaxDecodeEnabled,
SetSstvDecodeEnabled { enabled } <=> SetSstvDecodeEnabled,
SetBandwidth { bandwidth_hz } <=> SetBandwidth,
SetSdrGain { gain_db } <=> SetSdrGain,
SetSdrLnaGain { gain_db } <=> SetSdrLnaGain,
+4
View File
@@ -73,6 +73,9 @@ pub enum ClientCommand {
SetWefaxDecodeEnabled {
enabled: bool,
},
SetSstvDecodeEnabled {
enabled: bool,
},
ResetAprsDecoder,
ResetHfAprsDecoder,
ResetCwDecoder,
@@ -82,6 +85,7 @@ pub enum ClientCommand {
ResetWsprDecoder,
ResetLrptDecoder,
ResetWefaxDecoder,
ResetSstvDecoder,
SetBandwidth {
bandwidth_hz: u32,
},