use profiles instead of parsing to detect mode

This commit is contained in:
Jakob Ketterl 2020-12-09 11:38:46 +01:00
parent 3291dbe8d2
commit a8011e3a1a
3 changed files with 64 additions and 61 deletions

View File

@ -186,7 +186,7 @@ class AudioWriter(object):
) )
try: try:
for line in decoder.stdout: for line in decoder.stdout:
self.outputWriter.send((job.freq, line)) self.outputWriter.send((self.profile, job.freq, line))
except OSError: except OSError:
decoder.stdout.flush() decoder.stdout.flush()
# TODO uncouple parsing from the output so that decodes can still go to the map and the spotters # TODO uncouple parsing from the output so that decodes can still go to the map and the spotters

View File

@ -28,7 +28,7 @@ class Js8Profiles(object):
class Js8Profile(AudioChopperProfile, metaclass=ABCMeta): class Js8Profile(AudioChopperProfile, metaclass=ABCMeta):
def decoding_depth(self, mode): def decoding_depth(self):
pm = Config.get() pm = Config.get()
# return global default # return global default
if "js8_decoding_depth" in pm: if "js8_decoding_depth" in pm:
@ -40,7 +40,7 @@ class Js8Profile(AudioChopperProfile, metaclass=ABCMeta):
return "%y%m%d_%H%M%S" return "%y%m%d_%H%M%S"
def decoder_commandline(self, file): def decoder_commandline(self, file):
return ["js8", "--js8", "-b", self.get_sub_mode(), "-d", str(self.decoding_depth("js8")), file] return ["js8", "--js8", "-b", self.get_sub_mode(), "-d", str(self.decoding_depth()), file]
@abstractmethod @abstractmethod
def get_sub_mode(self): def get_sub_mode(self):
@ -85,7 +85,7 @@ class Js8Parser(Parser):
def parse(self, messages): def parse(self, messages):
for raw in messages: for raw in messages:
try: try:
freq, raw_msg = raw profile, freq, raw_msg = raw
self.setDialFrequency(freq) self.setDialFrequency(freq)
msg = raw_msg.decode().rstrip() msg = raw_msg.decode().rstrip()
if Js8Parser.decoderRegex.match(msg): if Js8Parser.decoderRegex.match(msg):

View File

