From 6de51ce1c63dabb9cba0ed27f2bb4e88bcb70c63 Mon Sep 17 00:00:00 2001 From: "Matthew McDougal, KA0S" <26339355+ars-ka0s@users.noreply.github.com> Date: Tue, 2 Apr 2024 12:37:35 -0500 Subject: [PATCH] Add EAS/SAME human-readable decoder --- csdr/chain/toolbox.py | 11 ++++++++++- owrx/dsp.py | 3 +++ owrx/feature.py | 7 +++++++ owrx/modes.py | 7 +++++++ owrx/toolbox.py | 28 ++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/csdr/chain/toolbox.py b/csdr/chain/toolbox.py index e87a3b43..c9f57668 100644 --- a/csdr/chain/toolbox.py +++ b/csdr/chain/toolbox.py @@ -2,7 +2,7 @@ from csdr.chain.demodulator import ServiceDemodulator, DialFrequencyReceiver from csdr.module.toolbox import Rtl433Module, MultimonModule, DumpHfdlModule, DumpVdl2Module, Dump1090Module, AcarsDecModule, RedseaModule, SatDumpModule from pycsdr.modules import FmDemod, AudioResampler, Convert, Agc, Squelch from pycsdr.types import Format -from owrx.toolbox import TextParser, PageParser, SelCallParser, IsmParser, RdsParser +from owrx.toolbox import TextParser, PageParser, SelCallParser, EasSameParser, IsmParser, RdsParser from owrx.aircraft import HfdlParser, Vdl2Parser, AdsbParser, AcarsParser from datetime import datetime @@ -92,6 +92,15 @@ class SelCallDemodulator(MultimonDemodulator): ) +class EasSameDemodulator(MultimonDemodulator): + def __init__(self, service: bool = False): + super().__init__( + ["EAS"], + EasSameParser(service=service), + withSquelch = True + ) + + class ZveiDemodulator(MultimonDemodulator): def __init__(self, service: bool = False): super().__init__( diff --git a/owrx/dsp.py b/owrx/dsp.py index 7742f3e8..0f198416 100644 --- a/owrx/dsp.py +++ b/owrx/dsp.py @@ -677,6 +677,9 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient) elif mod == "selcall": from csdr.chain.toolbox import SelCallDemodulator return SelCallDemodulator() + elif mod == "eassame": + from csdr.chain.toolbox import EasSameDemodulator + return EasSameDemodulator() elif mod == "zvei": from csdr.chain.toolbox import ZveiDemodulator return ZveiDemodulator() diff --git a/owrx/feature.py b/owrx/feature.py index 0b9c51a3..eb533c17 100644 --- a/owrx/feature.py +++ b/owrx/feature.py @@ -92,6 +92,7 @@ class FeatureDetector(object): "acars": ["acarsdec"], "page": ["multimon"], "selcall": ["multimon"], + "eas_same": ["multimon", "dsame3_simple"], "wxsat": ["satdump"], "png": ["imagemagick"], "rds": ["redsea"], @@ -737,6 +738,12 @@ class FeatureDetector(object): """ return self.command_is_runnable("multimon-ng --help") + def has_dsame3_simple(self): + """ + dsame3_simple is used to decode EAS SAME messages to readable text. + """ + return self.command_is_runnable("dsame3_simple --help") + def has_satdump(self): """ OpenWebRX uses [SatDump](https://github.com/SatDump/SatDump) software diff --git a/owrx/modes.py b/owrx/modes.py index 5881de8f..e2a38aea 100644 --- a/owrx/modes.py +++ b/owrx/modes.py @@ -216,6 +216,13 @@ class Modes(object): requirements=["selcall"], squelch=True ), + DigitalMode( + "eassame", + "EAS SAME", + underlying=["nfm"], + requirements=["eas_same"], + squelch=True + ), DigitalMode( "zvei", "Zvei", diff --git a/owrx/toolbox.py b/owrx/toolbox.py index b5b5c03e..dceb1f6a 100644 --- a/owrx/toolbox.py +++ b/owrx/toolbox.py @@ -370,3 +370,31 @@ class SelCallParser(TextParser): dec = None # Done return out + +class EasSameParser(TextParser): + def __init__(self, service: bool = False): + self.reSplit = re.compile(r"(EAS: \S+)") + self.reMatch = re.compile(r"EAS") + self.mode = "" + # Construct parent object + super().__init__(filePrefix="EAS_SAME", service=service) + + def parse(self, msg: bytes): + # Do not parse in service mode + if self.service: + return None + # Parse EAS SAME messages + from dsame3_simple.dsame import same_decode_string + msg = msg.decode('utf-8', 'replace') + out = [] + + r = self.reSplit.split(msg) + for s in r: + if not self.reMatch.match(s): + continue + dec = same_decode_string(s) + if not dec: + continue + out += [s, '\n'.join(dec), ''] + # Done + return '\n'.join(out)