flipperzero-firmware/scripts/flipper/assets/obdata.py
hedger 7ce305fca3
[FL-2269] Core2 OTA (#1144)
* C2OTA: wip
* Update Cube to 1.13.3
* Fixed prio
* Functional Core2 updater
* Removed hardware CRC usage; code cleanup & linter fixes
* Moved hardcoded stack params to copro.mk
* Fixing CI bundling of core2 fw
* Removed last traces of hardcoded radio stack
* OB processing draft
* Python scripts cleanup
* Support for comments in ob data
* Sacrificed SD card icon in favor of faster update. Waiting for Storage fix
* Additional handling for OB mismatched values
* Description for new furi_hal apis; spelling fixes
* Rework of OB write, WIP
* Properly restarting OB verification loop
* Split update_task_workers.c
* Checking OBs after enabling post-update mode
* Moved OB verification before flashing
* Removed ob.data for custom stacks
* Fixed progress calculation for OB
* Removed unnecessary OB mask cast

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2022-04-27 18:53:48 +03:00

209 lines
6.3 KiB
Python

#!/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()