"""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,))