Ported from zleffke/gr-sarsat (2018, GNU Radio 3.7): - Updated Python 2 → Python 3 - Converted XML block definitions to YAML - Added pyproject.toml for modern packaging - Preserved original MIT license Blocks: - biphase_l_decode_bb: Manchester decoder (decim_block) - pds_frame_sync: Frame synchronizer with PDU output - sarp_msg_extract: SARP message splitter/validator
84 lines
2.7 KiB
Python
84 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
# MIT License
|
|
# Copyright (c) 2018 zleffke
|
|
# Ported to GNU Radio 3.10+ by gr-mcp
|
|
|
|
"""
|
|
SARP (Search And Rescue Processor) Message Extractor.
|
|
|
|
Each 72-byte PDS frame contains three 24-byte SARP messages.
|
|
Each SARP message starts with a 12-bit sync word: 0xD60
|
|
|
|
This block:
|
|
1. Receives PDS frame PDUs
|
|
2. Splits into three 24-byte SARP messages
|
|
3. Validates sync word (0xD60)
|
|
4. Routes to 'valid' or 'invalid' output port
|
|
"""
|
|
|
|
import numpy as np
|
|
import pmt
|
|
import binascii
|
|
from gnuradio import gr
|
|
|
|
|
|
class sarp_msg_extract(gr.basic_block):
|
|
"""
|
|
SARP Message Extractor.
|
|
|
|
Input: PDU from PDS Frame Sync Block (72 bytes)
|
|
Output: Individual SARP messages (24 bytes each) on 'valid' or 'invalid' ports
|
|
|
|
A SARP message is considered valid if its sync word matches 0xD60.
|
|
Even invalid messages may contain recoverable beacon data via BCH codes.
|
|
"""
|
|
|
|
def __init__(self):
|
|
gr.basic_block.__init__(
|
|
self,
|
|
name="sarp_msg_extract",
|
|
in_sig=None,
|
|
out_sig=None,
|
|
)
|
|
|
|
self.message_port_register_in(pmt.intern("in"))
|
|
self.set_msg_handler(pmt.intern("in"), self.handle_msg)
|
|
self.message_port_register_out(pmt.intern("valid"))
|
|
self.message_port_register_out(pmt.intern("invalid"))
|
|
|
|
def _check_sync_word(self, msg: bytearray) -> bool:
|
|
"""Check if SARP message has valid sync word (0xD60)."""
|
|
# Sync word is first 12 bits: 0xD6 followed by upper nibble 0x0
|
|
return (msg[0] == 0xD6) and ((msg[1] & 0xF0) == 0x00)
|
|
|
|
def _publish_msg(self, msg: bytearray, valid: bool):
|
|
"""Publish SARP message to appropriate output port."""
|
|
port = "valid" if valid else "invalid"
|
|
pdu = pmt.cons(pmt.PMT_NIL, pmt.init_u8vector(len(msg), msg))
|
|
self.message_port_pub(pmt.intern(port), pdu)
|
|
|
|
def handle_msg(self, msg_pmt):
|
|
"""Process incoming PDS frame PDU."""
|
|
pds_msg = pmt.cdr(msg_pmt)
|
|
|
|
if not pmt.is_u8vector(pds_msg):
|
|
print("[ERROR] Received invalid message type. Expected u8vector")
|
|
return
|
|
|
|
buff = bytearray(pmt.u8vector_elements(pds_msg))
|
|
|
|
if len(buff) < 72:
|
|
print(f"[ERROR] PDS frame too short: {len(buff)} bytes (expected 72)")
|
|
return
|
|
|
|
# Extract three 24-byte SARP messages
|
|
sarp_msg_1 = bytearray(buff[0:24])
|
|
sarp_msg_2 = bytearray(buff[24:48])
|
|
sarp_msg_3 = bytearray(buff[48:72])
|
|
|
|
# Validate and publish each message
|
|
self._publish_msg(sarp_msg_1, self._check_sync_word(sarp_msg_1))
|
|
self._publish_msg(sarp_msg_2, self._check_sync_word(sarp_msg_2))
|
|
self._publish_msg(sarp_msg_3, self._check_sync_word(sarp_msg_3))
|