add more sample rate validation

This commit is contained in:
Jakob Ketterl 2024-01-17 22:39:05 +01:00
parent 374bbb599e
commit 402eadd280
21 changed files with 145 additions and 9 deletions

View file

@ -15,14 +15,16 @@ class RequiredValidator(Validator):
class Range(object):
def __init__(self, start: int, end: int):
def __init__(self, start: int, end: int = None):
self.start = start
self.end = end
self.end = end if end is not None else start
def isInRange(self, value):
return self.start <= value <= self.end
def __str__(self):
if self.start == self.end:
return str(self.start)
return "{start}...{end}".format(**vars(self))
@ -46,7 +48,7 @@ class RangeListValidator(Validator):
def validate(self, key, value) -> None:
if not any(range for range in self.rangeList if range.isInRange(value)):
raise ValidationError(
key, "Value is out of range {}".format(self._rangeStr())
key, "Value is outside of the allowed range(s) {}".format(self._rangeStr())
)
def _rangeStr(self):

View file

@ -679,6 +679,6 @@ class SdrDeviceDescription(object):
self.getProfileOptionalKeys(),
)
def getSampleRateRanges(self) -> List[Range]:
def getSampleRateRanges(self) -> list[Range]:
# semi-sane default value. should be overridden with more specific values per device.
return [Range(500000, 10000000)]

View file

@ -1,9 +1,8 @@
import re
from ipaddress import IPv4Address, AddressValueError
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input import Input, CheckboxInput, DropdownInput, Option
from owrx.form.input.device import TextInput
from owrx.form.input.validator import Validator, ValidationError
from owrx.form.input.validator import Validator, ValidationError, Range
from typing import List
@ -123,3 +122,6 @@ class AfedriDeviceDescription(SoapyConnectorDeviceDescription):
def getNumberOfChannels(self) -> int:
return 4
def getSampleRateRanges(self) -> list[Range]:
return [Range(48000, 2400000)]

View file

@ -1,6 +1,7 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input import Input, CheckboxInput
from owrx.form.input.device import BiasTeeInput
from owrx.form.input.validator import Range
from typing import List
@ -48,3 +49,14 @@ class AirspyDeviceDescription(SoapyConnectorDeviceDescription):
def getGainStages(self):
return ["LNA", "MIX", "VGA"]
def getSampleRateRanges(self) -> list[Range]:
# Airspy R2 does 2.5 or 10 MS/s
# Airspy mini does 3 or 6 MS/s
# we don't know what device we're actually dealing with, but we can still clamp it down to a sum of the options.
return [
Range(2500000),
Range(3000000),
Range(6000000),
Range(10000000),
]

View file

@ -1,4 +1,5 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input.validator import Range
class AirspyhfSource(SoapyConnectorSource):
@ -13,3 +14,13 @@ class AirspyhfDeviceDescription(SoapyConnectorDeviceDescription):
def supportsPpm(self):
# not currently supported by the SoapySDR module.
return False
def getSampleRateRanges(self) -> list[Range]:
return [
Range(192000),
Range(256000),
Range(384000),
Range(456000),
Range(768000),
Range(912000),
]

View file

@ -1,4 +1,5 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input.validator import Range
class BladerfSource(SoapyConnectorSource):
@ -9,3 +10,6 @@ class BladerfSource(SoapyConnectorSource):
class BladerfDeviceDescription(SoapyConnectorDeviceDescription):
def getName(self):
return "Blade RF"
def getSampleRateRanges(self) -> list[Range]:
return [Range(160000, 40000000)]

View file

@ -1,4 +1,5 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input.validator import Range
class FcdppSource(SoapyConnectorSource):
@ -9,3 +10,9 @@ class FcdppSource(SoapyConnectorSource):
class FcdppDeviceDescription(SoapyConnectorDeviceDescription):
def getName(self):
return "FunCube Dongle Pro+"
def getSampleRateRanges(self) -> list[Range]:
return [
Range(96000),
Range(192000),
]

View file

