#!/usr/bin/env python3 """Probe BCM4500 register behavior after boot. 1. Multi-byte reads via 0xB5 (do adjacent registers differ?) 2. Step-by-step indirect read via 0xB6 diagnostic 3. Write a register and read back (is the BCM alive or echoing?) 4. Try tuning to see if the signal path works """ import sys import time sys.path.insert(0, 'tools') from skywalker_lib import SkyWalker1 CMD_I2C_RAW_READ = 0xB5 CMD_I2C_DIAG = 0xB6 CMD_RAW_DEMOD_READ = 0xB1 CMD_RAW_DEMOD_WRITE = 0xB2 BCM4500_ADDR = 0x08 sw = SkyWalker1() sw.open() print('=== BCM4500 Register Probe ===') print(f'Firmware: {sw.get_fw_version()}') # Boot with full sequence print('\n--- Booting BCM4500 (full boot) ---') result = sw._vendor_in(0x89, value=1, index=0, length=3) cfg, stage = result[0], result[1] print(f' Config: 0x{cfg:02X}, Stage: 0x{stage:02X}') # ============================================================ # TEST 1: Multi-byte read — read 16 bytes starting at 0xA0 # ============================================================ print('\n=== Test 1: Multi-byte read (16 bytes from 0xA0) ===') print('If BCM4500 truly maps different registers, bytes should differ.') try: data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR, index=0xA0, length=16) hex_str = ' '.join(f'{b:02X}' for b in data) print(f' 0xA0-0xAF: {hex_str}') unique = set(data) print(f' Unique values: {sorted(f"0x{v:02X}" for v in unique)}') if len(unique) == 1: print(f' ALL SAME VALUE: 0x{data[0]:02X} — BCM4500 may be returning') print(f' a fixed status byte, not true register contents.') except Exception as e: print(f' Failed: {e}') # Read second block 0xB0-0xBF try: data2 = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR, index=0xB0, length=16) hex_str = ' '.join(f'{b:02X}' for b in data2) print(f' 0xB0-0xBF: {hex_str}') except Exception as e: print(f' Failed: {e}') # ============================================================ # TEST 2: Write-then-read — does the BCM4500 retain writes? # ============================================================ print('\n=== Test 2: Write-then-read (register 0xA6 PAGE) ===') print('Write 0x42 to 0xA6, read back. If we get 0x42, register works.') print('If we get 0x02, the chip may be ignoring writes.') # Read current value try: before = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR, index=0xA6, length=1) print(f' Before write: 0xA6 = 0x{before[0]:02X}') except Exception as e: print(f' Read failed: {e}') # Write 0x42 to 0xA6 via 0xB1 direct write try: # 0xB2: RAW_DEMOD_WRITE — wValue=register, wIndex=data sw._vendor_in(CMD_RAW_DEMOD_WRITE, value=0xA6, index=0x42, length=0) except Exception: # 0xB2 might not return data pass time.sleep(0.01) # Read back try: after = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR, index=0xA6, length=1) print(f' After write 0x42: 0xA6 = 0x{after[0]:02X}') if after[0] == 0x42: print(f' >> REGISTER WORKS — BCM4500 is alive and accepting writes!') elif after[0] == 0x02: print(f' >> Still 0x02 — chip may be ignoring writes or returning status') else: print(f' >> Got 0x{after[0]:02X} — unexpected') except Exception as e: print(f' Read failed: {e}') # Restore 0xA6 to 0x00 try: sw._vendor_in(CMD_RAW_DEMOD_WRITE, value=0xA6, index=0x00, length=0) except Exception: pass # ============================================================ # TEST 3: Step-by-step indirect read via 0xB6 # ============================================================ print('\n=== Test 3: Step-by-step indirect read (0xB6) ===') print('Reading indirect register page 0x06 (acquisition config)') try: diag = sw._vendor_in(CMD_I2C_DIAG, value=0x06, index=0, length=8) labels = [ 'Write 0xA6 ok', # [0] 'Readback 0xA6', # [1] 'Write 0xA8 ok', # [2] 'Readback 0xA8', # [3] 'Readback 0xA7', # [4] — the indirect register data 'Direct read 0xA6', # [5] 'Direct read 0xA7', # [6] 'Direct read 0xA8', # [7] ] for i, label in enumerate(labels): ok_marker = '' if i in [0, 2]: ok_marker = ' (success)' if diag[i] == 0x01 else ' (FAILED!)' if diag[i] == 0x00 else '' print(f' [{i}] {label:20s}: 0x{diag[i]:02X}{ok_marker}') print() if diag[0] == 0x01 and diag[2] == 0x01: print(' Writes to A6/A8 succeeded.') if diag[1] == 0x06: print(f' A6 readback = 0x06 — page register WORKS.') else: print(f' A6 readback = 0x{diag[1]:02X} — expected 0x06!') if diag[4] != 0x00: print(f' A7 (indirect data) = 0x{diag[4]:02X} — DSP responding!') else: print(f' A7 (indirect data) = 0x00 — DSP may not be running.') else: print(' Write step FAILED — I2C issue.') except Exception as e: print(f' Diagnostic failed: {e}') # Try a few more pages for page in [0x00, 0x07, 0x0F]: try: diag = sw._vendor_in(CMD_I2C_DIAG, value=page, index=0, length=8) a6_ok = 'ok' if diag[0] == 1 else 'FAIL' a8_ok = 'ok' if diag[2] == 1 else 'FAIL' print(f' Page 0x{page:02X}: A6={a6_ok} A6_rb=0x{diag[1]:02X} ' f'A8={a8_ok} A8_rb=0x{diag[3]:02X} ' f'A7_data=0x{diag[4]:02X} ' f'direct=[A6=0x{diag[5]:02X} A7=0x{diag[6]:02X} A8=0x{diag[7]:02X}]') except Exception as e: print(f' Page 0x{page:02X}: {e}') # ============================================================ # TEST 4: Read registers 0x00-0x9F (below the A0 range) # ============================================================ print('\n=== Test 4: Registers OUTSIDE 0xA0-0xBF range ===') print('If BCM4500 returns 0x02 for everything, it might do so for ALL addresses.') for reg in [0x00, 0x10, 0x50, 0x80, 0x90, 0x9F, 0xC0, 0xD0, 0xFF]: try: data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR, index=reg, length=1) print(f' Reg 0x{reg:02X}: 0x{data[0]:02X}') except Exception as e: print(f' Reg 0x{reg:02X}: FAILED ({e})') # ============================================================ # TEST 5: Quick tune test (no dish needed — just check AGC) # ============================================================ print('\n=== Test 5: Tune to 1200 MHz / 27500 ksps (AGC check) ===') try: # Enable Intersil (LNB controller) sw._vendor_in(0x8A, value=1, index=0, length=1) time.sleep(0.1) print(' Intersil enabled') # Tune: 1200 MHz, 27500 ksps, QPSK result = sw.tune_monitor(freq_mhz=1200, sr_ksps=27500, mod_index=0, dwell_ms=200) print(f' Tune result: {result}') if result.get('agc1', 0) > 0 or result.get('agc2', 0) > 0: print(' >> AGC non-zero — tuner + demod signal path is alive!') else: print(' >> AGC=0 — signal path not working (or tuner not configured)') except Exception as e: print(f' Tune failed: {e}') sw.close() print('\n=== Done ===')