mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Fix Morse mode HF reception, stop button, and UX guidance
Enable direct sampling (-D 2) for RTL-SDR at HF frequencies below 24 MHz so rtl_fm can actually receive CW signals. Add startup health check to detect immediate rtl_fm failures. Push stopped status event from decoder thread on EOF so the frontend auto-resets. Add frequency placeholder and help text. Fix stop button silently swallowing errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import contextlib
|
|||||||
import queue
|
import queue
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from flask import Blueprint, Response, jsonify, request
|
from flask import Blueprint, Response, jsonify, request
|
||||||
@@ -113,6 +114,9 @@ def start_morse() -> Response:
|
|||||||
sample_rate = 8000
|
sample_rate = 8000
|
||||||
bias_t = data.get('bias_t', False)
|
bias_t = data.get('bias_t', False)
|
||||||
|
|
||||||
|
# RTL-SDR needs direct sampling mode for HF frequencies below 24 MHz
|
||||||
|
direct_sampling = 2 if freq < 24.0 else None
|
||||||
|
|
||||||
rtl_cmd = builder.build_fm_demod_command(
|
rtl_cmd = builder.build_fm_demod_command(
|
||||||
device=sdr_device,
|
device=sdr_device,
|
||||||
frequency_mhz=freq,
|
frequency_mhz=freq,
|
||||||
@@ -121,6 +125,7 @@ def start_morse() -> Response:
|
|||||||
ppm=int(ppm) if ppm and ppm != '0' else None,
|
ppm=int(ppm) if ppm and ppm != '0' else None,
|
||||||
modulation='usb',
|
modulation='usb',
|
||||||
bias_t=bias_t,
|
bias_t=bias_t,
|
||||||
|
direct_sampling=direct_sampling,
|
||||||
)
|
)
|
||||||
|
|
||||||
full_cmd = ' '.join(rtl_cmd)
|
full_cmd = ' '.join(rtl_cmd)
|
||||||
@@ -134,6 +139,25 @@ def start_morse() -> Response:
|
|||||||
)
|
)
|
||||||
register_process(rtl_process)
|
register_process(rtl_process)
|
||||||
|
|
||||||
|
# Detect immediate startup failure (e.g. device busy, no device)
|
||||||
|
time.sleep(0.35)
|
||||||
|
if rtl_process.poll() is not None:
|
||||||
|
stderr_text = ''
|
||||||
|
try:
|
||||||
|
if rtl_process.stderr:
|
||||||
|
stderr_text = rtl_process.stderr.read().decode(
|
||||||
|
'utf-8', errors='replace'
|
||||||
|
).strip()
|
||||||
|
except Exception:
|
||||||
|
stderr_text = ''
|
||||||
|
msg = stderr_text or f'rtl_fm exited immediately (code {rtl_process.returncode})'
|
||||||
|
logger.error(f"Morse rtl_fm startup failed: {msg}")
|
||||||
|
unregister_process(rtl_process)
|
||||||
|
if morse_active_device is not None:
|
||||||
|
app_module.release_sdr_device(morse_active_device)
|
||||||
|
morse_active_device = None
|
||||||
|
return jsonify({'status': 'error', 'message': msg}), 500
|
||||||
|
|
||||||
# Monitor rtl_fm stderr
|
# Monitor rtl_fm stderr
|
||||||
def monitor_stderr():
|
def monitor_stderr():
|
||||||
for line in rtl_process.stderr:
|
for line in rtl_process.stderr:
|
||||||
|
|||||||
@@ -107,7 +107,14 @@ var MorseMode = (function () {
|
|||||||
disconnectSSE();
|
disconnectSSE();
|
||||||
stopScope();
|
stopScope();
|
||||||
})
|
})
|
||||||
.catch(function () {});
|
.catch(function (err) {
|
||||||
|
console.error('Morse stop request failed:', err);
|
||||||
|
// Reset UI regardless so the user isn't stuck
|
||||||
|
state.running = false;
|
||||||
|
updateUI(false);
|
||||||
|
disconnectSSE();
|
||||||
|
stopScope();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- SSE ----
|
// ---- SSE ----
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
<h3>Frequency</h3>
|
<h3>Frequency</h3>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Frequency (MHz)</label>
|
<label>Frequency (MHz)</label>
|
||||||
<input type="number" id="morseFrequency" value="14.060" step="0.001" min="1" max="30">
|
<input type="number" id="morseFrequency" value="14.060" step="0.001" min="1" max="30" placeholder="e.g., 14.060">
|
||||||
|
<span class="help-text" style="font-size: 10px; color: var(--text-dim); margin-top: 2px; display: block;">Enter frequency in MHz (e.g., 7.030 for 40m CW)</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Band Presets</label>
|
<label>Band Presets</label>
|
||||||
|
|||||||
@@ -274,3 +274,6 @@ def morse_decoder_thread(
|
|||||||
for event in decoder.flush():
|
for event in decoder.flush():
|
||||||
with contextlib.suppress(queue.Full):
|
with contextlib.suppress(queue.Full):
|
||||||
output_queue.put_nowait(event)
|
output_queue.put_nowait(event)
|
||||||
|
# Notify frontend that the decoder has stopped (e.g. rtl_fm died)
|
||||||
|
with contextlib.suppress(queue.Full):
|
||||||
|
output_queue.put_nowait({'type': 'status', 'status': 'stopped'})
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ from typing import Optional
|
|||||||
from .base import CommandBuilder, SDRCapabilities, SDRDevice, SDRType
|
from .base import CommandBuilder, SDRCapabilities, SDRDevice, SDRType
|
||||||
from utils.dependencies import get_tool_path
|
from utils.dependencies import get_tool_path
|
||||||
|
|
||||||
logger = logging.getLogger('intercept.sdr.rtlsdr')
|
logger = logging.getLogger('intercept.sdr.rtlsdr')
|
||||||
|
|
||||||
|
|
||||||
def _rtl_fm_demod_mode(modulation: str) -> str:
|
def _rtl_fm_demod_mode(modulation: str) -> str:
|
||||||
"""Map app/UI modulation names to rtl_fm demod tokens."""
|
"""Map app/UI modulation names to rtl_fm demod tokens."""
|
||||||
mod = str(modulation or '').lower().strip()
|
mod = str(modulation or '').lower().strip()
|
||||||
return 'wbfm' if mod == 'wfm' else mod
|
return 'wbfm' if mod == 'wfm' else mod
|
||||||
|
|
||||||
|
|
||||||
def _get_dump1090_bias_t_flag(dump1090_path: str) -> Optional[str]:
|
def _get_dump1090_bias_t_flag(dump1090_path: str) -> Optional[str]:
|
||||||
"""Detect the correct bias-t flag for the installed dump1090 variant.
|
"""Detect the correct bias-t flag for the installed dump1090 variant.
|
||||||
|
|
||||||
Different dump1090 forks use different flags:
|
Different dump1090 forks use different flags:
|
||||||
@@ -86,22 +86,27 @@ class RTLSDRCommandBuilder(CommandBuilder):
|
|||||||
ppm: Optional[int] = None,
|
ppm: Optional[int] = None,
|
||||||
modulation: str = "fm",
|
modulation: str = "fm",
|
||||||
squelch: Optional[int] = None,
|
squelch: Optional[int] = None,
|
||||||
bias_t: bool = False
|
bias_t: bool = False,
|
||||||
|
direct_sampling: Optional[int] = None,
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Build rtl_fm command for FM demodulation.
|
Build rtl_fm command for FM demodulation.
|
||||||
|
|
||||||
Used for pager decoding. Supports local devices and rtl_tcp connections.
|
Used for pager decoding. Supports local devices and rtl_tcp connections.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
direct_sampling: Enable direct sampling mode (0=off, 1=I-branch,
|
||||||
|
2=Q-branch). Use 2 for HF reception below 24 MHz.
|
||||||
"""
|
"""
|
||||||
rtl_fm_path = get_tool_path('rtl_fm') or 'rtl_fm'
|
rtl_fm_path = get_tool_path('rtl_fm') or 'rtl_fm'
|
||||||
demod_mode = _rtl_fm_demod_mode(modulation)
|
demod_mode = _rtl_fm_demod_mode(modulation)
|
||||||
cmd = [
|
cmd = [
|
||||||
rtl_fm_path,
|
rtl_fm_path,
|
||||||
'-d', self._get_device_arg(device),
|
'-d', self._get_device_arg(device),
|
||||||
'-f', f'{frequency_mhz}M',
|
'-f', f'{frequency_mhz}M',
|
||||||
'-M', demod_mode,
|
'-M', demod_mode,
|
||||||
'-s', str(sample_rate),
|
'-s', str(sample_rate),
|
||||||
]
|
]
|
||||||
|
|
||||||
if gain is not None and gain > 0:
|
if gain is not None and gain > 0:
|
||||||
cmd.extend(['-g', str(gain)])
|
cmd.extend(['-g', str(gain)])
|
||||||
@@ -112,6 +117,9 @@ class RTLSDRCommandBuilder(CommandBuilder):
|
|||||||
if squelch is not None and squelch > 0:
|
if squelch is not None and squelch > 0:
|
||||||
cmd.extend(['-l', str(squelch)])
|
cmd.extend(['-l', str(squelch)])
|
||||||
|
|
||||||
|
if direct_sampling is not None:
|
||||||
|
cmd.extend(['-D', str(direct_sampling)])
|
||||||
|
|
||||||
if bias_t:
|
if bias_t:
|
||||||
cmd.extend(['-T'])
|
cmd.extend(['-T'])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user