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

53 lines
1.9 KiB
Python
Executable File

#!/usr/bin/env python3
# cdc.py -- minimal host helper to talk to the c2probe CDC line protocol.
# Uses termios (no pyserial). Usage:
# ./cdc.py hello
# ./cdc.py id2
# ./cdc.py "read 2400 16"
# Sends one command, prints all reply lines until a known terminator/prompt.
import sys, os, termios, tty, time, select
DEV = os.environ.get("C2PROBE_DEV", "/dev/cu.usbmodem2101")
def open_port():
fd = os.open(DEV, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
attrs = termios.tcgetattr(fd)
attrs[2] = termios.CS8 | termios.CLOCAL | termios.CREAD # cflag
attrs[3] = 0 # lflag: raw
attrs[4] = termios.B115200 # ispeed
attrs[5] = termios.B115200 # ospeed
# no flow control, no special chars
attrs[0] = 0; attrs[1] = 0
termios.tcsetattr(fd, termios.TCSANOW, attrs)
return fd
def drain(fd, t=0.15):
r, _, _ = select.select([fd], [], [], t)
if r:
try: return os.read(fd, 4096).decode("utf-8", "replace")
except BlockingIOError: return ""
return ""
def cmd(fd, line, timeout=3.0):
os.write(fd, (line + "\n").encode())
out = ""
end = time.time() + timeout
while time.time() < end:
r, _, _ = select.select([fd], [], [], 0.1)
if r:
try: out += os.read(fd, 4096).decode("utf-8", "replace")
except BlockingIOError: pass
# stop once we have at least one complete line and the port goes quiet
if "\n" in out:
# give a short quiet window for any trailing lines
r2, _, _ = select.select([fd], [], [], 0.08)
if not r2:
break
return out
if __name__ == "__main__":
line = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else "hello"
fd = open_port()
drain(fd, 0.3) # drop any startup/banner
print(cmd(fd, line), end="")
os.close(fd)