diff --git a/CHANGELOG.md b/CHANGELOG.md index bccdffbc..47160762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,17 @@ **unreleased** - SDR device log messages are now available in the web configuration to simplify troubleshooting - Added support for the MSK144 digimode +- Added support for decoding ADS-B with dump1090 +- Added support for decoding HFDL and VDL2 aircraft communications +- Added decoding of ISM band transmissions using rtl_433 - Added IPv6 support - Added profile re-ordering using drag & drop - Added the ability to disable profiles +- New devices supported: + - Afedri SDR-Net + +**1.2.2** +- Fixed an over-the-air code injection vulnerability **1.2.1** - FifiSDR support fixed (pipeline formats now line up correctly) diff --git a/bands.json b/bands.json index 75a3f024..3d50ac71 100644 --- a/bands.json +++ b/bands.json @@ -367,5 +367,23 @@ "lower_bound": 446000000, "upper_bound": 446200000, "tags": ["public"] + }, + { + "name": "Aeronautical Radionavigation", + "lower_bound": 960000000, + "upper_bound": 1215000000, + "tags": [], + "frequencies": { + "adsb": 1090000000 + } + }, + { + "name": "ISM-433", + "lower_bound": 433050000, + "upper_bound": 434790000, + "tags": [], + "frequencies": { + "ism": 433920000 + } } ] diff --git a/csdr/chain/__init__.py b/csdr/chain/__init__.py index b9af86a9..bebe121d 100644 --- a/csdr/chain/__init__.py +++ b/csdr/chain/__init__.py @@ -94,19 +94,24 @@ class Chain(Module): if self.writer is not None: newWorker.setWriter(self.writer) - def insert(self, newWorker): + def insert(self, index, newWorker): nextWorker = None - if self.workers: - nextWorker = self.workers[0] + previousWorker = None + if index < len(self.workers): + nextWorker = self.workers[index] + if index > 0: + previousWorker = self.workers[index - 1] - self.workers.insert(0, newWorker) + self.workers.insert(index, newWorker) if nextWorker: self._connect(newWorker, nextWorker) elif self.writer is not None: newWorker.setWriter(self.writer) - if self.reader is not None: + if previousWorker: + self._connect(previousWorker, newWorker) + elif self.reader is not None: newWorker.setReader(self.reader) def remove(self, index): diff --git a/csdr/chain/analog.py b/csdr/chain/analog.py index 6bb277f0..2a2341e6 100644 --- a/csdr/chain/analog.py +++ b/csdr/chain/analog.py @@ -74,3 +74,14 @@ class Ssb(BaseDemodulatorChain): Agc(Format.FLOAT), ] super().__init__(workers) + + +class Empty(BaseDemodulatorChain): + def __init__(self): + super().__init__([]) + + def getOutputFormat(self) -> Format: + return Format.FLOAT + + def setWriter(self, writer): + pass diff --git a/csdr/chain/clientaudio.py b/csdr/chain/clientaudio.py index febfd15c..9fd748b8 100644 --- a/csdr/chain/clientaudio.py +++ b/csdr/chain/clientaudio.py @@ -42,7 +42,7 @@ class ClientAudioChain(Chain): if index >= 0: self.replace(index, converter) else: - self.insert(converter) + self.insert(0, converter) def setFormat(self, format: Format) -> None: if format == self.format: diff --git a/csdr/chain/demodulator.py b/csdr/chain/demodulator.py index c72658c3..b16f806d 100644 --- a/csdr/chain/demodulator.py +++ b/csdr/chain/demodulator.py @@ -64,6 +64,9 @@ class SecondaryDemodulator(Chain): def setSampleRate(self, sampleRate: int) -> None: pass + def isSecondaryFftShown(self): + return True + class ServiceDemodulator(SecondaryDemodulator, FixedAudioRateChain, metaclass=ABCMeta): pass diff --git a/csdr/chain/digiham.py b/csdr/chain/digiham.py index fbbd91af..ebd282f0 100644 --- a/csdr/chain/digiham.py +++ b/csdr/chain/digiham.py @@ -1,11 +1,15 @@ from csdr.chain.demodulator import BaseDemodulatorChain, FixedAudioRateChain, FixedIfSampleRateChain, DialFrequencyReceiver, MetaProvider, SlotFilterChain, DemodulatorError, ServiceDemodulator -from pycsdr.modules import FmDemod, Agc, Writer, Buffer +from pycsdr.modules import FmDemod, Agc, Writer, Buffer, DcBlock, Lowpass from pycsdr.types import Format -from digiham.modules import DstarDecoder, DcBlock, FskDemodulator, GfskDemodulator, DigitalVoiceFilter, MbeSynthesizer, NarrowRrcFilter, NxdnDecoder, DmrDecoder, WideRrcFilter, YsfDecoder, PocsagDecoder +from digiham.modules import DstarDecoder, FskDemodulator, GfskDemodulator, DigitalVoiceFilter, MbeSynthesizer, NarrowRrcFilter, NxdnDecoder, DmrDecoder, WideRrcFilter, YsfDecoder, PocsagDecoder from digiham.ambe import Modes, ServerError from owrx.meta import MetaParser from owrx.pocsag import PocsagParser +import logging + +logger = logging.getLogger(__name__) + class DigihamChain(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, DialFrequencyReceiver, MetaProvider): def __init__(self, fskDemodulator, decoder, mbeMode, filter=None, codecserver: str = ""): @@ -24,6 +28,9 @@ class DigihamChain(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateC raise DemodulatorError("Connection to codecserver failed: {}".format(ce)) except ServerError as se: raise DemodulatorError("Codecserver error: {}".format(se)) + except RuntimeError as re: + logger.exception("Codecserver error while instantiating MbeSynthesizer:") + raise DemodulatorError("Fatal codecserver error. Please check receiver logs.") workers += [ fskDemodulator, decoder, @@ -72,6 +79,7 @@ class Dstar(DigihamChain): fskDemodulator=FskDemodulator(samplesPerSymbol=10), decoder=DstarDecoder(), mbeMode=Modes.DStarMode, + filter=WideRrcFilter(), codecserver=codecserver ) @@ -117,6 +125,8 @@ class PocsagDemodulator(ServiceDemodulator, DialFrequencyReceiver): self.parser = PocsagParser() workers = [ FmDemod(), + DcBlock(), + Lowpass(Format.FLOAT, 1200 / self.getFixedAudioRate()), FskDemodulator(samplesPerSymbol=40, invert=True), PocsagDecoder(), self.parser, diff --git a/csdr/chain/digimodes.py b/csdr/chain/digimodes.py index d19deaae..a8420609 100644 --- a/csdr/chain/digimodes.py +++ b/csdr/chain/digimodes.py @@ -3,9 +3,9 @@ from csdr.module.msk144 import Msk144Module, ParserAdapter from owrx.audio.chopper import AudioChopper, AudioChopperParser from owrx.aprs.kiss import KissDeframer from owrx.aprs import Ax25Parser, AprsParser -from pycsdr.modules import Convert, FmDemod, Agc, TimingRecovery, DBPskDecoder, VaricodeDecoder +from pycsdr.modules import Convert, FmDemod, Agc, TimingRecovery, DBPskDecoder, VaricodeDecoder, RttyDecoder, BaudotDecoder, Lowpass from pycsdr.types import Format -from owrx.aprs.module import DirewolfModule +from owrx.aprs.direwolf import DirewolfModule class AudioChopperDemodulator(ServiceDemodulator, DialFrequencyReceiver): @@ -69,7 +69,7 @@ class PskDemodulator(SecondaryDemodulator, SecondarySelectorChain): secondary_samples_per_bits = int(round(self.sampleRate / self.baudRate)) & ~3 workers = [ Agc(Format.COMPLEX_FLOAT), - TimingRecovery(secondary_samples_per_bits, 0.5, 2, useQ=True), + TimingRecovery(Format.COMPLEX_FLOAT, secondary_samples_per_bits, 0.5, 2), DBPskDecoder(), VaricodeDecoder(), ] @@ -83,4 +83,38 @@ class PskDemodulator(SecondaryDemodulator, SecondarySelectorChain): return self.sampleRate = sampleRate secondary_samples_per_bits = int(round(self.sampleRate / self.baudRate)) & ~3 - self.replace(1, TimingRecovery(secondary_samples_per_bits, 0.5, 2, useQ=True)) + self.replace(1, TimingRecovery(Format.COMPLEX_FLOAT, secondary_samples_per_bits, 0.5, 2)) + + +class RttyDemodulator(SecondaryDemodulator, SecondarySelectorChain): + def __init__(self, baudRate, bandWidth, invert=False): + self.baudRate = baudRate + self.bandWidth = bandWidth + self.invert = invert + # this is an assumption, we will adjust in setSampleRate + self.sampleRate = 12000 + secondary_samples_per_bit = int(round(self.sampleRate / self.baudRate)) + cutoff = self.baudRate / self.sampleRate + loop_gain = self.sampleRate / self.getBandwidth() / 5 + workers = [ + Agc(Format.COMPLEX_FLOAT), + FmDemod(), + Lowpass(Format.FLOAT, cutoff), + TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10), + RttyDecoder(invert), + BaudotDecoder(), + ] + super().__init__(workers) + + def getBandwidth(self) -> float: + return self.bandWidth + + def setSampleRate(self, sampleRate: int) -> None: + if sampleRate == self.sampleRate: + return + self.sampleRate = sampleRate + secondary_samples_per_bit = int(round(self.sampleRate / self.baudRate)) + cutoff = self.baudRate / self.sampleRate + loop_gain = self.sampleRate / self.getBandwidth() / 5 + self.replace(2, Lowpass(Format.FLOAT, cutoff)) + self.replace(3, TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10)) diff --git a/csdr/chain/dump1090.py b/csdr/chain/dump1090.py new file mode 100644 index 00000000..04a29421 --- /dev/null +++ b/csdr/chain/dump1090.py @@ -0,0 +1,27 @@ +from pycsdr.modules import Convert +from pycsdr.types import Format +from csdr.chain.demodulator import ServiceDemodulator +from owrx.adsb.dump1090 import Dump1090Module, RawDeframer +from owrx.adsb.modes import ModeSParser + + +class Dump1090(ServiceDemodulator): + def __init__(self): + workers = [ + Convert(Format.COMPLEX_FLOAT, Format.COMPLEX_SHORT), + Dump1090Module(), + RawDeframer(), + ModeSParser(), + ] + + super().__init__(workers) + pass + + def getFixedAudioRate(self) -> int: + return 2400000 + + def isSecondaryFftShown(self): + return False + + def supportsSquelch(self) -> bool: + return False diff --git a/csdr/chain/dumphfdl.py b/csdr/chain/dumphfdl.py new file mode 100644 index 00000000..413b6150 --- /dev/null +++ b/csdr/chain/dumphfdl.py @@ -0,0 +1,16 @@ +from csdr.chain.demodulator import ServiceDemodulator +from owrx.hfdl.dumphfdl import DumpHFDLModule, HFDLMessageParser + + +class DumpHFDL(ServiceDemodulator): + def __init__(self): + super().__init__([ + DumpHFDLModule(), + HFDLMessageParser(), + ]) + + def getFixedAudioRate(self) -> int: + return 12000 + + def supportsSquelch(self) -> bool: + return False diff --git a/csdr/chain/dumpvdl2.py b/csdr/chain/dumpvdl2.py new file mode 100644 index 00000000..cae271f5 --- /dev/null +++ b/csdr/chain/dumpvdl2.py @@ -0,0 +1,19 @@ +from csdr.chain.demodulator import ServiceDemodulator +from owrx.vdl2.dumpvdl2 import DumpVDL2Module, VDL2MessageParser +from pycsdr.modules import Convert +from pycsdr.types import Format + + +class DumpVDL2(ServiceDemodulator): + def __init__(self): + super().__init__([ + Convert(Format.COMPLEX_FLOAT, Format.COMPLEX_SHORT), + DumpVDL2Module(), + VDL2MessageParser(), + ]) + + def getFixedAudioRate(self) -> int: + return 105000 + + def supportsSquelch(self) -> bool: + return False diff --git a/csdr/chain/m17.py b/csdr/chain/m17.py index a54ecd7d..937103c3 100644 --- a/csdr/chain/m17.py +++ b/csdr/chain/m17.py @@ -1,8 +1,7 @@ from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, MetaProvider from csdr.module.m17 import M17Module -from pycsdr.modules import FmDemod, Limit, Convert, Writer +from pycsdr.modules import FmDemod, Limit, Convert, Writer, DcBlock from pycsdr.types import Format -from digiham.modules import DcBlock class M17(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, MetaProvider): diff --git a/csdr/chain/rtl433.py b/csdr/chain/rtl433.py new file mode 100644 index 00000000..e0fa6850 --- /dev/null +++ b/csdr/chain/rtl433.py @@ -0,0 +1,19 @@ +from csdr.module import JsonParser +from owrx.ism.rtl433 import Rtl433Module +from csdr.chain.demodulator import ServiceDemodulator + + +class Rtl433(ServiceDemodulator): + def getFixedAudioRate(self) -> int: + return 250000 + + def __init__(self): + super().__init__( + [ + Rtl433Module(), + JsonParser("ISM"), + ] + ) + + def supportsSquelch(self) -> bool: + return False diff --git a/csdr/chain/selector.py b/csdr/chain/selector.py index d87342a2..74a86361 100644 --- a/csdr/chain/selector.py +++ b/csdr/chain/selector.py @@ -1,6 +1,7 @@ from csdr.chain import Chain from pycsdr.modules import Shift, FirDecimate, Bandpass, Squelch, FractionalDecimator, Writer from pycsdr.types import Format +from typing import Union import math @@ -28,6 +29,13 @@ class Decimator(Chain): super().__init__(workers) def _getDecimation(self, outputRate: int) -> (int, float): + if outputRate > self.inputRate: + raise SelectorError( + "cannot provide selected output rate {} since it is bigger than input rate {}".format( + outputRate, + self.inputRate + ) + ) d = self.inputRate / outputRate dInt = int(d) dFloat = float(self.inputRate / dInt) / outputRate @@ -72,10 +80,9 @@ class Selector(Chain): self.decimation = Decimator(inputRate, outputRate) self.bandpass = self._buildBandpass() - self.bandpassCutoffs = None - self.setBandpass(-4000, 4000) + self.bandpassCutoffs = [None, None] - workers = [self.shift, self.decimation, self.bandpass] + workers = [self.shift, self.decimation] if withSquelch: self.readings_per_second = 4 @@ -106,16 +113,30 @@ class Selector(Chain): def setSquelchLevel(self, level: float) -> None: self.squelch.setSquelchLevel(self._convertToLinear(level)) + def _enableBandpass(self): + index = self.indexOf(lambda x: isinstance(x, Bandpass)) + if index < 0: + self.insert(2, self.bandpass) + + def _disableBandpass(self): + index = self.indexOf(lambda x: isinstance(x, Bandpass)) + if index >= 0: + self.remove(index) + def setBandpass(self, lowCut: float, highCut: float) -> None: self.bandpassCutoffs = [lowCut, highCut] - scaled = [x / self.outputRate for x in self.bandpassCutoffs] - self.bandpass.setBandpass(*scaled) + if None in self.bandpassCutoffs: + self._disableBandpass() + else: + self._enableBandpass() + scaled = [x / self.outputRate for x in self.bandpassCutoffs] + self.bandpass.setBandpass(*scaled) - def setLowCut(self, lowCut: float) -> None: + def setLowCut(self, lowCut: Union[float, None]) -> None: self.bandpassCutoffs[0] = lowCut self.setBandpass(*self.bandpassCutoffs) - def setHighCut(self, highCut: float) -> None: + def setHighCut(self, highCut: Union[float, None]) -> None: self.bandpassCutoffs[1] = highCut self.setBandpass(*self.bandpassCutoffs) @@ -129,9 +150,11 @@ class Selector(Chain): self.decimation.setOutputRate(outputRate) self.squelch.setReportInterval(int(outputRate / (self.readings_per_second * 1024))) + index = self.indexOf(lambda x: isinstance(x, Bandpass)) self.bandpass = self._buildBandpass() self.setBandpass(*self.bandpassCutoffs) - self.replace(2, self.bandpass) + if index >= 0: + self.replace(index, self.bandpass) def setInputRate(self, inputRate: int) -> None: if inputRate == self.inputRate: @@ -158,3 +181,7 @@ class SecondarySelector(Chain): if self.frequencyOffset is None: return self.shift.setRate(-offset / self.sampleRate) + + +class SelectorError(Exception): + pass diff --git a/csdr/module/__init__.py b/csdr/module/__init__.py index 9168d4fb..189a75ea 100644 --- a/csdr/module/__init__.py +++ b/csdr/module/__init__.py @@ -1,12 +1,16 @@ from pycsdr.modules import Module as BaseModule -from pycsdr.modules import Reader, Writer +from pycsdr.modules import Reader, Writer, Buffer from pycsdr.types import Format from abc import ABCMeta, abstractmethod from threading import Thread from io import BytesIO -from subprocess import Popen, PIPE +from subprocess import Popen, PIPE, TimeoutExpired from functools import partial import pickle +import logging +import json + +logger = logging.getLogger(__name__) class Module(BaseModule, metaclass=ABCMeta): @@ -41,7 +45,10 @@ class Module(BaseModule, metaclass=ABCMeta): break if data is None or isinstance(data, bytes) and len(data) == 0: break - write(data) + try: + write(data) + except BrokenPipeError: + break return copy @@ -109,6 +116,57 @@ class PickleModule(ThreadModule): pass +class LineBasedModule(ThreadModule, metaclass=ABCMeta): + def __init__(self): + self.retained = bytes() + super().__init__() + + def getInputFormat(self) -> Format: + return Format.CHAR + + def getOutputFormat(self) -> Format: + return Format.CHAR + + def run(self): + while self.doRun: + data = self.reader.read() + if data is None: + self.doRun = False + else: + self.retained += data + lines = self.retained.split(b"\n") + + # keep the last line + # this should either be empty if the last char was \n + # or an incomplete line if the read returned early + self.retained = lines[-1] + + # log all completed lines + for line in lines[0:-1]: + parsed = self.process(line) + if parsed is not None: + self.writer.write(pickle.dumps(parsed)) + + @abstractmethod + def process(self, line: bytes) -> any: + pass + + +class JsonParser(LineBasedModule): + def __init__(self, mode: str): + self.mode = mode + super().__init__() + + def process(self, line): + try: + msg = json.loads(line) + msg["mode"] = self.mode + logger.debug(msg) + return msg + except json.JSONDecodeError: + logger.exception("error parsing rtl433 json") + + class PopenModule(AutoStartModule, metaclass=ABCMeta): def __init__(self): self.process = None @@ -130,7 +188,41 @@ class PopenModule(AutoStartModule, metaclass=ABCMeta): def stop(self): if self.process is not None: - self.process.terminate() - self.process.wait() + # Try terminating normally, kill if failed to terminate + try: + self.process.terminate() + self.process.wait(3) + except TimeoutExpired: + self.process.kill() self.process = None self.reader.stop() + + +class LogReader(Thread): + def __init__(self, prefix: str, buffer: Buffer): + self.reader = buffer.getReader() + self.logger = logging.getLogger(prefix) + self.retained = bytes() + super().__init__() + self.start() + + def run(self) -> None: + while True: + data = self.reader.read() + if data is None: + return + + self.retained += data + lines = self.retained.split(b"\n") + + # keep the last line + # this should either be empty if the last char was \n + # or an incomplete line if the read returned early + self.retained = lines[-1] + + # log all completed lines + for line in lines[0:-1]: + self.logger.info("{}: {}".format("STDOUT", line.decode(errors="replace"))) + + def stop(self): + self.reader.stop() diff --git a/csdr/module/drm.py b/csdr/module/drm.py index f8d59de1..a7515bd8 100644 --- a/csdr/module/drm.py +++ b/csdr/module/drm.py @@ -1,14 +1,11 @@ -from csdr.module import PopenModule +from pycsdr.modules import ExecModule from pycsdr.types import Format -class DrmModule(PopenModule): - def getInputFormat(self) -> Format: - return Format.COMPLEX_FLOAT - - def getOutputFormat(self) -> Format: - return Format.SHORT - - def getCommand(self): - # dream -c 6 --sigsrate 48000 --audsrate 48000 -I - -O - - return ["dream", "-c", "6", "--sigsrate", "48000", "--audsrate", "48000", "-I", "-", "-O", "-"] +class DrmModule(ExecModule): + def __init__(self): + super().__init__( + Format.COMPLEX_SHORT, + Format.SHORT, + ["dream", "-c", "6", "--sigsrate", "48000", "--audsrate", "48000", "-I", "-", "-O", "-"] + ) diff --git a/csdr/module/freedv.py b/csdr/module/freedv.py index 2c1014f4..90bc38a7 100644 --- a/csdr/module/freedv.py +++ b/csdr/module/freedv.py @@ -1,13 +1,11 @@ from pycsdr.types import Format -from csdr.module import PopenModule +from pycsdr.modules import ExecModule -class FreeDVModule(PopenModule): - def getInputFormat(self) -> Format: - return Format.SHORT - - def getOutputFormat(self) -> Format: - return Format.SHORT - - def getCommand(self): - return ["freedv_rx", "1600", "-", "-"] +class FreeDVModule(ExecModule): + def __init__(self): + super().__init__( + Format.SHORT, + Format.SHORT, + ["freedv_rx", "1600", "-", "-"] + ) diff --git a/csdr/module/msk144.py b/csdr/module/msk144.py index 2ccc64cc..532ed67f 100644 --- a/csdr/module/msk144.py +++ b/csdr/module/msk144.py @@ -1,5 +1,6 @@ from pycsdr.types import Format -from csdr.module import PopenModule, ThreadModule +from pycsdr.modules import ExecModule +from csdr.module import LineBasedModule from owrx.wsjt import WsjtParser, Msk144Profile import pickle @@ -7,51 +8,26 @@ import logging logger = logging.getLogger(__name__) -class Msk144Module(PopenModule): - def getCommand(self): - return ["msk144decoder"] - - def getInputFormat(self) -> Format: - return Format.SHORT - - def getOutputFormat(self) -> Format: - return Format.CHAR - - -class ParserAdapter(ThreadModule): +class Msk144Module(ExecModule): + def __init__(self): + super().__init__( + Format.SHORT, + Format.CHAR, + ["msk144decoder"] + ) + + +class ParserAdapter(LineBasedModule): def __init__(self): - self.retained = bytes() self.parser = WsjtParser() self.dialFrequency = 0 + self.profile = Msk144Profile() super().__init__() - def run(self): - profile = Msk144Profile() - - while self.doRun: - data = self.reader.read() - if data is None: - self.doRun = False - else: - self.retained += data - lines = self.retained.split(b"\n") - - # keep the last line - # this should either be empty if the last char was \n - # or an incomplete line if the read returned early - self.retained = lines[-1] - - # parse all completed lines - for line in lines[0:-1]: - # actual messages from msk144decoder should start with "*** " - if line[0:4] == b"*** ": - self.writer.write(pickle.dumps(self.parser.parse(profile, self.dialFrequency, line[4:]))) - - def getInputFormat(self) -> Format: - return Format.CHAR - - def getOutputFormat(self) -> Format: - return Format.CHAR + def process(self, line: bytes): + # actual messages from msk144decoder should start with "*** " + if line[0:4] == b"*** ": + return self.parser.parse(self.profile, self.dialFrequency, line[4:]) def setDialFrequency(self, frequency: int) -> None: self.dialFrequency = frequency diff --git a/debian/changelog b/debian/changelog index 1e639f8c..71feace2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,12 +2,23 @@ openwebrx (1.3.0) UNRELEASED; urgency=low * SDR device log messages are now available in the web configuration to simplify troubleshooting * Added support for the MSK144 digimode + * Added support for decoding ADS-B with dump1090 + * Added support for decoding HFDL and VDL2 aircraft communications + * Added decoding of ISM band transmissions using rtl_433 * Added IPv6 support * Added profile re-ordering using drag & drop * Added the ability to disable profiles + * New devices supported: + - Afedri SDR-Net -- Jakob Ketterl Fri, 30 Sep 2022 16:47:00 +0000 +openwebrx (1.2.2) bullseye jammy; urgency=high + + * - Fixed an over-the-air code injection vulnerability + + -- Jakob Ketterl Sun, 08 Oct 2023 21:29:00 +0000 + openwebrx (1.2.1) bullseye jammy; urgency=low * FifiSDR support fixed (pipeline formats now line up correctly) diff --git a/debian/control b/debian/control index 5cec3d18..3a85c660 100644 --- a/debian/control +++ b/debian/control @@ -2,15 +2,45 @@ Source: openwebrx Maintainer: Jakob Ketterl Section: hamradio Priority: optional +Rules-Requires-Root: no Standards-Version: 4.2.0 -Build-Depends: debhelper (>= 11), dh-python, python3-all (>= 3.5), python3-setuptools +Build-Depends: debhelper (>= 11), + dh-python, + python3-all (>= 3.5), + python3-setuptools Homepage: https://www.openwebrx.de/ Vcs-Browser: https://github.com/jketterl/openwebrx Vcs-Git: https://github.com/jketterl/openwebrx.git Package: openwebrx Architecture: all -Depends: adduser, python3 (>= 3.5), python3-pkg-resources, owrx-connector (>= 0.7), python3-csdr (>= 0.18), ${python3:Depends}, ${misc:Depends} -Recommends: python3-digiham (>= 0.6), direwolf (>= 1.4), wsjtx, js8call, runds-connector (>= 0.2), hpsdrconnector, aprs-symbols, m17-demod, js8call, python3-js8py (>= 0.2), nmux (>= 0.18), codecserver (>= 0.1), msk144decoder +Depends: adduser, + python3 (>= 3.5), + python3-pkg-resources, + owrx-connector (>= 0.7), + python3-csdr (>= 0.18), + ${python3:Depends}, + ${misc:Depends} +Recommends: python3-digiham (>= 0.6), + direwolf (>= 1.4), + wsjtx, + js8call, + runds-connector (>= 0.2), + hpsdrconnector, + aprs-symbols, + m17-demod, + js8call, + python3-js8py (>= 0.2), + nmux (>= 0.18), + codecserver (>= 0.1), + msk144decoder, + dump1090-fa-minimal, + dumphfdl, + dumpvdl2, + rtl-433, + extra-sdr-drivers, + perseus-tools, + dream-headless, + codec2 Description: multi-user web sdr Open source, multi-user SDR receiver with a web interface diff --git a/debian/openwebrx.config b/debian/openwebrx.config index 9a193930..2f17fb9a 100755 --- a/debian/openwebrx.config +++ b/debian/openwebrx.config @@ -3,6 +3,7 @@ db_get openwebrx/admin_user_configured if [ "${1:-}" = "reconfigure" ] || [ "${RET}" != true ]; then + db_settitle openwebrx/title db_input high openwebrx/admin_user_password || true db_go fi diff --git a/debian/openwebrx.postinst b/debian/openwebrx.postinst index 935a0fe6..e78b4630 100755 --- a/debian/openwebrx.postinst +++ b/debian/openwebrx.postinst @@ -14,25 +14,29 @@ case "$1" in adduser --system --group --no-create-home --home /nonexistent --quiet "${OWRX_USER}" usermod -aG plugdev "${OWRX_USER}" + # ensure group exists first (dependency is optional) + addgroup --system --quiet perseususb + usermod -aG perseususb "${OWRX_USER}" + # create OpenWebRX data directory and set the correct permissions if [ ! -d "${OWRX_DATADIR}" ] && [ ! -L "${OWRX_DATADIR}" ]; then mkdir "${OWRX_DATADIR}"; fi - chown "${OWRX_USER}". ${OWRX_DATADIR} + chown "${OWRX_USER}": ${OWRX_DATADIR} # create empty config files now to avoid permission problems later if [ ! -e "${OWRX_USERS_FILE}" ]; then echo "[]" > "${OWRX_USERS_FILE}" - chown "${OWRX_USER}". "${OWRX_USERS_FILE}" + chown "${OWRX_USER}": "${OWRX_USERS_FILE}" chmod 0600 "${OWRX_USERS_FILE}" fi if [ ! -e "${OWRX_SETTINGS_FILE}" ]; then echo "{}" > "${OWRX_SETTINGS_FILE}" - chown "${OWRX_USER}". "${OWRX_SETTINGS_FILE}" + chown "${OWRX_USER}": "${OWRX_SETTINGS_FILE}" fi if [ ! -e "${OWRX_BOOKMARKS_FILE}" ]; then touch "${OWRX_BOOKMARKS_FILE}" - chown "${OWRX_USER}". "${OWRX_BOOKMARKS_FILE}" + chown "${OWRX_USER}": "${OWRX_BOOKMARKS_FILE}" fi db_get openwebrx/admin_user_password diff --git a/debian/openwebrx.templates b/debian/openwebrx.templates index 8ef7e846..6819fbad 100644 --- a/debian/openwebrx.templates +++ b/debian/openwebrx.templates @@ -20,4 +20,8 @@ Type: boolean Default: false Description: OpenWebRX "admin" user previously configured? Marker used internally by the config scripts to remember if an admin user has - been created. \ No newline at end of file + been created. + +Template: openwebrx/title +Type: title +Description: Configuring OpenWebRX \ No newline at end of file diff --git a/docker.sh b/docker.sh index a1bfb897..b3657af6 100755 --- a/docker.sh +++ b/docker.sh @@ -2,7 +2,7 @@ set -euo pipefail ARCH=$(uname -m) -IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-rtltcp openwebrx-runds openwebrx-hpsdr openwebrx-bladerf openwebrx-full openwebrx" +IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-afedri openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-rtltcp openwebrx-runds openwebrx-hpsdr openwebrx-bladerf openwebrx-full openwebrx" ALL_ARCHS="x86_64 armv7l aarch64" TAG=${TAG:-"latest"} ARCHTAG="${TAG}-${ARCH}" diff --git a/docker/Dockerfiles/Dockerfile-afedri b/docker/Dockerfiles/Dockerfile-afedri new file mode 100644 index 00000000..ad7c88e9 --- /dev/null +++ b/docker/Dockerfiles/Dockerfile-afedri @@ -0,0 +1,8 @@ +ARG ARCHTAG +FROM openwebrx-soapysdr-base:$ARCHTAG + +COPY docker/scripts/install-dependencies-afedri.sh / +RUN /install-dependencies-afedri.sh &&\ + rm /install-dependencies-afedri.sh + +ADD . /opt/openwebrx diff --git a/docker/Dockerfiles/Dockerfile-base b/docker/Dockerfiles/Dockerfile-base index f59fcdac..e50f03a6 100644 --- a/docker/Dockerfiles/Dockerfile-base +++ b/docker/Dockerfiles/Dockerfile-base @@ -1,4 +1,4 @@ -FROM debian:bullseye-slim +FROM debian:bookworm-slim COPY docker/files/js8call/js8call-hamlib.patch \ docker/files/wsjtx/wsjtx.patch \ @@ -23,6 +23,6 @@ VOLUME /etc/openwebrx VOLUME /var/lib/openwebrx ENV S6_CMD_ARG0="/opt/openwebrx/docker/scripts/run.sh" -CMD [] +CMD [""] EXPOSE 8073 diff --git a/docker/Dockerfiles/Dockerfile-full b/docker/Dockerfiles/Dockerfile-full index 10826d21..6d68e8a0 100644 --- a/docker/Dockerfiles/Dockerfile-full +++ b/docker/Dockerfiles/Dockerfile-full @@ -10,6 +10,7 @@ RUN /install-dependencies-rtlsdr.sh &&\ /install-dependencies-hackrf.sh &&\ /install-dependencies-sdrplay.sh &&\ /install-dependencies-airspy.sh &&\ + /install-dependencies-afedri.sh &&\ /install-dependencies-rtlsdr-soapy.sh &&\ /install-dependencies-plutosdr.sh &&\ /install-dependencies-limesdr.sh &&\ diff --git a/docker/files/sdrplay/install-lib.aarch64.patch b/docker/files/sdrplay/install-lib.aarch64.patch deleted file mode 100644 index 1f3dc57a..00000000 --- a/docker/files/sdrplay/install-lib.aarch64.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff -ur sdrplay-orig/install_lib.sh sdrplay/install_lib.sh ---- sdrplay-orig/install_lib.sh 2020-05-24 14:30:06.022483867 +0000 -+++ sdrplay/install_lib.sh 2020-05-24 14:30:49.093435726 +0000 -@@ -4,19 +4,6 @@ - export MAJVERS="3" - - echo "Installing SDRplay RSP API library ${VERS}..." --read -p "Press RETURN to view the license agreement" ret -- --more sdrplay_license.txt -- --while true; do -- echo "Press y and RETURN to accept the license agreement and continue with" -- read -p "the installation, or press n and RETURN to exit the installer [y/n] " yn -- case $yn in -- [Yy]* ) break;; -- [Nn]* ) exit;; -- * ) echo "Please answer y or n";; -- esac --done - - export ARCH=`uname -m` - diff --git a/docker/files/sdrplay/install-lib.aarch64.patch b/docker/files/sdrplay/install-lib.aarch64.patch new file mode 120000 index 00000000..2ec83d02 --- /dev/null +++ b/docker/files/sdrplay/install-lib.aarch64.patch @@ -0,0 +1 @@ +install-lib.x86_64.patch \ No newline at end of file diff --git a/docker/files/sdrplay/install-lib.x86_64.patch b/docker/files/sdrplay/install-lib.x86_64.patch index d66023b0..7b53fc6b 100644 --- a/docker/files/sdrplay/install-lib.x86_64.patch +++ b/docker/files/sdrplay/install-lib.x86_64.patch @@ -1,14 +1,11 @@ -diff -ur sdrplay-orig/install_lib.sh sdrplay/install_lib.sh ---- sdrplay-orig/install_lib.sh 2020-05-24 13:56:56.622000041 +0000 -+++ sdrplay/install_lib.sh 2020-05-24 13:58:51.837801559 +0000 -@@ -4,19 +4,6 @@ - MAJVERS="3" +--- sdrplay-orig/install_lib.sh 2024-01-01 15:03:53.377291864 +0100 ++++ sdrplay/install_lib.sh 2024-01-01 16:09:25.948363042 +0100 +@@ -17,26 +17,7 @@ + echo "the system files." + echo " " - echo "Installing SDRplay RSP API library ${VERS}..." -read -p "Press RETURN to view the license agreement" ret -- --more sdrplay_license.txt -- +-more -d sdrplay_license.txt -while true; do - echo "Press y and RETURN to accept the license agreement and continue with" - read -p "the installation, or press n and RETURN to exit the installer [y/n] " yn @@ -18,22 +15,133 @@ diff -ur sdrplay-orig/install_lib.sh sdrplay/install_lib.sh - * ) echo "Please answer y or n";; - esac -done +- +-echo " " +-echo "A copy of the license agreement can be found here: ${HOME}/sdrplay_license.txt" +-cp sdrplay_license.txt ${HOME}/. +-chmod 644 ${HOME}/sdrplay_license.txt +-echo " " +- + ARCH=$(uname -m|sed -e 's/x86_64/64/' -e 's/aarch64/64/' -e 's/arm64/64/' -e 's/i.86/32/') +-INIT=$(file -L /sbin/init|sed -e 's/^.* \(32\|64\)-bit.*$/\1/') + COMPILER=$(getconf LONG_BIT) + ARCHM=$(uname -m) + INSTALLARCH=$(uname -m) +@@ -47,12 +28,11 @@ - ARCH=`uname -m` - OSDIST="Unknown" -@@ -157,15 +144,6 @@ echo " " - echo "SDRplay API ${VERS} Installation Finished" + echo "Architecture reported as being $ARCH bit" +-echo "System reports $INIT bit files found" + echo "System is also setup to produce $COMPILER bit files" + echo "Architecture reports machine as being $ARCHM compliant" echo " " + +-if [ "${ARCH}" != "64" ] || [ "${INIT}" != "64" ] || [ "${COMPILER}" != "64" ]; then ++if [ "${ARCH}" != "64" ] || [ "${COMPILER}" != "64" ]; then + echo "This installer only supports 64 bit architectures." + echo "One of the above indicates that something is not set for" + echo "64 bit operation. Please either fix the relevant OS issue or" +@@ -193,11 +173,6 @@ + sudo chmod 644 /etc/udev/hwdb.d/20-sdrplay.hwdb + sudo systemd-hwdb update + sudo udevadm trigger +- if [ "${SRVTYPE}" != "initd" ]; then +- sudo systemctl restart udev +- else +- sudo service udev restart +- fi + echo "Done" + fi + fi +@@ -227,7 +202,7 @@ + fi + + echo " " +-locservice="/opt/sdrplay_api" ++locservice="/usr/local/bin" + locheader="/usr/local/include" + loclib="/usr/local/lib" + locscripts="/etc/systemd/system" +@@ -247,45 +222,6 @@ + echo "Daemon start system : ${DAEMON_SYS}" + echo " " + +-# 0--------1---------2---------3---------4---------5---------6---------7---------8 -while true; do -- echo "Would you like to add SDRplay USB IDs to the local database for easier" -- read -p "identification in applications such as lsusb? [y/n] " yn +- echo "To continue the installation with these defaults press y and RETURN" +- read -p "or press n and RETURN to change them [y/n] " yn - case $yn in -- [Yy]* ) break;; -- [Nn]* ) exit;; +- [Yy]* ) change="n";break;; +- [Nn]* ) change="y";break;; - * ) echo "Please answer y or n";; - esac -done - sudo cp scripts/sdrplay_usbids.sh ${INSTALLBINDIR}/. - sudo chmod 755 ${INSTALLBINDIR}/sdrplay_usbids.sh - sudo cp scripts/sdrplay_ids.txt ${INSTALLBINDIR}/. +- +-if [ "${change}" == "y" ]; then +- echo "Changing default locations..." +- read -p "API service location [${locservice}]: " newloc +- if [ "${newloc}" != "" ]; then +- locservice=${newloc} +- fi +- read -p "API header files location [${locheader}]: " newloc +- if [ "${newloc}" != "" ]; then +- locheader=${newloc} +- fi +- read -p "API shared library location [${loclib}]: " newloc +- if [ "${newloc}" != "" ]; then +- loclib=${newloc} +- fi +- +- echo "API service : ${locservice}" +- echo "API header files : ${locheader}" +- echo "API shared library : ${loclib}" +- while true; do +- read -p "Please confirm these are correct [y/n] " yn +- case $yn in +- [Yy]* ) break;; +- [Nn]* ) echo "paths not confirmed. Exiting...";exit 1;; +- * ) echo "Please answer y or n";; +- esac +- done +-fi +- + sudo mkdir -p -m 755 ${locservice} >> /dev/null 2>&1 + sudo mkdir -p -m 755 ${locheader} >> /dev/null 2>&1 + sudo mkdir -p -m 755 ${loclib} >> /dev/null 2>&1 +@@ -317,10 +253,6 @@ + echo -n "Installing Service scripts and starting daemon..." + if [ -d "/etc/systemd/system" ]; then + SRVTYPE="systemd" +- if [ -f "/etc/systemd/system/sdrplay.service" ]; then +- sudo systemctl stop sdrplay +- sudo systemctl disable sdrplay +- fi + sudo bash -c 'cat > /etc/systemd/system/sdrplay.service' << EOF + [Unit] + Description=SDRplay API Service +@@ -339,8 +271,6 @@ + EOF + + sudo chmod 644 /etc/systemd/system/sdrplay.service +- sudo systemctl enable sdrplay +- sudo systemctl start sdrplay + else + SRVTYPE="initd" + if [ -f "/etc/init.d/sdrplayService" ]; then +@@ -443,16 +373,6 @@ + echo "finished, please reboot this device." + + echo " " +-echo "To start and stop the API service, use the following commands..." +-echo " " +-if [ "${SRVTYPE}" != "systemd" ]; then +- echo "sudo service sdrplayService start" +- echo "sudo service sdrplayService stop" +-else +- echo "sudo systemctl start sdrplay" +- echo "sudo systemctl stop sdrplay" +-fi +-echo " " + echo "If supported on your system, lsusb will now show the RSP name" + echo " " + echo "SDRplay API ${VERS} Installation Finished" diff --git a/docker/files/services/codecserver/run b/docker/files/services/codecserver/run index 43c8212c..13b7872e 100755 --- a/docker/files/services/codecserver/run +++ b/docker/files/services/codecserver/run @@ -1,2 +1,2 @@ -#!/usr/bin/execlineb -P +#!/command/execlineb -P /usr/local/bin/codecserver \ No newline at end of file diff --git a/docker/files/services/sdrplay/run b/docker/files/services/sdrplay/run index 0f31c4c5..cc8b6a7d 100755 --- a/docker/files/services/sdrplay/run +++ b/docker/files/services/sdrplay/run @@ -1,2 +1,2 @@ -#!/usr/bin/execlineb -P +#!/command/execlineb -P /usr/local/bin/sdrplay_apiService \ No newline at end of file diff --git a/docker/scripts/install-connectors.sh b/docker/scripts/install-connectors.sh index d67de1f9..f056f297 100755 --- a/docker/scripts/install-connectors.sh +++ b/docker/scripts/install-connectors.sh @@ -18,14 +18,15 @@ function cmakebuild() { cd /tmp +STATIC_PACKAGES="libfftw3-single3" BUILD_PACKAGES="git cmake make gcc g++ libsamplerate-dev libfftw3-dev" apt-get update -apt-get -y install --no-install-recommends $BUILD_PACKAGES +apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES git clone https://github.com/jketterl/owrx_connector.git -# latest develop as of 2023-03-18 (added --listdriver option) -cmakebuild owrx_connector beda260363c0e77617d4e17ef864e1f5c3fd86b2 +# latest develop as of 2024-01-01 (fixed startup race condition) +cmakebuild owrx_connector 62219d40e180abb539ad61fcd9625b90c34f0e26 apt-get -y purge --autoremove $BUILD_PACKAGES apt-get clean diff --git a/docker/scripts/install-dependencies-afedri.sh b/docker/scripts/install-dependencies-afedri.sh new file mode 100755 index 00000000..3843547b --- /dev/null +++ b/docker/scripts/install-dependencies-afedri.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +export MAKEFLAGS="-j4" + +function cmakebuild() { + cd $1 + if [[ ! -z "${2:-}" ]]; then + git checkout $2 + fi + mkdir build + cd build + cmake .. + make + make install + cd ../.. + rm -rf $1 +} + +cd /tmp + +STATIC_PACKAGES="" +BUILD_PACKAGES="git cmake make gcc g++" + +apt-get update +apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES + +git clone https://github.com/alexander-sholohov/SoapyAfedri.git +# latest from master as of 2023-11-16 +cmakebuild SoapyAfedri a7d0d942fe966c2b69c8817dd6f097fc94122660 + +apt-get -y purge --autoremove $BUILD_PACKAGES +apt-get clean +rm -rf /var/lib/apt/lists/* diff --git a/docker/scripts/install-dependencies-bladerf.sh b/docker/scripts/install-dependencies-bladerf.sh index 9a07565c..2b2e5320 100755 --- a/docker/scripts/install-dependencies-bladerf.sh +++ b/docker/scripts/install-dependencies-bladerf.sh @@ -25,11 +25,11 @@ apt-get update apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES git clone https://github.com/Nuand/bladeRF.git -cmakebuild bladeRF 2021.10 +cmakebuild bladeRF 2023.02 git clone https://github.com/pothosware/SoapyBladeRF.git -# latest from master as of 2022-01-12 -cmakebuild SoapyBladeRF 70505a5cdf8c9deabc4af3eb3384aa82a7b6f021 +# latest from master as of 2023-08-30 +cmakebuild SoapyBladeRF 85f6dc554ed4c618304d99395b19c4e1523675b0 apt-get -y purge --autoremove $BUILD_PACKAGES apt-get clean diff --git a/docker/scripts/install-dependencies-hackrf.sh b/docker/scripts/install-dependencies-hackrf.sh index 03704a3c..19a458a3 100755 --- a/docker/scripts/install-dependencies-hackrf.sh +++ b/docker/scripts/install-dependencies-hackrf.sh @@ -18,7 +18,7 @@ function cmakebuild() { cd /tmp -STATIC_PACKAGES="libusb-1.0-0 libfftw3-3 udev" +STATIC_PACKAGES="libusb-1.0-0 libfftw3-single3 udev" BUILD_PACKAGES="git cmake make patch wget sudo gcc g++ libusb-1.0-0-dev libfftw3-dev pkg-config" apt-get update diff --git a/docker/scripts/install-dependencies-hpsdr.sh b/docker/scripts/install-dependencies-hpsdr.sh index e9fd2290..24dd1e64 100755 --- a/docker/scripts/install-dependencies-hpsdr.sh +++ b/docker/scripts/install-dependencies-hpsdr.sh @@ -10,7 +10,7 @@ apt-get -y install --no-install-recommends $BUILD_PACKAGES pushd /tmp ARCH=$(uname -m) -GOVERSION=1.15.5 +GOVERSION=1.20.10 case ${ARCH} in x86_64) @@ -29,7 +29,7 @@ tar xfz $PACKAGE git clone https://github.com/jancona/hpsdrconnector.git pushd hpsdrconnector -git checkout v0.6.1 +git checkout v0.6.4 /tmp/go/bin/go build install -m 0755 hpsdrconnector /usr/local/bin diff --git a/docker/scripts/install-dependencies-radioberry.sh b/docker/scripts/install-dependencies-radioberry.sh index 01724621..44688e0d 100755 --- a/docker/scripts/install-dependencies-radioberry.sh +++ b/docker/scripts/install-dependencies-radioberry.sh @@ -18,8 +18,8 @@ function cmakebuild() { cd /tmp -STATIC_PACKAGES="libusb-1.0-0 libfftw3-3 udev" -BUILD_PACKAGES="git cmake make patch wget sudo gcc g++ libusb-1.0-0-dev libfftw3-dev pkg-config" +STATIC_PACKAGES="" +BUILD_PACKAGES="git cmake make gcc g++" apt-get update apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES diff --git a/docker/scripts/install-dependencies-rtlsdr-soapy.sh b/docker/scripts/install-dependencies-rtlsdr-soapy.sh index 695f31d0..9cea76f0 100755 --- a/docker/scripts/install-dependencies-rtlsdr-soapy.sh +++ b/docker/scripts/install-dependencies-rtlsdr-soapy.sh @@ -25,11 +25,12 @@ apt-get update apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES git clone https://github.com/osmocom/rtl-sdr.git -# latest from master as of 2020-09-04 -cmakebuild rtl-sdr ed0317e6a58c098874ac58b769cf2e609c18d9a5 +# latest from master as of 2023-09-13 (integration of rtlsdr blog v4 dongle) +cmakebuild rtl-sdr 1261fbb285297da08f4620b18871b6d6d9ec2a7b git clone https://github.com/pothosware/SoapyRTLSDR.git -cmakebuild SoapyRTLSDR soapy-rtl-sdr-0.3.1 +# latest from master as of 2023-09-13 +cmakebuild SoapyRTLSDR 068aa77a4c938b239c9d80cd42c4ee7986458e8f apt-get -y purge --autoremove $BUILD_PACKAGES apt-get clean diff --git a/docker/scripts/install-dependencies-rtlsdr.sh b/docker/scripts/install-dependencies-rtlsdr.sh index 942241ab..5501a670 100755 --- a/docker/scripts/install-dependencies-rtlsdr.sh +++ b/docker/scripts/install-dependencies-rtlsdr.sh @@ -25,8 +25,8 @@ apt-get update apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES git clone https://github.com/osmocom/rtl-sdr.git -# latest from master as of 2020-09-04 -cmakebuild rtl-sdr ed0317e6a58c098874ac58b769cf2e609c18d9a5 +# latest from master as of 2023-09-13 (integration of rtlsdr blog v4 dongle) +cmakebuild rtl-sdr 1261fbb285297da08f4620b18871b6d6d9ec2a7b apt-get -y purge --autoremove $BUILD_PACKAGES apt-get clean diff --git a/docker/scripts/install-dependencies-runds.sh b/docker/scripts/install-dependencies-runds.sh index e72902d4..fdf26301 100755 --- a/docker/scripts/install-dependencies-runds.sh +++ b/docker/scripts/install-dependencies-runds.sh @@ -18,15 +18,15 @@ function cmakebuild() { cd /tmp -STATIC_PACKAGES="" -BUILD_PACKAGES="git cmake make gcc g++ pkg-config" +STATIC_PACKAGES="libfftw3-single3" +BUILD_PACKAGES="git cmake make gcc g++ pkg-config libfftw3-dev" apt-get update apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES git clone https://github.com/jketterl/runds_connector.git -# latest develop as of 2022-12-11 (std::endl implicit flushing) -cmakebuild runds_connector 06ca993a3c81ddb0a2581b1474895da07752a9e1 +# latest develop as of 2023-07-04 (cmake exports) +cmakebuild runds_connector 435364002d756735015707e7f59aa40e8d743585 apt-get -y purge --autoremove $BUILD_PACKAGES apt-get clean diff --git a/docker/scripts/install-dependencies-sdrplay.sh b/docker/scripts/install-dependencies-sdrplay.sh index ca33b03c..ce3645b4 100755 --- a/docker/scripts/install-dependencies-sdrplay.sh +++ b/docker/scripts/install-dependencies-sdrplay.sh @@ -28,13 +28,13 @@ ARCH=$(uname -m) case $ARCH in x86_64) - BINARY=SDRplay_RSP_API-Linux-3.07.1.run + BINARY=SDRplay_RSP_API-Linux-3.12.1.run ;; armv*) BINARY=SDRplay_RSP_API-ARM32-3.07.2.run ;; aarch64) - BINARY=SDRplay_RSP_API-ARM64-3.07.1.run + BINARY=SDRplay_RSP_API-Linux-3.12.1.run ;; esac diff --git a/docker/scripts/install-dependencies.sh b/docker/scripts/install-dependencies.sh index ca3ffc42..42b16b50 100755 --- a/docker/scripts/install-dependencies.sh +++ b/docker/scripts/install-dependencies.sh @@ -21,8 +21,8 @@ function cmakebuild() { cd /tmp -STATIC_PACKAGES="libfftw3-bin python3 python3-setuptools netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline8 libgfortran5 libgomp1 libasound2 libudev1 ca-certificates libpulse0 libfaad2 libopus0 libboost-program-options1.74.0 libboost-log1.74.0 libcurl4" -BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-qmake libfaad-dev libopus-dev libboost-dev libboost-program-options-dev libboost-log-dev libboost-regex-dev libpulse-dev libcurl4-openssl-dev" +STATIC_PACKAGES="libfftw3-single3 libfftw3-double3 python3 python3-setuptools netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline8 libgfortran5 libgomp1 libasound2 libudev1 ca-certificates libpulse0 libfaad2 libopus0 libboost-program-options1.74.0 libboost-log1.74.0 libcurl4 libncurses6 libliquid1 libconfig++9v5" +BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-qmake libfaad-dev libopus-dev libboost-dev libboost-program-options-dev libboost-log-dev libboost-regex-dev libpulse-dev libcurl4-openssl-dev libncurses-dev xz-utils libliquid-dev libconfig++-dev" apt-get update apt-get -y install auto-apt-proxy apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES @@ -35,13 +35,16 @@ case `uname -m` in PLATFORM=aarch64 ;; x86_64*) - PLATFORM=amd64 + PLATFORM=x86_64 ;; esac -wget https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-${PLATFORM}.tar.gz -tar xzf s6-overlay-${PLATFORM}.tar.gz -C / -rm s6-overlay-${PLATFORM}.tar.gz +wget https://github.com/just-containers/s6-overlay/releases/download/v3.1.5.0/s6-overlay-noarch.tar.xz +tar -Jxpf /tmp/s6-overlay-noarch.tar.xz -C / +rm s6-overlay-noarch.tar.xz +wget https://github.com/just-containers/s6-overlay/releases/download/v3.1.5.0/s6-overlay-${PLATFORM}.tar.xz +tar -Jxpf /tmp/s6-overlay-${PLATFORM}.tar.xz -C / +rm s6-overlay-${PLATFORM}.tar.xz JS8CALL_VERSION=2.2.0 JS8CALL_DIR=js8call @@ -86,8 +89,7 @@ rm -rf /usr/local/share/doc/direwolf/examples/ git clone https://github.com/drowe67/codec2.git cd codec2 -# latest commit from master as of 2020-10-04 -git checkout 55d7bb8d1bddf881bdbfcb971a718b83e6344598 +git checkout 1.2.0 mkdir build cd build cmake .. @@ -111,6 +113,26 @@ rm dream-2.1.1-svn808.tar.gz git clone https://github.com/mobilinkd/m17-cxx-demod.git cmakebuild m17-cxx-demod v2.3 +git clone --depth 1 -b v9.0 https://github.com/flightaware/dump1090 +cd dump1090 +make +install -m 0755 dump1090 /usr/local/bin +cd .. +rm -rf dump1090 + +git clone https://github.com/merbanan/rtl_433.git +# latest from master as of 2023-09-06 +CMAKE_ARGS="-DENABLE_RTLSDR=OFF" cmakebuild rtl_433 70d84d01e1be87b459f7a10825966f3262b7dd34 + +git clone https://github.com/szpajder/libacars.git +cmakebuild libacars v2.2.0 + +git clone https://github.com/szpajder/dumphfdl +cmakebuild dumphfdl v1.4.1 + +git clone https://github.com/szpajder/dumpvdl2.git +cmakebuild dumpvdl2 v2.3.0 + git clone https://github.com/hessu/aprs-symbols /usr/share/aprs-symbols pushd /usr/share/aprs-symbols git checkout 5c2abe2658ee4d2563f3c73b90c6f59124839802 diff --git a/docker/scripts/install-owrx-tools.sh b/docker/scripts/install-owrx-tools.sh index ae9eb7ee..0c9db6d9 100755 --- a/docker/scripts/install-owrx-tools.sh +++ b/docker/scripts/install-owrx-tools.sh @@ -18,7 +18,7 @@ function cmakebuild() { cd /tmp -STATIC_PACKAGES="libfftw3-bin libprotobuf23 libsamplerate0 libicu67 libudev1" +STATIC_PACKAGES="libfftw3-single3 libprotobuf32 libsamplerate0 libicu72 libudev1" BUILD_PACKAGES="git autoconf automake libtool libfftw3-dev pkg-config cmake make gcc g++ libprotobuf-dev protobuf-compiler libsamplerate-dev libicu-dev libpython3-dev libudev-dev" apt-get update apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES @@ -32,11 +32,13 @@ popd rm -rf js8py git clone https://github.com/jketterl/csdr.git -cmakebuild csdr 0.18.1 +# latest develop as of 2023-09-08 (execmodule improvements) +cmakebuild csdr 764767933ed2b242190285f8ff56b11d80c7d530 git clone https://github.com/jketterl/pycsdr.git cd pycsdr -git checkout 0.18.1 +# latest develop as of 2023-08-21 (death of CallbackWriter)) +git checkout 77b3709c545f510b52c7cea2e300e2e1613038e2 ./setup.py install install_headers cd .. rm -rf pycsdr @@ -44,14 +46,17 @@ rm -rf pycsdr git clone https://github.com/jketterl/codecserver.git mkdir -p /usr/local/etc/codecserver cp codecserver/conf/codecserver.conf /usr/local/etc/codecserver -cmakebuild codecserver 0.2.0 +# latest develop as of 2023-07-03 (error handling) +cmakebuild codecserver 0f3703ce285acd85fcd28f6620d7795dc173cb50 git clone https://github.com/jketterl/digiham.git -cmakebuild digiham 0.6.1 +# latest develop as of 2023-07-02 (codecserver protocol version) +cmakebuild digiham 262e6dfd9a2c56778bd4b597240756ad0fb9861d git clone https://github.com/jketterl/pydigiham.git cd pydigiham -git checkout 0.6.1 +# latest develop as of 2023-06-30 (csdr cleanup) +git checkout 894aa87ea9a3534d1e7109da86194c7cd5e0b7c7 ./setup.py install cd .. rm -rf pydigiham diff --git a/docker/scripts/run.sh b/docker/scripts/run.sh index cde6fdf8..92ea968c 100755 --- a/docker/scripts/run.sh +++ b/docker/scripts/run.sh @@ -34,4 +34,3 @@ python3 openwebrx.py $@ & child=$! wait "$child" - diff --git a/htdocs/css/admin.css b/htdocs/css/admin.css index 55923dfc..2e1d3a7c 100644 --- a/htdocs/css/admin.css +++ b/htdocs/css/admin.css @@ -127,7 +127,7 @@ h1 { } .removable-group.removable .removable-item, .add-group .add-group-select { - flex: 1 0 auto; + flex: 1 0 0; margin-right: .25rem; } diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css index 49678619..f7c8115b 100644 --- a/htdocs/css/openwebrx.css +++ b/htdocs/css/openwebrx.css @@ -791,11 +791,10 @@ img.openwebrx-mirror-img #openwebrx-digimode-canvas-container { - /*margin: -10px -10px 10px -10px;*/ - margin: -10px -10px 0px -10px; - border-radius: 15px; - height: 150px; - background-color: #333; + margin: -10px -10px -10px -10px; + border-radius: 15px; + height: 200px; + background-color: #333; position: relative; overflow: hidden; } @@ -902,7 +901,7 @@ img.openwebrx-mirror-img #openwebrx-digimode-content-container { overflow-y: hidden; - display: block; + display: none; height: 50px; position: relative; } @@ -921,16 +920,16 @@ img.openwebrx-mirror-img { transition: all 500ms; background-color: Yellow; - display: block; + display: none; position: absolute; pointer-events: none; height: 100%; - width: 0px; - top: 0px; - left: 0px; + width: 0; + top: 0; + left: 0; opacity: 0.7; border-style: solid; - border-width: 0px; + border-width: 0; border-color: Red; } @@ -1095,28 +1094,44 @@ img.openwebrx-mirror-img } .openwebrx-message-panel { - height: 180px; + min-height: 180px; position: relative; } -.openwebrx-message-panel tbody { - display: block; - overflow: auto; - height: 150px; - width: 100%; +.openwebrx-message-panel#openwebrx-panel-adsb-message { + min-height: 380px; } -.openwebrx-message-panel thead tr { +.openwebrx-message-panel table { display: block; + overflow: auto; + height: 100%; + width: 100%; } .openwebrx-message-panel th, .openwebrx-message-panel td { - width: 50px; + min-width: 50px; text-align: left; + vertical-align: top; padding: 1px 3px; } +.openwebrx-message-panel th { + position: sticky; + top: 0; + background-color: #575757; +} + +.openwebrx-message-panel h4 { + margin: 0 0 .25em; +} + +.openwebrx-message-panel .acars-message { + white-space: pre; + font-family: roboto-mono, monospace; +} + #openwebrx-panel-wsjt-message .message { width: 380px; } @@ -1254,49 +1269,19 @@ img.openwebrx-mirror-img padding: 5px 10px; } -#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="jt9"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="ft4"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="packet"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="msk144"] #openwebrx-digimode-content-container, -#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="jt9"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="ft4"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="packet"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-select-channel, -#openwebrx-panel-digimodes[data-mode="msk144"] #openwebrx-digimode-select-channel +#openwebrx-panel-digimodes[data-mode^="bpsk"] #openwebrx-digimode-content-container, +#openwebrx-panel-digimodes[data-mode^="rtty"] #openwebrx-digimode-content-container, +#openwebrx-panel-digimodes[data-mode^="bpsk"] #openwebrx-digimode-select-channel, +#openwebrx-panel-digimodes[data-mode^="rtty"] #openwebrx-digimode-select-channel { - display: none; + display: block; } -#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="jt9"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="ft4"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="packet"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-canvas-container, -#openwebrx-panel-digimodes[data-mode="msk144"] #openwebrx-digimode-canvas-container +#openwebrx-panel-digimodes[data-mode^="bpsk"] #openwebrx-digimode-canvas-container, +#openwebrx-panel-digimodes[data-mode^="rtty"] #openwebrx-digimode-canvas-container { - height: 200px; - margin: -10px; + height: 150px; + margin-bottom: 0; } .openwebrx-zoom-button svg { diff --git a/htdocs/features.js b/htdocs/features.js index fef2817e..0add3b43 100644 --- a/htdocs/features.js +++ b/htdocs/features.js @@ -1,5 +1,5 @@ $(function(){ - var converter = new showdown.Converter(); + var converter = new showdown.Converter({openLinksInNewWindow: true}); $.ajax('api/features').done(function(data){ var $table = $('table.features'); $.each(data, function(name, details) { diff --git a/htdocs/index.html b/htdocs/index.html index 18834b3f..d1eb1564 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -74,6 +74,10 @@ + + + +