"""Test helper: listen on the server's configured send port and log outgoing frames. This test is diagnostic-only: it listens for a short period and writes human readable summaries to `logs/server_tx_monitor.log`. It does not fail the test suite if nothing is received (so it's safe to run while the real server is down). Run manually (PowerShell): & .venv\Scripts\python.exe -m pytest -q tests/test_server_transmit_monitor.py """ import socket import time import os import struct import ctypes from pymsc.core.app_controller import AppController from pymsc.lib1553.structures import Udp1553Header, Udp1553Message from pymsc.lib1553.constants import Marker def _ensure_logs_dir(path): try: os.makedirs(path, exist_ok=True) except Exception: pass def _decode_markers(data): """Return list of dicts for each CTRL_BEGIN marker found in data.""" res = [] ctrl_begin = struct.pack('> 5) & 0x1F tr = (cw_raw >> 10) & 0x1 rt = (cw_raw >> 11) & 0x1F payload_len = wc_field * 2 inv_pos = pos + 8 + payload_len inverted = None ctrl = None if inv_pos + 2 <= len(data): inverted = struct.unpack_from('= header_size: hdr = Udp1553Header.from_buffer_copy(data[:header_size]) f.write(f" Header: msg_counter={hdr.msg_counter} o_type=0x{hdr.o_type:04X}\n") except Exception as e: f.write(f" Header parse error: {e}\n") # scan for markers and CWs markers = _decode_markers(data) if not markers: f.write(" No CTRL_BEGIN markers found\n") else: for m in markers: expected_inv = (~m['cw_raw']) & 0xFFFF f.write( f" MARKER pos={m['pos']} SA={m['sa']} TR={m['tr']} RT={m['rt']} WC={m['wc']} " f"payload_len={m['payload_len']} inverted=0x{(m['inverted'] or 0):04X} ctrl_end={m['ctrl_end']} expected_inv=0x{expected_inv:04X}\n" ) f.flush() seen.append((t, addr, len(data))) # test must not fail; it's diagnostic assert True def test_server_transmit_active_controller(): """Start an AppController locally, initialize radar and capture what it transmits. This test creates an AppController instance, assigns ephemeral ports so it doesn't conflict with any running server, starts it, calls `initialize_radar()` and listens for outgoing frames on the controller's configured send port. Captured data is written to `logs/server_tx_monitor_active.log`. """ # pick ephemeral ports s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind(('127.0.0.1', 0)) send_port = s.getsockname()[1] s.close() r = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) r.bind(('127.0.0.1', 0)) recv_port = r.getsockname()[1] r.close() c = AppController() c.udp_send_port = send_port c.udp_recv_port = recv_port c.radar_dest_ip = '127.0.0.1' repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) logs_dir = os.path.join(repo_root, 'logs') _ensure_logs_dir(logs_dir) out_path = os.path.join(logs_dir, 'server_tx_monitor_active.log') # start controller c.start() time.sleep(0.1) # bind a socket to receive what the controller will send monitor = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: monitor.bind(('127.0.0.1', send_port)) monitor.settimeout(0.5) except OSError as e: with open(out_path, 'a', encoding='utf-8') as f: f.write(f"[{time.strftime('%H:%M:%S')}] Could not bind monitor to port {send_port}: {e}\n") c.stop() return # ask controller to initialize radar (this will schedule periodic sends) try: c.initialize_radar() except Exception as e: with open(out_path, 'a', encoding='utf-8') as f: f.write(f"[{time.strftime('%H:%M:%S')}] initialize_radar() raised: {e}\n") stop_at = time.time() + 4.0 received = 0 with open(out_path, 'a', encoding='utf-8') as f: f.write(f"[{time.strftime('%H:%M:%S')}] Active monitor listening on port {send_port}\n") while time.time() < stop_at: try: data, addr = monitor.recvfrom(4096) except socket.timeout: continue t = time.strftime('%H:%M:%S') f.write(f"[{t}] RX len={len(data)} from {addr[0]}:{addr[1]}\n") markers = _decode_markers(data) if markers: for m in markers: expected_inv = (~m['cw_raw']) & 0xFFFF f.write(f" MARKER SA={m['sa']} TR={m['tr']} RT={m['rt']} WC={m['wc']} payload_len={m['payload_len']} expected_inv=0x{expected_inv:04X}\n") else: f.write(" No markers found\n") f.flush() received += 1 monitor.close() c.stop() # record whether we saw any frames with open(out_path, 'a', encoding='utf-8') as f: f.write(f"[{time.strftime('%H:%M:%S')}] Active monitor finished, packets_received={received}\n") # don't fail if none received; this is diagnostic assert True