test sdrs and their availability early on

use polymorphism to load sdrs in
This commit is contained in:
Jakob Ketterl 2019-05-10 14:23:54 +02:00
parent 56ef86aab6
commit bbd6412e3d
3 changed files with 67 additions and 34 deletions

View File

@ -81,6 +81,9 @@ class PropertyManager(object):
p.setValue(other_pm[key])
return self
class UnknownFeatureException(Exception):
pass
class RequirementMissingException(Exception):
pass
@ -96,7 +99,10 @@ class FeatureDetector(object):
return self.has_requirements(self.get_requirements(feature))
def get_requirements(self, feature):
return FeatureDetector.features[feature]
try:
return FeatureDetector.features[feature]
except KeyError:
raise UnknownFeatureException("Feature \"{0}\" is not known.".format(feature))
def has_requirements(self, requirements):
passed = True

View File

@ -1,10 +1,11 @@
import subprocess
from owrx.config import PropertyManager, FeatureDetector
from owrx.config import PropertyManager, FeatureDetector, UnknownFeatureException
import threading
import csdr
import time
import os
import signal
import sys
class SdrService(object):
sdrProps = None
@ -22,39 +23,42 @@ class SdrService(object):
raise IndexError("no more available ports to start more sdrs")
return SdrService.lastPort
@staticmethod
def getSource(id = None):
def loadProps():
if SdrService.sdrProps is None:
pm = PropertyManager.getSharedInstance()
featureDetector = FeatureDetector()
def loadIntoPropertyManager(dict: dict):
propertyManager = PropertyManager()
for (name, value) in dict.items():
propertyManager[name] = value
return propertyManager
SdrService.sdrProps = dict((name, loadIntoPropertyManager(value)) for (name, value) in pm["sdrs"].items())
print(SdrService.sdrProps)
def sdrTypeAvailable(value):
try:
if not featureDetector.is_available(value["type"]):
print("The RTL source type \"{0}\" is not available. please check requirements.".format(value["type"]))
return False
return True
except UnknownFeatureException:
print("The RTL source type \"{0}\" is invalid. Please check your configuration".format(value["type"]))
return False
# transform all dictionary items into PropertyManager object, filtering out unavailable ones
SdrService.sdrProps = {
name: loadIntoPropertyManager(value) for (name, value) in pm["sdrs"].items() if sdrTypeAvailable(value)
}
print("SDR sources loaded. Availables SDRs: {0}".format(", ".join(map(lambda x: x["name"], SdrService.sdrProps.values()))))
@staticmethod
def getSource(id = None):
SdrService.loadProps()
if id is None:
# TODO: configure default sdr in config? right now it will pick the first one off the list.
id = list(SdrService.sdrProps.keys())[0]
if not id in SdrService.sources:
SdrService.sources[id] = SdrSource(SdrService.sdrProps[id], SdrService.getNextPort())
props = SdrService.sdrProps[id]
className = ''.join(x for x in props["type"].title() if x.isalnum()) + "Source"
cls = getattr(sys.modules[__name__], className)
SdrService.sources[id] = cls(props, SdrService.getNextPort())
return SdrService.sources[id]
sdr_types = {
"rtl_sdr": {
"command": "rtl_sdr -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -",
"format_conversion": "csdr convert_u8_f"
},
"hackrf": {
"command": "hackrf_transfer -s {samp_rate} -f {center_freq} -g {rf_gain} -l{lna_gain} -a{rf_amp} -r-",
"format_conversion": "csdr convert_s8_f"
},
"sdrplay": {
"command": "rx_sdr -F CF32 -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -",
"format_conversion": None,
"sleep": 1
}
}
class SdrSource(object):
def __init__(self, props, port):
self.props = props
@ -70,6 +74,10 @@ class SdrSource(object):
self.port = port
self.monitor = None
# override these in subclasses as necessary
self.command = None
self.format_conversion = None
def getProps(self):
return self.props
@ -81,14 +89,7 @@ class SdrSource(object):
props = self.rtlProps
featureDetector = FeatureDetector()
if not featureDetector.is_available(props["type"]):
print("The RTL source type {0} is not available. please check requirements.".format(props["rtl_type"]))
return
self.params = sdr_types[props["type"]]
start_sdr_command = self.params["command"].format(
start_sdr_command = self.command.format(
samp_rate = props["samp_rate"],
center_freq = props["center_freq"],
ppm = props["ppm"],
@ -97,8 +98,8 @@ class SdrSource(object):
rf_amp = props["rf_amp"]
)
if self.params["format_conversion"] is not None:
start_sdr_command += " | " + self.params["format_conversion"]
if self.format_conversion is not None:
start_sdr_command += " | " + self.format_conversion
nmux_bufcnt = nmux_bufsize = 0
while nmux_bufsize < props["samp_rate"]/4: nmux_bufsize += 4096
@ -125,8 +126,31 @@ class SdrSource(object):
def stop(self):
os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
self.monitor.join()
if "sleep" in self.params:
time.sleep(self.params["sleep"])
self.sleepOnRestart()
def sleepOnRestart(self):
pass
class RtlSdrSource(SdrSource):
def __init__(self, props, port):
super().__init__(props, port)
self.command = "rtl_sdr -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -"
self.format_conversion = "csdr convert_u8_f"
class HackrfSource(SdrSource):
def __init__(self, props, port):
super().__init__(props, port)
self.command = "hackrf_transfer -s {samp_rate} -f {center_freq} -g {rf_gain} -l{lna_gain} -a{rf_amp} -r-"
self.format_conversion = "csdr convert_s8_f"
class SdrplaySource(SdrSource):
def __init__(self, props, port):
super().__init__(props, port)
self.command = "rx_sdr -F CF32 -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -"
self.format_conversion = None
def sleepOnRestart(self):
time.sleep(1)
class SpectrumThread(object):
def __init__(self, sdrSource):

View File

@ -28,6 +28,9 @@ def main():
print(", ".join(featureDetector.get_requirements("core")))
return
# Get error messages about unknown / unavailable features as soon as possible
SdrService.loadProps()
server = ThreadedHttpServer(('0.0.0.0', pm.getPropertyValue("web_port")), RequestHandler)
server.serve_forever()