diff --git a/app.py b/app.py index 420f8a5..0c2c7f0 100644 --- a/app.py +++ b/app.py @@ -832,7 +832,7 @@ def health_check() -> Response: def kill_all() -> Response: """Kill all decoder, WiFi, and Bluetooth processes.""" global current_process, sensor_process, wifi_process, adsb_process, ais_process, acars_process - global vdl2_process, morse_process, radiosonde_process + global vdl2_process, morse_process, radiosonde_process, ook_process global aprs_process, aprs_rtl_process, dsc_process, dsc_rtl_process, bt_process # Import modules to reset their state @@ -896,6 +896,13 @@ def kill_all() -> Response: with morse_lock: morse_process = None + # Reset OOK state + with ook_lock: + if ook_process: + safe_terminate(ook_process) + unregister_process(ook_process) + ook_process = None + # Reset APRS state with aprs_lock: aprs_process = None diff --git a/routes/ook.py b/routes/ook.py index 87c209d..acedd0a 100644 --- a/routes/ook.py +++ b/routes/ook.py @@ -232,20 +232,39 @@ def start_ook() -> Response: return jsonify({'status': 'error', 'message': str(e)}), 500 +def _close_pipe(pipe_obj) -> None: + """Close a subprocess pipe, suppressing errors.""" + if pipe_obj is not None: + with contextlib.suppress(Exception): + pipe_obj.close() + + @ook_bp.route('/ook/stop', methods=['POST']) def stop_ook() -> Response: global ook_active_device with app_module.ook_lock: if app_module.ook_process: - stop_event = getattr(app_module.ook_process, '_stop_parser', None) + proc = app_module.ook_process + stop_event = getattr(proc, '_stop_parser', None) + parser_thread = getattr(proc, '_parser_thread', None) + + # Signal parser thread to stop if stop_event: stop_event.set() - safe_terminate(app_module.ook_process) - unregister_process(app_module.ook_process) + # Close pipes so parser thread unblocks from readline() + _close_pipe(getattr(proc, 'stdout', None)) + _close_pipe(getattr(proc, 'stderr', None)) + + safe_terminate(proc) + unregister_process(proc) app_module.ook_process = None + # Join parser thread with timeout + if parser_thread: + parser_thread.join(timeout=0.5) + if ook_active_device is not None: app_module.release_sdr_device(ook_active_device) ook_active_device = None diff --git a/static/css/modes/ook.css b/static/css/modes/ook.css new file mode 100644 index 0000000..beb0489 --- /dev/null +++ b/static/css/modes/ook.css @@ -0,0 +1,110 @@ +/* OOK Signal Decoder Styles */ + +.ook-presets { + display: flex; + flex-wrap: wrap; + gap: 4px; +} + +.ook-preset-add { + margin-top: 6px; + display: flex; + gap: 4px; +} + +.ook-preset-add input { + width: 80px; + background: var(--bg-tertiary, #111); + border: 1px solid var(--border-color, #222); + border-radius: 3px; + color: var(--text-dim); + font-family: var(--font-mono); + font-size: 11px; + padding: 3px 6px; +} + +.ook-preset-hint { + font-size: 9px; + color: var(--text-muted, #555); +} + +.ook-encoding-btns { + display: flex; + gap: 4px; +} + +.ook-encoding-btns .preset-btn { + flex: 1; +} + +.ook-timing-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; +} + +.ook-timing-presets { + display: flex; + flex-wrap: wrap; + gap: 4px; + margin-top: 4px; +} + +.ook-status-row { + display: flex; + align-items: center; + gap: 8px; + font-size: 12px; + color: var(--text-dim); +} + +.ook-status-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--text-dim); +} + +.ook-warning { + font-size: 11px; + color: #ffaa00; + line-height: 1.5; +} + +.ook-command-display { + display: none; + margin-top: 8px; +} + +.ook-command-label { + font-size: 10px; + color: var(--text-muted, #555); + text-transform: uppercase; + letter-spacing: 1px; +} + +.ook-command-text { + margin: 0; + padding: 6px 8px; + background: var(--bg-deep, #0a0a0a); + border: 1px solid var(--border-color, #1a2e1a); + border-radius: 4px; + font-family: var(--font-mono); + font-size: 10px; + color: var(--text-dim); + white-space: pre-wrap; + word-break: break-all; + line-height: 1.5; +} + +.ook-dedup-label { + display: flex; + align-items: center; + gap: 8px; + cursor: pointer; +} + +.ook-dedup-label input[type="checkbox"] { + width: auto; + margin: 0; +} diff --git a/templates/index.html b/templates/index.html index 8538606..4545891 100644 --- a/templates/index.html +++ b/templates/index.html @@ -86,7 +86,8 @@ morse: "{{ url_for('static', filename='css/modes/morse.css') }}", radiosonde: "{{ url_for('static', filename='css/modes/radiosonde.css') }}", meteor: "{{ url_for('static', filename='css/modes/meteor.css') }}", - system: "{{ url_for('static', filename='css/modes/system.css') }}" + system: "{{ url_for('static', filename='css/modes/system.css') }}", + ook: "{{ url_for('static', filename='css/modes/ook.css') }}" }; window.INTERCEPT_MODE_STYLE_LOADED = {}; window.INTERCEPT_MODE_STYLE_PROMISES = {}; diff --git a/templates/partials/modes/ook.html b/templates/partials/modes/ook.html index eb2919d..228b107 100644 --- a/templates/partials/modes/ook.html +++ b/templates/partials/modes/ook.html @@ -13,16 +13,15 @@
@@ -67,7 +64,7 @@
Pulse widths in microseconds for the flex decoder.
-