""" LimeSDR command builder implementation. Uses SoapySDR-based tools for FM demodulation and signal capture. LimeSDR supports 100 kHz to 3.8 GHz frequency range. """ from typing import Optional from .base import CommandBuilder, SDRCapabilities, SDRDevice, SDRType class LimeSDRCommandBuilder(CommandBuilder): """LimeSDR command builder using SoapySDR tools.""" CAPABILITIES = SDRCapabilities( sdr_type=SDRType.LIME_SDR, freq_min_mhz=0.1, # 100 kHz freq_max_mhz=3800.0, # 3.8 GHz gain_min=0.0, gain_max=73.0, # Combined LNA + TIA + PGA sample_rates=[1000000, 2000000, 4000000, 8000000, 10000000, 20000000], supports_bias_t=False, supports_ppm=False, # Uses TCXO, no PPM correction needed tx_capable=True ) def _build_device_string(self, device: SDRDevice) -> str: """Build SoapySDR device string for LimeSDR.""" if device.serial and device.serial != 'N/A': return f'driver=lime,serial={device.serial}' return f'driver=lime' def build_fm_demod_command( self, device: SDRDevice, frequency_mhz: float, sample_rate: int = 22050, gain: Optional[float] = None, ppm: Optional[int] = None, modulation: str = "fm", squelch: Optional[int] = None ) -> list[str]: """ Build SoapySDR rx_fm command for FM demodulation. For pager decoding and iridium capture with LimeSDR. """ device_str = self._build_device_string(device) cmd = [ 'rx_fm', '-d', device_str, '-f', f'{frequency_mhz}M', '-M', modulation, '-s', str(sample_rate), ] if gain is not None and gain > 0: # LimeSDR gain is applied to LNAH element cmd.extend(['-g', f'LNAH={int(gain)}']) if squelch is not None and squelch > 0: cmd.extend(['-l', str(squelch)]) # Output to stdout cmd.append('-') return cmd def build_adsb_command( self, device: SDRDevice, gain: Optional[float] = None ) -> list[str]: """ Build dump1090 command with SoapySDR support for ADS-B decoding. Uses dump1090 compiled with SoapySDR support, or readsb as alternative. Note: Requires dump1090 with SoapySDR support or readsb. """ device_str = self._build_device_string(device) # Try readsb first (better SoapySDR support), fallback to dump1090 cmd = [ 'readsb', '--net', '--device-type', 'soapysdr', '--device', device_str, '--quiet' ] if gain is not None: cmd.extend(['--gain', str(int(gain))]) return cmd def build_ism_command( self, device: SDRDevice, frequency_mhz: float = 433.92, gain: Optional[float] = None, ppm: Optional[int] = None ) -> list[str]: """ Build rtl_433 command with SoapySDR support for ISM band decoding. rtl_433 has native SoapySDR support via -d flag. """ device_str = self._build_device_string(device) cmd = [ 'rtl_433', '-d', device_str, '-f', f'{frequency_mhz}M', '-F', 'json' ] if gain is not None and gain > 0: cmd.extend(['-g', str(int(gain))]) # PPM not typically needed for LimeSDR (TCXO) # but include if specified if ppm is not None and ppm != 0: cmd.extend(['-p', str(ppm)]) return cmd def get_capabilities(self) -> SDRCapabilities: """Return LimeSDR capabilities.""" return self.CAPABILITIES @classmethod def get_sdr_type(cls) -> SDRType: """Return SDR type.""" return SDRType.LIME_SDR