"""Verify the Sensor/Avionics handler-set fix (input-path audit systemic cause #1). The MFD2 ENG1 page's power bank -- 6 clickable buttons, keys F5-F9 -- sends message ids 3-8 to subsystem 14 ("Avionics", class Sensor). Sensor's MessageHandlerSet was DEFAULT-CONSTRUCTED (entryCount 0, no parent chain), so Find() returned NullHandler for every id and Receiver::Receive dropped them in silence: 108 streamed records across the 18 mechs, all dead. Sensor now chains PoweredSubsystem::GetMessageHandlers() (ids 4-8) which chains HeatSink (id 3). PASS = a [gensel] line naming Avionics after an F-key press. Also prints any [msg] UNHANDLED pairs the new trace catches. Kills only the PID it spawns. """ import ctypes import os import re import subprocess import sys import time KEYUP = 0x0002 VK = {"K": 0x4B, "F5": 0x74, "F6": 0x75, "F7": 0x76, "F8": 0x77, "F9": 0x78, "C": 0x43, "H": 0x48, "N": 0x4E} user32 = ctypes.windll.user32 REPO = r"C:\git\bt411" LOG = os.path.join(REPO, "scratchpad_avionics.log") if os.path.exists(LOG): os.remove(LOG) env = dict(os.environ) env.update({ "BT_START_INSIDE": "1", "BT_KEY_NOFOCUS": "1", "BT_DEV_GAUGES": "1", "BT_FIRE_LOG": "1", # [gensel] lines "BT_HEAT_LOG": "1", "BT_MODE_LOG": "1", # [mode] preset page changes "BT_LOG": LOG, }) proc = subprocess.Popen( [os.path.join(REPO, "build", "Release", "btl4.exe"), "-egg", "LAST.EGG"], cwd=os.path.join(REPO, "content"), env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) print("pid", proc.pid) def tap(name, hold=0.10): vk = VK[name] user32.keybd_event(vk, 0, 0, 0) time.sleep(hold) user32.keybd_event(vk, 0, KEYUP, 0) time.sleep(0.25) try: deadline = time.time() + 200 while time.time() < deadline: if os.path.exists(LOG) and "first frame" in open(LOG, errors="replace").read(): break time.sleep(2) else: print("FAIL: never reached the mission"); sys.exit(2) time.sleep(6) # page MFD2 through its preset pages, pressing the bank on each for page in range(5): tap("K") time.sleep(1.0) for k in ("F5", "F6", "F7", "F8", "F9"): tap(k) time.sleep(1.5) print(" page %d: bank pressed" % page) # and the always-active coolant controls for comparison tap("C"); tap("H") time.sleep(3) finally: proc.terminate() time.sleep(1) t = open(LOG, errors="replace").read() if os.path.exists(LOG) else "" gensel = re.findall(r"^\[gensel\].*$", t, re.M) unh = re.findall(r"^\[msg\] UNHANDLED.*$", t, re.M) print("\n=============== RESULT ===============") print("[gensel] lines (Sensor fix working):", len(gensel)) for l in gensel[:10]: print(" ", l[:130]) print("\n[msg] UNHANDLED pairs caught by the new trace:", len(unh)) for l in unh[:14]: print(" ", l[:130]) print("\nVERDICT:", "PASS -- Avionics messages now reach a handler" if any("Avionics" in l or "Sensor" in l for l in gensel) else ("handlers ran but not on Avionics" if gensel else "no [gensel] -- still not reaching a handler"))