diff --git a/owrx/feature.py b/owrx/feature.py index e458a962..f626fb17 100644 --- a/owrx/feature.py +++ b/owrx/feature.py @@ -61,6 +61,7 @@ class FeatureDetector(object): "perseussdr": ["perseustest", "nmux"], "airspy": ["soapy_connector", "soapy_airspy"], "airspyhf": ["soapy_connector", "soapy_airspyhf"], + "hydrasdr": ["soapy_connector", "soapy_hydrasdr"], "afedri": ["soapy_connector", "soapy_afedri"], "lime_sdr": ["soapy_connector", "soapy_lime_sdr"], "fifi_sdr": ["alsa", "rockprog", "nmux"], @@ -346,6 +347,13 @@ class FeatureDetector(object): """ return self._has_soapy_driver("airspyhf") + def has_soapy_hydrasdr(self): + """ + The [SoapySDR module for RFOne](https://github.com/hydrasdr/SoapyHydraSDR) + device is required for interfacing with HydraSDR RFOne devices. + """ + return self._has_soapy_driver("hydrasdr") + def has_soapy_afedri(self): """ The [SoapyAfedri](https://github.com/alexander-sholohov/SoapyAfedri) module allows using Afedri SDR-Net devices diff --git a/owrx/source/hydrasdr.py b/owrx/source/hydrasdr.py new file mode 100644 index 00000000..98203dad --- /dev/null +++ b/owrx/source/hydrasdr.py @@ -0,0 +1,60 @@ +from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription +from owrx.form.input import Input, CheckboxInput +from owrx.form.input.device import BiasTeeInput +from owrx.form.input.validator import Range +from typing import List + +# case sensitive, be careful changing it +class HydrasdrSource(SoapyConnectorSource): + def getSoapySettingsMappings(self): + mappings = super().getSoapySettingsMappings() + mappings.update( + { + "bias_tee": "biastee", + "bitpack": "bitpack", + } + ) + return mappings + + def getDriver(self): + return "hydrasdr" + + +class HydrasdrDeviceDescription(SoapyConnectorDeviceDescription): + def getName(self): + return "HydraSDR RFone" + + def supportsPpm(self): + # not supported by the device API + # frequency calibration can be done with separate tools and will be persisted on the device. + # see discussion here: https://groups.io/g/openwebrx/topic/79360293 + return False + + def getInputs(self) -> List[Input]: + return super().getInputs() + [ + BiasTeeInput(), + CheckboxInput( + "bitpack", + "Enable bit-packing", + infotext="Packs two 12-bit samples into 3 bytes." + + " Lowers USB bandwidth consumption, increases CPU load", + ), + ] + + def getDeviceOptionalKeys(self): + return super().getDeviceOptionalKeys() + ["bias_tee", "bitpack"] + + def getProfileOptionalKeys(self): + return super().getProfileOptionalKeys() + ["bias_tee"] + + def getGainStages(self): + return ["LNA", "MIX", "VGA"] + + def getSampleRateRanges(self) -> List[Range]: + # Device only supports 2.5, 5, and 10 MSPS for now, mfg suggests it may + # be able to do up to 80 MSPS "with custom firmware" + return [ + Range(2500000), + Range(5000000), + Range(10000000), + ]