48 lines
1.6 KiB
Python
48 lines
1.6 KiB
Python
"""Packets and constants for the STM32 system-memory UART bootloader (AN3155)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
ACK = 0x79
|
|
NACK = 0x1F
|
|
SYNC = b"\x7f"
|
|
|
|
|
|
def command(code: int) -> bytes:
|
|
"""Encode an AN3155 command and its one's-complement checksum."""
|
|
if not 0 <= code <= 0xFF:
|
|
raise ValueError("Код команды вне диапазона байта")
|
|
return bytes((code, code ^ 0xFF))
|
|
|
|
|
|
def address(value: int) -> bytes:
|
|
"""Encode a big-endian 32-bit address followed by XOR checksum."""
|
|
if not 0 <= value <= 0xFFFFFFFF:
|
|
raise ValueError("Адрес вне диапазона u32")
|
|
raw = value.to_bytes(4, "big")
|
|
return raw + bytes((raw[0] ^ raw[1] ^ raw[2] ^ raw[3],))
|
|
|
|
|
|
def write_payload(data: bytes) -> bytes:
|
|
"""Encode one Write Memory payload (1..256 bytes)."""
|
|
if not 1 <= len(data) <= 256:
|
|
raise ValueError("Блок STM32 должен содержать от 1 до 256 байт")
|
|
count = len(data) - 1
|
|
checksum = count
|
|
for value in data:
|
|
checksum ^= value
|
|
return bytes((count,)) + data + bytes((checksum,))
|
|
|
|
|
|
MASS_ERASE = b"\xff\x00"
|
|
|
|
|
|
def erase_pages_payload(pages: list[int]) -> bytes:
|
|
"""Encode the standard Erase Memory page list used by STM32F1."""
|
|
if not pages or len(pages) > 256 or any(not 0 <= page <= 0xFF for page in pages):
|
|
raise ValueError("Список страниц STM32 должен содержать 1..256 номеров")
|
|
body = bytes((len(pages) - 1, *pages))
|
|
checksum = 0
|
|
for value in body:
|
|
checksum ^= value
|
|
return body + bytes((checksum,))
|