diff --git a/owrx/audio.py b/owrx/audio.py index 89956fd..1482310 100644 --- a/owrx/audio.py +++ b/owrx/audio.py @@ -186,7 +186,7 @@ class AudioWriter(object): ) try: for line in decoder.stdout: - self.outputWriter.send((job.freq, line)) + self.outputWriter.send((self.profile, job.freq, line)) except OSError: decoder.stdout.flush() # TODO uncouple parsing from the output so that decodes can still go to the map and the spotters diff --git a/owrx/js8.py b/owrx/js8.py index 7d3c474..18a6cef 100644 --- a/owrx/js8.py +++ b/owrx/js8.py @@ -28,7 +28,7 @@ class Js8Profiles(object): class Js8Profile(AudioChopperProfile, metaclass=ABCMeta): - def decoding_depth(self, mode): + def decoding_depth(self): pm = Config.get() # return global default if "js8_decoding_depth" in pm: @@ -40,7 +40,7 @@ class Js8Profile(AudioChopperProfile, metaclass=ABCMeta): return "%y%m%d_%H%M%S" 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 def get_sub_mode(self): @@ -85,7 +85,7 @@ class Js8Parser(Parser): def parse(self, messages): for raw in messages: try: - freq, raw_msg = raw + profile, freq, raw_msg = raw self.setDialFrequency(freq) msg = raw_msg.decode().rstrip() if Js8Parser.decoderRegex.match(msg): diff --git a/owrx/wsjt.py b/owrx/wsjt.py index cb9c15e..5a9b12f 100644 --- a/owrx/wsjt.py +++ b/owrx/wsjt.py @@ -14,8 +14,9 @@ logger = logging.getLogger(__name__) class WsjtProfile(AudioChopperProfile, metaclass=ABCMeta): - def decoding_depth(self, mode): + def decoding_depth(self): pm = Config.get() + mode = self.getMode().lower() # mode-specific setting? if "wsjt_decoding_depths" in pm and mode in pm["wsjt_decoding_depths"]: return pm["wsjt_decoding_depths"][mode] @@ -25,64 +26,76 @@ class WsjtProfile(AudioChopperProfile, metaclass=ABCMeta): # default when no setting is provided 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): def getInterval(self): return 15 - def getFileTimestampFormat(self): - return "%y%m%d_%H%M%S" - 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): def getInterval(self): return 120 - def getFileTimestampFormat(self): - return "%y%m%d_%H%M" - def decoder_commandline(self, file): cmd = ["wsprd"] - if self.decoding_depth("wspr") > 1: + if self.decoding_depth() > 1: cmd += ["-d"] cmd += [file] return cmd + def getMode(self): + return "WSPR" + class Jt65Profile(WsjtProfile): def getInterval(self): return 60 - def getFileTimestampFormat(self): - return "%y%m%d_%H%M" - 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): def getInterval(self): return 60 - def getFileTimestampFormat(self): - return "%y%m%d_%H%M" - 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): def getInterval(self): return 7.5 - def getFileTimestampFormat(self): - return "%y%m%d_%H%M%S" - 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): @@ -94,13 +107,11 @@ class Fst4Profile(WsjtProfile): def getInterval(self): 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): - 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 def getEnabledProfiles(): @@ -118,13 +129,11 @@ class Fst4wProfile(WsjtProfile): def getInterval(self): 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): - 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 def getEnabledProfiles(): @@ -134,12 +143,10 @@ class Fst4wProfile(WsjtProfile): class WsjtParser(Parser): - modes = {"~": "FT8", "#": "JT65", "@": "JT9", "+": "FT4", "`": "FST4"} - def parse(self, messages): for data in messages: try: - freq, raw_msg = data + profile, freq, raw_msg = data self.setDialFrequency(freq) msg = raw_msg.decode().rstrip() # known debug messages we know to skip @@ -148,19 +155,20 @@ class WsjtParser(Parser): if msg.startswith(" EOF on input file"): return - modes = list(WsjtParser.modes.keys()) - if msg[21] in modes or msg[19] in modes: - decoder = Jt9Decoder() + mode = profile.getMode() + if mode == "WSPR": + decoder = WsprDecoder(profile) else: - decoder = WsprDecoder() + decoder = Jt9Decoder(profile) out = decoder.parse(msg, freq) - if "mode" in out: - self.pushDecode(out["mode"]) - if "callsign" in out and "locator" in out: - Map.getSharedInstance().updateLocation( - out["callsign"], LocatorLocation(out["locator"]), out["mode"], self.band - ) - PskReporter.getSharedInstance().spot(out) + out["mode"] = mode + + self.pushDecode(mode) + if "callsign" in out and "locator" in out: + Map.getSharedInstance().updateLocation( + out["callsign"], LocatorLocation(out["locator"]), mode, self.band + ) + PskReporter.getSharedInstance().spot(out) self.handler.write_wsjt_message(out) except (ValueError, IndexError): @@ -189,6 +197,9 @@ class WsjtParser(Parser): class Decoder(ABC): 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): ts = datetime.strptime(instring, dateformat) return int( @@ -219,18 +230,12 @@ class Jt9Decoder(Decoder): # '0003 -4 0.4 1762 # CQ R2ABM KO85' # fst4 sample # '**** -23 0.6 3023 ` <...> <...> R 591631 BI53PV' - modes = list(WsjtParser.modes.keys()) - if msg[19] in modes: - dateformat = "%H%M" - else: - dateformat = "%H%M%S" + dateformat = self.profile.getTimestampFormat() try: - timestamp = self.parse_timestamp(msg[0 : len(dateformat)], dateformat) + timestamp = self.parse_timestamp(msg[0:len(dateformat)], dateformat) except ValueError: timestamp = None 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() result = { @@ -238,7 +243,6 @@ class Jt9Decoder(Decoder): "db": float(msg[0:3]), "dt": float(msg[4:8]), "freq": dial_freq + int(msg[9:13]), - "mode": mode, "msg": wsjt_msg, } result.update(self.parseMessage(wsjt_msg)) @@ -259,7 +263,6 @@ class WsprDecoder(Decoder): "dt": float(msg[9:13]), "freq": dial_freq + int(float(msg[14:24]) * 1e6), "drift": int(msg[25:28]), - "mode": "WSPR", "msg": wsjt_msg, } result.update(self.parseMessage(wsjt_msg))