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.
53 lines
1.9 KiB
Python
Executable File
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) |