From 1075ba03e71d5a2723be479568ded97e59506362 Mon Sep 17 00:00:00 2001 From: Smittix Date: Sat, 7 Feb 2026 11:44:35 +0000 Subject: [PATCH] Add VIS detector state to signal monitor for decode diagnostics Shows the current VIS detection state machine position (Idle, Leader, Break, Start bit, Data bits, etc.) in the signal monitor. This helps diagnose why decoding may not be starting - e.g. if the VIS detector is stuck in Idle despite a leader tone being present, the signal may not contain a valid VIS header. Co-Authored-By: Claude Opus 4.6 --- static/css/modes/sstv-general.css | 14 ++++++++++++++ static/css/modes/sstv.css | 14 ++++++++++++++ static/js/modes/sstv-general.js | 19 +++++++++++++++++++ static/js/modes/sstv.js | 19 +++++++++++++++++++ utils/sstv/sstv_decoder.py | 4 ++++ 5 files changed, 70 insertions(+) diff --git a/static/css/modes/sstv-general.css b/static/css/modes/sstv-general.css index 9ebad84..1bbec01 100644 --- a/static/css/modes/sstv-general.css +++ b/static/css/modes/sstv-general.css @@ -465,6 +465,20 @@ text-align: center; } +.sstv-general-signal-vis-state { + font-family: var(--font-mono); + font-size: 9px; + color: var(--text-dim); + text-align: center; + margin-top: 6px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.sstv-general-signal-vis-state.active { + color: var(--accent-cyan); +} + /* ============================================ IMAGE MODAL ============================================ */ diff --git a/static/css/modes/sstv.css b/static/css/modes/sstv.css index 588a25b..896a740 100644 --- a/static/css/modes/sstv.css +++ b/static/css/modes/sstv.css @@ -812,6 +812,20 @@ text-align: center; } +.sstv-signal-vis-state { + font-family: var(--font-mono); + font-size: 9px; + color: var(--text-dim); + text-align: center; + margin-top: 6px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.sstv-signal-vis-state.active { + color: var(--accent-cyan); +} + /* ============================================ IMAGE MODAL ============================================ */ diff --git a/static/js/modes/sstv-general.js b/static/js/modes/sstv-general.js index f023f0a..c0856e4 100644 --- a/static/js/modes/sstv-general.js +++ b/static/js/modes/sstv-general.js @@ -308,6 +308,7 @@ const SSTVGeneral = (function() { 0
No signal
+
VIS: idle
`; monitor = container.querySelector('.sstv-general-signal-monitor'); } @@ -317,6 +318,24 @@ const SSTVGeneral = (function() { fill.style.background = barColor; monitor.querySelector('.sstv-general-signal-status-text').textContent = statusText; monitor.querySelector('.sstv-general-signal-level-value').textContent = level; + + const visStateEl = monitor.querySelector('.sstv-general-signal-vis-state'); + if (visStateEl && data.vis_state) { + const stateLabels = { + 'idle': 'Idle', + 'leader_1': 'Leader', + 'break': 'Break', + 'leader_2': 'Leader 2', + 'start_bit': 'Start bit', + 'data_bits': 'Data bits', + 'parity': 'Parity', + 'stop_bit': 'Stop bit', + }; + const label = stateLabels[data.vis_state] || data.vis_state; + visStateEl.textContent = 'VIS: ' + label; + visStateEl.className = 'sstv-general-signal-vis-state' + + (data.vis_state !== 'idle' ? ' active' : ''); + } } /** diff --git a/static/js/modes/sstv.js b/static/js/modes/sstv.js index 2d02a24..227a7b6 100644 --- a/static/js/modes/sstv.js +++ b/static/js/modes/sstv.js @@ -743,6 +743,7 @@ const SSTV = (function() { 0
No signal
+
VIS: idle
`; monitor = container.querySelector('.sstv-signal-monitor'); } @@ -752,6 +753,24 @@ const SSTV = (function() { fill.style.background = barColor; monitor.querySelector('.sstv-signal-status-text').textContent = statusText; monitor.querySelector('.sstv-signal-level-value').textContent = level; + + const visStateEl = monitor.querySelector('.sstv-signal-vis-state'); + if (visStateEl && data.vis_state) { + const stateLabels = { + 'idle': 'Idle', + 'leader_1': 'Leader', + 'break': 'Break', + 'leader_2': 'Leader 2', + 'start_bit': 'Start bit', + 'data_bits': 'Data bits', + 'parity': 'Parity', + 'stop_bit': 'Stop bit', + }; + const label = stateLabels[data.vis_state] || data.vis_state; + visStateEl.textContent = 'VIS: ' + label; + visStateEl.className = 'sstv-signal-vis-state' + + (data.vis_state !== 'idle' ? ' active' : ''); + } } /** diff --git a/utils/sstv/sstv_decoder.py b/utils/sstv/sstv_decoder.py index 3035adc..f73c639 100644 --- a/utils/sstv/sstv_decoder.py +++ b/utils/sstv/sstv_decoder.py @@ -94,6 +94,7 @@ class DecodeProgress: image: SSTVImage | None = None signal_level: int | None = None # 0-100 RMS audio level, None = not measured sstv_tone: str | None = None # 'leader', 'sync', 'noise', None + vis_state: str | None = None # VIS detector state name def to_dict(self) -> dict: result: dict = { @@ -111,6 +112,8 @@ class DecodeProgress: result['signal_level'] = self.signal_level if self.sstv_tone: result['sstv_tone'] = self.sstv_tone + if self.vis_state: + result['vis_state'] = self.vis_state return result @@ -476,6 +479,7 @@ class SSTVDecoder: message='Listening...', signal_level=signal_level, sstv_tone=sstv_tone, + vis_state=vis_detector.state.value, )) except Exception as e: