import ctypes import struct from .structures import Udp1553Message, CommandWord, Marker from .constants import Direction class BaseMessage: """ Base class for all 1553 messages. Wraps the specific payload (ctypes structure) and the 1553 transport header. """ def __init__(self, label: str, payload_cls, sub_addr: int, frequency: int, is_transmit: bool = True): """ Args: label (str): Human readable label (e.g., "A1", "B7"). payload_cls (ctypes.Structure): The class definition of the data payload. sub_addr (int): 1553 Subaddress (1-30). frequency (int): Transmission frequency in Hz. is_transmit (bool): True if BC sends to RT, False if BC requests from RT. """ self.label = label self.frequency = frequency self.period_ms = 1000.0 / frequency if frequency > 0 else 0 # Instantiate the payload self.payload = payload_cls() self.payload_size = ctypes.sizeof(self.payload) # 1553 Word Count (bytes / 2) word_count = self.payload_size // 2 # Determine direction bit (BC->RT = 0 (Receive), RT->BC = 1 (Transmit)) # Note: The original code logic might interpret this differently, # usually BC sending is Receive for RT. Adjusting based on standard 1553. tr_bit = 0 if is_transmit else 1 # Create the 1553 Command Word self.cw = CommandWord(wc=word_count, sa=sub_addr, tr=tr_bit, rt=20) # RT 20 hardcoded from original # Create the UDP Encapsulation Header self.header = Udp1553Message( marker=Marker.CTRL_BEGIN, cw=self.cw ) self._is_request = not is_transmit def pack(self) -> bytes: """ Serializes the message into bytes for network transmission. Includes the quirks from the original protocol (inverted CW at the end). """ header_bytes = bytes(self.header) # Calculate inverted CW (Protocol specific quirk found in original code) inverted_cw_val = ~self.header.cw.raw & 0xFFFF inverted_cw_bytes = struct.pack("= self.payload_size: ctypes.memmove(ctypes.addressof(self.payload), data, self.payload_size) def to_dict(self): """ Helper for GUI to get values without knowing ctypes. Implementation to be expanded recursively. """ # Placeholder: deep introspection logic goes here later return {"label": self.label, "size": self.payload_size}