diff --git a/owrx/form/device.py b/owrx/form/device.py index 1da6791..d9f7653 100644 --- a/owrx/form/device.py +++ b/owrx/form/device.py @@ -1,33 +1,113 @@ from owrx.form import Input +from owrx.soapy import SoapySettings class GainInput(Input): - def render_input(self, value): - auto_mode = value is None or value == "auto" + def __init__(self, id, label, gain_stages=None): + super().__init__(id, label) + self.gain_stages = gain_stages + def render_input(self, value): return """
+ {stageoption}
""".format( id=self.id, classes=self.input_classes(), - value=value, + value="0.0" if value is None else value, label=self.label, - auto_selected="selected" if auto_mode else "", - manual_selected="" if auto_mode else "selected", + options=self.render_options(value), + stageoption=self.render_stage_option(value), + ) + + def render_options(self, value): + options = [ + ("auto", "Enable hardware AGC"), + ("manual", "Specify manual gain"), + ] + if self.gain_stages: + options.append(("stages", "Specify gain stages individually")) + + mode = self.getMode(value) + + return "".join( + """ + + """.format( + value=v[0], + text=v[1], + selected="selected" if mode == v[0] else "" + ) + for v in options + ) + + def getMode(self, value): + if value is None or value == "auto": + return "auto" + + try: + float(value) + return "manual" + except ValueError: + pass + + return "stages" + + def render_stage_option(self, value): + try: + value_dict = {k: v for item in SoapySettings.parse(value) for k, v in item.items()} + except (AttributeError, ValueError): + value_dict = {} + + return """ + + """.format( + inputs="".join( + """ +
+
{stage}
+ +
+ """.format( + id=self.id, + stage=stage, + value=value_dict[stage] if stage in value_dict else "", + classes=self.input_classes(), + ) + for stage in self.gain_stages + ) ) def parse(self, data): + def getStageValue(stage): + input_id = "{id}-{stage}".format(id=self.id, stage=stage) + if input_id in data: + return data[input_id][0] + else: + return 0.0 + select_id = "{id}-select".format(id=self.id) if select_id in data: - input_id = "{id}-manual".format(id=self.id) - if data[select_id][0] == "manual" and input_id in data: - return {self.id: float(data[input_id][0])} + if data[select_id][0] == "manual": + input_id = "{id}-manual".format(id=self.id) + value = 0.0 + if input_id in data: + try: + value = float(float(data[input_id][0])) + except ValueError: + pass + return {self.id: value} + if data[select_id][0] == "stages": + settings_dict = [{s: getStageValue(s)} for s in self.gain_stages] + return {self.id: SoapySettings.encode(settings_dict)} + return {self.id: None} diff --git a/owrx/form/soapy.py b/owrx/form/soapy.py deleted file mode 100644 index 6580585..0000000 --- a/owrx/form/soapy.py +++ /dev/null @@ -1,13 +0,0 @@ -from owrx.form import FloatInput - - -class SoapyGainInput(FloatInput): - def __init__(self, id, label, gain_stages): - super().__init__(id, label) - self.gain_stages = gain_stages - - def render_input(self, value): - if not self.gain_stages: - return super().render_input(value) - # TODO implement input for multiple gain stages here - return "soapy gain stages here..." diff --git a/owrx/soapy.py b/owrx/soapy.py new file mode 100644 index 0000000..25b5f35 --- /dev/null +++ b/owrx/soapy.py @@ -0,0 +1,21 @@ +class SoapySettings(object): + @staticmethod + def parse(dstr): + def decodeComponent(c): + kv = c.split("=", 1) + if len(kv) < 2: + return c + else: + return {kv[0]: kv[1]} + + return [decodeComponent(c) for c in dstr.split(",")] + + @staticmethod + def encode(dobj): + def encodeComponent(c): + if isinstance(c, str): + return c + else: + return ",".join(["{0}={1}".format(key, value) for key, value in c.items()]) + + return ",".join([encodeComponent(c) for c in dobj]) diff --git a/owrx/source/soapy.py b/owrx/source/soapy.py index b68636a..7603402 100644 --- a/owrx/source/soapy.py +++ b/owrx/source/soapy.py @@ -4,7 +4,8 @@ from owrx.source.connector import ConnectorSource, ConnectorDeviceDescription from typing import List from owrx.form import Input, TextInput from owrx.form.converter import OptionalConverter -from owrx.form.soapy import SoapyGainInput +from owrx.form.device import GainInput +from owrx.soapy import SoapySettings class SoapyConnectorSource(ConnectorSource, metaclass=ABCMeta): @@ -33,25 +34,6 @@ class SoapyConnectorSource(ConnectorSource, metaclass=ABCMeta): def getEventNames(self): return super().getEventNames() + list(self.getSoapySettingsMappings().keys()) - def parseDeviceString(self, dstr): - def decodeComponent(c): - kv = c.split("=", 1) - if len(kv) < 2: - return c - else: - return {kv[0]: kv[1]} - - return [decodeComponent(c) for c in dstr.split(",")] - - def encodeDeviceString(self, dobj): - def encodeComponent(c): - if isinstance(c, str): - return c - else: - return ",".join(["{0}={1}".format(key, value) for key, value in c.items()]) - - return ",".join([encodeComponent(c) for c in dobj]) - def buildSoapyDeviceParameters(self, parsed, values): """ this method always attempts to inject a driver= part into the soapysdr query, depending on what connector was used. @@ -79,11 +61,11 @@ class SoapyConnectorSource(ConnectorSource, metaclass=ABCMeta): def getCommandValues(self): values = super().getCommandValues() if "device" in values and values["device"] is not None: - parsed = self.parseDeviceString(values["device"]) + parsed = SoapySettings.parse(values["device"]) else: parsed = [] modified = self.buildSoapyDeviceParameters(parsed, values) - values["device"] = self.encodeDeviceString(modified) + values["device"] = SoapySettings.encode(modified) settings = ",".join(["{0}={1}".format(k, v) for k, v in self.buildSoapySettings(values).items()]) if len(settings): values["soapy_settings"] = settings @@ -111,7 +93,7 @@ class SoapyConnectorDeviceDescription(ConnectorDeviceDescription): infotext='SoapySDR device identifier string (example: "serial=123456789")', converter=OptionalConverter() ), - SoapyGainInput( + GainInput( "rf_gain", "Device Gain", gain_stages=self.getGainStages(), @@ -120,4 +102,4 @@ class SoapyConnectorDeviceDescription(ConnectorDeviceDescription): ) def getGainStages(self): - return [] + return None