SXXXXXXX_PyMsc/pymsc/lib1553/message_base.py
2025-12-02 11:21:05 +01:00

81 lines
3.2 KiB
Python

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("<H", inverted_cw_val)
footer_bytes = struct.pack("<H", Marker.CTRL_END)
if self._is_request:
# If requesting data, we send Header + InvertedCW + Footer (No Payload)
return header_bytes + bytes([]) + inverted_cw_bytes + footer_bytes
else:
# If sending data, we send Header + Payload + InvertedCW + Footer
payload_bytes = bytes(self.payload)
return header_bytes + payload_bytes + inverted_cw_bytes + footer_bytes
def unpack(self, data: bytes):
"""
Updates the payload with received binary data.
"""
if len(data) >= 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}