introduce the basic concept of optional keys

This commit is contained in:
Jakob Ketterl 2021-02-22 00:35:47 +01:00
parent 683a711b49
commit 770fd749cd
12 changed files with 146 additions and 122 deletions

View File

@ -71,7 +71,7 @@ class SdrDeviceController(SettingsFormController):
def getSections(self): def getSections(self):
try: try:
description = SdrDeviceDescription.getByType(self.device["type"]) description = SdrDeviceDescription.getByType(self.device["type"])
return [description.getSection()] return [description.getSection(self.device)]
except SdrDeviceDescriptionMissing: except SdrDeviceDescriptionMissing:
# TODO provide a generic interface that allows to switch the type # TODO provide a generic interface that allows to switch the type
return [] return []

View File

@ -376,6 +376,9 @@ class SdrDeviceDescriptionMissing(Exception):
class SdrDeviceDescription(object): class SdrDeviceDescription(object):
def __init__(self):
self.indexedInputs = {input.id: input for input in self.getInputs()}
@staticmethod @staticmethod
def getByType(sdr_type: str) -> "SdrDeviceDescription": def getByType(sdr_type: str) -> "SdrDeviceDescription":
try: try:
@ -423,10 +426,14 @@ class SdrDeviceDescription(object):
# TODO `schedule` # TODO `schedule`
] ]
def mergeInputs(self, *args): def getMandatoryKeys(self):
# build a dictionary indexed by the input id to make sure every id only exists once return ["name", "enabled"]
inputs = {input.id: input for input_list in args for input in input_list}
return inputs.values()
def getSection(self): def getOptionalKeys(self):
return Section("Device settings", *self.getInputs()) 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)

View File

