From ddfd85c586ee6188265b350c2101954e9c36e7fb Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Sun, 12 Apr 2020 13:10:23 +0200 Subject: [PATCH] add js8 decoding if available --- bands.json | 30 ++++++++++++++++++++---------- csdr/csdr.py | 9 +++++++-- htdocs/index.html | 1 + htdocs/openwebrx.js | 5 +++-- owrx/dsp.py | 3 ++- owrx/feature.py | 7 +++++++ owrx/js8.py | 32 ++++++++++++++++++++++++++++++++ 7 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 owrx/js8.py diff --git a/bands.json b/bands.json index 90e4c87..1629d4a 100644 --- a/bands.json +++ b/bands.json @@ -8,7 +8,8 @@ "ft8": 1840000, "wspr": 1836600, "jt65": 1838000, - "jt9": 1839000 + "jt9": 1839000, + "js8": 1842000 } }, { @@ -21,7 +22,8 @@ "wspr": 3592600, "jt65": 3570000, "jt9": 3572000, - "ft4": [3568000, 3575000] + "ft4": [3568000, 3575000], + "js8": 3578000 } }, { @@ -43,7 +45,8 @@ "wspr": 7038600, "jt65": 7076000, "jt9": 7078000, - "ft4": 7047500 + "ft4": 7047500, + "js8": 7078000 } }, { @@ -56,7 +59,8 @@ "wspr": 10138700, "jt65": 10138000, "jt9": 10140000, - "ft4": 10140000 + "ft4": 10140000, + "js8": 10130000 } }, { @@ -69,7 +73,8 @@ "wspr": 14095600, "jt65": 14076000, "jt9": 14078000, - "ft4": 14080000 + "ft4": 14080000, + "js8": 14078000 } }, { @@ -82,7 +87,8 @@ "wspr": 18104600, "jt65": 18102000, "jt9": 18104000, - "ft4": 18104000 + "ft4": 18104000, + "js8": 18104000 } }, { @@ -95,7 +101,8 @@ "wspr": 21094600, "jt65": 21076000, "jt9": 21078000, - "ft4": 21140000 + "ft4": 21140000, + "js8": 21078000 } }, { @@ -108,7 +115,8 @@ "wspr": 24924600, "jt65": 24917000, "jt9": 24919000, - "ft4": 24919000 + "ft4": 24919000, + "js8": 24922000 } }, { @@ -121,7 +129,8 @@ "wspr": 28124600, "jt65": 28076000, "jt9": 28078000, - "ft4": 28180000 + "ft4": 28180000, + "js8": 28078000 } }, { @@ -134,7 +143,8 @@ "wspr": 50293000, "jt65": 50310000, "jt9": 50312000, - "ft4": 50318000 + "ft4": 50318000, + "js8": 50318000 } }, { diff --git a/csdr/csdr.py b/csdr/csdr.py index 651944e..ac4dee3 100644 --- a/csdr/csdr.py +++ b/csdr/csdr.py @@ -30,6 +30,7 @@ from functools import partial from owrx.kiss import KissClient, DirewolfConfig from owrx.wsjt import Ft8Chopper, WsprChopper, Jt9Chopper, Jt65Chopper, Ft4Chopper +from owrx.js8 import Js8Chopper import logging @@ -450,6 +451,7 @@ class dsp(object): if self.isWsjtMode(): smd = self.get_secondary_demodulator() chopper_cls = None + output_name = "wsjt_demod" if smd == "ft8": chopper_cls = Ft8Chopper elif smd == "wspr": @@ -460,10 +462,13 @@ class dsp(object): chopper_cls = Jt9Chopper elif smd == "ft4": chopper_cls = Ft4Chopper + elif smd == "js8": + chopper_cls = Js8Chopper + output_name = "js8_demod" if chopper_cls is not None: chopper = chopper_cls(self, self.secondary_process_demod.stdout) chopper.start() - self.output.send_output("wsjt_demod", chopper.read) + self.output.send_output(output_name, chopper.read) elif self.isPacket(): # we best get the ax25 packets from the kiss socket kiss = KissClient(self.direwolf_port) @@ -576,7 +581,7 @@ class dsp(object): def isWsjtMode(self, demodulator=None): if demodulator is None: demodulator = self.get_secondary_demodulator() - return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4"] + return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4", "js8"] def isPacket(self, demodulator=None): if demodulator is None: diff --git a/htdocs/index.html b/htdocs/index.html index fefefbc..4ad78ef 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -193,6 +193,7 @@ + diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js index 52770c6..0c85f28 100644 --- a/htdocs/openwebrx.js +++ b/htdocs/openwebrx.js @@ -1305,7 +1305,7 @@ function update_wsjt_panel(msg) { }; var linkedmsg = msg['msg']; var matches; - if (['FT8', 'JT65', 'JT9', 'FT4'].indexOf(msg['mode']) >= 0) { + if (['FT8', 'JT65', 'JT9', 'FT4', 'JS8'].indexOf(msg['mode']) >= 0) { matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/); if (matches && matches[2] !== 'RR73') { linkedmsg = html_escape(matches[1]) + '' + matches[2] + ''; @@ -2019,6 +2019,7 @@ function demodulator_digital_replace(subtype) { case "jt65": case "jt9": case "ft4": + case "js8": secondary_demod_start(subtype); demodulator_analog_replace('usb', true); break; @@ -2045,7 +2046,7 @@ function demodulator_digital_replace(subtype) { demodulator_buttons_update(); $('#openwebrx-panel-digimodes').attr('data-mode', subtype); toggle_panel("openwebrx-panel-digimodes", true); - toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9', 'ft4'].indexOf(subtype) >= 0); + toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9', 'ft4', 'js8'].indexOf(subtype) >= 0); toggle_panel("openwebrx-panel-packet-message", subtype === "packet"); toggle_panel("openwebrx-panel-pocsag-message", subtype === "pocsag"); updateHash(); diff --git a/owrx/dsp.py b/owrx/dsp.py index 32b9116..d06a455 100644 --- a/owrx/dsp.py +++ b/owrx/dsp.py @@ -1,6 +1,6 @@ -from owrx.config import Config from owrx.meta import MetaParser from owrx.wsjt import WsjtParser +from owrx.js8 import Js8Parser from owrx.aprs import AprsParser from owrx.pocsag import PocsagParser from owrx.source import SdrSource @@ -22,6 +22,7 @@ class DspManager(csdr.output): "wsjt_demod": WsjtParser(self.handler), "packet_demod": AprsParser(self.handler), "pocsag_demod": PocsagParser(self.handler), + "js8_demod": Js8Parser(self.handler), } self.props = PropertyStack() diff --git a/owrx/feature.py b/owrx/feature.py index df2434b..7c7d457 100644 --- a/owrx/feature.py +++ b/owrx/feature.py @@ -40,6 +40,7 @@ class FeatureDetector(object): "wsjt-x": ["wsjtx", "sox"], "packet": ["direwolf", "sox"], "pocsag": ["digiham", "sox"], + "js8call": ["js8", "sox"], } def feature_availability(self): @@ -370,6 +371,12 @@ class FeatureDetector(object): """ return reduce(and_, map(self.command_is_runnable, ["jt9", "wsprd"]), True) + def has_js8(self): + """ + To decode JS8, you will need to install [JS8Call](http://js8call.com/) + """ + return self.command_is_runnable("js8") + def has_alsa(self): """ Some SDR receivers are identifying themselves as a soundcard. In order to read their data, OpenWebRX relies diff --git a/owrx/js8.py b/owrx/js8.py new file mode 100644 index 0000000..2042ad8 --- /dev/null +++ b/owrx/js8.py @@ -0,0 +1,32 @@ +from .wsjt import WsjtChopper +from .parser import Parser +import re + +import logging + +logger = logging.getLogger(__name__) + + +class Js8Chopper(WsjtChopper): + def getInterval(self): + return 15 + + def getFileTimestampFormat(self): + return "%y%m%d_%H%M%S" + + def decoder_commandline(self, file): + return ["js8", "--js8", "-d", str(self.decoding_depth("js8")), file] + + +class Js8Parser(Parser): + decoderRegex = re.compile(" ?") + + def parse(self, raw): + freq, raw_msg = raw + self.setDialFrequency(freq) + msg = raw_msg.decode().rstrip() + if Js8Parser.decoderRegex.match(msg): + return + if msg.startswith(" EOF on input file"): + return + logger.debug(msg)