2019-12-27 23:26:45 +00:00
|
|
|
from abc import ABCMeta, abstractmethod
|
|
|
|
from owrx.command import Option
|
2021-02-19 14:29:17 +00:00
|
|
|
from owrx.source.connector import ConnectorSource, ConnectorDeviceDescription
|
|
|
|
from typing import List
|
|
|
|
from owrx.form import Input, TextInput
|
2021-02-19 23:16:32 +00:00
|
|
|
from owrx.form.device import GainInput
|
|
|
|
from owrx.soapy import SoapySettings
|
2019-12-21 19:58:28 +00:00
|
|
|
|
|
|
|
|
2019-12-27 23:26:45 +00:00
|
|
|
class SoapyConnectorSource(ConnectorSource, metaclass=ABCMeta):
|
2019-12-31 18:14:05 +00:00
|
|
|
def getCommandMapper(self):
|
2021-01-20 16:01:46 +00:00
|
|
|
return (
|
|
|
|
super()
|
|
|
|
.getCommandMapper()
|
|
|
|
.setBase("soapy_connector")
|
|
|
|
.setMappings(
|
|
|
|
{
|
|
|
|
"antenna": Option("-a"),
|
|
|
|
"soapy_settings": Option("-t"),
|
|
|
|
}
|
|
|
|
)
|
2020-03-14 00:04:52 +00:00
|
|
|
)
|
2019-12-27 23:26:45 +00:00
|
|
|
|
2019-12-21 19:58:28 +00:00
|
|
|
"""
|
|
|
|
must be implemented by child classes to be able to build a driver-based device selector by default.
|
|
|
|
return value must be the corresponding soapy driver identifier.
|
|
|
|
"""
|
2019-12-28 00:24:07 +00:00
|
|
|
|
2019-12-27 23:26:45 +00:00
|
|
|
@abstractmethod
|
2019-12-21 19:58:28 +00:00
|
|
|
def getDriver(self):
|
|
|
|
pass
|
|
|
|
|
2019-12-27 23:26:45 +00:00
|
|
|
def getEventNames(self):
|
2020-04-01 22:10:28 +00:00
|
|
|
return super().getEventNames() + list(self.getSoapySettingsMappings().keys())
|
2019-12-27 23:26:45 +00:00
|
|
|
|
2020-02-09 12:59:37 +00:00
|
|
|
def buildSoapyDeviceParameters(self, parsed, values):
|
|
|
|
"""
|
|
|
|
this method always attempts to inject a driver= part into the soapysdr query, depending on what connector was used.
|
|
|
|
this prevents the soapy_connector from using the wrong device in scenarios where there's no same-type sdrs.
|
|
|
|
"""
|
|
|
|
parsed = [v for v in parsed if "driver" not in v]
|
|
|
|
parsed += [{"driver": self.getDriver()}]
|
|
|
|
return parsed
|
2019-12-28 00:24:07 +00:00
|
|
|
|
2020-03-14 00:04:52 +00:00
|
|
|
def getSoapySettingsMappings(self):
|
|
|
|
return {}
|
|
|
|
|
|
|
|
def buildSoapySettings(self, values):
|
|
|
|
settings = {}
|
|
|
|
for k, v in self.getSoapySettingsMappings().items():
|
2020-03-14 00:21:30 +00:00
|
|
|
if k in values and values[k] is not None:
|
2020-03-14 22:07:23 +00:00
|
|
|
settings[v] = self.convertSoapySettingsValue(values[k])
|
2020-03-14 00:04:52 +00:00
|
|
|
return settings
|
|
|
|
|
2020-03-14 22:07:23 +00:00
|
|
|
def convertSoapySettingsValue(self, value):
|
|
|
|
if isinstance(value, bool):
|
|
|
|
return "true" if value else "false"
|
|
|
|
return value
|
|
|
|
|
2019-12-21 19:58:28 +00:00
|
|
|
def getCommandValues(self):
|
|
|
|
values = super().getCommandValues()
|
|
|
|
if "device" in values and values["device"] is not None:
|
2021-02-19 23:16:32 +00:00
|
|
|
parsed = SoapySettings.parse(values["device"])
|
2019-12-21 19:58:28 +00:00
|
|
|
else:
|
2020-02-09 12:59:37 +00:00
|
|
|
parsed = []
|
|
|
|
modified = self.buildSoapyDeviceParameters(parsed, values)
|
2021-02-19 23:16:32 +00:00
|
|
|
values["device"] = SoapySettings.encode(modified)
|
2020-03-14 00:04:52 +00:00
|
|
|
settings = ",".join(["{0}={1}".format(k, v) for k, v in self.buildSoapySettings(values).items()])
|
|
|
|
if len(settings):
|
|
|
|
values["soapy_settings"] = settings
|
2019-12-21 19:58:28 +00:00
|
|
|
return values
|
2020-03-14 00:04:52 +00:00
|
|
|
|
2020-12-30 16:18:46 +00:00
|
|
|
def onPropertyChange(self, changes):
|
2020-03-14 00:04:52 +00:00
|
|
|
mappings = self.getSoapySettingsMappings()
|
2020-12-30 16:18:46 +00:00
|
|
|
settings = {}
|
|
|
|
for prop, value in changes.items():
|
|
|
|
if prop in mappings.keys():
|
|
|
|
settings[mappings[prop]] = self.convertSoapySettingsValue(value)
|
|
|
|
if settings:
|
|
|
|
changes["settings"] = ",".join("{0}={1}".format(k, v) for k, v in settings.items())
|
|
|
|
super().onPropertyChange(changes)
|
2021-02-19 14:29:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
class SoapyConnectorDeviceDescription(ConnectorDeviceDescription):
|
|
|
|
def getInputs(self) -> List[Input]:
|
2021-02-21 23:35:47 +00:00
|
|
|
return super().getInputs() + [
|
|
|
|
TextInput(
|
|
|
|
"device",
|
|
|
|
"Device Identifier",
|
|
|
|
infotext='SoapySDR device identifier string (example: "serial=123456789")',
|
|
|
|
),
|
|
|
|
GainInput(
|
|
|
|
"rf_gain",
|
|
|
|
"Device Gain",
|
|
|
|
gain_stages=self.getGainStages(),
|
2021-02-23 22:24:30 +00:00
|
|
|
has_agc=self.hasAgc(),
|
2021-02-21 23:35:47 +00:00
|
|
|
),
|
2021-02-22 23:27:29 +00:00
|
|
|
TextInput("antenna", "Antenna"),
|
2021-02-21 23:35:47 +00:00
|
|
|
]
|
|
|
|
|
2021-03-24 22:17:50 +00:00
|
|
|
def getDeviceOptionalKeys(self):
|
|
|
|
return super().getDeviceOptionalKeys() + ["device", "rf_gain", "antenna"]
|
2021-02-19 17:18:25 +00:00
|
|
|
|
2021-02-23 17:32:23 +00:00
|
|
|
def getProfileOptionalKeys(self):
|
|
|
|
return super().getProfileOptionalKeys() + ["antenna"]
|
|
|
|
|
2021-02-19 17:18:25 +00:00
|
|
|
def getGainStages(self):
|
2021-02-19 23:16:32 +00:00
|
|
|
return None
|