run the code formatter over all
This commit is contained in:
parent
f0dc2f8ebe
commit
64b7b485b3
19
csdr/csdr.py
19
csdr/csdr.py
@ -198,10 +198,7 @@ class dsp(object):
|
||||
"csdr limit_ff",
|
||||
]
|
||||
chain += last_decimation_block
|
||||
chain += [
|
||||
"csdr deemphasis_wfm_ff {audio_rate} {wfm_deemphasis_tau}",
|
||||
"csdr convert_f_s16"
|
||||
]
|
||||
chain += ["csdr deemphasis_wfm_ff {audio_rate} {wfm_deemphasis_tau}", "csdr convert_f_s16"]
|
||||
elif self.isDigitalVoice(which):
|
||||
chain += ["csdr fmdemod_quadri_cf"]
|
||||
chain += last_decimation_block
|
||||
@ -460,7 +457,9 @@ class dsp(object):
|
||||
def set_secondary_offset_freq(self, value):
|
||||
self.secondary_offset_freq = value
|
||||
if self.secondary_processes_running and self.has_pipe("secondary_shift_pipe"):
|
||||
self.pipes["secondary_shift_pipe"].write("%g\n" % (-float(self.secondary_offset_freq) / self.if_samp_rate()))
|
||||
self.pipes["secondary_shift_pipe"].write(
|
||||
"%g\n" % (-float(self.secondary_offset_freq) / self.if_samp_rate())
|
||||
)
|
||||
|
||||
def stop_secondary_demodulator(self):
|
||||
if not self.secondary_processes_running:
|
||||
@ -581,7 +580,7 @@ class dsp(object):
|
||||
demodulator = self.get_secondary_demodulator()
|
||||
return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w"]
|
||||
|
||||
def isJs8(self, demodulator = None):
|
||||
def isJs8(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_secondary_demodulator()
|
||||
return demodulator == "js8"
|
||||
@ -689,7 +688,11 @@ class dsp(object):
|
||||
def set_squelch_level(self, squelch_level):
|
||||
self.squelch_level = squelch_level
|
||||
# no squelch required on digital voice modes
|
||||
actual_squelch = -150 if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isFreeDV() else self.squelch_level
|
||||
actual_squelch = (
|
||||
-150
|
||||
if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isFreeDV()
|
||||
else self.squelch_level
|
||||
)
|
||||
if self.running:
|
||||
self.pipes["squelch_pipe"].write("%g\n" % (self.convertToLinear(actual_squelch)))
|
||||
|
||||
@ -842,6 +845,7 @@ class dsp(object):
|
||||
self.start_secondary_demodulator()
|
||||
|
||||
if self.has_pipe("smeter_pipe"):
|
||||
|
||||
def read_smeter():
|
||||
raw = self.pipes["smeter_pipe"].readline()
|
||||
if len(raw) == 0:
|
||||
@ -851,6 +855,7 @@ class dsp(object):
|
||||
|
||||
self.output.send_output("smeter", read_smeter)
|
||||
if self.has_pipe("meta_pipe"):
|
||||
|
||||
def read_meta():
|
||||
raw = self.pipes["meta_pipe"].readline()
|
||||
if len(raw) == 0:
|
||||
|
@ -42,6 +42,7 @@ class Pipe(object):
|
||||
immediately here), resulting in empty reads until data is available. This is handled specially in the
|
||||
ReadingPipe class.
|
||||
"""
|
||||
|
||||
def opener(path, flags):
|
||||
fd = os.open(path, flags | os.O_NONBLOCK)
|
||||
os.set_blocking(fd, True)
|
||||
@ -88,7 +89,7 @@ class WritingPipe(Pipe):
|
||||
except OSError as error:
|
||||
# ENXIO = FIFO has not been opened for reading
|
||||
if error.errno == 6:
|
||||
time.sleep(.1)
|
||||
time.sleep(0.1)
|
||||
retries += 1
|
||||
else:
|
||||
raise
|
||||
|
@ -40,9 +40,7 @@ Support and info: https://groups.io/g/openwebrx
|
||||
|
||||
configErrors = Config.validateConfig()
|
||||
if configErrors:
|
||||
logger.error(
|
||||
"your configuration contains errors. please address the following errors:"
|
||||
)
|
||||
logger.error("your configuration contains errors. please address the following errors:")
|
||||
for e in configErrors:
|
||||
logger.error(e)
|
||||
return
|
||||
|
@ -69,7 +69,9 @@ class DecoderQueue(Queue):
|
||||
with DecoderQueue.creationLock:
|
||||
if DecoderQueue.sharedInstance is None:
|
||||
pm = Config.get()
|
||||
DecoderQueue.sharedInstance = DecoderQueue(maxsize=pm["decoding_queue_length"], workers=pm["decoding_queue_workers"])
|
||||
DecoderQueue.sharedInstance = DecoderQueue(
|
||||
maxsize=pm["decoding_queue_length"], workers=pm["decoding_queue_workers"]
|
||||
)
|
||||
return DecoderQueue.sharedInstance
|
||||
|
||||
@staticmethod
|
||||
|
@ -17,7 +17,7 @@ class Band(object):
|
||||
for (mode, freqs) in dict["frequencies"].items():
|
||||
if mode not in availableModes:
|
||||
logger.info(
|
||||
"Modulation \"{mode}\" is not available, bandplan bookmark will not be displayed".format(
|
||||
'Modulation "{mode}" is not available, bandplan bookmark will not be displayed'.format(
|
||||
mode=mode
|
||||
)
|
||||
)
|
||||
|
@ -112,9 +112,7 @@ class Config:
|
||||
@staticmethod
|
||||
def validateConfig():
|
||||
pm = Config.get()
|
||||
errors = [
|
||||
Config.checkTempDirectory(pm)
|
||||
]
|
||||
errors = [Config.checkTempDirectory(pm)]
|
||||
|
||||
return [e for e in errors if e is not None]
|
||||
|
||||
|
@ -7,7 +7,9 @@ class Controller(object):
|
||||
self.request = request
|
||||
self.options = options
|
||||
|
||||
def send_response(self, content, code=200, content_type="text/html", last_modified: datetime = None, max_age=None, headers=None):
|
||||
def send_response(
|
||||
self, content, code=200, content_type="text/html", last_modified: datetime = None, max_age=None, headers=None
|
||||
):
|
||||
self.handler.send_response(code)
|
||||
if headers is None:
|
||||
headers = {}
|
||||
@ -27,7 +29,7 @@ class Controller(object):
|
||||
def send_redirect(self, location, code=303, cookies=None):
|
||||
self.handler.send_response(code)
|
||||
if cookies is not None:
|
||||
self.handler.send_header("Set-Cookie", cookies.output(header=''))
|
||||
self.handler.send_header("Set-Cookie", cookies.output(header=""))
|
||||
self.handler.send_header("Location", location)
|
||||
self.handler.end_headers()
|
||||
|
||||
|
@ -15,7 +15,7 @@ logger = logging.getLogger(__name__)
|
||||
class GzipMixin(object):
|
||||
def send_response(self, content, headers=None, content_type="text/html", *args, **kwargs):
|
||||
if self.zipable(content_type) and "accept-encoding" in self.request.headers:
|
||||
accepted = [s.strip().lower() for s in self.request.headers['accept-encoding'].split(",")]
|
||||
accepted = [s.strip().lower() for s in self.request.headers["accept-encoding"].split(",")]
|
||||
if "gzip" in accepted:
|
||||
if type(content) == str:
|
||||
content = content.encode()
|
||||
@ -26,11 +26,7 @@ class GzipMixin(object):
|
||||
super().send_response(content, headers=headers, content_type=content_type, *args, **kwargs)
|
||||
|
||||
def zipable(self, content_type):
|
||||
types = [
|
||||
"application/javascript",
|
||||
"text/css",
|
||||
"text/html"
|
||||
]
|
||||
types = ["application/javascript", "text/css", "text/html"]
|
||||
return content_type in types
|
||||
|
||||
def gzip(self, content):
|
||||
@ -143,7 +139,7 @@ class CompiledAssetsController(GzipMixin, ModificationAwareController):
|
||||
"lib/settings/Input.js",
|
||||
"lib/settings/SdrDevice.js",
|
||||
"settings.js",
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
def indexAction(self):
|
||||
|
@ -8,15 +8,19 @@ class ReceiverIdController(Controller):
|
||||
super().__init__(handler, request, options)
|
||||
self.authHeader = None
|
||||
|
||||
def send_response(self, content, code=200, content_type="text/html", last_modified: datetime = None, max_age=None, headers=None):
|
||||
def send_response(
|
||||
self, content, code=200, content_type="text/html", last_modified: datetime = None, max_age=None, headers=None
|
||||
):
|
||||
if self.authHeader is not None:
|
||||
if headers is None:
|
||||
headers = {}
|
||||
headers['Authorization'] = self.authHeader
|
||||
super().send_response(content, code=code, content_type=content_type, last_modified=last_modified, max_age=max_age, headers=headers)
|
||||
headers["Authorization"] = self.authHeader
|
||||
super().send_response(
|
||||
content, code=code, content_type=content_type, last_modified=last_modified, max_age=max_age, headers=headers
|
||||
)
|
||||
pass
|
||||
|
||||
def handle_request(self):
|
||||
if "Authorization" in self.request.headers:
|
||||
self.authHeader = ReceiverId.getResponseHeader(self.request.headers['Authorization'])
|
||||
self.authHeader = ReceiverId.getResponseHeader(self.request.headers["Authorization"])
|
||||
super().handle_request()
|
||||
|
@ -69,12 +69,16 @@ class SdrSettingsController(AdminController):
|
||||
{form}
|
||||
</div>
|
||||
</div>
|
||||
""".format(device_name=config["name"], form=self.render_form(device_id, config))
|
||||
""".format(
|
||||
device_name=config["name"], form=self.render_form(device_id, config)
|
||||
)
|
||||
|
||||
def render_form(self, device_id, config):
|
||||
return """
|
||||
<form class="sdrdevice" data-config="{formdata}"></form>
|
||||
""".format(device_id=device_id, formdata=quote(json.dumps(config)))
|
||||
""".format(
|
||||
device_id=device_id, formdata=quote(json.dumps(config))
|
||||
)
|
||||
|
||||
def indexAction(self):
|
||||
self.serve_template("sdrsettings.html", **self.template_variables())
|
||||
@ -119,12 +123,18 @@ class GeneralSettingsController(AdminController):
|
||||
DropdownInput(
|
||||
"audio_compression",
|
||||
"Audio compression",
|
||||
options=[Option("adpcm", "ADPCM"), Option("none", "None"),],
|
||||
options=[
|
||||
Option("adpcm", "ADPCM"),
|
||||
Option("none", "None"),
|
||||
],
|
||||
),
|
||||
DropdownInput(
|
||||
"fft_compression",
|
||||
"Waterfall compression",
|
||||
options=[Option("adpcm", "ADPCM"), Option("none", "None"),],
|
||||
options=[
|
||||
Option("adpcm", "ADPCM"),
|
||||
Option("none", "None"),
|
||||
],
|
||||
),
|
||||
),
|
||||
Section(
|
||||
@ -196,10 +206,7 @@ class GeneralSettingsController(AdminController):
|
||||
"Js8Call decoding depth",
|
||||
infotext="A higher decoding depth will allow more results, but will also consume more cpu",
|
||||
),
|
||||
Js8ProfileCheckboxInput(
|
||||
"js8_enabled_profiles",
|
||||
"Js8Call enabled modes"
|
||||
),
|
||||
Js8ProfileCheckboxInput("js8_enabled_profiles", "Js8Call enabled modes"),
|
||||
),
|
||||
Section(
|
||||
"Background decoding",
|
||||
@ -269,9 +276,7 @@ class GeneralSettingsController(AdminController):
|
||||
|
||||
def processFormData(self):
|
||||
data = parse_qs(self.get_body().decode("utf-8"))
|
||||
data = {
|
||||
k: v for i in GeneralSettingsController.sections for k, v in i.parse(data).items()
|
||||
}
|
||||
data = {k: v for i in GeneralSettingsController.sections for k, v in i.parse(data).items()}
|
||||
config = Config.get()
|
||||
for k, v in data.items():
|
||||
config[k] = v
|
||||
|
@ -22,7 +22,7 @@ class StatusController(ReceiverIdController):
|
||||
"name": receiver.getName(),
|
||||
# TODO would be better to have types from the config here
|
||||
"type": type(receiver).__name__,
|
||||
"profiles": [self.getProfileStats(p) for p in receiver.getProfiles().values()]
|
||||
"profiles": [self.getProfileStats(p) for p in receiver.getProfiles().values()],
|
||||
}
|
||||
return stats
|
||||
|
||||
@ -38,6 +38,6 @@ class StatusController(ReceiverIdController):
|
||||
},
|
||||
"max_clients": pm["max_clients"],
|
||||
"version": openwebrx_version,
|
||||
"sdrs": [self.getReceiverStats(r) for r in SdrService.getSources().values()]
|
||||
"sdrs": [self.getReceiverStats(r) for r in SdrService.getSources().values()],
|
||||
}
|
||||
self.send_response(json.dumps(status), content_type="application/json")
|
||||
|
@ -152,7 +152,14 @@ class FeatureDetector(object):
|
||||
# prevent X11 programs from opening windows if called from a GUI shell
|
||||
env.pop("DISPLAY", None)
|
||||
try:
|
||||
process = subprocess.Popen(cmd, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=tmp_dir, env=env)
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
cwd=tmp_dir,
|
||||
env=env,
|
||||
)
|
||||
rc = process.wait()
|
||||
if expected_result is None:
|
||||
return rc != 32512
|
||||
@ -214,7 +221,6 @@ class FeatureDetector(object):
|
||||
"""
|
||||
return self.command_is_runnable("perseustest -h")
|
||||
|
||||
|
||||
def has_digiham(self):
|
||||
"""
|
||||
To use digital voice modes, the digiham package is required. You can find the package and installation
|
||||
|
@ -10,9 +10,7 @@ class Input(ABC):
|
||||
self.infotext = infotext
|
||||
|
||||
def bootstrap_decorate(self, input):
|
||||
infotext = (
|
||||
"<small>{text}</small>".format(text=self.infotext) if self.infotext else ""
|
||||
)
|
||||
infotext = "<small>{text}</small>".format(text=self.infotext) if self.infotext else ""
|
||||
return """
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-form-label-sm col-3" for="{id}">{label}</label>
|
||||
@ -108,9 +106,7 @@ class LocationInput(Input):
|
||||
)
|
||||
|
||||
def parse(self, data):
|
||||
return {
|
||||
self.id: {k: float(data["{0}-{1}".format(self.id, k)][0]) for k in ["lat", "lon"]}
|
||||
}
|
||||
return {self.id: {k: float(data["{0}-{1}".format(self.id, k)][0]) for k in ["lat", "lon"]}}
|
||||
|
||||
|
||||
class TextAreaInput(Input):
|
||||
@ -195,9 +191,7 @@ class MultiCheckboxInput(Input):
|
||||
|
||||
class ServicesCheckboxInput(MultiCheckboxInput):
|
||||
def __init__(self, id, label, infotext=None):
|
||||
services = [
|
||||
Option(s.modulation, s.name) for s in Modes.getAvailableServices()
|
||||
]
|
||||
services = [Option(s.modulation, s.name) for s in Modes.getAvailableServices()]
|
||||
super().__init__(id, label, services, infotext)
|
||||
|
||||
|
||||
|
16
owrx/http.py
16
owrx/http.py
@ -1,14 +1,6 @@
|
||||
from owrx.controllers.status import StatusController
|
||||
from owrx.controllers.template import (
|
||||
IndexController,
|
||||
MapController,
|
||||
FeatureController
|
||||
)
|
||||
from owrx.controllers.assets import (
|
||||
OwrxAssetsController,
|
||||
AprsSymbolsController,
|
||||
CompiledAssetsController
|
||||
)
|
||||
from owrx.controllers.template import IndexController, MapController, FeatureController
|
||||
from owrx.controllers.assets import OwrxAssetsController, AprsSymbolsController, CompiledAssetsController
|
||||
from owrx.controllers.websocket import WebSocketController
|
||||
from owrx.controllers.api import ApiController
|
||||
from owrx.controllers.metrics import MetricsController
|
||||
@ -109,7 +101,9 @@ class Router(object):
|
||||
StaticRoute("/metrics", MetricsController),
|
||||
StaticRoute("/settings", SettingsController),
|
||||
StaticRoute("/generalsettings", GeneralSettingsController),
|
||||
StaticRoute("/generalsettings", GeneralSettingsController, method="POST", options={"action": "processFormData"}),
|
||||
StaticRoute(
|
||||
"/generalsettings", GeneralSettingsController, method="POST", options={"action": "processFormData"}
|
||||
),
|
||||
StaticRoute("/sdrsettings", SdrSettingsController),
|
||||
StaticRoute("/login", SessionController, options={"action": "loginAction"}),
|
||||
StaticRoute("/login", SessionController, method="POST", options={"action": "processLoginAction"}),
|
||||
|
@ -102,15 +102,17 @@ class Js8Parser(Parser):
|
||||
Map.getSharedInstance().updateLocation(
|
||||
frame.callsign, LocatorLocation(frame.grid), "JS8", self.band
|
||||
)
|
||||
ReportingEngine.getSharedInstance().spot({
|
||||
ReportingEngine.getSharedInstance().spot(
|
||||
{
|
||||
"callsign": frame.callsign,
|
||||
"mode": "JS8",
|
||||
"locator": frame.grid,
|
||||
"freq": self.dial_freq + frame.freq,
|
||||
"db": frame.db,
|
||||
"timestamp": frame.timestamp,
|
||||
"msg": str(frame)
|
||||
})
|
||||
"msg": str(frame),
|
||||
}
|
||||
)
|
||||
|
||||
except Exception:
|
||||
logger.exception("error while parsing js8 message")
|
||||
|
26
owrx/kiss.py
26
owrx/kiss.py
@ -13,6 +13,7 @@ TFESC = 0xDD
|
||||
|
||||
FEET_PER_METER = 3.28084
|
||||
|
||||
|
||||
class DirewolfConfig(object):
|
||||
def getConfig(self, port, is_service):
|
||||
pm = Config.get()
|
||||
@ -40,7 +41,7 @@ IGLOGIN {callsign} {password}
|
||||
)
|
||||
|
||||
if pm["aprs_igate_beacon"]:
|
||||
#Format beacon lat/lon
|
||||
# Format beacon lat/lon
|
||||
lat = pm["receiver_gps"]["lat"]
|
||||
lon = pm["receiver_gps"]["lon"]
|
||||
direction_ns = "N" if lat > 0 else "S"
|
||||
@ -50,13 +51,13 @@ IGLOGIN {callsign} {password}
|
||||
lat = "{0:02d}^{1:05.2f}{2}".format(int(lat), (lat - int(lat)) * 60, direction_ns)
|
||||
lon = "{0:03d}^{1:05.2f}{2}".format(int(lon), (lon - int(lon)) * 60, direction_we)
|
||||
|
||||
#Format beacon details
|
||||
# Format beacon details
|
||||
symbol = str(pm["aprs_igate_symbol"]) if "aprs_igate_symbol" in pm else "R&"
|
||||
gain = "GAIN=" + str(pm["aprs_igate_gain"]) if "aprs_igate_gain" in pm else ""
|
||||
adir = "DIR=" + str(pm["aprs_igate_dir"]) if "aprs_igate_dir" in pm else ""
|
||||
comment = str(pm["aprs_igate_comment"]) if "aprs_igate_comment" in pm else "\"OpenWebRX APRS gateway\""
|
||||
comment = str(pm["aprs_igate_comment"]) if "aprs_igate_comment" in pm else '"OpenWebRX APRS gateway"'
|
||||
|
||||
#Convert height from meters to feet if specified
|
||||
# Convert height from meters to feet if specified
|
||||
height = ""
|
||||
if "aprs_igate_height" in pm:
|
||||
try:
|
||||
@ -64,15 +65,18 @@ IGLOGIN {callsign} {password}
|
||||
height_ft = round(height_m * FEET_PER_METER)
|
||||
height = "HEIGHT=" + str(height_ft)
|
||||
except:
|
||||
logger.error("Cannot parse 'aprs_igate_height', expected float: " + str(pm["aprs_igate_height"]))
|
||||
logger.error(
|
||||
"Cannot parse 'aprs_igate_height', expected float: " + str(pm["aprs_igate_height"])
|
||||
)
|
||||
|
||||
if((len(comment) > 0) and ((comment[0] != '"') or (comment[len(comment)-1] != '"'))):
|
||||
comment = "\"" + comment + "\""
|
||||
elif(len(comment) == 0):
|
||||
comment = "\"\""
|
||||
if (len(comment) > 0) and ((comment[0] != '"') or (comment[len(comment) - 1] != '"')):
|
||||
comment = '"' + comment + '"'
|
||||
elif len(comment) == 0:
|
||||
comment = '""'
|
||||
|
||||
pbeacon = "PBEACON sendto=IG delay=0:30 every=60:00 symbol={symbol} lat={lat} long={lon} {height} {gain} {adir} comment={comment}".format(
|
||||
symbol=symbol, lat=lat, lon=lon, height=height, gain=gain, adir=adir, comment=comment )
|
||||
symbol=symbol, lat=lat, lon=lon, height=height, gain=gain, adir=adir, comment=comment
|
||||
)
|
||||
|
||||
logger.info("APRS PBEACON String: " + pbeacon)
|
||||
|
||||
@ -98,7 +102,7 @@ class KissClient(object):
|
||||
pass
|
||||
|
||||
def __init__(self, port):
|
||||
delay = .5
|
||||
delay = 0.5
|
||||
retries = 0
|
||||
while True:
|
||||
try:
|
||||
|
@ -60,24 +60,47 @@ class Modes(object):
|
||||
AnalogMode("usb", "USB", bandpass=Bandpass(300, 3000)),
|
||||
AnalogMode("cw", "CW", bandpass=Bandpass(700, 900)),
|
||||
AnalogMode("dmr", "DMR", bandpass=Bandpass(-4000, 4000), requirements=["digital_voice_digiham"], squelch=False),
|
||||
AnalogMode("dstar", "D-Star", bandpass=Bandpass(-3250, 3250), requirements=["digital_voice_dsd"], squelch=False),
|
||||
AnalogMode(
|
||||
"dstar", "D-Star", bandpass=Bandpass(-3250, 3250), requirements=["digital_voice_dsd"], squelch=False
|
||||
),
|
||||
AnalogMode("nxdn", "NXDN", bandpass=Bandpass(-3250, 3250), requirements=["digital_voice_dsd"], squelch=False),
|
||||
AnalogMode("ysf", "YSF", bandpass=Bandpass(-4000, 4000), requirements=["digital_voice_digiham"], squelch=False),
|
||||
AnalogMode("m17", "M17", bandpass=Bandpass(-4000, 4000), requirements=["digital_voice_m17"], squelch=False),
|
||||
AnalogMode("freedv", "FreeDV", bandpass=Bandpass(300, 3000), requirements=["digital_voice_freedv"], squelch=False),
|
||||
AnalogMode(
|
||||
"freedv", "FreeDV", bandpass=Bandpass(300, 3000), requirements=["digital_voice_freedv"], squelch=False
|
||||
),
|
||||
AnalogMode("drm", "DRM", bandpass=Bandpass(-5000, 5000), requirements=["drm"], squelch=False),
|
||||
DigitalMode("bpsk31", "BPSK31", underlying=["usb"]),
|
||||
DigitalMode("bpsk63", "BPSK63", underlying=["usb"]),
|
||||
DigitalMode("ft8", "FT8", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x"], service=True),
|
||||
DigitalMode("ft4", "FT4", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x"], service=True),
|
||||
DigitalMode("jt65", "JT65", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x"], service=True),
|
||||
DigitalMode("jt9", "JT9", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x"], service=True),
|
||||
DigitalMode(
|
||||
"ft8", "FT8", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x"], service=True
|
||||
),
|
||||
DigitalMode(
|
||||
"ft4", "FT4", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x"], service=True
|
||||
),
|
||||
DigitalMode(
|
||||
"jt65", "JT65", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x"], service=True
|
||||
),
|
||||
DigitalMode(
|
||||
"jt9", "JT9", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x"], service=True
|
||||
),
|
||||
DigitalMode(
|
||||
"wspr", "WSPR", underlying=["usb"], bandpass=Bandpass(1350, 1650), requirements=["wsjt-x"], service=True
|
||||
),
|
||||
DigitalMode("fst4", "FST4", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x-2-3"], service=True),
|
||||
DigitalMode("fst4w", "FST4W", underlying=["usb"], bandpass=Bandpass(1350, 1650), requirements=["wsjt-x-2-3"], service=True),
|
||||
DigitalMode("js8", "JS8Call", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["js8call"], service=True),
|
||||
DigitalMode(
|
||||
"fst4", "FST4", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["wsjt-x-2-3"], service=True
|
||||
),
|
||||
DigitalMode(
|
||||
"fst4w",
|
||||
"FST4W",
|
||||
underlying=["usb"],
|
||||
bandpass=Bandpass(1350, 1650),
|
||||
requirements=["wsjt-x-2-3"],
|
||||
service=True,
|
||||
),
|
||||
DigitalMode(
|
||||
"js8", "JS8Call", underlying=["usb"], bandpass=Bandpass(0, 3000), requirements=["js8call"], service=True
|
||||
),
|
||||
DigitalMode(
|
||||
"packet",
|
||||
"Packet",
|
||||
|
@ -150,10 +150,10 @@ class Uploader(object):
|
||||
# id
|
||||
[0x00, 0x03]
|
||||
# length
|
||||
+ list(length.to_bytes(2, 'big'))
|
||||
+ list(length.to_bytes(2, "big"))
|
||||
+ Uploader.receieverDelimiter
|
||||
# number of fields
|
||||
+ list(num_fields.to_bytes(2, 'big'))
|
||||
+ list(num_fields.to_bytes(2, "big"))
|
||||
# padding
|
||||
+ [0x00, 0x00]
|
||||
# receiverCallsign
|
||||
@ -163,9 +163,7 @@ class Uploader(object):
|
||||
# decodingSoftware
|
||||
+ [0x80, 0x08, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F]
|
||||
# antennaInformation
|
||||
+ (
|
||||
[0x80, 0x09, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F] if with_antenna else []
|
||||
)
|
||||
+ ([0x80, 0x09, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F] if with_antenna else [])
|
||||
# padding
|
||||
+ [0x00, 0x00]
|
||||
)
|
||||
|
@ -77,6 +77,7 @@ class ReceiverId(object):
|
||||
return Key(keyString)
|
||||
except KeyException as e:
|
||||
logger.error(e)
|
||||
|
||||
config = Config.get()
|
||||
if "receiver_keys" not in config or config["receiver_keys"] is None:
|
||||
return None
|
||||
|
@ -40,10 +40,12 @@ class ReportingEngine(object):
|
||||
if "pskreporter_enabled" in config and config["pskreporter_enabled"]:
|
||||
# inline import due to circular dependencies
|
||||
from owrx.pskreporter import PskReporter
|
||||
|
||||
self.reporters += [PskReporter()]
|
||||
if "wsprnet_enabled" in config and config["wsprnet_enabled"]:
|
||||
# inline import due to circular dependencies
|
||||
from owrx.wsprnet import WsprnetReporter
|
||||
|
||||
self.reporters += [WsprnetReporter()]
|
||||
|
||||
def stop(self):
|
||||
|
@ -137,9 +137,7 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
|
||||
dials = [
|
||||
dial
|
||||
for dial in Bandplan.getSharedInstance().collectDialFrequencies(
|
||||
frequency_range
|
||||
)
|
||||
for dial in Bandplan.getSharedInstance().collectDialFrequencies(frequency_range)
|
||||
if self.isSupported(dial["mode"])
|
||||
]
|
||||
|
||||
@ -150,16 +148,12 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
groups = self.optimizeResampling(dials, sr)
|
||||
if groups is None:
|
||||
for dial in dials:
|
||||
self.services.append(
|
||||
self.setupService(dial["mode"], dial["frequency"], self.source)
|
||||
)
|
||||
self.services.append(self.setupService(dial["mode"], dial["frequency"], self.source))
|
||||
else:
|
||||
for group in groups:
|
||||
cf = self.get_center_frequency(group)
|
||||
bw = self.get_bandwidth(group)
|
||||
logger.debug(
|
||||
"group center frequency: {0}, bandwidth: {1}".format(cf, bw)
|
||||
)
|
||||
logger.debug("group center frequency: {0}, bandwidth: {1}".format(cf, bw))
|
||||
resampler_props = PropertyLayer()
|
||||
resampler_props["center_freq"] = cf
|
||||
resampler_props["samp_rate"] = bw
|
||||
@ -167,11 +161,7 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
resampler.start()
|
||||
|
||||
for dial in group:
|
||||
self.services.append(
|
||||
self.setupService(
|
||||
dial["mode"], dial["frequency"], resampler
|
||||
)
|
||||
)
|
||||
self.services.append(self.setupService(dial["mode"], dial["frequency"], resampler))
|
||||
|
||||
# resampler goes in after the services since it must not be shutdown as long as the services are still running
|
||||
self.services.append(resampler)
|
||||
@ -238,9 +228,7 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
results = sorted(usages, key=lambda f: f["total_bandwidth"])
|
||||
|
||||
for r in results:
|
||||
logger.debug(
|
||||
"splits: {0}, total: {1}".format(r["num_splits"], r["total_bandwidth"])
|
||||
)
|
||||
logger.debug("splits: {0}, total: {1}".format(r["num_splits"], r["total_bandwidth"]))
|
||||
|
||||
best = results[0]
|
||||
if best["num_splits"] is None:
|
||||
@ -267,7 +255,7 @@ class ServiceHandler(SdrSourceEventClient):
|
||||
d.set_secondary_demodulator(mode)
|
||||
d.set_audio_compression("none")
|
||||
d.set_samp_rate(source.getProps()["samp_rate"])
|
||||
d.set_temporary_directory(Config.get()['temporary_directory'])
|
||||
d.set_temporary_directory(Config.get()["temporary_directory"])
|
||||
d.set_service()
|
||||
d.start()
|
||||
return d
|
||||
|
@ -68,6 +68,7 @@ class DatetimeScheduleEntry(ScheduleEntry):
|
||||
def getNextActivation(self):
|
||||
return self.startTime
|
||||
|
||||
|
||||
class Schedule(ABC):
|
||||
@staticmethod
|
||||
def parse(props):
|
||||
@ -140,7 +141,7 @@ class DaylightSchedule(TimerangeSchedule):
|
||||
degtorad = math.pi / 180
|
||||
radtodeg = 180 / math.pi
|
||||
|
||||
#Number of days since 01/01
|
||||
# Number of days since 01/01
|
||||
days = date.timetuple().tm_yday
|
||||
|
||||
# Longitudinal correction
|
||||
|
@ -82,17 +82,17 @@ class SdrSource(ABC):
|
||||
for id, p in self.props["profiles"].items():
|
||||
props.replaceLayer(0, self._getProfilePropertyLayer(p))
|
||||
if "center_freq" not in props:
|
||||
logger.warning("Profile \"%s\" does not specify a center_freq", id)
|
||||
logger.warning('Profile "%s" does not specify a center_freq', id)
|
||||
continue
|
||||
if "samp_rate" not in props:
|
||||
logger.warning("Profile \"%s\" does not specify a samp_rate", id)
|
||||
logger.warning('Profile "%s" does not specify a samp_rate', id)
|
||||
continue
|
||||
if "start_freq" in props:
|
||||
start_freq = props["start_freq"]
|
||||
srh = props["samp_rate"] / 2
|
||||
center_freq = props["center_freq"]
|
||||
if start_freq < center_freq - srh or start_freq > center_freq + srh:
|
||||
logger.warning("start_freq for profile \"%s\" is out of range", id)
|
||||
logger.warning('start_freq for profile "%s" is out of range', id)
|
||||
|
||||
def _getProfilePropertyLayer(self, profile):
|
||||
layer = PropertyLayer()
|
||||
|
@ -15,7 +15,10 @@ class ConnectorSource(SdrSource):
|
||||
super().__init__(id, props)
|
||||
|
||||
def getCommandMapper(self):
|
||||
return super().getCommandMapper().setMappings(
|
||||
return (
|
||||
super()
|
||||
.getCommandMapper()
|
||||
.setMappings(
|
||||
{
|
||||
"samp_rate": Option("-s"),
|
||||
"tuner_freq": Option("-f"),
|
||||
@ -28,6 +31,7 @@ class ConnectorSource(SdrSource):
|
||||
"rf_gain": Option("-g"),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
def sendControlMessage(self, changes):
|
||||
for prop, value in changes.items():
|
||||
|
@ -32,11 +32,14 @@ class DirectSource(SdrSource, metaclass=ABCMeta):
|
||||
"These depend on nmux_memory and samp_rate options in config_webrx.py"
|
||||
)
|
||||
|
||||
return ["nmux --bufsize %d --bufcnt %d --port %d --address 127.0.0.1" % (
|
||||
return [
|
||||
"nmux --bufsize %d --bufcnt %d --port %d --address 127.0.0.1"
|
||||
% (
|
||||
nmux_bufsize,
|
||||
nmux_bufcnt,
|
||||
self.port,
|
||||
)]
|
||||
)
|
||||
]
|
||||
|
||||
def getCommand(self):
|
||||
return super().getCommand() + self.getFormatConversion() + self.getNmuxCommand()
|
||||
|
@ -8,8 +8,10 @@ class Eb200Source(ConnectorSource):
|
||||
super()
|
||||
.getCommandMapper()
|
||||
.setBase("eb200_connector")
|
||||
.setMappings({
|
||||
.setMappings(
|
||||
{
|
||||
"long": Flag("-l"),
|
||||
"remote": Argument(),
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
|
@ -9,9 +9,13 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class FifiSdrSource(DirectSource):
|
||||
def getCommandMapper(self):
|
||||
return super().getCommandMapper().setBase("arecord").setMappings(
|
||||
{"device": Option("-D"), "samp_rate": Option("-r")}
|
||||
).setStatic("-t raw -f S16_LE -c2 -")
|
||||
return (
|
||||
super()
|
||||
.getCommandMapper()
|
||||
.setBase("arecord")
|
||||
.setMappings({"device": Option("-D"), "samp_rate": Option("-r")})
|
||||
.setStatic("-t raw -f S16_LE -c2 -")
|
||||
)
|
||||
|
||||
def getEventNames(self):
|
||||
return super().getEventNames() + ["device"]
|
||||
@ -20,7 +24,7 @@ class FifiSdrSource(DirectSource):
|
||||
return ["csdr convert_s16_f", "csdr gain_ff 5"]
|
||||
|
||||
def sendRockProgFrequency(self, frequency):
|
||||
process = Popen(["rockprog", "--vco", "-w", "--freq={}".format(frequency / 1E6)])
|
||||
process = Popen(["rockprog", "--vco", "-w", "--freq={}".format(frequency / 1e6)])
|
||||
process.communicate()
|
||||
rc = process.wait()
|
||||
if rc != 0:
|
||||
|
@ -17,6 +17,7 @@ from owrx.command import Flag, Option
|
||||
# If you omit `remote` from config_webrx.py, hpsdrconnector will use the HPSDR discovery protocol
|
||||
# to find radios on your local network and will connect to the first radio it discovered.
|
||||
|
||||
|
||||
class HpsdrSource(ConnectorSource):
|
||||
def getCommandMapper(self):
|
||||
return (
|
||||
@ -29,5 +30,6 @@ class HpsdrSource(ConnectorSource):
|
||||
"samp_rate": Option("--samplerate"),
|
||||
"remote": Option("--radio"),
|
||||
"rf_gain": Option("--gain"),
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
|
@ -17,9 +17,14 @@ from owrx.command import Flag, Option
|
||||
# floating points (option -p),no need for further conversions,
|
||||
# so the method getFormatConversion(self) is not implemented at all.
|
||||
|
||||
|
||||
class PerseussdrSource(DirectSource):
|
||||
def getCommandMapper(self):
|
||||
return super().getCommandMapper().setBase("perseustest -p -d -1 -a -t 0 -o - ").setMappings(
|
||||
return (
|
||||
super()
|
||||
.getCommandMapper()
|
||||
.setBase("perseustest -p -d -1 -a -t 0 -o - ")
|
||||
.setMappings(
|
||||
{
|
||||
"samp_rate": Option("-s"),
|
||||
"tuner_freq": Option("-f"),
|
||||
@ -29,3 +34,4 @@ class PerseussdrSource(DirectSource):
|
||||
"wideband": Option("-w"),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
@ -8,9 +8,11 @@ class RtlTcpSource(ConnectorSource):
|
||||
super()
|
||||
.getCommandMapper()
|
||||
.setBase("rtl_tcp_connector")
|
||||
.setMappings({
|
||||
.setMappings(
|
||||
{
|
||||
"bias_tee": Flag("-b"),
|
||||
"direct_sampling": Option("-e"),
|
||||
"remote": Argument(),
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
|
@ -5,12 +5,17 @@ from .connector import ConnectorSource
|
||||
|
||||
class SoapyConnectorSource(ConnectorSource, metaclass=ABCMeta):
|
||||
def getCommandMapper(self):
|
||||
return super().getCommandMapper().setBase("soapy_connector").setMappings(
|
||||
return (
|
||||
super()
|
||||
.getCommandMapper()
|
||||
.setBase("soapy_connector")
|
||||
.setMappings(
|
||||
{
|
||||
"antenna": Option("-a"),
|
||||
"soapy_settings": Option("-t"),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
"""
|
||||
must be implemented by child classes to be able to build a driver-based device selector by default.
|
||||
|
@ -29,7 +29,7 @@ class Password(ABC):
|
||||
|
||||
class CleartextPassword(Password):
|
||||
def is_valid(self, inp: str):
|
||||
return self.pwinfo['value'] == inp
|
||||
return self.pwinfo["value"] == inp
|
||||
|
||||
|
||||
class User(object):
|
||||
|
@ -208,7 +208,7 @@ class Decoder(ABC):
|
||||
dateformat = self.profile.getTimestampFormat()
|
||||
remain = instring[len(dateformat) + 1:]
|
||||
try:
|
||||
ts = datetime.strptime(instring[0:len(dateformat)], dateformat)
|
||||
ts = datetime.strptime(instring[0: len(dateformat)], dateformat)
|
||||
return remain, int(
|
||||
datetime.combine(datetime.utcnow().date(), ts.time()).replace(tzinfo=timezone.utc).timestamp() * 1000
|
||||
)
|
||||
|
@ -43,7 +43,8 @@ class Worker(threading.Thread):
|
||||
# function=wspr&date=210114&time=1732&sig=-15&dt=0.5&drift=0&tqrg=7.040019&tcall=DF2UU&tgrid=JN48&dbm=37&version=2.3.0-rc3&rcall=DD5JFK&rgrid=JN58SC&rqrg=7.040047&mode=2
|
||||
# {'timestamp': 1610655960000, 'db': -23.0, 'dt': 0.3, 'freq': 7040048, 'drift': -1, 'msg': 'LA3JJ JO59 37', 'callsign': 'LA3JJ', 'locator': 'JO59', 'mode': 'WSPR'}
|
||||
date = datetime.fromtimestamp(spot["timestamp"] / 1000, tz=timezone.utc)
|
||||
data = parse.urlencode({
|
||||
data = parse.urlencode(
|
||||
{
|
||||
"function": "wspr",
|
||||
"date": date.strftime("%y%m%d"),
|
||||
"time": date.strftime("%H%M"),
|
||||
@ -51,7 +52,7 @@ class Worker(threading.Thread):
|
||||
"dt": spot["dt"],
|
||||
# FST4W does not have drift
|
||||
"drift": spot["drift"] if "drift" in spot else 0,
|
||||
"tqrg": spot["freq"] / 1E6,
|
||||
"tqrg": spot["freq"] / 1e6,
|
||||
"tcall": spot["callsign"],
|
||||
"tgrid": spot["locator"],
|
||||
"dbm": spot["dbm"],
|
||||
@ -59,8 +60,9 @@ class Worker(threading.Thread):
|
||||
"rcall": self.callsign,
|
||||
"rgrid": self.locator,
|
||||
# mode 2 = WSPR 2 minutes
|
||||
"mode": self._getMode(spot)
|
||||
}).encode()
|
||||
"mode": self._getMode(spot),
|
||||
}
|
||||
).encode()
|
||||
request.urlopen("http://wsprnet.org/post/", data)
|
||||
|
||||
|
||||
|
14
setup.py
14
setup.py
@ -6,12 +6,24 @@ try:
|
||||
from setuptools import find_namespace_packages
|
||||
except ImportError:
|
||||
from setuptools import PEP420PackageFinder
|
||||
|
||||
find_namespace_packages = PEP420PackageFinder.find
|
||||
|
||||
setup(
|
||||
name="OpenWebRX",
|
||||
version=str(looseversion),
|
||||
packages=find_namespace_packages(include=["owrx", "owrx.source", "owrx.service", "owrx.controllers", "owrx.property", "owrx.form", "csdr", "htdocs"]),
|
||||
packages=find_namespace_packages(
|
||||
include=[
|
||||
"owrx",
|
||||
"owrx.source",
|
||||
"owrx.service",
|
||||
"owrx.controllers",
|
||||
"owrx.property",
|
||||
"owrx.form",
|
||||
"csdr",
|
||||
"htdocs",
|
||||
]
|
||||
),
|
||||
package_data={"htdocs": [f[len("htdocs/") :] for f in glob("htdocs/**/*", recursive=True)]},
|
||||
entry_points={"console_scripts": ["openwebrx=owrx.__main__:main"]},
|
||||
url="https://www.openwebrx.de/",
|
||||
|
@ -4,7 +4,6 @@ from owrx.property import PropertyLayer, PropertyFilter
|
||||
|
||||
|
||||
class PropertyFilterTest(TestCase):
|
||||
|
||||
def testPassesProperty(self):
|
||||
pm = PropertyLayer()
|
||||
pm["testkey"] = "testvalue"
|
||||
|
Loading…
Reference in New Issue
Block a user