#!/usr/bin/env python3 """Verify primary MeshCore chat while Ethernet RF traffic uses radio2. TRANSMITS LoRa and saves channel-0 TX policy=radio on the two explicit lab Companions. Does not flash, reset, edit WiFi, read channel secrets, or configure RF. Both primary and Ethernet tuples MUST already be 909.5/500/SF5/CR5; the script refuses all test transmission unless both devices report those tuples. Only an opposite radio's structured CHANNEL MSG reception proves chat delivery; a command echo or the sender's local Sent response never passes the check. """ from __future__ import annotations import argparse import json import os from pathlib import Path import re import secrets import threading import time from ethernet_kiss_probe import KissEndpoint, run_probe from serial_session import assert_port_idle, open_configured_session, read_command_reply def assert_lab_radio(reply): match = re.search(r"(?:^|\n)\s*(?:->\s*)?>\s*(\d+(?:\.\d+)?),(\d+(?:\.\d+)?),(\d+),(\d+)(?=[,;\s]|$)", reply) if not match or tuple(float(value) for value in match.groups()) != (909.5, 500, 5, 5): raise RuntimeError("Refusing TX: both primary and Ethernet must report 909.5,500,5,5") def received_channel_marker(text, marker): messages = re.findall(r"CHANNEL MSG -> [^\r\n]*\((?:FLOOD|DIRECT)\)\r?\n[ \t]*([^\r\n]*)", text) return any(re.search(r"(?