26 """DAQv2 BoardHeartbeatPacket: 32B hash + board_id + engine_state + board_state."""
28 "<BBI", PACKET_BOARD_HEARTBEAT, DIABLO_VERSION, ts_ms & 0xFFFFFFFF
30 firmware_hash = bytes(32)
31 body = firmware_hash + struct.pack(
32 "<BBB", board_id & 0xFF, ENGINE_SAFE, BOARD_STATE_SETUP
38 """sensor_results: list of (sensor_id, result) result 1=pass 0=fail."""
39 ts_ms = int(
time.time() * 1000) & 0xFFFFFFFF
40 header = struct.pack(
"<BBI", PACKET_SELF_TEST, DIABLO_VERSION, ts_ms)
41 n =
min(len(sensor_results), 255)
43 body = struct.pack(
"BB", adc_good, n)
45 sid, res = sensor_results[i]
46 body += struct.pack(
"BB", sid & 0xFF, 1
if res
else 0)
51 p = argparse.ArgumentParser(
52 description=
"Board startup E2E helper for integration tests"
54 p.add_argument(
"--board-ip", default=
"127.0.0.60")
55 p.add_argument(
"--listen-port", type=int, required=
True)
56 p.add_argument(
"--daq-host", default=
"127.0.0.1")
57 p.add_argument(
"--daq-port", type=int, required=
True)
58 p.add_argument(
"--board-id", type=int, default=60)
62 default=BOARD_TYPE_PT,
63 help=
"Heartbeat board_type byte",
65 p.add_argument(
"--timeout-s", type=float, default=90.0)
68 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
69 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
71 sock.bind((args.board_ip, args.listen_port))
74 f
"[board_startup_sim] bind {args.board_ip}:{args.listen_port} failed: {e}",
80 target = (args.daq_host, args.daq_port)
85 f
"[board_startup_sim] board_id={args.board_id} listen={args.board_ip}:{args.listen_port} "
86 f
"→ DAQ {target[0]}:{target[1]}",
92 if now - last_hb >= 1.0:
93 ts_ms = int(now * 1000) & 0xFFFFFFFF
95 sock.sendto(pkt, target)
98 data, _addr = sock.recvfrom(4096)
99 if data
and len(data) >= 1
and data[0] == PACKET_SENSOR_CONFIG:
105 f
"[board_startup_sim] SENSOR_CONFIG received enable_serial_printing={mode}, sending SELF_TEST",
112 sock.sendto(st, target)
116 except socket.timeout:
119 print(
"[board_startup_sim] timeout waiting for SENSOR_CONFIG", flush=
True)