@ -7,6 +7,7 @@ from pycsdr.modules import Convert, Gain
from pycsdr.types import Format
from typing import List
from owrx.form.input import Input, TextInput
from owrx.form.input.validator import Range
import logging
@ -69,3 +70,10 @@ class FifiSdrDeviceDescription(DirectSourceDeviceDescription):
def getDeviceOptionalKeys(self):
return super().getDeviceOptionalKeys() + ["device"]
def getSampleRateRanges(self) -> list[Range]:
return [
Range(48000),
Range(96000),
Range(192000),
]

View file

@ -1,6 +1,7 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input import Input
from owrx.form.input.device import BiasTeeInput
from owrx.form.input.validator import Range
from typing import List
@ -34,3 +35,6 @@ class HackrfDeviceDescription(SoapyConnectorDeviceDescription):
def getGainStages(self):
return ["LNA", "AMP", "VGA"]
def getSampleRateRanges(self) -> list[Range]:
return [Range(1000000, 20000000)]

View file

@ -1,8 +1,7 @@
from owrx.source.connector import ConnectorSource, ConnectorDeviceDescription
from owrx.command import Option, Flag
from owrx.form.error import ValidationError
from owrx.form.input import Input, NumberInput, TextInput, CheckboxInput
from owrx.form.input.validator import RangeValidator
from owrx.form.input.validator import RangeValidator, Range
from typing import List
# These are the command line options available:
@ -28,6 +27,7 @@ from typing import List
# Radio 1: (Remote IP: 192.168.1.11, Server port: 7300)
# Radio 2: (Remote IP: 192.168.1.22, Server port: 7301)
class HpsdrSource(ConnectorSource):
def getCommandMapper(self):
return (
@ -46,6 +46,7 @@ class HpsdrSource(ConnectorSource):
)
)
class RemoteInput(TextInput):
def __init__(self):
super().__init__(
@ -57,6 +58,7 @@ class RemoteInput(TextInput):
)
)
class HpsdrDeviceDescription(ConnectorDeviceDescription):
def getName(self):
return "HPSDR devices (Hermes / Hermes Lite 2 / Red Pitaya)"
@ -88,3 +90,10 @@ class HpsdrDeviceDescription(ConnectorDeviceDescription):
def getProfileOptionalKeys(self):
return list(filter(lambda x : x != "iqswap", super().getProfileOptionalKeys()))
def getSampleRateRanges(self) -> list[Range]:
return [
Range(48000),
Range(96000),
Range(192000),
Range(384000),
]

View file

@ -1,4 +1,5 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input.validator import Range
class LimeSdrSource(SoapyConnectorSource):
@ -9,3 +10,6 @@ class LimeSdrSource(SoapyConnectorSource):
class LimeSdrDeviceDescription(SoapyConnectorDeviceDescription):
def getName(self):
return "LimeSDR device"
def getSampleRateRanges(self) -> list[Range]:
return [Range(100000, 65000000)]

View file

@ -1,6 +1,7 @@
from owrx.source.direct import DirectSource, DirectSourceDeviceDescription
from owrx.command import Option, Flag
from owrx.form.input import Input, DropdownEnum, DropdownInput, CheckboxInput
from owrx.form.input.validator import Range
from typing import List
@ -81,3 +82,12 @@ class PerseussdrDeviceDescription(DirectSourceDeviceDescription):
"adc_dither",
"wideband",
]
def getSampleRateRanges(self) -> list[Range]:
return [
Range(125000),
Range(250000),
Range(500000),
Range(1000000),
Range(2000000),
]

View file

@ -1,4 +1,5 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input.validator import Range
class PlutoSdrSource(SoapyConnectorSource):
@ -9,3 +10,6 @@ class PlutoSdrSource(SoapyConnectorSource):
class PlutoSdrDeviceDescription(SoapyConnectorDeviceDescription):
def getName(self):
return "PlutoSDR"
def getSampleRateRanges(self) -> list[Range]:
return [Range(520833, 61440000)]

View file

@ -1,4 +1,5 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input.validator import Range
class RadioberrySource(SoapyConnectorSource):
@ -9,3 +10,11 @@ class RadioberrySource(SoapyConnectorSource):
class RadioberryDeviceDescription(SoapyConnectorDeviceDescription):
def getName(self):
return "RadioBerry"
def getSampleRateRanges(self) -> list[Range]:
return [
Range(48000),
Range(96000),
Range(192000),
Range(384000),
]

