mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
fix: HackRF users get misleading RTL-SDR error in rtlamr/sstv/weather-sat modes
Several modes didn't pass sdr_type to claim_sdr_device(), defaulting to 'rtlsdr' and triggering an rtl_test USB probe that fails for HackRF with a confusing "check that the RTL-SDR is connected" message. - Add sdr_type to frontend start requests for rtlamr, weather-sat, sstv-general - Read sdr_type in backend routes and pass to claim/release_sdr_device() - Add early guard returning clear "not yet supported" error for non-RTL-SDR hardware in modes that are hardcoded to RTL-SDR tools - Make probe_rtlsdr_device error message device-type-agnostic Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,7 @@ rtl_tcp_lock = threading.Lock()
|
|||||||
|
|
||||||
# Track which device is being used
|
# Track which device is being used
|
||||||
rtlamr_active_device: int | None = None
|
rtlamr_active_device: int | None = None
|
||||||
|
rtlamr_active_sdr_type: str = 'rtlsdr'
|
||||||
|
|
||||||
|
|
||||||
def stream_rtlamr_output(process: subprocess.Popen[bytes]) -> None:
|
def stream_rtlamr_output(process: subprocess.Popen[bytes]) -> None:
|
||||||
@@ -62,7 +63,7 @@ def stream_rtlamr_output(process: subprocess.Popen[bytes]) -> None:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
app_module.rtlamr_queue.put({'type': 'error', 'text': str(e)})
|
app_module.rtlamr_queue.put({'type': 'error', 'text': str(e)})
|
||||||
finally:
|
finally:
|
||||||
global rtl_tcp_process, rtlamr_active_device
|
global rtl_tcp_process, rtlamr_active_device, rtlamr_active_sdr_type
|
||||||
# Ensure rtlamr process is terminated
|
# Ensure rtlamr process is terminated
|
||||||
try:
|
try:
|
||||||
process.terminate()
|
process.terminate()
|
||||||
@@ -91,19 +92,26 @@ def stream_rtlamr_output(process: subprocess.Popen[bytes]) -> None:
|
|||||||
app_module.rtlamr_process = None
|
app_module.rtlamr_process = None
|
||||||
# Release SDR device
|
# Release SDR device
|
||||||
if rtlamr_active_device is not None:
|
if rtlamr_active_device is not None:
|
||||||
app_module.release_sdr_device(rtlamr_active_device)
|
app_module.release_sdr_device(rtlamr_active_device, rtlamr_active_sdr_type)
|
||||||
rtlamr_active_device = None
|
rtlamr_active_device = None
|
||||||
|
|
||||||
|
|
||||||
@rtlamr_bp.route('/start_rtlamr', methods=['POST'])
|
@rtlamr_bp.route('/start_rtlamr', methods=['POST'])
|
||||||
def start_rtlamr() -> Response:
|
def start_rtlamr() -> Response:
|
||||||
global rtl_tcp_process, rtlamr_active_device
|
global rtl_tcp_process, rtlamr_active_device, rtlamr_active_sdr_type
|
||||||
|
|
||||||
with app_module.rtlamr_lock:
|
with app_module.rtlamr_lock:
|
||||||
if app_module.rtlamr_process:
|
if app_module.rtlamr_process:
|
||||||
return jsonify({'status': 'error', 'message': 'RTLAMR already running'}), 409
|
return jsonify({'status': 'error', 'message': 'RTLAMR already running'}), 409
|
||||||
|
|
||||||
data = request.json or {}
|
data = request.json or {}
|
||||||
|
sdr_type_str = data.get('sdr_type', 'rtlsdr')
|
||||||
|
|
||||||
|
if sdr_type_str != 'rtlsdr':
|
||||||
|
return jsonify({
|
||||||
|
'status': 'error',
|
||||||
|
'message': f'{sdr_type_str.replace("_", " ").title()} is not yet supported for this mode. Please use an RTL-SDR device.'
|
||||||
|
}), 400
|
||||||
|
|
||||||
# Validate inputs
|
# Validate inputs
|
||||||
try:
|
try:
|
||||||
@@ -116,7 +124,7 @@ def start_rtlamr() -> Response:
|
|||||||
|
|
||||||
# Check if device is available
|
# Check if device is available
|
||||||
device_int = int(device)
|
device_int = int(device)
|
||||||
error = app_module.claim_sdr_device(device_int, 'rtlamr')
|
error = app_module.claim_sdr_device(device_int, 'rtlamr', sdr_type_str)
|
||||||
if error:
|
if error:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
@@ -125,6 +133,7 @@ def start_rtlamr() -> Response:
|
|||||||
}), 409
|
}), 409
|
||||||
|
|
||||||
rtlamr_active_device = device_int
|
rtlamr_active_device = device_int
|
||||||
|
rtlamr_active_sdr_type = sdr_type_str
|
||||||
|
|
||||||
# Clear queue
|
# Clear queue
|
||||||
while not app_module.rtlamr_queue.empty():
|
while not app_module.rtlamr_queue.empty():
|
||||||
@@ -170,7 +179,7 @@ def start_rtlamr() -> Response:
|
|||||||
logger.error(f"Failed to start rtl_tcp: {e}")
|
logger.error(f"Failed to start rtl_tcp: {e}")
|
||||||
# Release SDR device on rtl_tcp failure
|
# Release SDR device on rtl_tcp failure
|
||||||
if rtlamr_active_device is not None:
|
if rtlamr_active_device is not None:
|
||||||
app_module.release_sdr_device(rtlamr_active_device)
|
app_module.release_sdr_device(rtlamr_active_device, rtlamr_active_sdr_type)
|
||||||
rtlamr_active_device = None
|
rtlamr_active_device = None
|
||||||
return jsonify({'status': 'error', 'message': f'Failed to start rtl_tcp: {e}'}), 500
|
return jsonify({'status': 'error', 'message': f'Failed to start rtl_tcp: {e}'}), 500
|
||||||
|
|
||||||
@@ -242,7 +251,7 @@ def start_rtlamr() -> Response:
|
|||||||
rtl_tcp_process.wait(timeout=2)
|
rtl_tcp_process.wait(timeout=2)
|
||||||
rtl_tcp_process = None
|
rtl_tcp_process = None
|
||||||
if rtlamr_active_device is not None:
|
if rtlamr_active_device is not None:
|
||||||
app_module.release_sdr_device(rtlamr_active_device)
|
app_module.release_sdr_device(rtlamr_active_device, rtlamr_active_sdr_type)
|
||||||
rtlamr_active_device = None
|
rtlamr_active_device = None
|
||||||
return jsonify({'status': 'error', 'message': 'rtlamr not found. Install from https://github.com/bemasher/rtlamr'})
|
return jsonify({'status': 'error', 'message': 'rtlamr not found. Install from https://github.com/bemasher/rtlamr'})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -253,14 +262,14 @@ def start_rtlamr() -> Response:
|
|||||||
rtl_tcp_process.wait(timeout=2)
|
rtl_tcp_process.wait(timeout=2)
|
||||||
rtl_tcp_process = None
|
rtl_tcp_process = None
|
||||||
if rtlamr_active_device is not None:
|
if rtlamr_active_device is not None:
|
||||||
app_module.release_sdr_device(rtlamr_active_device)
|
app_module.release_sdr_device(rtlamr_active_device, rtlamr_active_sdr_type)
|
||||||
rtlamr_active_device = None
|
rtlamr_active_device = None
|
||||||
return jsonify({'status': 'error', 'message': str(e)})
|
return jsonify({'status': 'error', 'message': str(e)})
|
||||||
|
|
||||||
|
|
||||||
@rtlamr_bp.route('/stop_rtlamr', methods=['POST'])
|
@rtlamr_bp.route('/stop_rtlamr', methods=['POST'])
|
||||||
def stop_rtlamr() -> Response:
|
def stop_rtlamr() -> Response:
|
||||||
global rtl_tcp_process, rtlamr_active_device
|
global rtl_tcp_process, rtlamr_active_device, rtlamr_active_sdr_type
|
||||||
|
|
||||||
# Grab process refs inside locks, clear state, then terminate outside
|
# Grab process refs inside locks, clear state, then terminate outside
|
||||||
rtlamr_proc = None
|
rtlamr_proc = None
|
||||||
@@ -293,7 +302,7 @@ def stop_rtlamr() -> Response:
|
|||||||
|
|
||||||
# Release device from registry
|
# Release device from registry
|
||||||
if rtlamr_active_device is not None:
|
if rtlamr_active_device is not None:
|
||||||
app_module.release_sdr_device(rtlamr_active_device)
|
app_module.release_sdr_device(rtlamr_active_device, rtlamr_active_sdr_type)
|
||||||
rtlamr_active_device = None
|
rtlamr_active_device = None
|
||||||
|
|
||||||
return jsonify({'status': 'stopped'})
|
return jsonify({'status': 'stopped'})
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ _timescale_lock = threading.Lock()
|
|||||||
|
|
||||||
# Track which device is being used
|
# Track which device is being used
|
||||||
sstv_active_device: int | None = None
|
sstv_active_device: int | None = None
|
||||||
|
sstv_active_sdr_type: str = 'rtlsdr'
|
||||||
|
|
||||||
|
|
||||||
def _progress_callback(data: dict) -> None:
|
def _progress_callback(data: dict) -> None:
|
||||||
@@ -154,6 +155,14 @@ def start_decoder():
|
|||||||
|
|
||||||
# Get parameters
|
# Get parameters
|
||||||
data = request.get_json(silent=True) or {}
|
data = request.get_json(silent=True) or {}
|
||||||
|
sdr_type_str = data.get('sdr_type', 'rtlsdr')
|
||||||
|
|
||||||
|
if sdr_type_str != 'rtlsdr':
|
||||||
|
return jsonify({
|
||||||
|
'status': 'error',
|
||||||
|
'message': f'{sdr_type_str.replace("_", " ").title()} is not yet supported for this mode. Please use an RTL-SDR device.'
|
||||||
|
}), 400
|
||||||
|
|
||||||
frequency = data.get('frequency', ISS_SSTV_FREQ)
|
frequency = data.get('frequency', ISS_SSTV_FREQ)
|
||||||
modulation = str(data.get('modulation', ISS_SSTV_MODULATION)).strip().lower()
|
modulation = str(data.get('modulation', ISS_SSTV_MODULATION)).strip().lower()
|
||||||
device_index = data.get('device', 0)
|
device_index = data.get('device', 0)
|
||||||
@@ -209,9 +218,9 @@ def start_decoder():
|
|||||||
longitude = None
|
longitude = None
|
||||||
|
|
||||||
# Claim SDR device
|
# Claim SDR device
|
||||||
global sstv_active_device
|
global sstv_active_device, sstv_active_sdr_type
|
||||||
device_int = int(device_index)
|
device_int = int(device_index)
|
||||||
error = app_module.claim_sdr_device(device_int, 'sstv')
|
error = app_module.claim_sdr_device(device_int, 'sstv', sdr_type_str)
|
||||||
if error:
|
if error:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
@@ -231,6 +240,7 @@ def start_decoder():
|
|||||||
|
|
||||||
if success:
|
if success:
|
||||||
sstv_active_device = device_int
|
sstv_active_device = device_int
|
||||||
|
sstv_active_sdr_type = sdr_type_str
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
'status': 'started',
|
'status': 'started',
|
||||||
@@ -247,7 +257,7 @@ def start_decoder():
|
|||||||
return jsonify(result)
|
return jsonify(result)
|
||||||
else:
|
else:
|
||||||
# Release device on failure
|
# Release device on failure
|
||||||
app_module.release_sdr_device(device_int)
|
app_module.release_sdr_device(device_int, sdr_type_str)
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
'message': 'Failed to start decoder'
|
'message': 'Failed to start decoder'
|
||||||
@@ -262,13 +272,13 @@ def stop_decoder():
|
|||||||
Returns:
|
Returns:
|
||||||
JSON confirmation.
|
JSON confirmation.
|
||||||
"""
|
"""
|
||||||
global sstv_active_device
|
global sstv_active_device, sstv_active_sdr_type
|
||||||
decoder = get_sstv_decoder()
|
decoder = get_sstv_decoder()
|
||||||
decoder.stop()
|
decoder.stop()
|
||||||
|
|
||||||
# Release device from registry
|
# Release device from registry
|
||||||
if sstv_active_device is not None:
|
if sstv_active_device is not None:
|
||||||
app_module.release_sdr_device(sstv_active_device)
|
app_module.release_sdr_device(sstv_active_device, sstv_active_sdr_type)
|
||||||
sstv_active_device = None
|
sstv_active_device = None
|
||||||
|
|
||||||
return jsonify({'status': 'stopped'})
|
return jsonify({'status': 'stopped'})
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ _sstv_general_queue: queue.Queue = queue.Queue(maxsize=100)
|
|||||||
|
|
||||||
# Track which device is being used
|
# Track which device is being used
|
||||||
_sstv_general_active_device: int | None = None
|
_sstv_general_active_device: int | None = None
|
||||||
|
_sstv_general_active_sdr_type: str = 'rtlsdr'
|
||||||
|
|
||||||
# Predefined SSTV frequencies
|
# Predefined SSTV frequencies
|
||||||
SSTV_FREQUENCIES = [
|
SSTV_FREQUENCIES = [
|
||||||
@@ -119,6 +120,14 @@ def start_decoder():
|
|||||||
break
|
break
|
||||||
|
|
||||||
data = request.get_json(silent=True) or {}
|
data = request.get_json(silent=True) or {}
|
||||||
|
sdr_type_str = data.get('sdr_type', 'rtlsdr')
|
||||||
|
|
||||||
|
if sdr_type_str != 'rtlsdr':
|
||||||
|
return jsonify({
|
||||||
|
'status': 'error',
|
||||||
|
'message': f'{sdr_type_str.replace("_", " ").title()} is not yet supported for this mode. Please use an RTL-SDR device.'
|
||||||
|
}), 400
|
||||||
|
|
||||||
frequency = data.get('frequency')
|
frequency = data.get('frequency')
|
||||||
modulation = data.get('modulation')
|
modulation = data.get('modulation')
|
||||||
device_index = data.get('device', 0)
|
device_index = data.get('device', 0)
|
||||||
@@ -155,9 +164,9 @@ def start_decoder():
|
|||||||
}), 400
|
}), 400
|
||||||
|
|
||||||
# Claim SDR device
|
# Claim SDR device
|
||||||
global _sstv_general_active_device
|
global _sstv_general_active_device, _sstv_general_active_sdr_type
|
||||||
device_int = int(device_index)
|
device_int = int(device_index)
|
||||||
error = app_module.claim_sdr_device(device_int, 'sstv_general')
|
error = app_module.claim_sdr_device(device_int, 'sstv_general', sdr_type_str)
|
||||||
if error:
|
if error:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
@@ -175,6 +184,7 @@ def start_decoder():
|
|||||||
|
|
||||||
if success:
|
if success:
|
||||||
_sstv_general_active_device = device_int
|
_sstv_general_active_device = device_int
|
||||||
|
_sstv_general_active_sdr_type = sdr_type_str
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'started',
|
'status': 'started',
|
||||||
'frequency': frequency,
|
'frequency': frequency,
|
||||||
@@ -182,7 +192,7 @@ def start_decoder():
|
|||||||
'device': device_index,
|
'device': device_index,
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
app_module.release_sdr_device(device_int)
|
app_module.release_sdr_device(device_int, sdr_type_str)
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
'message': 'Failed to start decoder',
|
'message': 'Failed to start decoder',
|
||||||
@@ -192,12 +202,12 @@ def start_decoder():
|
|||||||
@sstv_general_bp.route('/stop', methods=['POST'])
|
@sstv_general_bp.route('/stop', methods=['POST'])
|
||||||
def stop_decoder():
|
def stop_decoder():
|
||||||
"""Stop general SSTV decoder."""
|
"""Stop general SSTV decoder."""
|
||||||
global _sstv_general_active_device
|
global _sstv_general_active_device, _sstv_general_active_sdr_type
|
||||||
decoder = get_general_sstv_decoder()
|
decoder = get_general_sstv_decoder()
|
||||||
decoder.stop()
|
decoder.stop()
|
||||||
|
|
||||||
if _sstv_general_active_device is not None:
|
if _sstv_general_active_device is not None:
|
||||||
app_module.release_sdr_device(_sstv_general_active_device)
|
app_module.release_sdr_device(_sstv_general_active_device, _sstv_general_active_sdr_type)
|
||||||
_sstv_general_active_device = None
|
_sstv_general_active_device = None
|
||||||
|
|
||||||
return jsonify({'status': 'stopped'})
|
return jsonify({'status': 'stopped'})
|
||||||
|
|||||||
@@ -136,6 +136,13 @@ def start_capture():
|
|||||||
})
|
})
|
||||||
|
|
||||||
data = request.get_json(silent=True) or {}
|
data = request.get_json(silent=True) or {}
|
||||||
|
sdr_type_str = data.get('sdr_type', 'rtlsdr')
|
||||||
|
|
||||||
|
if sdr_type_str != 'rtlsdr':
|
||||||
|
return jsonify({
|
||||||
|
'status': 'error',
|
||||||
|
'message': f'{sdr_type_str.replace("_", " ").title()} is not yet supported for this mode. Please use an RTL-SDR device.'
|
||||||
|
}), 400
|
||||||
|
|
||||||
# Validate satellite
|
# Validate satellite
|
||||||
satellite = data.get('satellite')
|
satellite = data.get('satellite')
|
||||||
@@ -173,7 +180,7 @@ def start_capture():
|
|||||||
if not rtl_tcp_host:
|
if not rtl_tcp_host:
|
||||||
try:
|
try:
|
||||||
import app as app_module
|
import app as app_module
|
||||||
error = app_module.claim_sdr_device(device_index, 'weather_sat')
|
error = app_module.claim_sdr_device(device_index, 'weather_sat', sdr_type_str)
|
||||||
if error:
|
if error:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ const SSTVGeneral = (function() {
|
|||||||
const response = await fetch('/sstv-general/start', {
|
const response = await fetch('/sstv-general/start', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ frequency, modulation, device })
|
body: JSON.stringify({ frequency, modulation, device, sdr_type: typeof getSelectedSDRType === 'function' ? getSelectedSDRType() : 'rtlsdr' })
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|||||||
@@ -258,6 +258,7 @@ const WeatherSat = (function() {
|
|||||||
device,
|
device,
|
||||||
gain,
|
gain,
|
||||||
bias_t: biasT,
|
bias_t: biasT,
|
||||||
|
sdr_type: typeof getSelectedSDRType === 'function' ? getSelectedSDRType() : 'rtlsdr',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add rtl_tcp params if using remote SDR
|
// Add rtl_tcp params if using remote SDR
|
||||||
|
|||||||
@@ -5329,6 +5329,7 @@
|
|||||||
gain: gain,
|
gain: gain,
|
||||||
ppm: ppm,
|
ppm: ppm,
|
||||||
device: device,
|
device: device,
|
||||||
|
sdr_type: getSelectedSDRType(),
|
||||||
msgtype: msgtype,
|
msgtype: msgtype,
|
||||||
filterid: filterid,
|
filterid: filterid,
|
||||||
unique: unique,
|
unique: unique,
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ def probe_rtlsdr_device(device_index: int) -> str | None:
|
|||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
f'SDR device {device_index} is not available — '
|
f'SDR device {device_index} is not available — '
|
||||||
f'check that the RTL-SDR is connected and not in use by another process.'
|
f'check that the SDR device is connected and not in use by another process.'
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user