""" SDR Hardware Abstraction Layer. This module provides a unified interface for multiple SDR hardware types including RTL-SDR, LimeSDR, and HackRF. Use SDRFactory to detect devices and get appropriate command builders. Example usage: from utils.sdr import SDRFactory, SDRType # Detect all connected devices devices = SDRFactory.detect_devices() # Get a command builder for a specific device builder = SDRFactory.get_builder_for_device(devices[0]) # Or get a builder by type builder = SDRFactory.get_builder(SDRType.RTL_SDR) # Build commands cmd = builder.build_fm_demod_command(device, frequency_mhz=153.35) """ from __future__ import annotations from typing import Optional from .base import CommandBuilder, SDRCapabilities, SDRDevice, SDRType from .detection import detect_all_devices from .rtlsdr import RTLSDRCommandBuilder from .limesdr import LimeSDRCommandBuilder from .hackrf import HackRFCommandBuilder from .airspy import AirspyCommandBuilder from .sdrplay import SDRPlayCommandBuilder from .validation import ( SDRValidationError, validate_frequency, validate_gain, validate_sample_rate, validate_ppm, validate_device_index, validate_squelch, get_capabilities_for_type, ) class SDRFactory: """Factory for creating SDR command builders and detecting devices.""" _builders: dict[SDRType, type[CommandBuilder]] = { SDRType.RTL_SDR: RTLSDRCommandBuilder, SDRType.LIME_SDR: LimeSDRCommandBuilder, SDRType.HACKRF: HackRFCommandBuilder, SDRType.AIRSPY: AirspyCommandBuilder, SDRType.SDRPLAY: SDRPlayCommandBuilder, } @classmethod def get_builder(cls, sdr_type: SDRType) -> CommandBuilder: """ Get a command builder for the specified SDR type. Args: sdr_type: The SDR hardware type Returns: CommandBuilder instance for the specified type Raises: ValueError: If the SDR type is not supported """ builder_class = cls._builders.get(sdr_type) if not builder_class: raise ValueError(f"Unsupported SDR type: {sdr_type}") return builder_class() @classmethod def get_builder_for_device(cls, device: SDRDevice) -> CommandBuilder: """ Get a command builder for a specific device. Args: device: The SDR device Returns: CommandBuilder instance for the device's type """ return cls.get_builder(device.sdr_type) @classmethod def detect_devices(cls) -> list[SDRDevice]: """ Detect all available SDR devices. Returns: List of detected SDR devices """ return detect_all_devices() @classmethod def get_supported_types(cls) -> list[SDRType]: """ Get list of supported SDR types. Returns: List of supported SDRType values """ return list(cls._builders.keys()) @classmethod def get_capabilities(cls, sdr_type: SDRType) -> SDRCapabilities: """ Get capabilities for an SDR type. Args: sdr_type: The SDR hardware type Returns: SDRCapabilities for the specified type """ builder = cls.get_builder(sdr_type) return builder.get_capabilities() @classmethod def get_all_capabilities(cls) -> dict[str, dict]: """ Get capabilities for all supported SDR types. Returns: Dictionary mapping SDR type names to capability dicts """ capabilities = {} for sdr_type in cls._builders: caps = cls.get_capabilities(sdr_type) capabilities[sdr_type.value] = { 'name': sdr_type.name.replace('_', ' '), 'freq_min_mhz': caps.freq_min_mhz, 'freq_max_mhz': caps.freq_max_mhz, 'gain_min': caps.gain_min, 'gain_max': caps.gain_max, 'sample_rates': caps.sample_rates, 'supports_bias_t': caps.supports_bias_t, 'supports_ppm': caps.supports_ppm, 'tx_capable': caps.tx_capable, } return capabilities @classmethod def create_default_device( cls, sdr_type: SDRType, index: int = 0, serial: str = 'N/A' ) -> SDRDevice: """ Create a default device object for a given SDR type. Useful when device detection didn't provide full details but you know the hardware type. Args: sdr_type: The SDR hardware type index: Device index (default 0) serial: Device serial (default 'N/A') Returns: SDRDevice with default capabilities for the type """ caps = cls.get_capabilities(sdr_type) return SDRDevice( sdr_type=sdr_type, index=index, name=f'{sdr_type.name.replace("_", " ")} Device {index}', serial=serial, driver=sdr_type.value, capabilities=caps ) @classmethod def create_network_device( cls, host: str, port: int = 1234 ) -> SDRDevice: """ Create a network device for rtl_tcp connection. Args: host: rtl_tcp server hostname or IP address port: rtl_tcp server port (default 1234) Returns: SDRDevice configured for rtl_tcp connection """ caps = cls.get_capabilities(SDRType.RTL_SDR) return SDRDevice( sdr_type=SDRType.RTL_SDR, index=0, name=f'{host}:{port}', serial='rtl_tcp', driver='rtl_tcp', capabilities=caps, rtl_tcp_host=host, rtl_tcp_port=port ) # Export commonly used items at package level __all__ = [ # Factory 'SDRFactory', # Types and classes 'SDRType', 'SDRDevice', 'SDRCapabilities', 'CommandBuilder', # Builders 'RTLSDRCommandBuilder', 'LimeSDRCommandBuilder', 'HackRFCommandBuilder', 'AirspyCommandBuilder', 'SDRPlayCommandBuilder', # Validation 'SDRValidationError', 'validate_frequency', 'validate_gain', 'validate_sample_rate', 'validate_ppm', 'validate_device_index', 'validate_squelch', 'get_capabilities_for_type', ]