# -*- coding: utf-8 -*- """独立校验交付的 .face(只看交付物 + 固件镜像,不看中间产物)。 rome: replace -> dist/S4Chg.face pay 应等于**改后镜像**的字节,fp 应等于**原厂**前 64 B restore -> dist/S4ChgRestore.face pay 应等于**原厂**字节, fp 应等于**改后镜像**前 64 B ① 从 .face 里抠出 Lua 表(pay / rb),按表里的偏移取字节 ② 每条 pay 长度必须 == 原厂槽位长度(等长覆盖的底线),且能按 LVGL RLE 解出 464x464 ③ rb 每条必须是 64 B 指纹,且等于另一侧字节的前 64 B(版本校验数据正确) ④ 目标镜像的 inode 表 / superblock / 分区长度与原厂逐位一致 """ import os, re, sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from paths import PROJ, INPUTS, WORK from romfs import Romfs import lvgl_bin as L ROLE = (sys.argv[1] if len(sys.argv) > 1 else 'replace').lower() NAME = 'S4Chg' if ROLE == 'replace' else 'S4ChgRestore' FACE = os.path.join(PROJ, 'dist', NAME + '.face') STOCK = os.path.join(INPUTS, 'target', 'vela_system.bin') PATCHED = os.path.join(WORK, 'charge', 'vela_system_charge.bin') DIRP = 'charging/' FP_LEN = 64 ok = fail = 0 def ck(cond, msg): global ok, fail if cond: ok += 1 else: fail += 1 print(' !! ' + msg) face = open(FACE, 'rb').read() src = face.decode('latin1') m = re.search(r'pay = \{(.*?)\n \},', src, re.S) m2 = re.search(r'rb = \{(.*?)\n \},', src, re.S) ck(m is not None and m2 is not None, '在 .face 里找不到 pay / rb 表') pay = [tuple(int(x) for x in r) for r in re.findall(r'\{(\d+),(\d+),(\d+)\}', m.group(1))] rb = [tuple(int(x) for x in r) for r in re.findall(r'\{(\d+),(\d+),(\d+)\}', m2.group(1))] print('%s:pay %d 条,rb %d 条' % (NAME, len(pay), len(rb))) stock_b = open(STOCK, 'rb').read() patch_b = open(PATCHED, 'rb').read() c = re.search(r"local ROLE = '(\w+)'", src) ck(c is not None and c.group(1) == ROLE, 'Lua 里的 ROLE 不是 %s' % ROLE) EXPECT_PAY = patch_b if ROLE == 'replace' else stock_b EXPECT_FP = stock_b if ROLE == 'replace' else patch_b stock = Romfs(STOCK) slots = {} for p, i in stock.entries(): if i.type == 1 or not p.startswith(DIRP) or not p.endswith('.bin') or i.size == 0: continue slots[i.data_off] = (p, i.size) canary = [r for r in pay if r[1] == 0 and r[2] == 32] ck(len(canary) <= 1, 'canary 记录不止一条') if canary: ck(face[canary[0][0]:canary[0][0] + 32] == stock_b[:32], 'canary 不对') data = [r for r in pay if not (r[1] == 0 and r[2] == 32)] bad_len = bad_dec = bad_bytes = 0 for o, t, ln in data: blob = face[o:o + ln] if t not in slots or slots[t][1] != ln: bad_len += 1; continue if EXPECT_PAY[t:t + ln] != blob: bad_bytes += 1 h = L.parse_header(blob) if h is None or not (h['flags'] & L.FLAG_COMPRESSED) or h['w'] != 464 or h['h'] != 464: bad_dec += 1; continue # ★ 设备端解码器要求流解出**正好 usize 字节**(1024 + w*h + 1),少一字节就整帧不画 import struct as _s _m, _cs, _us = _s.unpack('