add more inputs, bind to actual data
This commit is contained in:
		| @@ -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 """ | ||||
|             <div class="col-12 settings-section"> | ||||
|                 <h3 class="settings-header"> | ||||
| @@ -23,7 +22,7 @@ class Section(object): | ||||
|                 {inputs} | ||||
|             </div> | ||||
|         """.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 """ | ||||
|             <form class="settings-body" method="POST"> | ||||
|                 {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) | ||||
|   | ||||
| @@ -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"]) | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
							
								
								
									
										13
									
								
								owrx/form/soapy.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								owrx/form/soapy.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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..." | ||||
| @@ -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"}), | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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.<br />" | ||||
|                     + "Note: Port is only available on the local machine, not on the network.<br />" | ||||
|                     + "Note: IQ data may be degraded by the downsampling process to 8 bits.", | ||||
|                     converter=OptionalConverter(IntConverter()), | ||||
|                 ) | ||||
|             ], | ||||
|         ) | ||||
|   | ||||
| @@ -20,4 +20,5 @@ class SdrplaySource(SoapyConnectorSource): | ||||
|  | ||||
|  | ||||
| class SdrplayDeviceDescription(SoapyConnectorDeviceDescription): | ||||
|     pass | ||||
|     def getGainStages(self): | ||||
|         return ["RFGR", "IFGR"] | ||||
|   | ||||
| @@ -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 [] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jakob Ketterl
					Jakob Ketterl