diff --git a/owrx/controllers/settings/__init__.py b/owrx/controllers/settings/__init__.py index 9800801..030e9fc 100644 --- a/owrx/controllers/settings/__init__.py +++ b/owrx/controllers/settings/__init__.py @@ -10,11 +10,10 @@ class Section(object): self.title = title self.inputs = inputs - def render_inputs(self): - config = Config.get() - return "".join([i.render(config) for i in self.inputs]) + def render_inputs(self, data): + return "".join([i.render(data) for i in self.inputs]) - def render(self): + def render(self, data): return """

@@ -23,7 +22,7 @@ class Section(object): {inputs}

""".format( - title=self.title, inputs=self.render_inputs() + title=self.title, inputs=self.render_inputs(data) ) def parse(self, data): @@ -44,8 +43,11 @@ class SettingsFormController(AuthorizationMixin, WebpageController, metaclass=AB def getTitle(self): pass + def getData(self): + return Config.get() + def render_sections(self): - sections = "".join(section.render() for section in self.getSections()) + sections = "".join(section.render(self.getData()) for section in self.getSections()) return """
{sections} @@ -78,6 +80,7 @@ class SettingsFormController(AuthorizationMixin, WebpageController, metaclass=AB def processFormData(self): self.processData(self.parseFormData()) + self.send_redirect(self.request.path) def processData(self, data): config = Config.get() @@ -88,4 +91,3 @@ class SettingsFormController(AuthorizationMixin, WebpageController, metaclass=AB else: config[k] = v config.store() - self.send_redirect(self.request.path) diff --git a/owrx/controllers/settings/sdr.py b/owrx/controllers/settings/sdr.py index f490ef8..0b9f940 100644 --- a/owrx/controllers/settings/sdr.py +++ b/owrx/controllers/settings/sdr.py @@ -5,6 +5,10 @@ from owrx.source import SdrDeviceDescription, SdrDeviceDescriptionMissing from owrx.config import Config from urllib.parse import quote, unquote +import logging + +logger = logging.getLogger(__name__) + class SdrDeviceListController(AuthorizationMixin, WebpageController): def header_variables(self): @@ -52,6 +56,13 @@ class SdrDeviceController(SettingsFormController): super().__init__(handler, request, options) self.device = self._get_device() + def getData(self): + return self.device + + def processData(self, data): + # TODO implement storing of data here + logger.debug(data) + def getSections(self): try: description = SdrDeviceDescription.getByType(self.device["type"]) diff --git a/owrx/form/__init__.py b/owrx/form/__init__.py index 5323cc0..27ad9ed 100644 --- a/owrx/form/__init__.py +++ b/owrx/form/__init__.py @@ -139,8 +139,8 @@ class TextAreaInput(Input): class CheckboxInput(Input): - def __init__(self, id, label, checkboxText, infotext=None): - super().__init__(id, label, infotext=infotext) + def __init__(self, id, label, checkboxText, infotext=None, converter: Converter = None): + super().__init__(id, label, infotext=infotext, converter=converter) self.checkboxText = checkboxText def render_input(self, value): @@ -162,7 +162,7 @@ class CheckboxInput(Input): return " ".join(["form-check", "form-control-sm"]) def parse(self, data): - return {self.id: self.id in data and data[self.id][0] == "on"} + return {self.id: self.converter.convert_from_form(self.id in data and data[self.id][0] == "on")} class Option(object): diff --git a/owrx/form/converter.py b/owrx/form/converter.py index 580b368..d825cc5 100644 --- a/owrx/form/converter.py +++ b/owrx/form/converter.py @@ -22,15 +22,21 @@ class NullConverter(Converter): class OptionalConverter(Converter): """ - Maps None to an empty string, and reverse - useful for optional fields + Transforms a special form value to None + The default is look for an empty string, but this can be used to adopt to other types. + If the default is not found, the actual value is passed to the sub_converter for further transformation. + useful for optional fields since None is not stored in the configuration """ + def __init__(self, sub_converter: Converter = None, defaultFormValue=""): + self.sub_converter = NullConverter() if sub_converter is None else sub_converter + self.defaultFormValue = defaultFormValue + def convert_to_form(self, value): - return "" if value is None else value + return self.defaultFormValue if value is None else self.sub_converter.convert_to_form(value) def convert_from_form(self, value): - return value if value else None + return None if value == self.defaultFormValue else self.sub_converter.convert_to_form(value) class IntConverter(Converter): diff --git a/owrx/form/soapy.py b/owrx/form/soapy.py new file mode 100644 index 0000000..6580585 --- /dev/null +++ b/owrx/form/soapy.py @@ -0,0 +1,13 @@ +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/http.py b/owrx/http.py index 9360fb6..7fd53b0 100644 --- a/owrx/http.py +++ b/owrx/http.py @@ -117,6 +117,7 @@ class Router(object): ), StaticRoute("/settings/sdr", SdrDeviceListController), RegexRoute("/settings/sdr/(.+)", SdrDeviceController), + RegexRoute("/settings/sdr/(.+)", SdrDeviceController, method="POST", options={"action": "processFormData"}), StaticRoute("/settings/bookmarks", BookmarksController), StaticRoute("/settings/bookmarks", BookmarksController, method="POST", options={"action": "new"}), RegexRoute("/settings/bookmarks/(.+)", BookmarksController, method="POST", options={"action": "update"}), diff --git a/owrx/source/__init__.py b/owrx/source/__init__.py index f03e752..dfaa449 100644 --- a/owrx/source/__init__.py +++ b/owrx/source/__init__.py @@ -10,7 +10,8 @@ from abc import ABC, abstractmethod from owrx.command import CommandMapper from owrx.socket import getAvailablePort from owrx.property import PropertyStack, PropertyLayer -from owrx.form import Input, TextInput, NumberInput, CheckboxInput +from owrx.form import Input, TextInput, NumberInput, CheckboxInput, FloatInput +from owrx.form.converter import IntConverter, OptionalConverter from owrx.controllers.settings import Section from typing import List @@ -375,14 +376,25 @@ class SdrDeviceDescription(object): def getInputs(self) -> List[Input]: return [ TextInput("name", "Device name"), - NumberInput("ppm", "Frequency correction", append="ppm"), + NumberInput( + "ppm", + "Frequency correction", + append="ppm", + converter=OptionalConverter(IntConverter(), defaultFormValue="0"), + ), CheckboxInput( "always-on", "", checkboxText="Keep device running at all times", - infotext="Prevents shutdown of the device when idle. Useful for devices with unreliable startup." + infotext="Prevents shutdown of the device when idle. Useful for devices with unreliable startup.", ), - CheckboxInput("services", "", "Run services on this device"), + CheckboxInput( + "services", + "", + "Run background services on this device", + converter=OptionalConverter(defaultFormValue=True), + ), + FloatInput("rf_gain", "Device gain"), ] def mergeInputs(self, *args): diff --git a/owrx/source/connector.py b/owrx/source/connector.py index 60ce212..f757d7c 100644 --- a/owrx/source/connector.py +++ b/owrx/source/connector.py @@ -4,6 +4,7 @@ import socket from owrx.command import Flag, Option from typing import List from owrx.form import Input, NumberInput +from owrx.form.converter import OptionalConverter, IntConverter import logging @@ -84,6 +85,7 @@ class ConnectorDeviceDescription(SdrDeviceDescription): 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()), ) ], ) diff --git a/owrx/source/sdrplay.py b/owrx/source/sdrplay.py index 5b3ef23..0012140 100644 --- a/owrx/source/sdrplay.py +++ b/owrx/source/sdrplay.py @@ -20,4 +20,5 @@ class SdrplaySource(SoapyConnectorSource): class SdrplayDeviceDescription(SoapyConnectorDeviceDescription): - pass + def getGainStages(self): + return ["RFGR", "IFGR"] diff --git a/owrx/source/soapy.py b/owrx/source/soapy.py index d9c4b2e..e19833a 100644 --- a/owrx/source/soapy.py +++ b/owrx/source/soapy.py @@ -3,6 +3,7 @@ from owrx.command import Option from owrx.source.connector import ConnectorSource, ConnectorDeviceDescription from typing import List from owrx.form import Input, TextInput +from owrx.form.soapy import SoapyGainInput class SoapyConnectorSource(ConnectorSource, metaclass=ABCMeta): @@ -108,5 +109,13 @@ class SoapyConnectorDeviceDescription(ConnectorDeviceDescription): "Device Identifier", infotext='SoapySDR device identifier string (example: "serial=123456789")', ), + SoapyGainInput( + "rf_gain", + "Device Gain", + gain_stages=self.getGainStages(), + ), ], ) + + def getGainStages(self): + return []