Add shared waveform processing, generation and firmware image support

This commit is contained in:
2026-09-27 01:45:08 +03:00
parent 2ad29e7ffd
commit cc22c803d1
36 changed files with 2591 additions and 61 deletions

View File

@@ -7,15 +7,12 @@
from __future__ import annotations
import hashlib
from dataclasses import dataclass
from pathlib import Path
from set_devices.protocol import crc32_ieee
class FirmwareImageError(ValueError):
"""@brief Файл нельзя безопасно представить как непрерывный бинарный образ."""
from firmware_image.core import FirmwareImageError, contiguous_image, image_digest
@dataclass(frozen=True)
@@ -34,18 +31,18 @@ class FirmwareImage:
@property
def crc32(self) -> int:
return crc32_ieee(self.data)
return int(image_digest(self.data)[0], 16)
@property
def sha256(self) -> str:
return hashlib.sha256(self.data).hexdigest()
return image_digest(self.data)[1].lower()
@classmethod
def load(cls, path: str | Path, maximum_size: int = 2 * 1024 * 1024) -> "FirmwareImage":
file_path = Path(path)
raw = file_path.read_bytes()
if file_path.suffix.lower() == ".hex":
data, base = _parse_intel_hex(raw.decode("ascii"))
data, base = _parse_intel_hex(raw, maximum_size)
elif file_path.suffix.lower() == ".bin":
data, base = raw, 0
else:
@@ -57,49 +54,8 @@ class FirmwareImage:
return cls(file_path, data, base)
def _parse_intel_hex(text: str) -> tuple[bytes, int]:
memory: dict[int, int] = {}
upper = 0
eof = False
for line_number, source in enumerate(text.splitlines(), 1):
line = source.strip()
if not line:
continue
if not line.startswith(":"):
raise FirmwareImageError(f"Intel HEX: строка {line_number} без ':'")
try:
record = bytes.fromhex(line[1:])
except ValueError as error:
raise FirmwareImageError(f"Intel HEX: неверный HEX в строке {line_number}") from error
if len(record) < 5 or len(record) != record[0] + 5 or sum(record) & 0xFF:
raise FirmwareImageError(f"Intel HEX: неверная длина/CRC строки {line_number}")
count = record[0]
address = int.from_bytes(record[1:3], "big")
kind = record[3]
payload = record[4 : 4 + count]
if kind == 0x00:
absolute = upper + address
for index, value in enumerate(payload):
key = absolute + index
if key in memory and memory[key] != value:
raise FirmwareImageError("Intel HEX содержит конфликтующие диапазоны")
memory[key] = value
elif kind == 0x01:
eof = True
break
elif kind == 0x04 and count == 2:
upper = int.from_bytes(payload, "big") << 16
elif kind == 0x02 and count == 2:
upper = int.from_bytes(payload, "big") << 4
elif kind not in (0x03, 0x05):
raise FirmwareImageError(f"Intel HEX: тип записи {kind:#x} не поддержан")
if not eof or not memory:
raise FirmwareImageError("Intel HEX не содержит данных или EOF")
start, end = min(memory), max(memory) + 1
image = bytearray(b"\xFF" * (end - start))
for address, value in memory.items():
image[address - start] = value
return bytes(image), start
def _parse_intel_hex(text: str, maximum_size=2 * 1024 * 1024) -> tuple[bytes, int]:
return contiguous_image(text, maximum_size)
@dataclass