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 """
""".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 """
+
+ {inputs}
+
+ """.format(
+ inputs="".join(
+ """
+
+ """.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