#!/usr/bin/env python3 """A/B test: compare BCM4500 register state with and without firmware download. Uses wIndex boot flags on BOOT_8PSK (0x89): bit 0 (0x01): skip EEPROM firmware download bit 1 (0x02): add 200ms DSP startup delay after download bit 2 (0x04): skip register init blocks Test matrix: A) wIndex=0x01 — skip FW download, init blocks only B) wIndex=0x00 — full boot (FW download + init blocks) C) wIndex=0x02 — full boot + 200ms DSP delay D) wIndex=0x04 — FW download only, skip init blocks """ import sys import time sys.path.insert(0, 'tools') from skywalker_lib import SkyWalker1 CMD_RAW_DEMOD_READ = 0xB1 CMD_I2C_RAW_READ = 0xB5 CMD_GET_PLL_DIAG = 0xBF BCM4500_ADDR = 0x08 # Key direct registers KEY_REGS = [ (0xA0, 'CFG_MODE'), (0xA2, 'STATUS'), (0xA4, 'LOCK'), (0xA6, 'PAGE'), (0xA7, 'DATA'), (0xA8, 'CMD'), (0xA9, 'PLL_A9'), (0xAA, 'PLL_AA'), (0xAB, 'PLL_AB'), ] def read_key_regs(sw, label): """Read key BCM4500 registers via raw I2C (ground truth).""" print(f' --- {label} ---') results = {} for reg, name in KEY_REGS: try: data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR, index=reg, length=1) val = data[0] results[reg] = val marker = '' if val == 0x00: marker = ' (zero)' elif val == 0x02: marker = ' << non-zero!' elif val != 0x00: marker = ' << non-zero!' print(f' 0x{reg:02X} ({name:8s}): 0x{val:02X}{marker}') except Exception as e: results[reg] = None print(f' 0x{reg:02X} ({name:8s}): FAILED ({e})') nonzero = sum(1 for v in results.values() if v and v != 0) print(f' Non-zero registers: {nonzero}/{len(results)}') return results def boot_with_flags(sw, wval=1, flags=0, label=''): """Send BOOT_8PSK with wValue and wIndex (boot flags).""" print(f'\n{"="*60}') print(f'BOOT: wValue={wval}, wIndex=0x{flags:02X} — {label}') print(f'{"="*60}') # Send boot command: wValue=boot mode, wIndex=flags try: result = sw._vendor_in(0x89, value=wval, index=flags, length=3) cfg = result[0] stage = result[1] bits = [] if cfg & 0x01: bits.append('Started') if cfg & 0x02: bits.append('FW_Loaded') if cfg & 0x04: bits.append('Intersil') if cfg & 0x08: bits.append('DVBmode') print(f' Config: 0x{cfg:02X} ({" | ".join(bits) if bits else "none"})') print(f' Boot stage: 0x{stage:02X}' + (' (COMPLETE)' if stage == 0xFF else f' (stopped at {stage})')) except Exception as e: print(f' Boot command failed: {e}') return None # PLL diagnostics try: pd = sw._vendor_in(CMD_GET_PLL_DIAG, value=0, index=0, length=10) print(f' PLL diag: eeprom={"Y" if pd[0] else "N"} ' f'blocks={pd[2]} ' f'exit={"OK" if pd[6]==1 else "FAIL" if pd[6]==0 else "skip"} ' f'result={"OK" if pd[7]==1 else "FAIL"}') except Exception: pass return read_key_regs(sw, 'Registers immediately after boot') def main(): sw = SkyWalker1() sw.open() print('=== BCM4500 Boot A/B Test ===') print(f'Firmware: {sw.get_fw_version()}') # Pre-boot register state (BCM4500 may still be in stock-firmware state) print('\n' + '='*60) print('PRE-BOOT: Register state before any boot command') print('='*60) pre = read_key_regs(sw, 'Before boot') # Shutdown first to establish baseline print('\n--- Shutting down BCM4500 ---') sw._vendor_in(0x89, value=0, index=0, length=3) time.sleep(0.5) # ===== TEST A: Init blocks only (no firmware download) ===== regs_a = boot_with_flags(sw, wval=1, flags=0x01, label='Init blocks ONLY (skip FW download)') # Read again after 200ms time.sleep(0.2) regs_a2 = read_key_regs(sw, 'After 200ms settle (test A)') # Shutdown and wait print('\n--- Shutting down BCM4500 ---') sw._vendor_in(0x89, value=0, index=0, length=3) time.sleep(0.5) # ===== TEST B: Full boot (firmware download + init blocks) ===== regs_b = boot_with_flags(sw, wval=1, flags=0x00, label='Full boot (FW download + init blocks)') # Read again after 200ms time.sleep(0.2) regs_b2 = read_key_regs(sw, 'After 200ms settle (test B)') # Shutdown and wait print('\n--- Shutting down BCM4500 ---') sw._vendor_in(0x89, value=0, index=0, length=3) time.sleep(0.5) # ===== TEST C: Full boot + 200ms DSP startup delay ===== regs_c = boot_with_flags(sw, wval=1, flags=0x02, label='Full boot + 200ms DSP delay') regs_c2 = read_key_regs(sw, 'Registers (test C)') # Shutdown and wait print('\n--- Shutting down BCM4500 ---') sw._vendor_in(0x89, value=0, index=0, length=3) time.sleep(0.5) # ===== TEST D: Firmware download only (no init blocks) ===== regs_d = boot_with_flags(sw, wval=1, flags=0x04, label='FW download ONLY (skip init blocks)') time.sleep(0.2) regs_d2 = read_key_regs(sw, 'After 200ms settle (test D)') # ===== SUMMARY ===== print('\n' + '='*60) print('SUMMARY: Register 0xA2 (STATUS) across tests') print('='*60) def val_str(regs, reg=0xA2): if regs is None: return 'FAIL' v = regs.get(reg) if v is None: return 'FAIL' return f'0x{v:02X}' print(f' Pre-boot (stock FW state): {val_str(pre)}') print(f' A) Init only, immediate: {val_str(regs_a)}') print(f' A) Init only, +200ms: {val_str(regs_a2)}') print(f' B) Full boot, immediate: {val_str(regs_b)}') print(f' B) Full boot, +200ms: {val_str(regs_b2)}') print(f' C) Full boot + DSP delay: {val_str(regs_c)}') print(f' D) FW only, +200ms: {val_str(regs_d2)}') print() print('Expected: A should show 0x02 (previous working state)') print(' B should show 0x00 (current broken state)') print(' C tests if DSP just needs more startup time') print(' D isolates firmware download effect') sw.close() print('\n=== Done ===') if __name__ == '__main__': main()