From 06c218c736efbdfffa9fcce9e72f9b6059da4cef 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: