Merge branch 'develop' into packet
This commit is contained in:
@ -2,6 +2,8 @@ import os
|
||||
import subprocess
|
||||
from functools import reduce
|
||||
from operator import and_
|
||||
import re
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -16,8 +18,9 @@ class FeatureDetector(object):
|
||||
"rtl_sdr": [ "rtl_sdr" ],
|
||||
"sdrplay": [ "rx_tools" ],
|
||||
"hackrf": [ "hackrf_transfer" ],
|
||||
"airspy": [ "airspy_rx" ],
|
||||
"digital_voice_digiham": [ "digiham", "sox" ],
|
||||
"digital_voice_dsd": [ "dsd", "sox" ],
|
||||
"digital_voice_dsd": [ "dsd", "sox", "digiham" ],
|
||||
"packet": [ "direwolf" ]
|
||||
}
|
||||
|
||||
@ -82,19 +85,31 @@ class FeatureDetector(object):
|
||||
def command_exists(self, command):
|
||||
return os.system("which {0}".format(command)) == 0
|
||||
|
||||
"""
|
||||
To use DMR and YSF, the digiham package is required. You can find the package and installation instructions here:
|
||||
https://github.com/jketterl/digiham
|
||||
|
||||
Please note: there is close interaction between digiham and openwebrx, so older versions will probably not work.
|
||||
If you have an older verison of digiham installed, please update it along with openwebrx.
|
||||
As of now, we require version 0.2 of digiham.
|
||||
"""
|
||||
def has_digiham(self):
|
||||
# the digiham tools expect to be fed via stdin, they will block until their stdin is closed.
|
||||
def check_with_stdin(command):
|
||||
required_version = LooseVersion("0.2")
|
||||
|
||||
digiham_version_regex = re.compile('^digiham version (.*)$')
|
||||
def check_digiham_version(command):
|
||||
try:
|
||||
process = subprocess.Popen(command, stdin=subprocess.PIPE)
|
||||
process.communicate("")
|
||||
return process.wait() == 0
|
||||
process = subprocess.Popen([command, "--version"], stdout=subprocess.PIPE)
|
||||
version = LooseVersion(digiham_version_regex.match(process.stdout.readline().decode()).group(1))
|
||||
process.wait(1)
|
||||
return version >= required_version
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
return reduce(and_,
|
||||
map(
|
||||
check_with_stdin,
|
||||
["rrc_filter", "ysf_decoder", "dmr_decoder", "mbe_synthesizer", "gfsk_demodulator"]
|
||||
check_digiham_version,
|
||||
["rrc_filter", "ysf_decoder", "dmr_decoder", "mbe_synthesizer", "gfsk_demodulator",
|
||||
"digitalvoice_filter"]
|
||||
),
|
||||
True)
|
||||
|
||||
@ -105,4 +120,7 @@ class FeatureDetector(object):
|
||||
return self.command_is_runnable("sox")
|
||||
|
||||
def has_direwolf(self):
|
||||
return self.command_is_runnable("direwolf --help")
|
||||
return self.command_is_runnable("direwolf --help")
|
||||
|
||||
def has_airspy_rx(self):
|
||||
return self.command_is_runnable("airspy_rx --help 2> /dev/null")
|
||||
|
@ -18,7 +18,9 @@ class Router(object):
|
||||
{"route": "/status", "controller": StatusController},
|
||||
{"regex": "/static/(.+)", "controller": AssetsController},
|
||||
{"route": "/ws/", "controller": WebSocketController},
|
||||
{"regex": "(/favicon.ico)", "controller": AssetsController}
|
||||
{"regex": "(/favicon.ico)", "controller": AssetsController},
|
||||
# backwards compatibility for the sdr.hu portal
|
||||
{"regex": "/(gfx/openwebrx-avatar.png)", "controller": AssetsController}
|
||||
]
|
||||
def find_controller(self, path):
|
||||
for m in Router.mappings:
|
||||
|
@ -64,11 +64,13 @@ class MetaParser(object):
|
||||
enrichers = {
|
||||
"DMR": DmrMetaEnricher()
|
||||
}
|
||||
|
||||
def __init__(self, handler):
|
||||
self.handler = handler
|
||||
|
||||
def parse(self, meta):
|
||||
fields = meta.split(";")
|
||||
meta = {v[0] : "".join(v[1:]) for v in map(lambda x: x.split(":"), fields)}
|
||||
meta = {v[0]: "".join(v[1:]) for v in map(lambda x: x.split(":"), fields) if v[0] != ""}
|
||||
|
||||
if "protocol" in meta:
|
||||
protocol = meta["protocol"]
|
||||
|
@ -257,6 +257,16 @@ class SdrplaySource(SdrSource):
|
||||
def sleepOnRestart(self):
|
||||
time.sleep(1)
|
||||
|
||||
class AirspySource(SdrSource):
|
||||
def getCommand(self):
|
||||
frequency = self.props['center_freq'] / 1e6
|
||||
command = "airspy_rx"
|
||||
command += " -f{0}".format(frequency)
|
||||
command += " -r /dev/stdout -a{samp_rate} -g {rf_gain}"
|
||||
return command
|
||||
def getFormatConversion(self):
|
||||
return "csdr convert_s16_f"
|
||||
|
||||
class SpectrumThread(csdr.output):
|
||||
def __init__(self, sdrSource):
|
||||
self.sdrSource = sdrSource
|
||||
@ -339,7 +349,8 @@ class DspManager(csdr.output):
|
||||
|
||||
self.localProps = self.sdrSource.getProps().collect(
|
||||
"audio_compression", "fft_compression", "digimodes_fft_size", "csdr_dynamic_bufsize",
|
||||
"csdr_print_bufsizes", "csdr_through", "digimodes_enable", "samp_rate", "digital_voice_unvoiced_quality"
|
||||
"csdr_print_bufsizes", "csdr_through", "digimodes_enable", "samp_rate", "digital_voice_unvoiced_quality",
|
||||
"dmr_filter"
|
||||
).defaults(PropertyManager.getSharedInstance())
|
||||
|
||||
self.dsp = csdr.dsp(self)
|
||||
@ -366,7 +377,8 @@ class DspManager(csdr.output):
|
||||
self.localProps.getProperty("low_cut").wire(set_low_cut),
|
||||
self.localProps.getProperty("high_cut").wire(set_high_cut),
|
||||
self.localProps.getProperty("mod").wire(self.dsp.set_demodulator),
|
||||
self.localProps.getProperty("digital_voice_unvoiced_quality").wire(self.dsp.set_unvoiced_quality)
|
||||
self.localProps.getProperty("digital_voice_unvoiced_quality").wire(self.dsp.set_unvoiced_quality),
|
||||
self.localProps.getProperty("dmr_filter").wire(self.dsp.set_dmr_filter)
|
||||
]
|
||||
|
||||
self.dsp.set_offset_freq(0)
|
||||
|
@ -38,12 +38,16 @@ class WebSocketConnection(object):
|
||||
# string-type messages are sent as text frames
|
||||
if (type(data) == str):
|
||||
header = self.get_header(len(data), 1)
|
||||
self.handler.wfile.write(header + data.encode('utf-8'))
|
||||
self.handler.wfile.flush()
|
||||
data_to_send = header + data.encode('utf-8')
|
||||
# anything else as binary
|
||||
else:
|
||||
header = self.get_header(len(data), 2)
|
||||
self.handler.wfile.write(header + data)
|
||||
data_to_send = header + data
|
||||
written = self.handler.wfile.write(data_to_send)
|
||||
if (written != len(data_to_send)):
|
||||
logger.error("incomplete write! closing socket!")
|
||||
self.close()
|
||||
else:
|
||||
self.handler.wfile.flush()
|
||||
|
||||
def read_loop(self):
|
||||
@ -78,7 +82,9 @@ class WebSocketConnection(object):
|
||||
self.handler.wfile.write(header)
|
||||
self.handler.wfile.flush()
|
||||
except ValueError:
|
||||
logger.exception("while writing close frame:")
|
||||
logger.exception("ValueError while writing close frame:")
|
||||
except OSError:
|
||||
logger.exception("OSError while writing close frame:")
|
||||
|
||||
try:
|
||||
self.handler.finish()
|
||||
|
Reference in New Issue
Block a user