For public

This commit is contained in:
Joppe Blondel
2026-09-10 15:26:43 +02:00
parent b43c979b13
commit 2e0727c58c
107 changed files with 49843 additions and 16 deletions
Regular → Executable
+58 -5
View File
@@ -10,6 +10,7 @@ import serial
FRAME_START = 0x55
CMD_INFO = ord("I")
CMD_READ = ord("R")
CMD_WRITE_BYTE = ord("B")
CMD_WRITE_PAGE = ord("W")
REPLY_OK = ord("K")
@@ -24,6 +25,27 @@ class ProtocolError(RuntimeError):
pass
class DeviceError(ProtocolError):
def __init__(self, code: int, detail: bytes = b"", address: int | None = None):
self.code = code
self.detail = detail
self.address = address
super().__init__(format_device_error(code, detail, address))
def format_device_error(code: int, detail: bytes, address: int | None) -> str:
location = f" at 0x{address:04x}" if address is not None else ""
if code == 4 and len(detail) >= 4:
verify_address = detail[0] | (detail[1] << 8)
expected = detail[2]
observed = detail[3]
return (
f"WRITE verify failed{location}: last byte 0x{verify_address:04x}, "
f"expected 0x{expected:02x}, observed 0x{observed:02x}"
)
return f"device error code {code}{location}"
def read_exact(port: serial.Serial, length: int) -> bytes:
data = bytearray()
while len(data) < length:
@@ -47,6 +69,16 @@ def send_command(port: serial.Serial, command: int, payload: bytes = b"") -> int
return expect_frame_start(port)
def read_device_error(port: serial.Serial, address: int | None = None) -> DeviceError:
code = read_exact(port, 1)[0]
try:
detail_len = read_exact(port, 1)[0]
detail = read_exact(port, detail_len)
except ProtocolError:
detail = b""
return DeviceError(code, detail, address)
def query_info(port: serial.Serial) -> tuple[int, int]:
reply = send_command(port, CMD_INFO)
if reply != REPLY_DATA:
@@ -64,8 +96,7 @@ def read_chunk(port: serial.Serial, address: int, length: int) -> bytes:
payload = bytes([address & 0xFF, (address >> 8) & 0xFF, length])
reply = send_command(port, CMD_READ, payload)
if reply == REPLY_ERROR:
code = read_exact(port, 1)[0]
raise ProtocolError(f"READ failed with error code {code}")
raise read_device_error(port, address)
if reply != REPLY_DATA:
raise ProtocolError(f"unexpected READ reply: {reply!r}")
returned_length = read_exact(port, 1)[0]
@@ -80,8 +111,16 @@ def write_page(port: serial.Serial, address: int, data: bytes) -> None:
payload = bytes([address & 0xFF, (address >> 8) & 0xFF, len(data)]) + data
reply = send_command(port, CMD_WRITE_PAGE, payload)
if reply == REPLY_ERROR:
code = read_exact(port, 1)[0]
raise ProtocolError(f"WRITE failed with error code {code} at 0x{address:04x}")
raise read_device_error(port, address)
if reply != REPLY_OK:
raise ProtocolError(f"unexpected WRITE reply: {reply!r}")
def write_byte(port: serial.Serial, address: int, value: int) -> None:
payload = bytes([address & 0xFF, (address >> 8) & 0xFF, value & 0xFF])
reply = send_command(port, CMD_WRITE_BYTE, payload)
if reply == REPLY_ERROR:
raise read_device_error(port, address)
if reply != REPLY_OK:
raise ProtocolError(f"unexpected WRITE reply: {reply!r}")
@@ -104,6 +143,16 @@ def write_image(port: serial.Serial, data: bytes, page_size: int) -> None:
print(f"wrote and verified page 0x{address:04x}")
def write_image_bytes(port: serial.Serial, data: bytes) -> None:
for address, value in enumerate(data):
write_byte(port, address, value)
verify = read_chunk(port, address, 1)
if verify != bytes([value]):
raise ProtocolError(f"verify failed at 0x{address:04x}")
if (address & 0x3F) == 0:
print(f"wrote and verified byte 0x{address:04x}")
def open_port(device: str, baud: int) -> serial.Serial:
port = serial.Serial(device, baudrate=baud, timeout=2)
time.sleep(2.0)
@@ -119,6 +168,7 @@ def parse_args() -> argparse.Namespace:
parser.add_argument("file", type=Path)
parser.add_argument("--baud", type=int, default=115200)
parser.add_argument("--size", type=int, default=MAX_SIZE, help="bytes to read in read mode")
parser.add_argument("--write-mode", choices=["page", "byte"], default="page")
return parser.parse_args()
@@ -146,7 +196,10 @@ def main() -> int:
print(f"read {len(image)} bytes to {args.file}")
return 0
write_image(port, data, page_size)
if args.write_mode == "byte":
write_image_bytes(port, data)
else:
write_image(port, data, page_size)
print(f"programmed {len(data)} bytes from {args.file}")
return 0