129 lines
5.4 KiB
Python
129 lines
5.4 KiB
Python
import time
|
|
import threading
|
|
import binascii
|
|
from .packet_builder import PacketBuilder
|
|
from .packet_builder_simple import SimplePacketBuilder
|
|
|
|
# Debug flag - set to True for detailed packet logging
|
|
DEBUG_PACKETS = False
|
|
|
|
# Quiet mode - set to True to suppress scheduler output (for GUI mode)
|
|
QUIET_MODE = False
|
|
|
|
# Use simple format (like qg1553overudp.cpp) instead of full UDP1553 protocol
|
|
# Set to False to use the full UDP1553 protocol (like avddriverudp.cpp)
|
|
USE_SIMPLE_FORMAT = False # Server expects 0x1553 marker, so use full format
|
|
|
|
def hex_dump(data: bytes, prefix: str = "") -> str:
|
|
"""Create a hex dump of bytes for debugging."""
|
|
hex_str = binascii.hexlify(data).decode('ascii')
|
|
# Format in groups of 4 bytes (8 hex chars)
|
|
formatted = ' '.join(hex_str[i:i+4] for i in range(0, len(hex_str), 4))
|
|
return f"{prefix}[{len(data)} bytes] {formatted}"
|
|
|
|
class TrafficScheduler:
|
|
"""
|
|
Manages the periodic transmission of 1553 messages (BC -> RT)
|
|
and requests for tell-backs (RT -> BC) using the RadarController state.
|
|
"""
|
|
def __init__(self, udp_handler, radar_controller, target_ip, target_port):
|
|
self.udp = udp_handler
|
|
self.controller = radar_controller
|
|
self.target_ip = target_ip
|
|
self.target_port = target_port
|
|
|
|
self.builder = PacketBuilder()
|
|
self.simple_builder = SimplePacketBuilder()
|
|
self._running = False
|
|
self._thread = None
|
|
self._on_message_sent = None # Callback for sent messages
|
|
self._on_message_sent = None # Callback for sent messages
|
|
|
|
def register_sent_callback(self, callback_func):
|
|
"""
|
|
Registers a function to be called when messages are sent.
|
|
Signature: callback_func(message_obj)
|
|
"""
|
|
self._on_message_sent = callback_func
|
|
|
|
def start(self):
|
|
if self._running:
|
|
return
|
|
self._running = True
|
|
self._thread = threading.Thread(target=self._loop, daemon=True)
|
|
self._thread.start()
|
|
mode = "SIMPLE" if USE_SIMPLE_FORMAT else "FULL UDP1553"
|
|
print(f"[Scheduler] Traffic generation started ({mode} format, 1Hz).")
|
|
|
|
def stop(self):
|
|
self._running = False
|
|
if self._thread:
|
|
self._thread.join()
|
|
print("[Scheduler] Traffic generation stopped.")
|
|
|
|
def _send_a(self, msg_obj):
|
|
"""Sends an 'A' message (Data to Server)."""
|
|
pkt = self.builder.build_packet(msg_obj, is_request=False)
|
|
self.udp.send(pkt, self.target_ip, self.target_port)
|
|
print(f"[Scheduler] Sent {msg_obj.__class__.__name__} (SA {msg_obj.SUBADDRESS}) -> {self.target_ip}:{self.target_port}")
|
|
if DEBUG_PACKETS:
|
|
print(hex_dump(pkt, " TX: "))
|
|
|
|
def _req_b(self, msg_obj):
|
|
"""Sends a request for a 'B' message (Ask Server for Data)."""
|
|
pkt = self.builder.build_packet(msg_obj, is_request=True)
|
|
self.udp.send(pkt, self.target_ip, self.target_port)
|
|
print(f"[Scheduler] Requested {msg_obj.__class__.__name__} (SA {msg_obj.SUBADDRESS}, TR={msg_obj.IS_TRANSMIT}) -> {self.target_ip}:{self.target_port}")
|
|
if DEBUG_PACKETS:
|
|
print(hex_dump(pkt, " TX-REQ: "))
|
|
|
|
def _send_frame_simple(self, messages):
|
|
"""Sends all messages in a single frame using simple format."""
|
|
pkt = self.simple_builder.build_frame(messages)
|
|
self.udp.send(pkt, self.target_ip, self.target_port)
|
|
msg_names = [m.__class__.__name__ for m in messages]
|
|
print(f"[Scheduler] Sent FRAME [{', '.join(msg_names)}] -> {self.target_ip}:{self.target_port}")
|
|
if DEBUG_PACKETS:
|
|
print(hex_dump(pkt[:100], " TX-FRAME (first 100B): "))
|
|
print(f" Frame total size: {len(pkt)} bytes")
|
|
|
|
def _send_frame_udp1553(self, messages):
|
|
"""Sends all messages in a single frame using full UDP1553 format."""
|
|
pkt = self.builder.build_frame(messages)
|
|
self.udp.send(pkt, self.target_ip, self.target_port)
|
|
if not QUIET_MODE:
|
|
msg_names = [m.__class__.__name__ for m in messages]
|
|
print(f"[Scheduler] Sent UDP1553 FRAME [{', '.join(msg_names)}] -> {self.target_ip}:{self.target_port}")
|
|
if DEBUG_PACKETS:
|
|
print(hex_dump(pkt[:100], " TX-FRAME (first 100B): "))
|
|
print(f" Frame total size: {len(pkt)} bytes")
|
|
|
|
# Notify callback for each sent message
|
|
if self._on_message_sent:
|
|
for msg in messages:
|
|
self._on_message_sent(msg)
|
|
|
|
def _loop(self):
|
|
"""
|
|
Scheduling loop.
|
|
Sends configuration messages (A) and requests status (B).
|
|
"""
|
|
while self._running:
|
|
# Send all messages in a single frame
|
|
messages = [
|
|
self.controller.msg_a1, # SA 1 - Settings
|
|
self.controller.msg_a2, # SA 2 - Operation Command
|
|
self.controller.msg_a3, # SA 3 - Graphics
|
|
self.controller.msg_a4, # SA 4 - Nav Data
|
|
self.controller.msg_a5, # SA 5 - INU Data
|
|
# Tell-back requests (TR=1)
|
|
self.controller.msg_b6, # SA 16 - Settings Tell-Back (request)
|
|
self.controller.msg_b7, # SA 17 - Status Tell-Back (request)
|
|
]
|
|
|
|
if USE_SIMPLE_FORMAT:
|
|
self._send_frame_simple(messages)
|
|
else:
|
|
self._send_frame_udp1553(messages)
|
|
|
|
time.sleep(1.0) |