Add one-shot recovery script for post-intervention testing
Waits for bare FX2 or SkyWalker-1 enumeration, loads firmware, then runs a full diagnostic: I2C gateway, BOOT_8PSK, signal monitor, and config status readback. Usage: bash tools/recover.sh
This commit is contained in:
parent
33b6aa92db
commit
2b87228e29
152
tools/recover.sh
Executable file
152
tools/recover.sh
Executable file
@ -0,0 +1,152 @@
|
|||||||
|
#!/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 ==="
|
||||||
Loading…
x
Reference in New Issue
Block a user