flipperzero-firmware/scripts/flipper/assets/obdata.py

209 lines
6.3 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
import logging
import struct
from enum import Enum
from dataclasses import dataclass
from typing import Tuple
from array import array
class OBException(ValueError):
pass
@dataclass
class OBParams:
word_idx: int
bits: Tuple[int, int]
name: str
_OBS_descr = (
OBParams(0, (0, 8), "RDP"),
OBParams(0, (8, 9), "ESE"),
OBParams(0, (9, 12), "BOR_LEV"),
OBParams(0, (12, 13), "nRST_STOP"),
OBParams(0, (13, 14), "nRST_STDBY"),
OBParams(0, (14, 15), "nRSTSHDW"),
OBParams(0, (15, 16), "UNUSED1"),
OBParams(0, (16, 17), "IWDGSW"),
OBParams(0, (17, 18), "IWDGSTOP"),
OBParams(0, (18, 19), "IWGDSTDBY"), # ST's typo: IWDGSTDBY
OBParams(0, (18, 19), "IWDGSTDBY"), # ST's typo: IWDGSTDBY
OBParams(0, (19, 20), "WWDGSW"),
OBParams(0, (20, 23), "UNUSED2"),
OBParams(0, (23, 24), "nBOOT1"),
OBParams(0, (24, 25), "SRAM2PE"),
OBParams(0, (25, 26), "SRAM2RST"),
OBParams(0, (26, 27), "nSWBOOT0"),
OBParams(0, (27, 28), "nBOOT0"),
OBParams(0, (28, 29), "UNUSED3"),
OBParams(0, (29, 32), "AGC_TRIM"),
OBParams(1, (0, 9), "PCROP1A_STRT"),
OBParams(1, (9, 32), "UNUSED"),
OBParams(2, (0, 9), "PCROP1A_END"),
OBParams(2, (9, 31), "UNUSED"),
OBParams(2, (31, 32), "PCROP_RDP"),
OBParams(3, (0, 8), "WRP1A_STRT"),
OBParams(3, (8, 16), "UNUSED1"),
OBParams(3, (16, 24), "WRP1A_END"),
OBParams(3, (24, 32), "UNUSED2"),
OBParams(4, (0, 8), "WRP1B_STRT"),
OBParams(4, (8, 16), "UNUSED1"),
OBParams(4, (16, 24), "WRP1B_END"),
OBParams(4, (24, 32), "UNUSED2"),
OBParams(5, (0, 9), "PCROP1B_STRT"),
OBParams(5, (9, 32), "UNUSED"),
OBParams(6, (0, 9), "PCROP1B_END"),
OBParams(6, (9, 32), "UNUSED"),
OBParams(13, (0, 14), "IPCCDBA"),
OBParams(13, (14, 32), "UNUSED"),
OBParams(14, (0, 8), "SFSA"),
OBParams(14, (8, 9), "FSD"),
OBParams(14, (9, 12), "UNUSED1"),
OBParams(14, (12, 13), "DDS"),
OBParams(14, (13, 32), "UNUSED2"),
OBParams(15, (0, 18), "SBRV"),
OBParams(15, (18, 23), "SBRSA"),
OBParams(15, (23, 24), "BRSD"),
OBParams(15, (24, 25), "UNUSED1"),
OBParams(15, (25, 30), "SNBRSA"),
OBParams(15, (30, 31), "NBRSD"),
OBParams(15, (31, 32), "C2OPT"),
)
_OBS = dict((param.name, param) for param in _OBS_descr)
@dataclass
class EncodedOBValue:
value: int
mask: int
params: OBParams
class OptionByte:
class OBMode(Enum):
IGNORE = 0
READ = 1
READ_WRITE = 2
@classmethod
def from_str(cls, value):
if value == "r":
return cls.READ
elif value == "rw":
return cls.READ_WRITE
else:
raise OBException(f"Unknown OB check mode '{value}'")
def __init__(self, obstr):
parts = obstr.split(":")
if len(parts) != 3:
raise OBException(f"Invalid OB value definition {obstr}")
self.name = parts[0]
self.value = int(parts[1], 16)
self.mode = OptionByte.OBMode.from_str(parts[2].strip())
self.descr = _OBS.get(self.name, None)
if self.descr is None:
raise OBException(f"Missing OB descriptor for {self.name}")
def encode(self):
startbit, endbit = self.descr.bits
value_mask = 2 ** (endbit - startbit) - 1
value_corrected = self.value & value_mask
value_shifted = value_corrected << startbit
value_mask_shifted = value_mask << startbit
return EncodedOBValue(value_shifted, value_mask_shifted, self)
def __repr__(self):
return f"<OB {self.name}, 0x{self.value:x}, {self.mode} at 0x{id(self):X}>"
@dataclass
class ObReferenceValues:
reference: bytes
compare_mask: bytes
write_mask: bytes
class ObReferenceValuesGenerator:
def __init__(self):
self.compare_mask = array("I", [0] * 16)
self.write_mask = array("I", [0] * 16)
self.ref_values = array("I", [0] * 16)
def __repr__(self):
return (
f"<OBRefs REFS=[{' '.join(hex(v) for v in self.ref_values)}] "
f"CMPMASK=[{' '.join(hex(v) for v in self.compare_mask)}] "
f"WRMASK=[{' '.join(hex(v) for v in self.write_mask)}] "
)
def export_values(self):
export_cmpmask = array("I")
for value in self.compare_mask:
export_cmpmask.append(value)
export_cmpmask.append(value)
export_wrmask = array("I")
for value in self.write_mask:
export_wrmask.append(value)
export_wrmask.append(value)
export_refvals = array("I")
for cmpmask, refval in zip(self.compare_mask, self.ref_values):
export_refvals.append(refval)
export_refvals.append((refval ^ 0xFFFFFFFF) & cmpmask)
return export_refvals, export_cmpmask, export_wrmask
def export(self):
return ObReferenceValues(*map(lambda a: a.tobytes(), self.export_values()))
def apply(self, ob):
ob_params = ob.descr
encoded_ob = ob.encode()
self.compare_mask[ob_params.word_idx] |= encoded_ob.mask
self.ref_values[ob_params.word_idx] |= encoded_ob.value
if ob.mode == OptionByte.OBMode.READ_WRITE:
self.write_mask[ob_params.word_idx] |= encoded_ob.mask
class OptionBytesData:
def __init__(self, obfname):
self.obs = list()
with open(obfname, "rt") as obfin:
self.obs = list(
OptionByte(line) for line in obfin if not line.startswith("#")
)
def gen_values(self):
obref = ObReferenceValuesGenerator()
converted_refs = list(obref.apply(ob) for ob in self.obs)
return obref
def main():
with open("../../../../logs/obs.bin", "rb") as obsbin:
ob_sample = obsbin.read(128)
ob_sample_arr = array("I", ob_sample)
print(ob_sample_arr)
obd = OptionBytesData("../../ob.data")
print(obd.obs)
# print(obd.gen_values().export())
ref, mask, wrmask = obd.gen_values().export_values()
for idx in range(len(ob_sample_arr)):
real_masked = ob_sample_arr[idx] & mask[idx]
print(
f"#{idx}: ref {ref[idx]:08x} real {real_masked:08x} ({ob_sample_arr[idx]:08x} & {mask[idx]:08x}) match {ref[idx]==real_masked}"
)
# print(ob_sample)
if __name__ == "__main__":
main()