From 770fd749cd5d4bc888bae8b762a4213417e94f0b Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Mon, 22 Feb 2021 00:35:47 +0100 Subject: [PATCH] introduce the basic concept of optional keys --- owrx/controllers/settings/sdr.py | 2 +- owrx/source/__init__.py | 19 ++++++++---- owrx/source/airspy.py | 32 +++++++++++--------- owrx/source/connector.py | 40 ++++++++++++------------- owrx/source/hackrf.py | 9 +++++- owrx/source/rtl_sdr.py | 26 ++++++++--------- owrx/source/rtl_sdr_soapy.py | 5 +++- owrx/source/rtl_tcp.py | 5 +++- owrx/source/runds.py | 20 ++++++------- owrx/source/sdrplay.py | 50 ++++++++++++++++---------------- owrx/source/soapy.py | 42 +++++++++++++-------------- owrx/source/soapy_remote.py | 18 ++++++------ 12 files changed, 146 insertions(+), 122 deletions(-) diff --git a/owrx/controllers/settings/sdr.py b/owrx/controllers/settings/sdr.py index 926001e..90bb131 100644 --- a/owrx/controllers/settings/sdr.py +++ b/owrx/controllers/settings/sdr.py @@ -71,7 +71,7 @@ class SdrDeviceController(SettingsFormController): def getSections(self): try: description = SdrDeviceDescription.getByType(self.device["type"]) - return [description.getSection()] + return [description.getSection(self.device)] except SdrDeviceDescriptionMissing: # TODO provide a generic interface that allows to switch the type return [] diff --git a/owrx/source/__init__.py b/owrx/source/__init__.py index 423a8b7..ecea90d 100644 --- a/owrx/source/__init__.py +++ b/owrx/source/__init__.py @@ -376,6 +376,9 @@ class SdrDeviceDescriptionMissing(Exception): class SdrDeviceDescription(object): + def __init__(self): + self.indexedInputs = {input.id: input for input in self.getInputs()} + @staticmethod def getByType(sdr_type: str) -> "SdrDeviceDescription": try: @@ -423,10 +426,14 @@ class SdrDeviceDescription(object): # TODO `schedule` ] - def mergeInputs(self, *args): - # build a dictionary indexed by the input id to make sure every id only exists once - inputs = {input.id: input for input_list in args for input in input_list} - return inputs.values() + def getMandatoryKeys(self): + return ["name", "enabled"] - def getSection(self): - return Section("Device settings", *self.getInputs()) + def getOptionalKeys(self): + return ["ppm", "always-on", "services", "rf_gain", "lfo_offset", "waterfall_min_level", "waterfall_max_level"] + + def getSection(self, data): + visible_keys = set(self.getMandatoryKeys() + [k for k in self.getOptionalKeys() if k in data]) + inputs = [input for k, input in self.indexedInputs.items() if k in visible_keys] + # TODO: render remaining keys in optional area + return Section("Device settings", *inputs) diff --git a/owrx/source/airspy.py b/owrx/source/airspy.py index 773d8b2..70005be 100644 --- a/owrx/source/airspy.py +++ b/owrx/source/airspy.py @@ -22,17 +22,21 @@ class AirspySource(SoapyConnectorSource): class AirspyDeviceDescription(SoapyConnectorDeviceDescription): def getInputs(self) -> List[Input]: - return self.mergeInputs( - super().getInputs(), - [ - BiasTeeInput(), - CheckboxInput( - "bitpack", - "", - checkboxText="Enable bit-packing", - infotext="Packs two 12-bit samples into 3 bytes." - + " Lowers USB bandwidth consumption, increases CPU load", - converter=OptionalConverter(defaultFormValue=False), - ), - ], - ) + return super().getInputs() + [ + BiasTeeInput(), + CheckboxInput( + "bitpack", + "", + checkboxText="Enable bit-packing", + infotext="Packs two 12-bit samples into 3 bytes." + + " Lowers USB bandwidth consumption, increases CPU load", + converter=OptionalConverter(defaultFormValue=False), + ), + ] + + def getOptionalKeys(self): + return super().getOptionalKeys() + ["bias_tee", "bitpack"] + + # TODO: find actual gain stages for airspay + # def getGainStages(self): + # return None diff --git a/owrx/source/connector.py b/owrx/source/connector.py index 40fd795..10d6bcb 100644 --- a/owrx/source/connector.py +++ b/owrx/source/connector.py @@ -76,23 +76,23 @@ class ConnectorSource(SdrSource): class ConnectorDeviceDescription(SdrDeviceDescription): def getInputs(self) -> List[Input]: - return self.mergeInputs( - super().getInputs(), - [ - NumberInput( - "rtltcp_compat", - "Port for rtl_tcp compatible data", - infotext="Activate an rtl_tcp compatible interface on the port number specified.
" - + "Note: Port is only available on the local machine, not on the network.
" - + "Note: IQ data may be degraded by the downsampling process to 8 bits.", - converter=OptionalConverter(IntConverter()), - ), - CheckboxInput( - "iqswap", - "", - checkboxText="Swap I and Q channels", - infotext="Swapping inverts the spectrum, so this is useful in combination with an inverting mixer", - converter=OptionalConverter(defaultFormValue=False), - ), - ], - ) + return super().getInputs() + [ + NumberInput( + "rtltcp_compat", + "Port for rtl_tcp compatible data", + infotext="Activate an rtl_tcp compatible interface on the port number specified.
" + + "Note: Port is only available on the local machine, not on the network.
" + + "Note: IQ data may be degraded by the downsampling process to 8 bits.", + converter=OptionalConverter(IntConverter()), + ), + CheckboxInput( + "iqswap", + "", + checkboxText="Swap I and Q channels", + infotext="Swapping inverts the spectrum, so this is useful in combination with an inverting mixer", + converter=OptionalConverter(defaultFormValue=False), + ), + ] + + def getOptionalKeys(self): + return super().getOptionalKeys() + ["rtltcp_compat", "iqswap"] diff --git a/owrx/source/hackrf.py b/owrx/source/hackrf.py index f597168..978d152 100644 --- a/owrx/source/hackrf.py +++ b/owrx/source/hackrf.py @@ -16,4 +16,11 @@ class HackrfSource(SoapyConnectorSource): class HackrfDeviceDescription(SoapyConnectorDeviceDescription): def getInputs(self) -> List[Input]: - return self.mergeInputs(super().getInputs(), [BiasTeeInput()]) + return super().getInputs() + [BiasTeeInput()] + + def getOptionalKeys(self): + return super().getOptionalKeys() + ["bias_tee"] + + # TODO: find actual gain stages for hackrf + # def getGainStages(self): + # return None diff --git a/owrx/source/rtl_sdr.py b/owrx/source/rtl_sdr.py index 91b97b5..a01e41d 100644 --- a/owrx/source/rtl_sdr.py +++ b/owrx/source/rtl_sdr.py @@ -18,16 +18,16 @@ class RtlSdrSource(ConnectorSource): class RtlSdrDeviceDescription(ConnectorDeviceDescription): def getInputs(self) -> List[Input]: - return self.mergeInputs( - super().getInputs(), - [ - TextInput( - "device", - "Device identifier", - infotext="Device serial number or index", - converter=OptionalConverter(), - ), - BiasTeeInput(), - DirectSamplingInput() - ], - ) + return super().getInputs() + [ + TextInput( + "device", + "Device identifier", + infotext="Device serial number or index", + converter=OptionalConverter(), + ), + BiasTeeInput(), + DirectSamplingInput() + ] + + def getOptionalKeys(self): + return super().getOptionalKeys() + ["device", "bias_tee", "direct_sampling"] diff --git a/owrx/source/rtl_sdr_soapy.py b/owrx/source/rtl_sdr_soapy.py index fec40bd..0257810 100644 --- a/owrx/source/rtl_sdr_soapy.py +++ b/owrx/source/rtl_sdr_soapy.py @@ -16,4 +16,7 @@ class RtlSdrSoapySource(SoapyConnectorSource): class RtlSdrSoapyDeviceDescription(SoapyConnectorDeviceDescription): def getInputs(self) -> List[Input]: - return self.mergeInputs(super().getInputs(), [BiasTeeInput(), DirectSamplingInput()]) + return super().getInputs() + [BiasTeeInput(), DirectSamplingInput()] + + def getOptionalKeys(self): + return super().getOptionalKeys() + ["bias_tee", "direct_sampling"] diff --git a/owrx/source/rtl_tcp.py b/owrx/source/rtl_tcp.py index ef80c38..5bf2712 100644 --- a/owrx/source/rtl_tcp.py +++ b/owrx/source/rtl_tcp.py @@ -23,4 +23,7 @@ class RtlTcpSource(ConnectorSource): class RtlTcpDeviceDescription(ConnectorDeviceDescription): def getInputs(self) -> List[Input]: - return self.mergeInputs(super().getInputs(), [RemoteInput()]) + return super().getInputs() + [RemoteInput()] + + def getMandatoryKeys(self): + return super().getMandatoryKeys() + ["device"] diff --git a/owrx/source/runds.py b/owrx/source/runds.py index d820dfd..9b33da5 100644 --- a/owrx/source/runds.py +++ b/owrx/source/runds.py @@ -39,13 +39,13 @@ class ProtocolOptions(DropdownEnum): class RundsDeviceDescription(ConnectorDeviceDescription): def getInputs(self) -> List[Input]: - return self.mergeInputs( - super().getInputs(), - [ - RemoteInput(), - DropdownInput("protocol", "Protocol", ProtocolOptions), - CheckboxInput( - "long", "", "Use 32-bit sample size (LONG)", converter=OptionalConverter(defaultFormValue=False) - ), - ], - ) + return super().getInputs() + [ + RemoteInput(), + DropdownInput("protocol", "Protocol", ProtocolOptions), + CheckboxInput( + "long", "", "Use 32-bit sample size (LONG)", converter=OptionalConverter(defaultFormValue=False) + ), + ] + + def getMandatoryKeys(self): + return super().getMandatoryKeys() + ["device"] diff --git a/owrx/source/sdrplay.py b/owrx/source/sdrplay.py index 5cf5587..63b0cef 100644 --- a/owrx/source/sdrplay.py +++ b/owrx/source/sdrplay.py @@ -38,29 +38,29 @@ class SdrplayDeviceDescription(SoapyConnectorDeviceDescription): return ["RFGR", "IFGR"] def getInputs(self) -> List[Input]: - return self.mergeInputs( - super().getInputs(), - [ - BiasTeeInput(), - CheckboxInput( - "rf_notch", - "", - checkboxText="Enable RF notch filter", - converter=OptionalConverter(defaultFormValue=True), + return super().getInputs() + [ + BiasTeeInput(), + CheckboxInput( + "rf_notch", + "", + checkboxText="Enable RF notch filter", + converter=OptionalConverter(defaultFormValue=True), + ), + CheckboxInput( + "dab_notch", + "", + checkboxText="Enable DAB notch filter", + converter=OptionalConverter(defaultFormValue=True), + ), + DropdownInput( + "if_mode", + "IF Mode", + IfModeOptions, + converter=OptionalConverter( + EnumConverter(IfModeOptions), defaultFormValue=IfModeOptions.IFMODE_ZERO_IF.name ), - CheckboxInput( - "dab_notch", - "", - checkboxText="Enable DAB notch filter", - converter=OptionalConverter(defaultFormValue=True), - ), - DropdownInput( - "if_mode", - "IF Mode", - IfModeOptions, - converter=OptionalConverter( - EnumConverter(IfModeOptions), defaultFormValue=IfModeOptions.IFMODE_ZERO_IF.name - ), - ), - ], - ) + ), + ] + + def getOptionalKeys(self): + return super().getOptionalKeys() + ["bias_tee", "rf_notch", "dab_notch", "if_mode"] diff --git a/owrx/source/soapy.py b/owrx/source/soapy.py index 8e4778b..0db1c45 100644 --- a/owrx/source/soapy.py +++ b/owrx/source/soapy.py @@ -84,27 +84,27 @@ class SoapyConnectorSource(ConnectorSource, metaclass=ABCMeta): class SoapyConnectorDeviceDescription(ConnectorDeviceDescription): def getInputs(self) -> List[Input]: - return self.mergeInputs( - super().getInputs(), - [ - TextInput( - "device", - "Device Identifier", - infotext='SoapySDR device identifier string (example: "serial=123456789")', - converter=OptionalConverter() - ), - GainInput( - "rf_gain", - "Device Gain", - gain_stages=self.getGainStages(), - ), - TextInput( - "antenna", - "Antenna", - converter=OptionalConverter(), - ), - ], - ) + return super().getInputs() + [ + TextInput( + "device", + "Device Identifier", + infotext='SoapySDR device identifier string (example: "serial=123456789")', + converter=OptionalConverter() + ), + GainInput( + "rf_gain", + "Device Gain", + gain_stages=self.getGainStages(), + ), + TextInput( + "antenna", + "Antenna", + converter=OptionalConverter(), + ), + ] + + def getOptionalKeys(self): + return super().getOptionalKeys() + ["device", "rf_gain", "antenna"] def getGainStages(self): return None diff --git a/owrx/source/soapy_remote.py b/owrx/source/soapy_remote.py index 080ee7d..19be5a5 100644 --- a/owrx/source/soapy_remote.py +++ b/owrx/source/soapy_remote.py @@ -22,12 +22,12 @@ class SoapyRemoteSource(SoapyConnectorSource): class SoapyRemoteDeviceDescription(SoapyConnectorDeviceDescription): def getInputs(self) -> List[Input]: - return self.mergeInputs( - super().getInputs(), - [ - RemoteInput(), - TextInput( - "remote_driver", "Remote driver", infotext="SoapySDR driver to be used on the remote SoapySDRServer" - ), - ], - ) + return super().getInputs() + [ + RemoteInput(), + TextInput( + "remote_driver", "Remote driver", infotext="SoapySDR driver to be used on the remote SoapySDRServer" + ), + ] + + def getOptionalKeys(self): + return super().getOptionalKeys() + ["remote_driver"]