@ -14,8 +14,9 @@ logger = logging.getLogger(__name__)
class WsjtProfile(AudioChopperProfile, metaclass=ABCMeta): class WsjtProfile(AudioChopperProfile, metaclass=ABCMeta):
def decoding_depth(self, mode): def decoding_depth(self):
pm = Config.get() pm = Config.get()
mode = self.getMode().lower()
# mode-specific setting? # mode-specific setting?
if "wsjt_decoding_depths" in pm and mode in pm["wsjt_decoding_depths"]: if "wsjt_decoding_depths" in pm and mode in pm["wsjt_decoding_depths"]:
return pm["wsjt_decoding_depths"][mode] return pm["wsjt_decoding_depths"][mode]
@ -25,64 +26,76 @@ class WsjtProfile(AudioChopperProfile, metaclass=ABCMeta):
# default when no setting is provided # default when no setting is provided
return 3 return 3
def getTimestampFormat(self):
if self.getInterval() < 60:
return "%H%M%S"
return "%H%M"
def getFileTimestampFormat(self):
return "%y%m%d_" + self.getTimestampFormat()
@abstractmethod
def getMode(self):
pass
class Ft8Profile(WsjtProfile): class Ft8Profile(WsjtProfile):
def getInterval(self): def getInterval(self):
return 15 return 15
def getFileTimestampFormat(self):
return "%y%m%d_%H%M%S"
def decoder_commandline(self, file): def decoder_commandline(self, file):
return ["jt9", "--ft8", "-d", str(self.decoding_depth("ft8")), file] return ["jt9", "--ft8", "-d", str(self.decoding_depth()), file]
def getMode(self):
return "FT8"
class WsprProfile(WsjtProfile): class WsprProfile(WsjtProfile):
def getInterval(self): def getInterval(self):
return 120 return 120
def getFileTimestampFormat(self):
return "%y%m%d_%H%M"
def decoder_commandline(self, file): def decoder_commandline(self, file):
cmd = ["wsprd"] cmd = ["wsprd"]
if self.decoding_depth("wspr") > 1: if self.decoding_depth() > 1:
cmd += ["-d"] cmd += ["-d"]
cmd += [file] cmd += [file]
return cmd return cmd
def getMode(self):
return "WSPR"
class Jt65Profile(WsjtProfile): class Jt65Profile(WsjtProfile):
def getInterval(self): def getInterval(self):
return 60 return 60
def getFileTimestampFormat(self):
return "%y%m%d_%H%M"
def decoder_commandline(self, file): def decoder_commandline(self, file):
return ["jt9", "--jt65", "-d", str(self.decoding_depth("jt65")), file] return ["jt9", "--jt65", "-d", str(self.decoding_depth()), file]
def getMode(self):
return "JT65"
class Jt9Profile(WsjtProfile): class Jt9Profile(WsjtProfile):
def getInterval(self): def getInterval(self):
return 60 return 60
def getFileTimestampFormat(self):
return "%y%m%d_%H%M"
def decoder_commandline(self, file): def decoder_commandline(self, file):
return ["jt9", "--jt9", "-d", str(self.decoding_depth("jt9")), file] return ["jt9", "--jt9", "-d", str(self.decoding_depth()), file]
def getMode(self):
return "JT9"
class Ft4Profile(WsjtProfile): class Ft4Profile(WsjtProfile):
def getInterval(self): def getInterval(self):
return 7.5 return 7.5
def getFileTimestampFormat(self):
return "%y%m%d_%H%M%S"
def decoder_commandline(self, file): def decoder_commandline(self, file):
return ["jt9", "--ft4", "-d", str(self.decoding_depth("ft4")), file] return ["jt9", "--ft4", "-d", str(self.decoding_depth()), file]
def getMode(self):
return "FT4"
class Fst4Profile(WsjtProfile): class Fst4Profile(WsjtProfile):
@ -94,13 +107,11 @@ class Fst4Profile(WsjtProfile):
def getInterval(self): def getInterval(self):
return self.interval return self.interval
def getFileTimestampFormat(self):
if self.interval < 60:
return "%y%m%d_%H%M%S"
return "%y%m%d_%H%M"
def decoder_commandline(self, file): def decoder_commandline(self, file):
return ["jt9", "--fst4", "-p", str(self.interval), "-d", str(self.decoding_depth("fst4")), file] return ["jt9", "--fst4", "-p", str(self.interval), "-d", str(self.decoding_depth()), file]
def getMode(self):
return "FST4"
@staticmethod @staticmethod
def getEnabledProfiles(): def getEnabledProfiles():
@ -118,13 +129,11 @@ class Fst4wProfile(WsjtProfile):
def getInterval(self): def getInterval(self):
return self.interval return self.interval
def getFileTimestampFormat(self):
if self.interval < 60:
return "%y%m%d_%H%M%S"
return "%y%m%d_%H%M"
def decoder_commandline(self, file): def decoder_commandline(self, file):
return ["jt9", "--fst4w", "-p", str(self.interval), "-d", str(self.decoding_depth("fst4w")), file] return ["jt9", "--fst4w", "-p", str(self.interval), "-d", str(self.decoding_depth()), file]
def getMode(self):
return "FST4W"
@staticmethod @staticmethod
def getEnabledProfiles(): def getEnabledProfiles():
@ -134,12 +143,10 @@ class Fst4wProfile(WsjtProfile):
class WsjtParser(Parser): class WsjtParser(Parser):
modes = {"~": "FT8", "#": "JT65", "@": "JT9", "+": "FT4", "`": "FST4"}
def parse(self, messages): def parse(self, messages):
for data in messages: for data in messages:
try: try:
freq, raw_msg = data profile, freq, raw_msg = data
self.setDialFrequency(freq) self.setDialFrequency(freq)
msg = raw_msg.decode().rstrip() msg = raw_msg.decode().rstrip()
# known debug messages we know to skip # known debug messages we know to skip
@ -148,17 +155,18 @@ class WsjtParser(Parser):
if msg.startswith(" EOF on input file"): if msg.startswith(" EOF on input file"):
return return
modes = list(WsjtParser.modes.keys()) mode = profile.getMode()
if msg[21] in modes or msg[19] in modes: if mode == "WSPR":
decoder = Jt9Decoder() decoder = WsprDecoder(profile)
else: else:
decoder = WsprDecoder() decoder = Jt9Decoder(profile)
out = decoder.parse(msg, freq) out = decoder.parse(msg, freq)
if "mode" in out: out["mode"] = mode
self.pushDecode(out["mode"])
self.pushDecode(mode)
if "callsign" in out and "locator" in out: if "callsign" in out and "locator" in out:
Map.getSharedInstance().updateLocation( Map.getSharedInstance().updateLocation(
out["callsign"], LocatorLocation(out["locator"]), out["mode"], self.band out["callsign"], LocatorLocation(out["locator"]), mode, self.band
) )
PskReporter.getSharedInstance().spot(out) PskReporter.getSharedInstance().spot(out)
@ -189,6 +197,9 @@ class WsjtParser(Parser):
class Decoder(ABC): class Decoder(ABC):
locator_pattern = re.compile(".*\\s([A-Z0-9]{2,})(\\sR)?\\s([A-R]{2}[0-9]{2})$") locator_pattern = re.compile(".*\\s([A-Z0-9]{2,})(\\sR)?\\s([A-R]{2}[0-9]{2})$")
def __init__(self, profile):
self.profile = profile
def parse_timestamp(self, instring, dateformat): def parse_timestamp(self, instring, dateformat):
ts = datetime.strptime(instring, dateformat) ts = datetime.strptime(instring, dateformat)
return int( return int(
@ -219,18 +230,12 @@ class Jt9Decoder(Decoder):
# '0003 -4 0.4 1762 # CQ R2ABM KO85' # '0003 -4 0.4 1762 # CQ R2ABM KO85'
# fst4 sample # fst4 sample
# '**** -23 0.6 3023 ` <...> <...> R 591631 BI53PV' # '**** -23 0.6 3023 ` <...> <...> R 591631 BI53PV'
modes = list(WsjtParser.modes.keys()) dateformat = self.profile.getTimestampFormat()
if msg[19] in modes:
dateformat = "%H%M"
else:
dateformat = "%H%M%S"
try: try:
timestamp = self.parse_timestamp(msg[0 : len(dateformat)], dateformat) timestamp = self.parse_timestamp(msg[0:len(dateformat)], dateformat)
except ValueError: except ValueError:
timestamp = None timestamp = None
msg = msg[len(dateformat) + 1:] msg = msg[len(dateformat) + 1:]
modeChar = msg[14:15]
mode = WsjtParser.modes[modeChar] if modeChar in WsjtParser.modes else "unknown"
wsjt_msg = msg[17:53].strip() wsjt_msg = msg[17:53].strip()
result = { result = {
@ -238,7 +243,6 @@ class Jt9Decoder(Decoder):
"db": float(msg[0:3]), "db": float(msg[0:3]),
"dt": float(msg[4:8]), "dt": float(msg[4:8]),
"freq": dial_freq + int(msg[9:13]), "freq": dial_freq + int(msg[9:13]),
"mode": mode,
"msg": wsjt_msg, "msg": wsjt_msg,
} }
result.update(self.parseMessage(wsjt_msg)) result.update(self.parseMessage(wsjt_msg))
@ -259,7 +263,6 @@ class WsprDecoder(Decoder):
"dt": float(msg[9:13]), "dt": float(msg[9:13]),
"freq": dial_freq + int(float(msg[14:24]) * 1e6), "freq": dial_freq + int(float(msg[14:24]) * 1e6),
"drift": int(msg[25:28]), "drift": int(msg[25:28]),
"mode": "WSPR",
"msg": wsjt_msg, "msg": wsjt_msg,
} }
result.update(self.parseMessage(wsjt_msg)) result.update(self.parseMessage(wsjt_msg))