96 lines
3.0 KiB
Python
96 lines
3.0 KiB
Python
import struct
|
|
import ctypes
|
|
|
|
class MessageBase:
|
|
"""
|
|
Abstract base class for all 1553 Messages.
|
|
|
|
Manages the underlying data buffer (32 words of 16 bits) and
|
|
handles serialization/deserialization ensuring Big Endian format
|
|
(Network Byte Order) typically used in 1553 transmission over UDP.
|
|
"""
|
|
|
|
# Subaddress ID must be defined in subclasses
|
|
SUBADDRESS = None
|
|
# Direction (True=Transmit/RT->BC, False=Receive/BC->RT)
|
|
IS_TRANSMIT = False
|
|
# Rate in Hz (defined in subclasses, used by scheduler)
|
|
RATE_HZ = None
|
|
|
|
def __init__(self, raw_bytes=None):
|
|
"""
|
|
Initialize the message.
|
|
|
|
Args:
|
|
raw_bytes (bytes, optional): If provided, populates the message
|
|
from raw bytes (e.g. received from UDP).
|
|
"""
|
|
# Internal storage: List of 32 integers (16-bit)
|
|
# We initialize with 0.
|
|
# Note: 1553 messages max length is 32 words.
|
|
self._data = [0] * 32
|
|
|
|
# Store raw bytes for GUI display
|
|
self._raw_data = None
|
|
|
|
if raw_bytes:
|
|
self.unpack(raw_bytes)
|
|
|
|
@property
|
|
def data(self):
|
|
"""
|
|
Exposes the internal data buffer to Field descriptors.
|
|
The descriptors in fields.py expect an object with a 'data' attribute
|
|
that supports indexing (get/set).
|
|
"""
|
|
return self._data
|
|
|
|
def pack(self):
|
|
"""
|
|
Serializes the message words into bytes using Big Endian format.
|
|
|
|
Returns:
|
|
bytes: The binary representation of the 32 words (64 bytes).
|
|
"""
|
|
# Pack 32 unsigned shorts (H) in Big Endian (>)
|
|
return struct.pack(f">{len(self._data)}H", *self._data)
|
|
|
|
def unpack(self, raw_bytes):
|
|
"""
|
|
Populates the message words from raw bytes using Big Endian format.
|
|
|
|
Args:
|
|
raw_bytes (bytes): The raw data received.
|
|
"""
|
|
if not raw_bytes:
|
|
return
|
|
|
|
# Store raw bytes for GUI display
|
|
self._raw_data = raw_bytes
|
|
|
|
# Calculate how many words we can read
|
|
num_bytes = len(raw_bytes)
|
|
num_words = num_bytes // 2
|
|
|
|
# Clamp to 32 words max
|
|
if num_words > 32:
|
|
num_words = 32
|
|
|
|
# Unpack available words
|
|
unpacked = struct.unpack(f">{num_words}H", raw_bytes[:num_words * 2])
|
|
|
|
# Update internal buffer
|
|
for i in range(num_words):
|
|
self._data[i] = unpacked[i]
|
|
|
|
def __repr__(self):
|
|
"""
|
|
String representation for debugging.
|
|
Shows Subaddress and non-zero words.
|
|
"""
|
|
direction = "TX" if self.IS_TRANSMIT else "RX"
|
|
sa = self.SUBADDRESS if self.SUBADDRESS is not None else "??"
|
|
|
|
# Show only first few words or non-zero ones for brevity
|
|
words_str = " ".join([f"{w:04X}" for w in self._data[:8]])
|
|
return f"<{self.__class__.__name__} ({direction} SA:{sa}) Data[{words_str}...]>" |