From 3b8324d3f44c5bcd79110aff2b9a1ecfe7573709 Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Sun, 15 Oct 2023 17:31:59 +0700 Subject: [PATCH 01/12] add support of soapy afedri driver --- owrx/feature.py | 9 +++++ owrx/source/afedri.py | 87 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 owrx/source/afedri.py diff --git a/owrx/feature.py b/owrx/feature.py index bcb73d2b..92c03e57 100644 --- a/owrx/feature.py +++ b/owrx/feature.py @@ -61,6 +61,7 @@ class FeatureDetector(object): "perseussdr": ["perseustest", "nmux"], "airspy": ["soapy_connector", "soapy_airspy"], "airspyhf": ["soapy_connector", "soapy_airspyhf"], + "afedri": ["soapy_connector", "soapy_afedri"], "lime_sdr": ["soapy_connector", "soapy_lime_sdr"], "fifi_sdr": ["alsa", "rockprog", "nmux"], "pluto_sdr": ["soapy_connector", "soapy_pluto_sdr"], @@ -344,6 +345,14 @@ class FeatureDetector(object): """ return self._has_soapy_driver("airspyhf") + def has_soapy_afedri(self): + """ + The SoapyAfedri module allows using Afedri SDR-Net devices with SoapySDR. + + You can get it [here](https://github.com/alexander-sholohov/SoapyAfedri). + """ + return self._has_soapy_driver("afedri") + def has_soapy_lime_sdr(self): """ The Lime Suite installs - amongst others - a Soapy driver for the LimeSDR device series. diff --git a/owrx/source/afedri.py b/owrx/source/afedri.py new file mode 100644 index 00000000..258555ac --- /dev/null +++ b/owrx/source/afedri.py @@ -0,0 +1,87 @@ +from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription +from owrx.form.input import Input, TextInput, NumberInput, CheckboxInput +from owrx.form.input.device import RemoteInput +from owrx.form.input.converter import OptionalConverter +from owrx.form.input.validator import RangeValidator +from typing import List + + +AFEDRI_DEVICE_KEYS = ["rx_mode", "force_set_channel"] + + +class AfedriSource(SoapyConnectorSource): + + def getSoapySettingsMappings(self): + mappings = super().getSoapySettingsMappings() + mappings.update( + { + "r820t_lna_agc": "r820t_lna_agc", + "r820t_mixer_agc": "r820t_mixer_agc", + } + ) + return mappings + + def getEventNames(self): + return super().getEventNames() + ["remote"] + AFEDRI_DEVICE_KEYS + + def getDriver(self): + return "afedri" + + def buildSoapyDeviceParameters(self, parsed, values): + params = super().buildSoapyDeviceParameters(parsed, values) + params = [v for v in params if not "remote" in params] + remote = values["remote"] + address, port = remote.split(":") + params += [{"address": address, "port": port}] + + can_be_set_at_start = AFEDRI_DEVICE_KEYS + for elm in can_be_set_at_start: + if elm in values: + params += [{elm: values[elm]}] + + return params + + +class AfedriDeviceDescription(SoapyConnectorDeviceDescription): + def getName(self): + return "Afedri device" + + def supportsPpm(self): + # not currently mapped, and it's unclear how this should be sent to the device + return False + + def hasAgc(self): + # not currently mapped + return False + + def getInputs(self) -> List[Input]: + return super().getInputs() + [ + RemoteInput(), + NumberInput("current_channel_for_settings", "Afedri: Current channel for settings.", validator=RangeValidator(0, 4)), + CheckboxInput("r820t_lna_agc", "Afedri: Enable R820T LNA AGC"), + CheckboxInput("r820t_mixer_agc", "Afedri: Enable R820T Mixer AGC"), + NumberInput("force_set_channel", "Afedri: Use this channel instead of default when connect to master seed server.", "Number in range [0,3]", validator=RangeValidator(0, 3)), + # NumberInput("channels_overload_mode", "Afedri: Overload mode for channels.", "Number in range [0,15]. One bit for each channel. 4 bits in total.", validator=RangeValidator(0, 15)), + # NumberInput("rx_mode", "Afedri: RX Mode (Single/Dual/Quad Channel)", "Number in range [0,5]. Switch device to specific RX mode. (Single/DualDiversity/Dual/DiversityInternal/QuadDiversity/Quad)", validator=RangeValidator(0, 15)), + ] + + def getDeviceMandatoryKeys(self): + return super().getDeviceMandatoryKeys() + ["remote"] + + def getDeviceOptionalKeys(self): + items_to_remove = [] + res = super().getDeviceOptionalKeys() + res = [x for x in super().getProfileOptionalKeys() if x not in items_to_remove] + res += AFEDRI_DEVICE_KEYS + return res + + def getProfileOptionalKeys(self): + items_to_remove = [] + res = [x for x in super().getProfileOptionalKeys() if x not in items_to_remove] + res.append("r820t_lna_agc") + res.append("r820t_mixer_agc") + return res + + def getGainStages(self): + return ["RF", "FE", "R820T_LNA_GAIN", "R820T_MIXER_GAIN", "R820T_VGA_GAIN"] + From f5bcbdc854de89a01d4064a583f3b72fa5f65aa5 Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Sat, 21 Oct 2023 10:07:50 +0700 Subject: [PATCH 02/12] clean up afedri driver code --- owrx/source/afedri.py | 59 +++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/owrx/source/afedri.py b/owrx/source/afedri.py index 258555ac..a73a701f 100644 --- a/owrx/source/afedri.py +++ b/owrx/source/afedri.py @@ -1,24 +1,18 @@ from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription -from owrx.form.input import Input, TextInput, NumberInput, CheckboxInput +from owrx.form.input import Input, CheckboxInput, NumberInput from owrx.form.input.device import RemoteInput -from owrx.form.input.converter import OptionalConverter from owrx.form.input.validator import RangeValidator from typing import List AFEDRI_DEVICE_KEYS = ["rx_mode", "force_set_channel"] +AFEDRI_PROFILE_KEYS = ["r820t_lna_agc", "r820t_mixer_agc"] class AfedriSource(SoapyConnectorSource): - def getSoapySettingsMappings(self): mappings = super().getSoapySettingsMappings() - mappings.update( - { - "r820t_lna_agc": "r820t_lna_agc", - "r820t_mixer_agc": "r820t_mixer_agc", - } - ) + mappings.update({x: x for x in AFEDRI_PROFILE_KEYS}) return mappings def getEventNames(self): @@ -57,31 +51,42 @@ class AfedriDeviceDescription(SoapyConnectorDeviceDescription): def getInputs(self) -> List[Input]: return super().getInputs() + [ RemoteInput(), - NumberInput("current_channel_for_settings", "Afedri: Current channel for settings.", validator=RangeValidator(0, 4)), - CheckboxInput("r820t_lna_agc", "Afedri: Enable R820T LNA AGC"), - CheckboxInput("r820t_mixer_agc", "Afedri: Enable R820T Mixer AGC"), - NumberInput("force_set_channel", "Afedri: Use this channel instead of default when connect to master seed server.", "Number in range [0,3]", validator=RangeValidator(0, 3)), - # NumberInput("channels_overload_mode", "Afedri: Overload mode for channels.", "Number in range [0,15]. One bit for each channel. 4 bits in total.", validator=RangeValidator(0, 15)), - # NumberInput("rx_mode", "Afedri: RX Mode (Single/Dual/Quad Channel)", "Number in range [0,5]. Switch device to specific RX mode. (Single/DualDiversity/Dual/DiversityInternal/QuadDiversity/Quad)", validator=RangeValidator(0, 15)), + CheckboxInput( + "r820t_lna_agc", + "Enable R820T LNA AGC", + ), + CheckboxInput( + "r820t_mixer_agc", + "Enable R820T Mixer AGC", + ), + NumberInput( + "force_set_channel", + "Use this channel instead of default when connect to master seed server.", + "Number in range [0,3]", + validator=RangeValidator(0, 3), + ), + NumberInput( + "rx_mode", + "RX Mode (Single/Dual/Quad Channel)", + "Number in range [0,5]. Switch device to specific RX mode. (Single/DualDiversity/Dual/DiversityInternal/QuadDiversity/Quad)", + validator=RangeValidator(0, 5), + ), ] def getDeviceMandatoryKeys(self): return super().getDeviceMandatoryKeys() + ["remote"] def getDeviceOptionalKeys(self): - items_to_remove = [] - res = super().getDeviceOptionalKeys() - res = [x for x in super().getProfileOptionalKeys() if x not in items_to_remove] - res += AFEDRI_DEVICE_KEYS - return res + return super().getDeviceOptionalKeys() + AFEDRI_DEVICE_KEYS def getProfileOptionalKeys(self): - items_to_remove = [] - res = [x for x in super().getProfileOptionalKeys() if x not in items_to_remove] - res.append("r820t_lna_agc") - res.append("r820t_mixer_agc") - return res + return super().getProfileOptionalKeys() + AFEDRI_PROFILE_KEYS def getGainStages(self): - return ["RF", "FE", "R820T_LNA_GAIN", "R820T_MIXER_GAIN", "R820T_VGA_GAIN"] - + return [ + "RF", + "FE", + "R820T_LNA_GAIN", + "R820T_MIXER_GAIN", + "R820T_VGA_GAIN", + ] From bf8eb50c0ba064396fe483758835f103106e3b9c Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Sun, 22 Oct 2023 13:05:25 +0700 Subject: [PATCH 03/12] add parameter map_ch0 to afedri driver, clean up infotext --- owrx/source/afedri.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/owrx/source/afedri.py b/owrx/source/afedri.py index a73a701f..036172dd 100644 --- a/owrx/source/afedri.py +++ b/owrx/source/afedri.py @@ -5,7 +5,7 @@ from owrx.form.input.validator import RangeValidator from typing import List -AFEDRI_DEVICE_KEYS = ["rx_mode", "force_set_channel"] +AFEDRI_DEVICE_KEYS = ["rx_mode", "map_ch0"] AFEDRI_PROFILE_KEYS = ["r820t_lna_agc", "r820t_mixer_agc"] @@ -60,15 +60,16 @@ class AfedriDeviceDescription(SoapyConnectorDeviceDescription): "Enable R820T Mixer AGC", ), NumberInput( - "force_set_channel", - "Use this channel instead of default when connect to master seed server.", - "Number in range [0,3]", + "map_ch0", + "Substitute channel 0", + infotext="Number in range [0,3]. Substitute SoapySDR channel 0 with a specific Afedri channel", validator=RangeValidator(0, 3), ), NumberInput( "rx_mode", "RX Mode (Single/Dual/Quad Channel)", - "Number in range [0,5]. Switch device to specific RX mode. (Single/DualDiversity/Dual/DiversityInternal/QuadDiversity/Quad)", + infotext="Number in range [0,5]. Switch the device to a specific RX mode.
" + + "(0-Single 1-DualDiversity 2-Dual 3-DiversityInternal 4-QuadDiversity 5-Quad)", validator=RangeValidator(0, 5), ), ] From 06b3c198e119956f1551502d90adcae2abb59b74 Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Mon, 23 Oct 2023 08:53:03 +0700 Subject: [PATCH 04/12] add Afedri SDR-Net SoapySDR driver to docker files --- docker.sh | 2 +- docker/Dockerfiles/Dockerfile-afedri | 8 +++++ docker/Dockerfiles/Dockerfile-full | 1 + docker/scripts/install-dependencies-afedri.sh | 33 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 docker/Dockerfiles/Dockerfile-afedri create mode 100644 docker/scripts/install-dependencies-afedri.sh diff --git a/docker.sh b/docker.sh index a1bfb897..b3657af6 100755 --- a/docker.sh +++ b/docker.sh @@ -2,7 +2,7 @@ set -euo pipefail ARCH=$(uname -m) -IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-rtltcp openwebrx-runds openwebrx-hpsdr openwebrx-bladerf openwebrx-full openwebrx" +IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-afedri openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-rtltcp openwebrx-runds openwebrx-hpsdr openwebrx-bladerf openwebrx-full openwebrx" ALL_ARCHS="x86_64 armv7l aarch64" TAG=${TAG:-"latest"} ARCHTAG="${TAG}-${ARCH}" diff --git a/docker/Dockerfiles/Dockerfile-afedri b/docker/Dockerfiles/Dockerfile-afedri new file mode 100644 index 00000000..ad7c88e9 --- /dev/null +++ b/docker/Dockerfiles/Dockerfile-afedri @@ -0,0 +1,8 @@ +ARG ARCHTAG +FROM openwebrx-soapysdr-base:$ARCHTAG + +COPY docker/scripts/install-dependencies-afedri.sh / +RUN /install-dependencies-afedri.sh &&\ + rm /install-dependencies-afedri.sh + +ADD . /opt/openwebrx diff --git a/docker/Dockerfiles/Dockerfile-full b/docker/Dockerfiles/Dockerfile-full index 10826d21..6d68e8a0 100644 --- a/docker/Dockerfiles/Dockerfile-full +++ b/docker/Dockerfiles/Dockerfile-full @@ -10,6 +10,7 @@ RUN /install-dependencies-rtlsdr.sh &&\ /install-dependencies-hackrf.sh &&\ /install-dependencies-sdrplay.sh &&\ /install-dependencies-airspy.sh &&\ + /install-dependencies-afedri.sh &&\ /install-dependencies-rtlsdr-soapy.sh &&\ /install-dependencies-plutosdr.sh &&\ /install-dependencies-limesdr.sh &&\ diff --git a/docker/scripts/install-dependencies-afedri.sh b/docker/scripts/install-dependencies-afedri.sh new file mode 100644 index 00000000..96283271 --- /dev/null +++ b/docker/scripts/install-dependencies-afedri.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +export MAKEFLAGS="-j4" + +function cmakebuild() { + cd $1 + if [[ ! -z "${2:-}" ]]; then + git checkout $2 + fi + mkdir build + cd build + cmake .. + make + make install + cd ../.. + rm -rf $1 +} + +cd /tmp + +STATIC_PACKAGES="" +BUILD_PACKAGES="git cmake make gcc g++" + +apt-get update +apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES + +git clone https://github.com/alexander-sholohov/SoapyAfedri.git +# latest from master as of 2023-10-22 +cmakebuild SoapyAfedri cf90c195f8ad25a3c55947a441fb8ec1418d5486 + +apt-get -y purge --autoremove $BUILD_PACKAGES +apt-get clean +rm -rf /var/lib/apt/lists/* From 9f091e57d08bd89b850388d15c56dfd577510ad6 Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Mon, 23 Oct 2023 08:57:36 +0700 Subject: [PATCH 05/12] update changelog with Adedri SDR-Net --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bb3468d..6c3a3713 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - Added support for decoding HFDL and VDL2 aircraft communications - Added decoding of ISM band transmissions using rtl_433 - Added IPv6 support +- New devices supported: + - Afedri SDR-Net **1.2.2** - Fixed an over-the-air code injection vulnerability From ad7b54cac62e8e719a815f854ffea16dd45a1d0c Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Wed, 25 Oct 2023 19:25:21 +0700 Subject: [PATCH 06/12] SoapyAfedri reference to latest commit --- docker/scripts/install-dependencies-afedri.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/scripts/install-dependencies-afedri.sh b/docker/scripts/install-dependencies-afedri.sh index 96283271..3eec1138 100644 --- a/docker/scripts/install-dependencies-afedri.sh +++ b/docker/scripts/install-dependencies-afedri.sh @@ -25,8 +25,8 @@ apt-get update apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES git clone https://github.com/alexander-sholohov/SoapyAfedri.git -# latest from master as of 2023-10-22 -cmakebuild SoapyAfedri cf90c195f8ad25a3c55947a441fb8ec1418d5486 +# latest from master as of 2023-10-25 +cmakebuild SoapyAfedri b525301b1fc8dd8f46744d5a33402419f843ce22 apt-get -y purge --autoremove $BUILD_PACKAGES apt-get clean From 79c199d90565c70aead2ba6f1e9270c437727afb Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Fri, 27 Oct 2023 20:00:21 +0700 Subject: [PATCH 07/12] SoapyAfedri reference to latest commit --- docker/scripts/install-dependencies-afedri.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/scripts/install-dependencies-afedri.sh b/docker/scripts/install-dependencies-afedri.sh index 3eec1138..f99cbe7f 100644 --- a/docker/scripts/install-dependencies-afedri.sh +++ b/docker/scripts/install-dependencies-afedri.sh @@ -25,8 +25,8 @@ apt-get update apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES git clone https://github.com/alexander-sholohov/SoapyAfedri.git -# latest from master as of 2023-10-25 -cmakebuild SoapyAfedri b525301b1fc8dd8f46744d5a33402419f843ce22 +# latest from master as of 2023-10-27 +cmakebuild SoapyAfedri e044d96d89e2a211455318845d760eea34347a27 apt-get -y purge --autoremove $BUILD_PACKAGES apt-get clean From 08c5c97dcbed1602e97e799236d5edbc12974f5c Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Tue, 31 Oct 2023 21:10:35 +0700 Subject: [PATCH 08/12] allow to work through soapyRemote driver --- owrx/source/afedri.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/owrx/source/afedri.py b/owrx/source/afedri.py index 036172dd..b3f40a7a 100644 --- a/owrx/source/afedri.py +++ b/owrx/source/afedri.py @@ -1,7 +1,9 @@ from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription from owrx.form.input import Input, CheckboxInput, NumberInput -from owrx.form.input.device import RemoteInput +from owrx.form.input.device import RemoteInput, TextInput from owrx.form.input.validator import RangeValidator +from owrx.form.input.converter import OptionalConverter +from owrx.form.input.validator import RequiredValidator from typing import List @@ -9,6 +11,17 @@ AFEDRI_DEVICE_KEYS = ["rx_mode", "map_ch0"] AFEDRI_PROFILE_KEYS = ["r820t_lna_agc", "r820t_mixer_agc"] +class AfedriAddressPortInput(TextInput): + def __init__(self): + super().__init__( + "afedri_adress_port", + "Afedri IP and Port", + infotext="Afedri IP and port to connect to. Format = IP:Port", + converter=OptionalConverter(), + validator=RequiredValidator(), + ) + + class AfedriSource(SoapyConnectorSource): def getSoapySettingsMappings(self): mappings = super().getSoapySettingsMappings() @@ -16,16 +29,20 @@ class AfedriSource(SoapyConnectorSource): return mappings def getEventNames(self): - return super().getEventNames() + ["remote"] + AFEDRI_DEVICE_KEYS + return super().getEventNames() + ["remote", "afedri_adress_port"] + AFEDRI_DEVICE_KEYS def getDriver(self): return "afedri" def buildSoapyDeviceParameters(self, parsed, values): params = super().buildSoapyDeviceParameters(parsed, values) - params = [v for v in params if not "remote" in params] - remote = values["remote"] - address, port = remote.split(":") + + # replace driver with sopayRemote + if "remote" in values: + params = [v for v in params if "driver" not in v] # remove present driver + params += [{"driver": "remote", "remote:driver": self.getDriver(), "remote": values["remote"]}] + + address, port = values["afedri_adress_port"].split(":") params += [{"address": address, "port": port}] can_be_set_at_start = AFEDRI_DEVICE_KEYS @@ -51,6 +68,7 @@ class AfedriDeviceDescription(SoapyConnectorDeviceDescription): def getInputs(self) -> List[Input]: return super().getInputs() + [ RemoteInput(), + AfedriAddressPortInput(), CheckboxInput( "r820t_lna_agc", "Enable R820T LNA AGC", @@ -75,10 +93,10 @@ class AfedriDeviceDescription(SoapyConnectorDeviceDescription): ] def getDeviceMandatoryKeys(self): - return super().getDeviceMandatoryKeys() + ["remote"] + return super().getDeviceMandatoryKeys() + ["afedri_adress_port"] def getDeviceOptionalKeys(self): - return super().getDeviceOptionalKeys() + AFEDRI_DEVICE_KEYS + return super().getDeviceOptionalKeys() + ["remote"] + AFEDRI_DEVICE_KEYS def getProfileOptionalKeys(self): return super().getProfileOptionalKeys() + AFEDRI_PROFILE_KEYS From 2bd2e81d579234bf1ba6e7b3db071c95f033cd64 Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Tue, 31 Oct 2023 21:11:52 +0700 Subject: [PATCH 09/12] remove parameter map_ch0 --- owrx/source/afedri.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/owrx/source/afedri.py b/owrx/source/afedri.py index b3f40a7a..9f1b6fad 100644 --- a/owrx/source/afedri.py +++ b/owrx/source/afedri.py @@ -7,7 +7,7 @@ from owrx.form.input.validator import RequiredValidator from typing import List -AFEDRI_DEVICE_KEYS = ["rx_mode", "map_ch0"] +AFEDRI_DEVICE_KEYS = ["rx_mode"] AFEDRI_PROFILE_KEYS = ["r820t_lna_agc", "r820t_mixer_agc"] @@ -77,12 +77,6 @@ class AfedriDeviceDescription(SoapyConnectorDeviceDescription): "r820t_mixer_agc", "Enable R820T Mixer AGC", ), - NumberInput( - "map_ch0", - "Substitute channel 0", - infotext="Number in range [0,3]. Substitute SoapySDR channel 0 with a specific Afedri channel", - validator=RangeValidator(0, 3), - ), NumberInput( "rx_mode", "RX Mode (Single/Dual/Quad Channel)", From 8f02574df147f526b1a98e91e48892647588ec13 Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Sun, 19 Nov 2023 18:28:15 +0700 Subject: [PATCH 10/12] remove SoapyRemote reference --- owrx/source/afedri.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/owrx/source/afedri.py b/owrx/source/afedri.py index 9f1b6fad..315a69f9 100644 --- a/owrx/source/afedri.py +++ b/owrx/source/afedri.py @@ -1,6 +1,6 @@ from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription from owrx.form.input import Input, CheckboxInput, NumberInput -from owrx.form.input.device import RemoteInput, TextInput +from owrx.form.input.device import TextInput from owrx.form.input.validator import RangeValidator from owrx.form.input.converter import OptionalConverter from owrx.form.input.validator import RequiredValidator @@ -29,7 +29,7 @@ class AfedriSource(SoapyConnectorSource): return mappings def getEventNames(self): - return super().getEventNames() + ["remote", "afedri_adress_port"] + AFEDRI_DEVICE_KEYS + return super().getEventNames() + ["afedri_adress_port"] + AFEDRI_DEVICE_KEYS def getDriver(self): return "afedri" @@ -37,11 +37,6 @@ class AfedriSource(SoapyConnectorSource): def buildSoapyDeviceParameters(self, parsed, values): params = super().buildSoapyDeviceParameters(parsed, values) - # replace driver with sopayRemote - if "remote" in values: - params = [v for v in params if "driver" not in v] # remove present driver - params += [{"driver": "remote", "remote:driver": self.getDriver(), "remote": values["remote"]}] - address, port = values["afedri_adress_port"].split(":") params += [{"address": address, "port": port}] @@ -67,7 +62,6 @@ class AfedriDeviceDescription(SoapyConnectorDeviceDescription): def getInputs(self) -> List[Input]: return super().getInputs() + [ - RemoteInput(), AfedriAddressPortInput(), CheckboxInput( "r820t_lna_agc", @@ -90,7 +84,7 @@ class AfedriDeviceDescription(SoapyConnectorDeviceDescription): return super().getDeviceMandatoryKeys() + ["afedri_adress_port"] def getDeviceOptionalKeys(self): - return super().getDeviceOptionalKeys() + ["remote"] + AFEDRI_DEVICE_KEYS + return super().getDeviceOptionalKeys() + AFEDRI_DEVICE_KEYS def getProfileOptionalKeys(self): return super().getProfileOptionalKeys() + AFEDRI_PROFILE_KEYS From ccd42d0f9a006a1ee18b99b808a753a7035e09c8 Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Sun, 19 Nov 2023 18:30:47 +0700 Subject: [PATCH 11/12] SoapyAfedri reference to latest commit --- docker/scripts/install-dependencies-afedri.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/scripts/install-dependencies-afedri.sh b/docker/scripts/install-dependencies-afedri.sh index f99cbe7f..3843547b 100644 --- a/docker/scripts/install-dependencies-afedri.sh +++ b/docker/scripts/install-dependencies-afedri.sh @@ -25,8 +25,8 @@ apt-get update apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES git clone https://github.com/alexander-sholohov/SoapyAfedri.git -# latest from master as of 2023-10-27 -cmakebuild SoapyAfedri e044d96d89e2a211455318845d760eea34347a27 +# latest from master as of 2023-11-16 +cmakebuild SoapyAfedri a7d0d942fe966c2b69c8817dd6f097fc94122660 apt-get -y purge --autoremove $BUILD_PACKAGES apt-get clean From e71d38b15a6483ccc74c1d23b28c3b26e21e1f7e Mon Sep 17 00:00:00 2001 From: Alexander Sholohov Date: Fri, 5 Jan 2024 11:28:26 +0700 Subject: [PATCH 12/12] improve address:port validation, add DropdownInput for rx_mode --- owrx/source/afedri.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/owrx/source/afedri.py b/owrx/source/afedri.py index 315a69f9..3f3c2357 100644 --- a/owrx/source/afedri.py +++ b/owrx/source/afedri.py @@ -1,9 +1,8 @@ +import re from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription -from owrx.form.input import Input, CheckboxInput, NumberInput +from owrx.form.input import Input, CheckboxInput, DropdownInput, Option from owrx.form.input.device import TextInput -from owrx.form.input.validator import RangeValidator -from owrx.form.input.converter import OptionalConverter -from owrx.form.input.validator import RequiredValidator +from owrx.form.input.validator import Validator, ValidationError from typing import List @@ -11,14 +10,20 @@ AFEDRI_DEVICE_KEYS = ["rx_mode"] AFEDRI_PROFILE_KEYS = ["r820t_lna_agc", "r820t_mixer_agc"] +class IPv4AndPortValidator(Validator): + def validate(self, key, value) -> None: + m = re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}$", value) + if not m: + raise ValidationError(key, "Wrong format. IPv4:Port expected") + + class AfedriAddressPortInput(TextInput): def __init__(self): super().__init__( "afedri_adress_port", "Afedri IP and Port", - infotext="Afedri IP and port to connect to. Format = IP:Port", - converter=OptionalConverter(), - validator=RequiredValidator(), + infotext="Afedri IP and port to connect to. Format = IPv4:Port", + validator=IPv4AndPortValidator(), ) @@ -71,12 +76,17 @@ class AfedriDeviceDescription(SoapyConnectorDeviceDescription): "r820t_mixer_agc", "Enable R820T Mixer AGC", ), - NumberInput( + DropdownInput( "rx_mode", - "RX Mode (Single/Dual/Quad Channel)", - infotext="Number in range [0,5]. Switch the device to a specific RX mode.
" - + "(0-Single 1-DualDiversity 2-Dual 3-DiversityInternal 4-QuadDiversity 5-Quad)", - validator=RangeValidator(0, 5), + "Switch the device to a specific RX mode at start", + options=[ + Option("0", "Single"), + Option("1", "DualDiversity"), + Option("2", "Dual"), + Option("3", "DiversityInternal"), + Option("4", "QuadDiversity"), + Option("5", "Quad"), + ], ), ]