@ -22,17 +22,21 @@ class AirspySource(SoapyConnectorSource):
class AirspyDeviceDescription(SoapyConnectorDeviceDescription): class AirspyDeviceDescription(SoapyConnectorDeviceDescription):
def getInputs(self) -> List[Input]: def getInputs(self) -> List[Input]:
return self.mergeInputs( return super().getInputs() + [
super().getInputs(), BiasTeeInput(),
[ CheckboxInput(
BiasTeeInput(), "bitpack",
CheckboxInput( "",
"bitpack", checkboxText="Enable bit-packing",
"", infotext="Packs two 12-bit samples into 3 bytes."
checkboxText="Enable bit-packing", + " Lowers USB bandwidth consumption, increases CPU load",
infotext="Packs two 12-bit samples into 3 bytes." converter=OptionalConverter(defaultFormValue=False),
+ " 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

View File

@ -76,23 +76,23 @@ class ConnectorSource(SdrSource):
class ConnectorDeviceDescription(SdrDeviceDescription): class ConnectorDeviceDescription(SdrDeviceDescription):
def getInputs(self) -> List[Input]: def getInputs(self) -> List[Input]:
return self.mergeInputs( return super().getInputs() + [
super().getInputs(), NumberInput(
[ "rtltcp_compat",
NumberInput( "Port for rtl_tcp compatible data",
"rtltcp_compat", infotext="Activate an rtl_tcp compatible interface on the port number specified.<br />"
"Port for rtl_tcp compatible data", + "Note: Port is only available on the local machine, not on the network.<br />"
infotext="Activate an rtl_tcp compatible interface on the port number specified.<br />" + "Note: IQ data may be degraded by the downsampling process to 8 bits.",
+ "Note: Port is only available on the local machine, not on the network.<br />" converter=OptionalConverter(IntConverter()),
+ "Note: IQ data may be degraded by the downsampling process to 8 bits.", ),
converter=OptionalConverter(IntConverter()), CheckboxInput(
), "iqswap",
CheckboxInput( "",
"iqswap", checkboxText="Swap I and Q channels",
"", infotext="Swapping inverts the spectrum, so this is useful in combination with an inverting mixer",
checkboxText="Swap I and Q channels", converter=OptionalConverter(defaultFormValue=False),
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"]

View File

@ -16,4 +16,11 @@ class HackrfSource(SoapyConnectorSource):
class HackrfDeviceDescription(SoapyConnectorDeviceDescription): class HackrfDeviceDescription(SoapyConnectorDeviceDescription):
def getInputs(self) -> List[Input]: 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

View File

@ -18,16 +18,16 @@ class RtlSdrSource(ConnectorSource):
class RtlSdrDeviceDescription(ConnectorDeviceDescription): class RtlSdrDeviceDescription(ConnectorDeviceDescription):
def getInputs(self) -> List[Input]: def getInputs(self) -> List[Input]:
return self.mergeInputs( return super().getInputs() + [
super().getInputs(), TextInput(
[ "device",
TextInput( "Device identifier",
"device", infotext="Device serial number or index",
"Device identifier", converter=OptionalConverter(),
infotext="Device serial number or index", ),
converter=OptionalConverter(), BiasTeeInput(),
), DirectSamplingInput()
BiasTeeInput(), ]
DirectSamplingInput()
], def getOptionalKeys(self):
) return super().getOptionalKeys() + ["device", "bias_tee", "direct_sampling"]

View File

@ -16,4 +16,7 @@ class RtlSdrSoapySource(SoapyConnectorSource):
class RtlSdrSoapyDeviceDescription(SoapyConnectorDeviceDescription): class RtlSdrSoapyDeviceDescription(SoapyConnectorDeviceDescription):
def getInputs(self) -> List[Input]: 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"]

View File

@ -23,4 +23,7 @@ class RtlTcpSource(ConnectorSource):
class RtlTcpDeviceDescription(ConnectorDeviceDescription): class RtlTcpDeviceDescription(ConnectorDeviceDescription):
def getInputs(self) -> List[Input]: def getInputs(self) -> List[Input]:
return self.mergeInputs(super().getInputs(), [RemoteInput()]) return super().getInputs() + [RemoteInput()]
def getMandatoryKeys(self):
return super().getMandatoryKeys() + ["device"]

View File

@ -39,13 +39,13 @@ class ProtocolOptions(DropdownEnum):
class RundsDeviceDescription(ConnectorDeviceDescription): class RundsDeviceDescription(ConnectorDeviceDescription):
def getInputs(self) -> List[Input]: def getInputs(self) -> List[Input]:
return self.mergeInputs( return super().getInputs() + [
super().getInputs(), RemoteInput(),
[ DropdownInput("protocol", "Protocol", ProtocolOptions),
RemoteInput(), CheckboxInput(
DropdownInput("protocol", "Protocol", ProtocolOptions), "long", "", "Use 32-bit sample size (LONG)", converter=OptionalConverter(defaultFormValue=False)
CheckboxInput( ),
"long", "", "Use 32-bit sample size (LONG)", converter=OptionalConverter(defaultFormValue=False) ]
),
], def getMandatoryKeys(self):
) return super().getMandatoryKeys() + ["device"]

View File

@ -38,29 +38,29 @@ class SdrplayDeviceDescription(SoapyConnectorDeviceDescription):
return ["RFGR", "IFGR"] return ["RFGR", "IFGR"]
def getInputs(self) -> List[Input]: def getInputs(self) -> List[Input]:
return self.mergeInputs( return super().getInputs() + [
super().getInputs(), BiasTeeInput(),
[ CheckboxInput(
BiasTeeInput(), "rf_notch",
CheckboxInput( "",
"rf_notch", checkboxText="Enable RF notch filter",
"", converter=OptionalConverter(defaultFormValue=True),
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", def getOptionalKeys(self):
converter=OptionalConverter(defaultFormValue=True), return super().getOptionalKeys() + ["bias_tee", "rf_notch", "dab_notch", "if_mode"]
),
DropdownInput(
"if_mode",
"IF Mode",
IfModeOptions,
converter=OptionalConverter(
EnumConverter(IfModeOptions), defaultFormValue=IfModeOptions.IFMODE_ZERO_IF.name
),
),
],
)

View File

@ -84,27 +84,27 @@ class SoapyConnectorSource(ConnectorSource, metaclass=ABCMeta):
class SoapyConnectorDeviceDescription(ConnectorDeviceDescription): class SoapyConnectorDeviceDescription(ConnectorDeviceDescription):
def getInputs(self) -> List[Input]: def getInputs(self) -> List[Input]:
return self.mergeInputs( return super().getInputs() + [
super().getInputs(), TextInput(
[ "device",
TextInput( "Device Identifier",
"device", infotext='SoapySDR device identifier string (example: "serial=123456789")',
"Device Identifier", converter=OptionalConverter()
infotext='SoapySDR device identifier string (example: "serial=123456789")', ),
converter=OptionalConverter() GainInput(
), "rf_gain",
GainInput( "Device Gain",
"rf_gain", gain_stages=self.getGainStages(),
"Device Gain", ),
gain_stages=self.getGainStages(), TextInput(
), "antenna",
TextInput( "Antenna",
"antenna", converter=OptionalConverter(),
"Antenna", ),
converter=OptionalConverter(), ]
),
], def getOptionalKeys(self):
) return super().getOptionalKeys() + ["device", "rf_gain", "antenna"]
def getGainStages(self): def getGainStages(self):
return None return None

View File

@ -22,12 +22,12 @@ class SoapyRemoteSource(SoapyConnectorSource):
class SoapyRemoteDeviceDescription(SoapyConnectorDeviceDescription): class SoapyRemoteDeviceDescription(SoapyConnectorDeviceDescription):
def getInputs(self) -> List[Input]: def getInputs(self) -> List[Input]:
return self.mergeInputs( return super().getInputs() + [
super().getInputs(), RemoteInput(),
[ TextInput(
RemoteInput(), "remote_driver", "Remote driver", infotext="SoapySDR driver to be used on the remote SoapySDRServer"
TextInput( ),
"remote_driver", "Remote driver", infotext="SoapySDR driver to be used on the remote SoapySDRServer" ]
),
], def getOptionalKeys(self):
) return super().getOptionalKeys() + ["remote_driver"]