feat(tools): fw_info/fw_pack 镜像解析重打包(CRC32验证+字节级往返),112 测试全绿
This commit is contained in:
1 parent
0e2a6a351f
commit
7079053dde
10 files changed
+987
-1
No files matched your search
Whitespace-only changes.
+54
@@ -0,0 +1,54 @@
|
||||
"""DA14585 SUOTA 镜像解析/重打包(tools 交付物)。
|
||||
格式(证据:app/ 样本 + CRC 反推验证):
|
||||
[0:2] magic 'pQ' = 0x7051(LE)
|
||||
[2:4] flags = 0x01AA
|
||||
[4:8] body 长度(= 文件长 - 64)
|
||||
[8:12] CRC32(body)(zlib 多项式,LE)
|
||||
[12:64] 0xFF 填充
|
||||
[64:] 镜像体,起始为 Cortex-M 向量表(SP, Reset, ...),加载基址 0x07FC0000
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import struct
|
||||
import zlib
|
||||
|
||||
MAGIC_BYTES = b"pQ" # 文件头两字节 70 51
|
||||
MAGIC = 0x7051
|
||||
FLAGS_DEFAULT = 0x01AA
|
||||
HEADER_SIZE = 64
|
||||
LOAD_BASE = 0x07FC0000
|
||||
|
||||
|
||||
def parse_image(data: bytes) -> dict:
|
||||
if len(data) < HEADER_SIZE:
|
||||
raise ValueError("文件小于 64 字节头")
|
||||
if data[0:2] != MAGIC_BYTES:
|
||||
raise ValueError(f"magic 错误: {data[0:2].hex()}(期望 {MAGIC_BYTES.hex()}='pQ')")
|
||||
flags, body_size, crc = struct.unpack_from("<HII", data, 2)
|
||||
body = data[HEADER_SIZE:HEADER_SIZE + body_size]
|
||||
sp, reset = struct.unpack_from("<II", body, 0)
|
||||
return {
|
||||
"magic": MAGIC,
|
||||
"flags": flags,
|
||||
"body_size": body_size,
|
||||
"crc_stored": crc,
|
||||
"crc_valid": (zlib.crc32(body) & 0xFFFFFFFF) == crc,
|
||||
"initial_sp": sp,
|
||||
"reset_handler": reset,
|
||||
"load_base": LOAD_BASE,
|
||||
"file_size": len(data),
|
||||
}
|
||||
|
||||
|
||||
def unpack_body(data: bytes) -> bytes:
|
||||
info = parse_image(data)
|
||||
return data[HEADER_SIZE:HEADER_SIZE + info["body_size"]]
|
||||
|
||||
|
||||
def pack_image(body: bytes, flags: int = FLAGS_DEFAULT) -> bytes:
|
||||
header = MAGIC_BYTES + struct.pack("<HII", flags, len(body),
|
||||
zlib.crc32(body) & 0xFFFFFFFF)
|
||||
# 填充:黄金样本 0x20 处为 0x00(含义未知,保留以字节级一致),其余 0xFF
|
||||
pad = bytearray(b"\xFF" * (HEADER_SIZE - len(header)))
|
||||
pad[0x20 - len(header)] = 0x00
|
||||
return header + bytes(pad) + body
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
"""fw_info: 打印 DA14585 镜像头信息(JSON)。"""
|
||||
import json, sys
|
||||
from pathlib import Path
|
||||
from fw import parse_image
|
||||
|
||||
if __name__ == "__main__":
|
||||
data = Path(sys.argv[1]).read_bytes()
|
||||
info = parse_image(data)
|
||||
print(json.dumps({k: (hex(v) if isinstance(v, int) else v) for k, v in info.items()}, indent=2))
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""fw_pack: 体→完整镜像(重算 CRC)。用法: fw_pack.py body.bin out.img [flags_hex]"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from fw import pack_image
|
||||
|
||||
if __name__ == "__main__":
|
||||
body = Path(sys.argv[1]).read_bytes()
|
||||
flags = int(sys.argv[3], 16) if len(sys.argv) > 3 else 0x01AA
|
||||
Path(sys.argv[2]).write_bytes(pack_image(body, flags))
|
||||
print(f"OK: {sys.argv[2]} ({len(body)}B body)")
|
||||
Reference in new issue
Block a user