let's try to implement jt65 and jt9 as well
This commit is contained in:
parent
0bb8b5349d
commit
7dcfead843
8
csdr.py
8
csdr.py
@ -25,7 +25,7 @@ import os
|
|||||||
import signal
|
import signal
|
||||||
import threading
|
import threading
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from owrx.wsjt import Ft8Chopper, WsprChopper
|
from owrx.wsjt import Ft8Chopper, WsprChopper, Jt9Chopper, Jt65Chopper
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -277,6 +277,10 @@ class dsp(object):
|
|||||||
chopper = Ft8Chopper(self.secondary_process_demod.stdout)
|
chopper = Ft8Chopper(self.secondary_process_demod.stdout)
|
||||||
elif smd == "wspr":
|
elif smd == "wspr":
|
||||||
chopper = WsprChopper(self.secondary_process_demod.stdout)
|
chopper = WsprChopper(self.secondary_process_demod.stdout)
|
||||||
|
elif smd == "jt65":
|
||||||
|
chopper = Jt65Chopper(self.secondary_process_demod.stdout)
|
||||||
|
elif smd == "jt9":
|
||||||
|
chopper = Jt9Chopper(self.secondary_process_demod.stdout)
|
||||||
chopper.start()
|
chopper.start()
|
||||||
self.output.add_output("wsjt_demod", chopper.read)
|
self.output.add_output("wsjt_demod", chopper.read)
|
||||||
else:
|
else:
|
||||||
@ -371,7 +375,7 @@ class dsp(object):
|
|||||||
def isWsjtMode(self, demodulator = None):
|
def isWsjtMode(self, demodulator = None):
|
||||||
if demodulator is None:
|
if demodulator is None:
|
||||||
demodulator = self.get_secondary_demodulator()
|
demodulator = self.get_secondary_demodulator()
|
||||||
return demodulator in ["ft8", "wspr"]
|
return demodulator in ["ft8", "wspr", "jt65", "jt9"]
|
||||||
|
|
||||||
def set_output_rate(self,output_rate):
|
def set_output_rate(self,output_rate):
|
||||||
self.output_rate=output_rate
|
self.output_rate=output_rate
|
||||||
|
@ -840,20 +840,22 @@ img.openwebrx-mirror-img
|
|||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-content-container,
|
#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="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="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
|
||||||
{
|
{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-canvas-container,
|
#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="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
|
||||||
{
|
{
|
||||||
height: 200px;
|
height: 200px;
|
||||||
margin: -10px;
|
margin: -10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-select-channel,
|
|
||||||
#openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-select-channel
|
|
||||||
{
|
|
||||||
display: none;
|
|
||||||
}
|
|
@ -82,6 +82,8 @@
|
|||||||
<option value="bpsk31">BPSK31</option>
|
<option value="bpsk31">BPSK31</option>
|
||||||
<option value="ft8">FT8</option>
|
<option value="ft8">FT8</option>
|
||||||
<option value="wspr">WSPR</option>
|
<option value="wspr">WSPR</option>
|
||||||
|
<option value="jt65">JT65</option>
|
||||||
|
<option value="jt9">JT9</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="openwebrx-panel-line">
|
<div class="openwebrx-panel-line">
|
||||||
|
@ -1385,7 +1385,7 @@ function update_wsjt_panel(msg) {
|
|||||||
var t = new Date(msg['timestamp']);
|
var t = new Date(msg['timestamp']);
|
||||||
var pad = function(i) { return ('' + i).padStart(2, "0"); }
|
var pad = function(i) { return ('' + i).padStart(2, "0"); }
|
||||||
var linkedmsg = msg['msg'];
|
var linkedmsg = msg['msg'];
|
||||||
if (msg['mode'] == 'FT8') {
|
if (['FT8', 'JT65', 'JT9'].indexOf(msg['mode']) >= 0) {
|
||||||
var matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/);
|
var matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/);
|
||||||
if (matches && matches[2] != 'RR73') {
|
if (matches && matches[2] != 'RR73') {
|
||||||
linkedmsg = html_escape(matches[1]) + '<a href="/map?locator=' + matches[2] + '" target="_blank">' + matches[2] + '</a>';
|
linkedmsg = html_escape(matches[1]) + '<a href="/map?locator=' + matches[2] + '" target="_blank">' + matches[2] + '</a>';
|
||||||
@ -2709,6 +2709,8 @@ function demodulator_digital_replace(subtype)
|
|||||||
case "rtty":
|
case "rtty":
|
||||||
case "ft8":
|
case "ft8":
|
||||||
case "wspr":
|
case "wspr":
|
||||||
|
case "jt65":
|
||||||
|
case "jt9":
|
||||||
secondary_demod_start(subtype);
|
secondary_demod_start(subtype);
|
||||||
demodulator_analog_replace('usb', true);
|
demodulator_analog_replace('usb', true);
|
||||||
demodulator_buttons_update();
|
demodulator_buttons_update();
|
||||||
@ -2716,7 +2718,7 @@ function demodulator_digital_replace(subtype)
|
|||||||
}
|
}
|
||||||
$('#openwebrx-panel-digimodes').attr('data-mode', subtype);
|
$('#openwebrx-panel-digimodes').attr('data-mode', subtype);
|
||||||
toggle_panel("openwebrx-panel-digimodes", true);
|
toggle_panel("openwebrx-panel-digimodes", true);
|
||||||
toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr'].indexOf(subtype) >= 0);
|
toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9'].indexOf(subtype) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function secondary_demod_create_canvas()
|
function secondary_demod_create_canvas()
|
||||||
@ -2888,6 +2890,8 @@ function secondary_demod_listbox_changed()
|
|||||||
case "rtty":
|
case "rtty":
|
||||||
case "ft8":
|
case "ft8":
|
||||||
case "wspr":
|
case "wspr":
|
||||||
|
case "jt65":
|
||||||
|
case "jt9":
|
||||||
demodulator_digital_replace(sdm);
|
demodulator_digital_replace(sdm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
47
owrx/wsjt.py
47
owrx/wsjt.py
@ -144,9 +144,29 @@ class WsprChopper(WsjtChopper):
|
|||||||
return ["wsprd", "-d", file]
|
return ["wsprd", "-d", file]
|
||||||
|
|
||||||
|
|
||||||
|
class Jt65Chopper(WsjtChopper):
|
||||||
|
def __init__(self, source):
|
||||||
|
self.interval = 60
|
||||||
|
super().__init__(source)
|
||||||
|
|
||||||
|
def decoder_commandline(self, file):
|
||||||
|
#TODO expose decoding quality parameters through config
|
||||||
|
return ["jt9", "--jt65", "-d", "3", file]
|
||||||
|
|
||||||
|
|
||||||
|
class Jt9Chopper(WsjtChopper):
|
||||||
|
def __init__(self, source):
|
||||||
|
self.interval = 60
|
||||||
|
super().__init__(source)
|
||||||
|
|
||||||
|
def decoder_commandline(self, file):
|
||||||
|
#TODO expose decoding quality parameters through config
|
||||||
|
return ["jt9", "--jt9", "-d", "3", file]
|
||||||
|
|
||||||
|
|
||||||
class WsjtParser(object):
|
class WsjtParser(object):
|
||||||
locator_pattern = re.compile(".*\\s([A-Z0-9]+)\\s([A-R]{2}[0-9]{2})$")
|
locator_pattern = re.compile(".*\\s([A-Z0-9]+)\\s([A-R]{2}[0-9]{2})$")
|
||||||
jt9_pattern = re.compile("^[0-9]{6} .*")
|
jt9_pattern = re.compile("^([0-9]{6}|\\*{4}) .*")
|
||||||
wspr_pattern = re.compile("^[0-9]{4} .*")
|
wspr_pattern = re.compile("^[0-9]{4} .*")
|
||||||
wspr_splitter_pattern = re.compile("([A-Z0-9]*)\\s([A-R]{2}[0-9]{2})\\s([0-9]+)")
|
wspr_splitter_pattern = re.compile("([A-Z0-9]*)\\s([A-R]{2}[0-9]{2})\\s([0-9]+)")
|
||||||
|
|
||||||
@ -154,7 +174,9 @@ class WsjtParser(object):
|
|||||||
self.handler = handler
|
self.handler = handler
|
||||||
|
|
||||||
modes = {
|
modes = {
|
||||||
"~": "FT8"
|
"~": "FT8",
|
||||||
|
"#": "JT65",
|
||||||
|
"@": "JT9"
|
||||||
}
|
}
|
||||||
|
|
||||||
def parse(self, data):
|
def parse(self, data):
|
||||||
@ -179,15 +201,22 @@ class WsjtParser(object):
|
|||||||
def parse_from_jt9(self, msg):
|
def parse_from_jt9(self, msg):
|
||||||
# ft8 sample
|
# ft8 sample
|
||||||
# '222100 -15 -0.0 508 ~ CQ EA7MJ IM66'
|
# '222100 -15 -0.0 508 ~ CQ EA7MJ IM66'
|
||||||
|
# jt65 sample
|
||||||
|
# '**** -10 0.4 1556 # CQ RN6AM KN95'
|
||||||
out = {}
|
out = {}
|
||||||
ts = datetime.strptime(msg[0:6], "%H%M%S")
|
if msg.startswith("****"):
|
||||||
out["timestamp"] = int(datetime.combine(date.today(), ts.time(), datetime.now().tzinfo).timestamp() * 1000)
|
out["timestamp"] = int(datetime.now().timestamp() * 1000)
|
||||||
out["db"] = float(msg[7:10])
|
msg = msg[5:]
|
||||||
out["dt"] = float(msg[11:15])
|
else:
|
||||||
out["freq"] = int(msg[16:20])
|
ts = datetime.strptime(msg[0:6], "%H%M%S")
|
||||||
modeChar = msg[21:22]
|
out["timestamp"] = int(datetime.combine(date.today(), ts.time(), datetime.now().tzinfo).timestamp() * 1000)
|
||||||
|
msg = msg[7:]
|
||||||
|
out["db"] = float(msg[0:3])
|
||||||
|
out["dt"] = float(msg[4:8])
|
||||||
|
out["freq"] = int(msg[9:13])
|
||||||
|
modeChar = msg[14:15]
|
||||||
out["mode"] = mode = WsjtParser.modes[modeChar] if modeChar in WsjtParser.modes else "unknown"
|
out["mode"] = mode = WsjtParser.modes[modeChar] if modeChar in WsjtParser.modes else "unknown"
|
||||||
wsjt_msg = msg[24:60].strip()
|
wsjt_msg = msg[17:53].strip()
|
||||||
self.parseLocator(wsjt_msg, mode)
|
self.parseLocator(wsjt_msg, mode)
|
||||||
out["msg"] = wsjt_msg
|
out["msg"] = wsjt_msg
|
||||||
return out
|
return out
|
||||||
|
Loading…
Reference in New Issue
Block a user