@@ -209,26 +209,69 @@ def send_serial_command(self):
209209 else :
210210 QMessageBox .warning (self , "Not Connected" , "No serial connection is active." )
211211
212+ def parse_raw_modem_fields (self , line : str ) -> dict :
213+ pattern = (
214+ r'(?:Modem Raw:|SD Raw:)\s*' # allow “Modem Raw:” or “SD Raw:”
215+ r'SRC:\s*\[(?P<SRC>[^\]]+)\]\s*' # SRC:[…]
216+ r'DST:\s*\[(?P<DST>[^\]]+)\]\s*' # DST:[…]
217+ r'PATH:\s*(?P<PATH>(?:\[[^\]]+\]\s*)+)\s*' # one or more PATH:[…] groups
218+ r'DATA:\s*(?P<DATA>.*)' # everything after DATA:
219+ )
220+ m = re .match (pattern , line , re .IGNORECASE )
221+ if not m :
222+ return {}
223+ fields = m .groupdict ()
224+ fields ['PATH' ] = "," .join (re .findall (r'\[([^\]]+)\]' , fields ['PATH' ]))
225+
226+ return fields
227+
228+ def decode_aprs (self , line ):
229+ fields = self .parse_raw_modem_fields (line )
230+ if fields :
231+ # KN6ARG-9>SWQTWR,WIDE1-1:`2Z5lr|j/`"7I}146.520MHz_1
232+ message = fields ['SRC' ] + '>' + fields ['DST' ] + ',' + fields ['PATH' ] + ':' + fields ['DATA' ]
233+ try :
234+ packet = self .aprs_parser .parse (message )
235+ return packet
236+ except :
237+ pass
238+
239+ return None
240+
212241 def handle_serial_data (self , line ):
213242 timestamp = datetime .now ().strftime ("[%H:%M:%S]" )
243+
244+ # Check for SD Raw prefix and decode base64 if present
245+ if re .search (r"^SD Raw:" , line , re .IGNORECASE ):
246+ try :
247+ b64 = line [7 :].strip ()
248+ data = base64 .b64decode (b64 )
249+ if len (data ) != 173 :
250+ self .msg_output .appendPlainText (f"{ timestamp } Unexpected packet size: { len (data )} " )
251+ return
252+ src = data [0 :15 ].decode ('ascii' , errors = 'ignore' ).strip ('\x00 ' )
253+ dst = data [15 :30 ].decode ('ascii' , errors = 'ignore' ).strip ('\x00 ' )
254+ path = data [30 :40 ].decode ('ascii' , errors = 'ignore' ).strip ('\x00 ' )
255+ msg = data [40 :165 ].decode ('ascii' , errors = 'ignore' ).strip ('\x00 ' )
256+ line = f"SD Raw:SRC:{ src } DST:{ dst } PATH:{ path } DATA:{ msg } "
257+ except Exception as e :
258+ self .msg_output .appendPlainText (f"{ timestamp } Base64 decode error: { e } " )
259+
214260 self .log_output .appendPlainText (f"{ timestamp } { line } " )
215261
216262 # Attempt to parse APRS
217263 try :
218- parsed = self .aprs_parser .parse (line )
219- if parsed :
220- message_queue .put (parsed )
221- formatted = json .dumps (parsed , indent = 2 )
222- self .msg_output .appendPlainText (f"{ timestamp } APRS: { formatted } " )
223-
224- # Plot on map if lat/lon present
225- lat = parsed .get ("latitude" )
226- lon = parsed .get ("longitude" )
227- src = parsed .get ("source" )
264+ packet = self .decode_aprs (line )
265+ if packet :
266+ message_queue .put (packet )
267+ self .msg_output .appendPlainText (f"{ timestamp } APRS: { packet } " )
268+
269+ lat = getattr (packet , "latitude" , None )
270+ lon = getattr (packet , "longitude" , None )
271+ src = getattr (packet , "source" , "" )
228272 if lat and lon :
229273 js = f"addMarker({ lat } , { lon } , '{ src } ');"
230274 self .map_view .page ().runJavaScript (js )
231-
232275 except Exception as e :
233276 self .msg_output .appendPlainText (f"{ timestamp } Failed to parse APRS: { e } " )
234277
0 commit comments