Make the repo self-contained (no dependency on the parent firmware-tools/ checkout): copy in the patch/disasm/syx tools and the c2probe RP2040 C2 flash-reader/patcher firmware. - patch_usb1_to_cv.py : byte-level USB-1->CV patch (imported by roundtrip.py) - d8051.py : standalone 8051 disassembler - syx_extract.py : SysEx extractor - c2probe/ : RP2040 C2 flash reader + host scripts (c2probe.c, cdc/dump_flash/patch_c2/reflash_page/verify.py, CMake build) - RECOVERY.md : C2 flash recovery procedure - EFM8UB20_PINOUT.md : reverse-engineered QFP48 pinout + firmware pin usage - roundtrip.py : import local patch_usb1_to_cv (parent as fallback) - .gitignore : exclude c2probe/.venv, c2probe/build Verified: stock + patched round-trips still re-assemble byte-identical.
57 lines
2.0 KiB
Python
57 lines
2.0 KiB
Python
#!/usr/bin/env python3
|
|
# verify.py -- re-read specific flash regions N times to check whether the
|
|
# bytes are stable (real flash) or vary (C2 read errors). Also re-reads the
|
|
# known-intact 0xE800 page as a control.
|
|
import os, sys, time, select, termios
|
|
|
|
DEV = os.environ.get("C2PROBE_DEV", "/dev/cu.usbmodem2101")
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import cdc
|
|
|
|
REGIONS = [
|
|
("0xE800 (control, intact)", 0xE800, 256),
|
|
("0xEDFF (big diff run)", 0xEDFF, 256),
|
|
("0xEF00 (within diff run)", 0xEF00, 128),
|
|
("0xF1D0 (scattered diffs)", 0xF1D0, 64),
|
|
("0xF200 (diff)", 0xF200, 16),
|
|
("0xF800 (6B diff @app end)", 0xF800, 16),
|
|
("0xFC00 (gap region)", 0xFC00, 64),
|
|
]
|
|
N = 4
|
|
|
|
def main():
|
|
fd = cdc.open_port()
|
|
cdc.drain(fd, 0.4)
|
|
r = cdc.cmd(fd, "piinit", 12)
|
|
print("piinit:", r)
|
|
if r.strip() != "ok piinit":
|
|
print("piinit failed"); return 1
|
|
for name, addr, n in REGIONS:
|
|
reads = []
|
|
ok = True
|
|
for _ in range(N):
|
|
lc = n if n < 256 else 0
|
|
r = cdc.cmd(fd, f"read {addr:04x} {lc}", 12).strip()
|
|
if r.startswith("data "):
|
|
parts = r.split()
|
|
try:
|
|
reads.append(bytes.fromhex(parts[3]))
|
|
except (IndexError, ValueError):
|
|
reads.append(None); ok = False
|
|
else:
|
|
reads.append(None); ok = False
|
|
# stability check
|
|
good = [b for b in reads if b is not None and len(b) == n]
|
|
stable = len(set(good)) == 1 and len(good) == N
|
|
print(f"\n{name} @0x{addr:04x} len={n}")
|
|
if not good:
|
|
print(" ALL READS FAILED")
|
|
continue
|
|
for i, b in enumerate(reads):
|
|
tag = "ok " if (b is not None and len(b)==n) else "FAIL"
|
|
print(f" [{i}] {tag} {b.hex() if b else ''}")
|
|
print(f" stable={stable} distinct={len(set(good))}")
|
|
return 0
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main()) |