mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
chore: commit all changes and remove large IQ captures from tracking
Add .gitignore entry for data/subghz/captures/ to prevent large IQ recording files from being committed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -256,6 +256,50 @@ MAX_DSC_MESSAGE_AGE_SECONDS = 3600 # 1 hour
|
||||
DSC_TERMINATE_TIMEOUT = 3
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# SUBGHZ TRANSCEIVER (HackRF)
|
||||
# =============================================================================
|
||||
|
||||
# Allowed ISM TX frequency bands (MHz) - transmit only within these ranges
|
||||
SUBGHZ_TX_ALLOWED_BANDS = [
|
||||
(300.0, 348.0), # 315 MHz ISM band
|
||||
(387.0, 464.0), # 433 MHz ISM band
|
||||
(779.0, 928.0), # 868/915 MHz ISM band
|
||||
]
|
||||
|
||||
# HackRF frequency limits (MHz)
|
||||
SUBGHZ_FREQ_MIN_MHZ = 1.0
|
||||
SUBGHZ_FREQ_MAX_MHZ = 6000.0
|
||||
|
||||
# HackRF gain ranges
|
||||
SUBGHZ_LNA_GAIN_MIN = 0
|
||||
SUBGHZ_LNA_GAIN_MAX = 40
|
||||
SUBGHZ_VGA_GAIN_MIN = 0
|
||||
SUBGHZ_VGA_GAIN_MAX = 62
|
||||
SUBGHZ_TX_VGA_GAIN_MIN = 0
|
||||
SUBGHZ_TX_VGA_GAIN_MAX = 47
|
||||
|
||||
# Default sample rates available (Hz)
|
||||
SUBGHZ_SAMPLE_RATES = [2000000, 4000000, 8000000, 10000000, 20000000]
|
||||
|
||||
# Maximum TX duration watchdog (seconds)
|
||||
SUBGHZ_TX_MAX_DURATION = 30
|
||||
|
||||
# Sweep defaults
|
||||
SUBGHZ_SWEEP_BIN_WIDTH = 100000 # 100 kHz bins
|
||||
|
||||
# SubGHz process termination timeout
|
||||
SUBGHZ_TERMINATE_TIMEOUT = 3
|
||||
|
||||
# Common SubGHz preset frequencies (MHz)
|
||||
SUBGHZ_PRESETS = {
|
||||
'315 MHz': 315.0,
|
||||
'433.92 MHz': 433.92,
|
||||
'868 MHz': 868.0,
|
||||
'915 MHz': 915.0,
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# DEAUTH ATTACK DETECTION
|
||||
# =============================================================================
|
||||
|
||||
@@ -394,6 +394,38 @@ TOOL_DEPENDENCIES = {
|
||||
}
|
||||
}
|
||||
},
|
||||
'subghz': {
|
||||
'name': 'SubGHz Transceiver',
|
||||
'tools': {
|
||||
'hackrf_transfer': {
|
||||
'required': True,
|
||||
'description': 'HackRF IQ capture and replay',
|
||||
'install': {
|
||||
'apt': 'sudo apt install hackrf',
|
||||
'brew': 'brew install hackrf',
|
||||
'manual': 'https://github.com/greatscottgadgets/hackrf'
|
||||
}
|
||||
},
|
||||
'hackrf_sweep': {
|
||||
'required': False,
|
||||
'description': 'HackRF wideband spectrum sweep',
|
||||
'install': {
|
||||
'apt': 'sudo apt install hackrf',
|
||||
'brew': 'brew install hackrf',
|
||||
'manual': 'https://github.com/greatscottgadgets/hackrf'
|
||||
}
|
||||
},
|
||||
'rtl_433': {
|
||||
'required': False,
|
||||
'description': 'Protocol decoder for SubGHz signals',
|
||||
'install': {
|
||||
'apt': 'sudo apt install rtl-433',
|
||||
'brew': 'brew install rtl_433',
|
||||
'manual': 'https://github.com/merbanan/rtl_433'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'tscm': {
|
||||
'name': 'TSCM Counter-Surveillance',
|
||||
'tools': {
|
||||
|
||||
@@ -6,15 +6,31 @@ Detects RTL-SDR devices via rtl_test and other SDR hardware via SoapySDR.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
from typing import Optional
|
||||
import logging
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
from .base import SDRCapabilities, SDRDevice, SDRType
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Cache HackRF detection results so polling endpoints don't repeatedly run
|
||||
# hackrf_info while the device is actively streaming in SubGHz mode.
|
||||
_hackrf_cache: list[SDRDevice] = []
|
||||
_hackrf_cache_ts: float = 0.0
|
||||
_HACKRF_CACHE_TTL_SECONDS = 3.0
|
||||
|
||||
|
||||
def _hackrf_probe_blocked() -> bool:
|
||||
"""Return True when probing HackRF would interfere with an active stream."""
|
||||
try:
|
||||
from utils.subghz import get_subghz_manager
|
||||
return get_subghz_manager().active_mode in {'rx', 'decode', 'tx', 'sweep'}
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _check_tool(name: str) -> bool:
|
||||
@@ -295,16 +311,29 @@ def _add_soapy_device(
|
||||
))
|
||||
|
||||
|
||||
def detect_hackrf_devices() -> list[SDRDevice]:
|
||||
"""
|
||||
Detect HackRF devices using native hackrf_info tool.
|
||||
|
||||
Fallback for when SoapySDR is not available.
|
||||
"""
|
||||
devices: list[SDRDevice] = []
|
||||
|
||||
if not _check_tool('hackrf_info'):
|
||||
return devices
|
||||
def detect_hackrf_devices() -> list[SDRDevice]:
|
||||
"""
|
||||
Detect HackRF devices using native hackrf_info tool.
|
||||
|
||||
Fallback for when SoapySDR is not available.
|
||||
"""
|
||||
global _hackrf_cache, _hackrf_cache_ts
|
||||
now = time.time()
|
||||
|
||||
# While HackRF is actively streaming in SubGHz mode, skip probe calls.
|
||||
# Re-running hackrf_info during active RX/TX can disrupt the USB stream.
|
||||
if _hackrf_probe_blocked():
|
||||
return list(_hackrf_cache)
|
||||
|
||||
if _hackrf_cache and (now - _hackrf_cache_ts) < _HACKRF_CACHE_TTL_SECONDS:
|
||||
return list(_hackrf_cache)
|
||||
|
||||
devices: list[SDRDevice] = []
|
||||
|
||||
if not _check_tool('hackrf_info'):
|
||||
_hackrf_cache = devices
|
||||
_hackrf_cache_ts = now
|
||||
return devices
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
@@ -342,10 +371,12 @@ def detect_hackrf_devices() -> list[SDRDevice]:
|
||||
capabilities=HackRFCommandBuilder.CAPABILITIES
|
||||
))
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"HackRF detection error: {e}")
|
||||
|
||||
return devices
|
||||
except Exception as e:
|
||||
logger.debug(f"HackRF detection error: {e}")
|
||||
|
||||
_hackrf_cache = list(devices)
|
||||
_hackrf_cache_ts = now
|
||||
return devices
|
||||
|
||||
|
||||
def probe_rtlsdr_device(device_index: int) -> str | None:
|
||||
|
||||
@@ -14,10 +14,16 @@ from typing import Optional
|
||||
from .base import CommandBuilder, SDRCapabilities, SDRDevice, SDRType
|
||||
from utils.dependencies import get_tool_path
|
||||
|
||||
logger = logging.getLogger('intercept.sdr.rtlsdr')
|
||||
|
||||
|
||||
def _get_dump1090_bias_t_flag(dump1090_path: str) -> Optional[str]:
|
||||
logger = logging.getLogger('intercept.sdr.rtlsdr')
|
||||
|
||||
|
||||
def _rtl_fm_demod_mode(modulation: str) -> str:
|
||||
"""Map app/UI modulation names to rtl_fm demod tokens."""
|
||||
mod = str(modulation or '').lower().strip()
|
||||
return 'wbfm' if mod == 'wfm' else mod
|
||||
|
||||
|
||||
def _get_dump1090_bias_t_flag(dump1090_path: str) -> Optional[str]:
|
||||
"""Detect the correct bias-t flag for the installed dump1090 variant.
|
||||
|
||||
Different dump1090 forks use different flags:
|
||||
@@ -87,14 +93,15 @@ class RTLSDRCommandBuilder(CommandBuilder):
|
||||
|
||||
Used for pager decoding. Supports local devices and rtl_tcp connections.
|
||||
"""
|
||||
rtl_fm_path = get_tool_path('rtl_fm') or 'rtl_fm'
|
||||
cmd = [
|
||||
rtl_fm_path,
|
||||
'-d', self._get_device_arg(device),
|
||||
'-f', f'{frequency_mhz}M',
|
||||
'-M', modulation,
|
||||
'-s', str(sample_rate),
|
||||
]
|
||||
rtl_fm_path = get_tool_path('rtl_fm') or 'rtl_fm'
|
||||
demod_mode = _rtl_fm_demod_mode(modulation)
|
||||
cmd = [
|
||||
rtl_fm_path,
|
||||
'-d', self._get_device_arg(device),
|
||||
'-f', f'{frequency_mhz}M',
|
||||
'-M', demod_mode,
|
||||
'-s', str(sample_rate),
|
||||
]
|
||||
|
||||
if gain is not None and gain > 0:
|
||||
cmd.extend(['-g', str(gain)])
|
||||
|
||||
@@ -311,6 +311,10 @@ class VISDetector:
|
||||
if len(self._data_bits) != 8:
|
||||
return None
|
||||
|
||||
# VIS uses even parity across 8 data bits + parity bit.
|
||||
if (sum(self._data_bits) + self._parity_bit) % 2 != 0:
|
||||
return None
|
||||
|
||||
# Decode VIS code (LSB first)
|
||||
vis_code = 0
|
||||
for i, bit in enumerate(self._data_bits):
|
||||
|
||||
2809
utils/subghz.py
Normal file
2809
utils/subghz.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,10 +3,11 @@
|
||||
Provides automated capture and decoding of weather satellite images using SatDump.
|
||||
|
||||
Supported satellites:
|
||||
- NOAA-15: 137.620 MHz (APT)
|
||||
- NOAA-18: 137.9125 MHz (APT)
|
||||
- NOAA-19: 137.100 MHz (APT)
|
||||
- NOAA-15: 137.620 MHz (APT) [DEFUNCT - decommissioned Aug 2025]
|
||||
- NOAA-18: 137.9125 MHz (APT) [DEFUNCT - decommissioned Jun 2025]
|
||||
- NOAA-19: 137.100 MHz (APT) [DEFUNCT - decommissioned Aug 2025]
|
||||
- Meteor-M2-3: 137.900 MHz (LRPT)
|
||||
- Meteor-M2-4: 137.900 MHz (LRPT)
|
||||
|
||||
Uses SatDump CLI for live SDR capture and decoding, with fallback to
|
||||
rtl_fm capture for manual decoding when SatDump is unavailable.
|
||||
@@ -42,8 +43,8 @@ WEATHER_SATELLITES = {
|
||||
'mode': 'APT',
|
||||
'pipeline': 'noaa_apt',
|
||||
'tle_key': 'NOAA-15',
|
||||
'description': 'NOAA-15 APT (analog weather imagery)',
|
||||
'active': True,
|
||||
'description': 'NOAA-15 APT (decommissioned Aug 2025)',
|
||||
'active': False,
|
||||
},
|
||||
'NOAA-18': {
|
||||
'name': 'NOAA 18',
|
||||
@@ -51,8 +52,8 @@ WEATHER_SATELLITES = {
|
||||
'mode': 'APT',
|
||||
'pipeline': 'noaa_apt',
|
||||
'tle_key': 'NOAA-18',
|
||||
'description': 'NOAA-18 APT (analog weather imagery)',
|
||||
'active': True,
|
||||
'description': 'NOAA-18 APT (decommissioned Jun 2025)',
|
||||
'active': False,
|
||||
},
|
||||
'NOAA-19': {
|
||||
'name': 'NOAA 19',
|
||||
@@ -60,8 +61,8 @@ WEATHER_SATELLITES = {
|
||||
'mode': 'APT',
|
||||
'pipeline': 'noaa_apt',
|
||||
'tle_key': 'NOAA-19',
|
||||
'description': 'NOAA-19 APT (analog weather imagery)',
|
||||
'active': True,
|
||||
'description': 'NOAA-19 APT (decommissioned Aug 2025)',
|
||||
'active': False,
|
||||
},
|
||||
'METEOR-M2-3': {
|
||||
'name': 'Meteor-M2-3',
|
||||
@@ -72,6 +73,15 @@ WEATHER_SATELLITES = {
|
||||
'description': 'Meteor-M2-3 LRPT (digital color imagery)',
|
||||
'active': True,
|
||||
},
|
||||
'METEOR-M2-4': {
|
||||
'name': 'Meteor-M2-4',
|
||||
'frequency': 137.900,
|
||||
'mode': 'LRPT',
|
||||
'pipeline': 'meteor_m2-x_lrpt',
|
||||
'tle_key': 'METEOR-M2-4',
|
||||
'description': 'Meteor-M2-4 LRPT (digital color imagery)',
|
||||
'active': True,
|
||||
},
|
||||
}
|
||||
|
||||
# Default sample rate for weather satellite reception
|
||||
|
||||
Reference in New Issue
Block a user