#!/usr/bin/env python3 """Isolate whether bcm_direct_read is broken or if re-reset causes the failure. Test sequence: 1. Power on BCM4500 with 0x81 (GPIO only) 2. Wait 1s for chip to settle 3. Confirm chip alive via raw read 0xB5 4. Try bcm_direct_read via debug mode 0x82 (which RE-RESETS the chip) 5. Immediately try raw read 0xB5 again (is chip alive after 0x82's reset?) 6. Wait various delays and retry raw reads This tells us if the issue is bcm_direct_read vs insufficient post-reset delay. """ import usb.core import usb.util import sys import time BOOT_8PSK = 0x89 def find_device(): dev = usb.core.find(idVendor=0x09C0, idProduct=0x0203) if not dev: print("Device not found!") sys.exit(1) return dev def setup_device(dev): try: if dev.is_kernel_driver_active(0): dev.detach_kernel_driver(0) except Exception: pass try: dev.set_configuration() except usb.core.USBError: pass def raw_read(dev, addr, reg, label=""): """Read via 0xB5 raw I2C handler.""" try: r = dev.ctrl_transfer(0xC0, 0xB5, addr, reg, 1, timeout=1000) val = r[0] ok = val != 0xFF mark = "OK" if ok else "no-resp" print(f" {label}Raw read addr=0x{addr:02X} reg=0x{reg:02X} → 0x{val:02X} ({mark})") return val, ok except usb.core.USBError as e: print(f" {label}Raw read addr=0x{addr:02X} reg=0x{reg:02X} → USB ERROR: {e}") return None, False def main(): dev = find_device() setup_device(dev) ret = dev.ctrl_transfer(0xC0, 0x92, 0, 0, 6, timeout=2000) major, minor, patch = ret[2], ret[1], ret[0] print(f"Firmware: v{major}.{minor:02d}.{patch}\n") # --- Test A: Verify BCM4500 alive from cold --- print("=" * 55) print("TEST A: Power on BCM4500, wait, then raw read") print("=" * 55) print(" Sending 0x81 (GPIO power on + reset release)...") ret = dev.ctrl_transfer(0xC0, BOOT_8PSK, 0x81, 0, 3, timeout=3000) print(f" GPIO done: stage=0x{ret[1]:02X}") print(" Waiting 1000ms for BCM4500 to settle...") time.sleep(1.0) raw_read(dev, 0x08, 0xA2, "After 1s: ") # --- Test B: Now try bcm_direct_read (which re-resets) --- print() print("=" * 55) print("TEST B: Run debug mode 0x82 (re-resets + probe via bcm_direct_read)") print("=" * 55) ret = dev.ctrl_transfer(0xC0, BOOT_8PSK, 0x82, 0, 3, timeout=3000) stage = ret[1] probe = ret[2] if stage == 0xA2: print(f" bcm_direct_read SUCCEEDED: status=0x{probe:02X}") else: print(f" bcm_direct_read FAILED: stage=0x{stage:02X} probe=0x{probe:02X}") # --- Test C: Immediately try raw read after 0x82 (same I2C function, no reset) --- print() print("=" * 55) print("TEST C: Immediately try raw read 0xB5 (same i2c_combined_read)") print("=" * 55) raw_read(dev, 0x08, 0xA2, "Immediate: ") # --- Test D: Wait and retry at various intervals --- print() print("=" * 55) print("TEST D: Raw reads with increasing delays after 0x82's reset") print("=" * 55) for delay_ms in [100, 200, 500, 1000, 2000]: time.sleep(delay_ms / 1000.0) raw_read(dev, 0x08, 0xA2, f"After {delay_ms}ms: ") # --- Test E: Redo power-on without reset, then probe --- print() print("=" * 55) print("TEST E: Run 0x81 again (re-power), wait 1s, then 0x82") print("=" * 55) ret = dev.ctrl_transfer(0xC0, BOOT_8PSK, 0x81, 0, 3, timeout=3000) print(f" GPIO done: stage=0x{ret[1]:02X}") time.sleep(1.0) raw_read(dev, 0x08, 0xA2, "After 0x81+1s: ") print(" Now running 0x82 (re-reset + probe)...") ret = dev.ctrl_transfer(0xC0, BOOT_8PSK, 0x82, 0, 3, timeout=3000) stage = ret[1] probe = ret[2] if stage == 0xA2: print(f" bcm_direct_read SUCCEEDED: status=0x{probe:02X}") else: print(f" bcm_direct_read FAILED: stage=0x{stage:02X} probe=0x{probe:02X}") print("\n" + "=" * 55) print("Analysis complete.") if __name__ == "__main__": main()