#!/bin/bash # Quick recovery script — run after physical intervention (SDA pull-up / SOIC clip) # Waits for bare FX2 or SkyWalker enumeration, loads firmware, runs full test set -euo pipefail TOOLS="$(cd "$(dirname "$0")" && pwd)" FW="$TOOLS/../firmware/build/skywalker1.ihx" if [ ! -f "$FW" ]; then echo "ERROR: Firmware not found at $FW" echo "Run: cd firmware && make" exit 1 fi echo "=== SkyWalker-1 Recovery ===" echo "Waiting for device to appear... (plug in now, Ctrl+C to stop)" echo "" # Poll for up to 60 seconds for i in $(seq 1 120); do DEV=$(lsusb -d 09c0:0203 2>/dev/null || true) BARE=$(lsusb -d 04b4:8613 2>/dev/null || true) if [ -n "$DEV" ]; then echo "FOUND SkyWalker-1 (09c0:0203): $DEV" echo "Device already has firmware — skipping load" break elif [ -n "$BARE" ]; then echo "FOUND bare FX2 (04b4:8613): $BARE" sleep 0.5 echo "Loading firmware..." python3 "$TOOLS/fw_load.py" load "$FW" echo "Waiting 3s for re-enumeration..." sleep 3 # Verify it came back DEV=$(lsusb -d 09c0:0203 2>/dev/null || true) if [ -z "$DEV" ]; then echo "WARNING: Device did not re-enumerate as SkyWalker-1" echo "Check dmesg for errors" exit 1 fi echo "Re-enumerated: $DEV" break fi [ $((i % 20)) -eq 0 ] && printf "." sleep 0.5 done # If we got here without finding anything DEV=$(lsusb -d 09c0:0203 2>/dev/null || true) if [ -z "$DEV" ]; then echo "" echo "Timeout — no device detected in 60s" echo "Check physical connections and try again" exit 1 fi echo "" echo "--- Running post-recovery test ---" python3 -c " import usb.core, usb.util, time, sys dev = usb.core.find(idVendor=0x09C0, idProduct=0x0203) if not dev: print('Device not found'); sys.exit(1) print(f'Product: {dev.product}') # Detach kernel drivers for c in dev: for i in c: if dev.is_kernel_driver_active(i.bInterfaceNumber): dev.detach_kernel_driver(i.bInterfaceNumber) try: dev.set_configuration() except: pass A0 = 0xA0 VIN = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_IN # Read FX2 registers def read_reg(addr, n=1): return bytes(dev.ctrl_transfer(VIN, A0, addr, 0, n, 2000)) cpucs = read_reg(0xE600)[0] i2cs = read_reg(0xE678)[0] print(f'CPUCS=0x{cpucs:02X} I2CS=0x{i2cs:02X}') # Test BCM3440 I2C gateway print() print('--- I2C Gateway Test ---') try: d = dev.ctrl_transfer(VIN, 0x84, 0x10, 0xA7, 1, 3000) print(f'BCM3440 gateway (A7): 0x{d[0]:02X} -- OK') except Exception as e: print(f'BCM3440 gateway: FAIL ({e})') # Boot BCM4500 (wValue=1 = full boot, wIndex=0 = normal) print() print('--- BOOT_8PSK (wValue=1) ---') try: d = dev.ctrl_transfer(VIN, 0x89, 1, 0, 3, 15000) config = d[0] stage = d[1] print(f'config_status=0x{config:02X} boot_stage=0x{stage:02X}') if config & 0x03 == 0x03: print('Boot: SUCCESS (started + fw_loaded)') elif stage == 0xFF: print('Boot: SUCCESS (stage=0xFF = complete)') else: print(f'Boot: INCOMPLETE (check stage 0x{stage:02X})') except Exception as e: print(f'Boot: FAIL ({e})') # Wait for demod to settle time.sleep(3) # Signal check print() print('--- Signal Monitor ---') try: d = dev.ctrl_transfer(VIN, 0x90, 0, 0, 8, 3000) snr = (d[0] << 8) | d[1] agc1 = (d[2] << 8) | d[3] agc2 = (d[4] << 8) | d[5] lock = d[6] status = d[7] print(f'SNR={snr} AGC1={agc1} AGC2={agc2} Lock=0x{lock:02X} Status=0x{status:02X}') except Exception as e: print(f'Signal: FAIL ({e})') # GET_8PSK_CONFIG print() print('--- Config Status ---') try: d = dev.ctrl_transfer(VIN, 0x80, 0, 0, 1, 2000) print(f'config_status: 0x{d[0]:02X}') flags = [] if d[0] & 0x01: flags.append('STARTED') if d[0] & 0x02: flags.append('FW_LOADED') if d[0] & 0x04: flags.append('INTERSIL') if d[0] & 0x08: flags.append('DVB_MODE') if d[0] & 0x80: flags.append('ARMED') print(f'Flags: {\" | \".join(flags) if flags else \"(none)\"}') except Exception as e: print(f'Config: FAIL ({e})') print() print('=== Recovery test complete ===') " 2>&1 echo "" echo "=== Done ==="