Checkpoint EEPROM, firmware analysis and instrument protocol updates
This commit is contained in:
64
python/set_devices/bin_compare.py
Normal file
64
python/set_devices/bin_compare.py
Normal 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)
|
||||
Reference in New Issue
Block a user