SXXXXXXX_PyBusMonitor1553/pybusmonitor1553/lib1553/message_base.py

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}...]>"