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: