Files
nils 514983c158 Add tooling + EFM8UB20 QFP48 pinout doc
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.
2026-08-17 23:35:09 +02:00

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())