Apply .gitattributes normalization to convert all CRLF line endings inherited from Windows-origin source files to Unix LF. 175 files, zero content changes.
128 lines
3.7 KiB
Python
128 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Incremental BOOT_8PSK debug tester for SkyWalker-1.
|
|
|
|
Sends debug boot modes (wValue=0x80..0x83) one at a time to isolate
|
|
which stage of the BCM4500 boot sequence hangs the FX2 firmware.
|
|
|
|
Usage:
|
|
sudo python3 test_boot_debug.py # run all debug stages
|
|
sudo python3 test_boot_debug.py 0x82 # run only stage 0x82
|
|
"""
|
|
|
|
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 decode_stage(stage):
|
|
names = {
|
|
0x00: "NOT_STARTED",
|
|
0x01: "GPIO_SETUP",
|
|
0x02: "PWR_SETTLED",
|
|
0x03: "I2C_PROBE",
|
|
0x04: "INIT_BLK0",
|
|
0x05: "INIT_BLK1",
|
|
0x06: "INIT_BLK2",
|
|
0xA1: "DEBUG_GPIO_OK",
|
|
0xA2: "DEBUG_PROBE_OK",
|
|
0xA3: "DEBUG_BLK0_OK",
|
|
0xE3: "DEBUG_PROBE_FAIL",
|
|
0xE4: "DEBUG_BLK0_FAIL",
|
|
0xFF: "COMPLETE",
|
|
}
|
|
return names.get(stage, f"UNKNOWN(0x{stage:02X})")
|
|
|
|
def test_mode(dev, wval, label, timeout_ms=3000):
|
|
"""Send a debug boot mode and read 3-byte response."""
|
|
print(f"\n{'─' * 50}")
|
|
print(f" Testing wValue=0x{wval:02X}: {label}")
|
|
print(f"{'─' * 50}")
|
|
|
|
t0 = time.monotonic()
|
|
try:
|
|
ret = dev.ctrl_transfer(0xC0, BOOT_8PSK, wval, 0, 3, timeout=timeout_ms)
|
|
except usb.core.USBError as e:
|
|
elapsed = (time.monotonic() - t0) * 1000
|
|
print(f" FAILED after {elapsed:.0f}ms: {e}")
|
|
# Try to see if device is still alive
|
|
try:
|
|
dev.ctrl_transfer(0xC0, 0x92, 0, 0, 6, timeout=1000)
|
|
print(" Device still responds to GET_FW_VERS")
|
|
except:
|
|
print(" Device is HUNG (no response to GET_FW_VERS)")
|
|
return None
|
|
elapsed = (time.monotonic() - t0) * 1000
|
|
|
|
status = ret[0]
|
|
stage = ret[1] if len(ret) > 1 else 0
|
|
probe = ret[2] if len(ret) > 2 else 0
|
|
|
|
print(f" Response in {elapsed:.0f}ms:")
|
|
print(f" config_status: 0x{status:02X}")
|
|
print(f" boot_stage: 0x{stage:02X} [{decode_stage(stage)}]")
|
|
print(f" probe_byte: 0x{probe:02X}")
|
|
return ret
|
|
|
|
def main():
|
|
dev = find_device()
|
|
setup_device(dev)
|
|
|
|
# Verify firmware is responding
|
|
try:
|
|
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}")
|
|
except usb.core.USBError as e:
|
|
print(f"GET_FW_VERS failed: {e}")
|
|
print("Device may be hung. Try reloading firmware with fw_load.py.")
|
|
sys.exit(1)
|
|
|
|
ret = dev.ctrl_transfer(0xC0, 0x80, 0, 0, 1)
|
|
print(f"Config: 0x{ret[0]:02X}")
|
|
|
|
# Parse optional argument for single-stage testing
|
|
single_stage = None
|
|
if len(sys.argv) > 1:
|
|
single_stage = int(sys.argv[1], 0)
|
|
|
|
stages = [
|
|
(0x80, "No-op: return current state only"),
|
|
(0x81, "GPIO setup + power + delays (no I2C)"),
|
|
(0x82, "GPIO + I2C bus reset + BCM4500 probe read"),
|
|
(0x83, "GPIO + I2C probe + write init block 0"),
|
|
]
|
|
|
|
for wval, label in stages:
|
|
if single_stage is not None and wval != single_stage:
|
|
continue
|
|
result = test_mode(dev, wval, label)
|
|
if result is None:
|
|
print("\n*** STOPPING: device not responding ***")
|
|
break
|
|
|
|
print(f"\n{'=' * 50}")
|
|
print("Debug complete.")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|