[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>
This commit is contained in:
208
scripts/flipper/assets/obdata.py
Normal file
208
scripts/flipper/assets/obdata.py
Normal file
@@ -0,0 +1,208 @@
|
||||
#!/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()
|
Reference in New Issue
Block a user