Checkpoint EEPROM, firmware analysis and instrument protocol updates

This commit is contained in:
2026-10-08 21:51:44 +03:00
parent b0c0c05cfa
commit fe9b5a246e
24 changed files with 848 additions and 62 deletions

View File

@@ -0,0 +1,64 @@
"""Renderer-independent comparison of arbitrary binary files."""
from __future__ import annotations
from dataclasses import dataclass
import hashlib
def compare_sha256(image: bytes, readback: bytes):
"""Compare a complete physical readback against an immutable BIN snapshot."""
if not image or len(image) != len(readback):
raise ValueError('Для SHA-256 нужен полный прочитанный диапазон размером с BIN.')
expected = hashlib.sha256(image).hexdigest()
actual = hashlib.sha256(readback).hexdigest()
return expected == actual, expected, actual
@dataclass(frozen=True)
class Comparison:
left: bytes
right: bytes
offsets: tuple[int, ...]
changed_bits: int
@property
def changed_bytes(self) -> int:
return len(self.offsets)
@property
def size(self) -> int:
return max(len(self.left), len(self.right))
def compare(left: bytes, right: bytes) -> Comparison:
"""Count bit differences in overlap; unmatched bytes count as changed bytes."""
common = min(len(left), len(right))
offsets = tuple(i for i in range(common) if left[i] != right[i])
bits = sum(bin(left[i] ^ right[i]).count('1') for i in offsets)
return Comparison(left, right, offsets + tuple(range(common, max(len(left), len(right)))), bits)
@dataclass(frozen=True)
class MultiComparison:
images: tuple[bytes, ...]
offsets: tuple[int, ...]
pairs: tuple
@property
def size(self): return max(map(len, self.images))
@property
def changed_bytes(self): return len(self.offsets)
def compare_many(images):
"""Highlight offsets where any pair differs, including missing bytes."""
images = tuple(images)
if len(images) not in (1, 2, 3):
raise ValueError('Выберите от 1 до 3 BIN-файлов.')
if len(images) == 2:
return compare(*images)
pairs = tuple((a, b, compare(images[a], images[b]))
for a in range(len(images)) for b in range(a + 1, len(images)))
offsets = tuple(sorted({offset for _, _, result in pairs for offset in result.offsets}))
return MultiComparison(images, offsets, pairs)