better timestamping and overhaul
This commit is contained in:
parent
abd5cf0795
commit
18b65f769f
76
owrx/wsjt.py
76
owrx/wsjt.py
@ -1,6 +1,6 @@
|
|||||||
import threading
|
import threading
|
||||||
import wave
|
import wave
|
||||||
from datetime import datetime, timedelta, date
|
from datetime import datetime, timedelta, date, timezone
|
||||||
import time
|
import time
|
||||||
import sched
|
import sched
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -31,7 +31,7 @@ class WsjtChopper(threading.Thread):
|
|||||||
filename = "{tmp_dir}/openwebrx-wsjtchopper-{id}-{timestamp}.wav".format(
|
filename = "{tmp_dir}/openwebrx-wsjtchopper-{id}-{timestamp}.wav".format(
|
||||||
tmp_dir = self.tmp_dir,
|
tmp_dir = self.tmp_dir,
|
||||||
id = id(self),
|
id = id(self),
|
||||||
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
timestamp = datetime.utcnow().strftime(self.fileTimestampFormat)
|
||||||
)
|
)
|
||||||
wavefile = wave.open(filename, "wb")
|
wavefile = wave.open(filename, "wb")
|
||||||
wavefile.setnchannels(1)
|
wavefile.setnchannels(1)
|
||||||
@ -71,9 +71,9 @@ class WsjtChopper(threading.Thread):
|
|||||||
self._scheduleNextSwitch()
|
self._scheduleNextSwitch()
|
||||||
|
|
||||||
def decoder_commandline(self, file):
|
def decoder_commandline(self, file):
|
||||||
'''
|
"""
|
||||||
must be overridden in child classes
|
must be overridden in child classes
|
||||||
'''
|
"""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def decode(self):
|
def decode(self):
|
||||||
@ -128,6 +128,7 @@ class WsjtChopper(threading.Thread):
|
|||||||
class Ft8Chopper(WsjtChopper):
|
class Ft8Chopper(WsjtChopper):
|
||||||
def __init__(self, source):
|
def __init__(self, source):
|
||||||
self.interval = 15
|
self.interval = 15
|
||||||
|
self.fileTimestampFormat = "%y%m%d_%H%M%S"
|
||||||
super().__init__(source)
|
super().__init__(source)
|
||||||
|
|
||||||
def decoder_commandline(self, file):
|
def decoder_commandline(self, file):
|
||||||
@ -138,6 +139,7 @@ class Ft8Chopper(WsjtChopper):
|
|||||||
class WsprChopper(WsjtChopper):
|
class WsprChopper(WsjtChopper):
|
||||||
def __init__(self, source):
|
def __init__(self, source):
|
||||||
self.interval = 120
|
self.interval = 120
|
||||||
|
self.fileTimestampFormat = "%y%m%d_%H%M"
|
||||||
super().__init__(source)
|
super().__init__(source)
|
||||||
|
|
||||||
def decoder_commandline(self, file):
|
def decoder_commandline(self, file):
|
||||||
@ -148,6 +150,7 @@ class WsprChopper(WsjtChopper):
|
|||||||
class Jt65Chopper(WsjtChopper):
|
class Jt65Chopper(WsjtChopper):
|
||||||
def __init__(self, source):
|
def __init__(self, source):
|
||||||
self.interval = 60
|
self.interval = 60
|
||||||
|
self.fileTimestampFormat = "%y%m%d_%H%M"
|
||||||
super().__init__(source)
|
super().__init__(source)
|
||||||
|
|
||||||
def decoder_commandline(self, file):
|
def decoder_commandline(self, file):
|
||||||
@ -158,6 +161,7 @@ class Jt65Chopper(WsjtChopper):
|
|||||||
class Jt9Chopper(WsjtChopper):
|
class Jt9Chopper(WsjtChopper):
|
||||||
def __init__(self, source):
|
def __init__(self, source):
|
||||||
self.interval = 60
|
self.interval = 60
|
||||||
|
self.fileTimestampFormat = "%y%m%d_%H%M"
|
||||||
super().__init__(source)
|
super().__init__(source)
|
||||||
|
|
||||||
def decoder_commandline(self, file):
|
def decoder_commandline(self, file):
|
||||||
@ -167,8 +171,6 @@ class Jt9Chopper(WsjtChopper):
|
|||||||
|
|
||||||
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}|\\*{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]+)")
|
||||||
|
|
||||||
def __init__(self, handler):
|
def __init__(self, handler):
|
||||||
@ -191,38 +193,45 @@ class WsjtParser(object):
|
|||||||
if msg.startswith(" EOF on input file"):
|
if msg.startswith(" EOF on input file"):
|
||||||
return
|
return
|
||||||
|
|
||||||
out = {}
|
modes = list(WsjtParser.modes.keys())
|
||||||
if WsjtParser.jt9_pattern.match(msg):
|
if msg[21] in modes or msg[19] in modes:
|
||||||
out = self.parse_from_jt9(msg)
|
out = self.parse_from_jt9(msg)
|
||||||
elif WsjtParser.wspr_pattern.match(msg):
|
else:
|
||||||
out = self.parse_from_wsprd(msg)
|
out = self.parse_from_wsprd(msg)
|
||||||
|
|
||||||
self.handler.write_wsjt_message(out)
|
self.handler.write_wsjt_message(out)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.exception("error while parsing wsjt message")
|
logger.exception("error while parsing wsjt message")
|
||||||
|
|
||||||
|
def parse_timestamp(self, instring, dateformat):
|
||||||
|
ts = datetime.strptime(instring, dateformat).replace(tzinfo=timezone.utc)
|
||||||
|
return int(datetime.combine(date.today(), ts.time(), timezone.utc).timestamp() * 1000)
|
||||||
|
|
||||||
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
|
# jt65 sample
|
||||||
# '**** -10 0.4 1556 # CQ RN6AM KN95'
|
# '2352 -7 0.4 1801 # R0WAS R2ABM KO85'
|
||||||
out = {}
|
# '0003 -4 0.4 1762 # CQ R2ABM KO85'
|
||||||
if msg.startswith("****"):
|
modes = list(WsjtParser.modes.keys())
|
||||||
out["timestamp"] = int(datetime.now().timestamp() * 1000)
|
if msg[19] in modes:
|
||||||
msg = msg[5:]
|
dateformat = "%H%M"
|
||||||
else:
|
else:
|
||||||
ts = datetime.strptime(msg[0:6], "%H%M%S")
|
dateformat = "%H%M%S"
|
||||||
out["timestamp"] = int(datetime.combine(date.today(), ts.time(), datetime.now().tzinfo).timestamp() * 1000)
|
timestamp = self.parse_timestamp(msg[0:len(dateformat)], dateformat)
|
||||||
msg = msg[7:]
|
msg = msg[len(dateformat) + 1:]
|
||||||
out["db"] = float(msg[0:3])
|
|
||||||
out["dt"] = float(msg[4:8])
|
|
||||||
out["freq"] = int(msg[9:13])
|
|
||||||
modeChar = msg[14:15]
|
modeChar = msg[14:15]
|
||||||
out["mode"] = mode = WsjtParser.modes[modeChar] if modeChar in WsjtParser.modes else "unknown"
|
mode = WsjtParser.modes[modeChar] if modeChar in WsjtParser.modes else "unknown"
|
||||||
wsjt_msg = msg[17:53].strip()
|
wsjt_msg = msg[17:53].strip()
|
||||||
self.parseLocator(wsjt_msg, mode)
|
self.parseLocator(wsjt_msg, mode)
|
||||||
out["msg"] = wsjt_msg
|
return {
|
||||||
return out
|
"timestamp": timestamp,
|
||||||
|
"db": float(msg[0:3]),
|
||||||
|
"dt": float(msg[4:8]),
|
||||||
|
"freq": int(msg[9:13]),
|
||||||
|
"mode": mode,
|
||||||
|
"msg": wsjt_msg
|
||||||
|
}
|
||||||
|
|
||||||
def parseLocator(self, msg, mode):
|
def parseLocator(self, msg, mode):
|
||||||
m = WsjtParser.locator_pattern.match(msg)
|
m = WsjtParser.locator_pattern.match(msg)
|
||||||
@ -237,19 +246,18 @@ class WsjtParser(object):
|
|||||||
def parse_from_wsprd(self, msg):
|
def parse_from_wsprd(self, msg):
|
||||||
# wspr sample
|
# wspr sample
|
||||||
# '2600 -24 0.4 0.001492 -1 G8AXA JO01 33'
|
# '2600 -24 0.4 0.001492 -1 G8AXA JO01 33'
|
||||||
out = {}
|
# '0052 -29 2.6 0.001486 0 G02CWT IO92 23'
|
||||||
now = datetime.now()
|
|
||||||
ts = datetime.strptime(msg[0:4], "%M%S").replace(hour=now.hour)
|
|
||||||
out["timestamp"] = int(datetime.combine(date.today(), ts.time(), now.tzinfo).timestamp() * 1000)
|
|
||||||
out["db"] = float(msg[5:8])
|
|
||||||
out["dt"] = float(msg[9:13])
|
|
||||||
out["freq"] = float(msg[14:24])
|
|
||||||
out["drift"] = int(msg[25:28])
|
|
||||||
out["mode"] = "WSPR"
|
|
||||||
wsjt_msg = msg[29:].strip()
|
wsjt_msg = msg[29:].strip()
|
||||||
out["msg"] = wsjt_msg
|
|
||||||
self.parseWsprMessage(wsjt_msg)
|
self.parseWsprMessage(wsjt_msg)
|
||||||
return out
|
return {
|
||||||
|
"timestamp": self.parse_timestamp(msg[0:4], "%H%M"),
|
||||||
|
"db": float(msg[5:8]),
|
||||||
|
"dt": float(msg[9:13]),
|
||||||
|
"freq": float(msg[14:24]),
|
||||||
|
"drift": int(msg[25:28]),
|
||||||
|
"mode": "WSPR",
|
||||||
|
"msg": wsjt_msg
|
||||||
|
}
|
||||||
|
|
||||||
def parseWsprMessage(self, msg):
|
def parseWsprMessage(self, msg):
|
||||||
m = WsjtParser.wspr_splitter_pattern.match(msg)
|
m = WsjtParser.wspr_splitter_pattern.match(msg)
|
||||||
|
Loading…
Reference in New Issue
Block a user