diff --git a/csdr.py b/csdr.py index 05b8973..8b8edef 100755 --- a/csdr.py +++ b/csdr.py @@ -25,7 +25,7 @@ import os import signal import threading from functools import partial -from owrx.wsjt import Ft8Chopper, WsprChopper, Jt9Chopper, Jt65Chopper +from owrx.wsjt import Ft8Chopper, WsprChopper, Jt9Chopper, Jt65Chopper, Ft4Chopper import logging logger = logging.getLogger(__name__) @@ -281,6 +281,8 @@ class dsp(object): chopper = Jt65Chopper(self.secondary_process_demod.stdout) elif smd == "jt9": chopper = Jt9Chopper(self.secondary_process_demod.stdout) + elif smd == "ft4": + chopper = Ft4Chopper(self.secondary_process_demod.stdout) chopper.start() self.output.add_output("wsjt_demod", chopper.read) else: @@ -375,7 +377,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"] + return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4"] def set_output_rate(self,output_rate): self.output_rate=output_rate diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css index 47cf9cf..91e03e8 100644 --- a/htdocs/css/openwebrx.css +++ b/htdocs/css/openwebrx.css @@ -843,10 +843,12 @@ img.openwebrx-mirror-img #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="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="jt9"] #openwebrx-digimode-select-channel, +#openwebrx-panel-digimodes[data-mode="ft4"] #openwebrx-digimode-select-channel { display: none; } @@ -854,7 +856,8 @@ img.openwebrx-mirror-img #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="jt9"] #openwebrx-digimode-canvas-container, +#openwebrx-panel-digimodes[data-mode="ft4"] #openwebrx-digimode-canvas-container { height: 200px; margin: -10px; diff --git a/htdocs/index.html b/htdocs/index.html index 7e9f380..e2b8010 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -84,6 +84,7 @@ +
diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js index eee6175..be79ee5 100644 --- a/htdocs/openwebrx.js +++ b/htdocs/openwebrx.js @@ -1385,7 +1385,7 @@ function update_wsjt_panel(msg) { var t = new Date(msg['timestamp']); var pad = function(i) { return ('' + i).padStart(2, "0"); } var linkedmsg = msg['msg']; - if (['FT8', 'JT65', 'JT9'].indexOf(msg['mode']) >= 0) { + if (['FT8', 'JT65', 'JT9', 'FT4'].indexOf(msg['mode']) >= 0) { var 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] + ''; @@ -2711,6 +2711,7 @@ function demodulator_digital_replace(subtype) case "wspr": case "jt65": case "jt9": + case "ft4": secondary_demod_start(subtype); demodulator_analog_replace('usb', true); demodulator_buttons_update(); @@ -2718,7 +2719,7 @@ function demodulator_digital_replace(subtype) } $('#openwebrx-panel-digimodes').attr('data-mode', subtype); toggle_panel("openwebrx-panel-digimodes", true); - toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9'].indexOf(subtype) >= 0); + toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9', 'ft4'].indexOf(subtype) >= 0); } function secondary_demod_create_canvas() @@ -2892,6 +2893,7 @@ function secondary_demod_listbox_changed() case "wspr": case "jt65": case "jt9": + case "ft4": demodulator_digital_replace(sdm); break; } diff --git a/owrx/wsjt.py b/owrx/wsjt.py index b0c8c4b..0e89e11 100644 --- a/owrx/wsjt.py +++ b/owrx/wsjt.py @@ -169,6 +169,17 @@ class Jt9Chopper(WsjtChopper): return ["jt9", "--jt9", "-d", "3", file] +class Ft4Chopper(WsjtChopper): + def __init__(self, source): + self.interval = 7.5 + self.fileTimestampFormat = "%y%m%d_%H%M%S" + super().__init__(source) + + def decoder_commandline(self, file): + #TODO expose decoding quality parameters through config + return ["jt9", "--ft4", "-d", "3", file] + + class WsjtParser(object): locator_pattern = re.compile(".*\\s([A-Z0-9]+)\\s([A-R]{2}[0-9]{2})$") wspr_splitter_pattern = re.compile("([A-Z0-9]*)\\s([A-R]{2}[0-9]{2})\\s([0-9]+)") @@ -181,7 +192,8 @@ class WsjtParser(object): modes = { "~": "FT8", "#": "JT65", - "@": "JT9" + "@": "JT9", + "+": "FT4" } def parse(self, data):