Skip to content

Commit eac18a0

Browse files
committed
[Qt.py] add pins to map
1 parent 1337c9e commit eac18a0

File tree

2 files changed

+55
-13
lines changed

2 files changed

+55
-13
lines changed

Source/GUI/Main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,10 +688,9 @@ def change_filter_mode(*args):
688688
#root.iconbitmap("ham_messenger_icon.ico")
689689
root.title("HamMessenger Serial GUI")
690690
root.geometry("950x620")
691-
root.rowconfigure(5, weight=1)
691+
root.rowconfigure(6, weight=8)
692692
root.columnconfigure(0, weight=1)
693693

694-
root.rowconfigure(6, weight=8)
695694
tabs = ttk_gui.Notebook(root)
696695
tabs.grid(row=6, column=0, sticky="nsew", padx=10, pady=(0, 10))
697696

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)