View file

@ -37,5 +37,5 @@ class RtlSdrDeviceDescription(ConnectorDeviceDescription):
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["bias_tee", "direct_sampling"]
def getSampleRateRanges(self) -> List[Range]:
def getSampleRateRanges(self) -> list[Range]:
return [Range(250000, 3200000)]

View file

@ -1,6 +1,7 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input import Input
from owrx.form.input.device import BiasTeeInput, DirectSamplingInput
from owrx.form.input.validator import Range
from typing import List
@ -26,3 +27,6 @@ class RtlSdrSoapyDeviceDescription(SoapyConnectorDeviceDescription):
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["bias_tee", "direct_sampling"]
def getSampleRateRanges(self) -> list[Range]:
return [Range(250000, 3200000)]

View file

@ -2,6 +2,7 @@ from owrx.source.connector import ConnectorSource, ConnectorDeviceDescription
from owrx.command import Flag, Option, Argument
from owrx.form.input import Input
from owrx.form.input.device import RemoteInput, DirectSamplingInput
from owrx.form.input.validator import Range
from typing import List
@ -36,3 +37,6 @@ class RtlTcpDeviceDescription(ConnectorDeviceDescription):
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["direct_sampling"]
def getSampleRateRanges(self) -> list[Range]:
return [Range(250000, 3200000)]

View file

@ -2,6 +2,7 @@ from owrx.source.connector import ConnectorSource, ConnectorDeviceDescription
from owrx.command import Argument, Flag, Option
from owrx.form.input import Input, DropdownInput, DropdownEnum, CheckboxInput
from owrx.form.input.device import RemoteInput
from owrx.form.input.validator import Range
from typing import List
@ -56,3 +57,7 @@ class RundsDeviceDescription(ConnectorDeviceDescription):
def getDeviceOptionalKeys(self):
return super().getDeviceOptionalKeys() + ["protocol", "long"]
def getSampleRateRanges(self) -> list[Range]:
# can't be very specific here due to the wide range of devices, so this is more of a sanity check.
return [Range(0, 20000000)]

View file

@ -1,4 +1,5 @@
from owrx.source.connector import ConnectorSource, ConnectorDeviceDescription
from owrx.form.input.validator import Range
class SddcSource(ConnectorSource):
@ -12,3 +13,7 @@ class SddcDeviceDescription(ConnectorDeviceDescription):
def hasAgc(self):
return False
def getSampleRateRanges(self) -> list[Range]:
# resampling is done in software... it can't cover the full range, but it's not finished either.
return [Range(0, 64000000)]

View file

@ -1,6 +1,7 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input import Input, CheckboxInput, DropdownInput, DropdownEnum
from owrx.form.input.device import BiasTeeInput
from owrx.form.input.validator import Range
from typing import List
@ -62,3 +63,29 @@ class SdrplayDeviceDescription(SoapyConnectorDeviceDescription):
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["bias_tee", "rf_notch", "dab_notch", "if_mode"]
def getSampleRateRanges(self) -> list[Range]:
# this is from SoapySDRPlay3's implementation of listSampleRates().
# i don't think it's accurate, but this is the limitation we'd be running into if we had proper soapy
# integration.
return [
Range(62500),
Range(96000),
Range(125000),
Range(192000),
Range(250000),
Range(384000),
Range(500000),
Range(768000),
Range(1000000),
Range(2000000),
Range(2048000),
Range(3000000),
Range(4000000),
Range(5000000),
Range(6000000),
Range(7000000),
Range(8000000),
Range(9000000),
Range(10000000),
]

View file

@ -1,4 +1,5 @@
from owrx.source.soapy import SoapyConnectorSource, SoapyConnectorDeviceDescription
from owrx.form.input.validator import Range
class UhdSource(SoapyConnectorSource):
@ -9,3 +10,7 @@ class UhdSource(SoapyConnectorSource):
class UhdDeviceDescription(SoapyConnectorDeviceDescription):
def getName(self):
return "Ettus Research USRP device"
def getSampleRateRanges(self) -> list[Range]:
# not sure since this depends of the specific model
return [Range(0, 64000000)]