K1Guitar/tools/log_decode.py

96 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
log_decode.py — 将 K1 LOG.BINW25Q 日志分区镜像)解码为可读时间线
布局:
[0x0000 .. 0x0FFF] header (magic K1LG ...)
[0x1000 .. end] 文本环形区,行以 \\n 结束
用法:
python log_decode.py LOG.BIN -o problem.log
python log_decode.py LOG.BIN --write-off 1234 --wrap 1 -o problem.log
"""
from __future__ import annotations
import argparse
import struct
MAGIC = 0x4B314C47 # 'K1LG'
HDR_SIZE = 0x1000
def unpack_header(blob: bytes) -> dict:
if len(blob) < 36:
return {"valid": False}
magic = struct.unpack_from("<I", blob, 0)[0]
ver = struct.unpack_from("<H", blob, 4)[0]
boot = struct.unpack_from("<I", blob, 8)[0]
write_off = struct.unpack_from("<I", blob, 12)[0]
wrap = struct.unpack_from("<I", blob, 16)[0]
lines = struct.unpack_from("<I", blob, 20)[0]
overflow = struct.unpack_from("<I", blob, 24)[0]
seq = struct.unpack_from("<I", blob, 28)[0]
return {
"valid": magic == MAGIC,
"magic": magic,
"ver": ver,
"boot_count": boot,
"write_off": write_off,
"wrap_count": wrap,
"line_count": lines,
"overflow": overflow,
"seq": seq,
}
def extract_text(data: bytes, write_off: int, wrapped: bool) -> str:
"""Linearize ring: if wrapped, [write_off..end) + [0..write_off); else [0..write_off)."""
if not data:
return ""
if write_off > len(data):
write_off = len(data)
if wrapped and write_off < len(data):
raw = data[write_off:] + data[:write_off]
else:
raw = data[:write_off] if write_off else data
text = raw.decode("utf-8", errors="replace")
text = text.replace("\xff", "")
return text
def decode_file(bin_path: str, out_path: str, write_off=None, wrap_count=None) -> None:
with open(bin_path, "rb") as f:
blob = f.read()
hdr = unpack_header(blob)
data = blob[HDR_SIZE:] if len(blob) > HDR_SIZE else b""
wo = write_off if write_off is not None else hdr.get("write_off", 0)
wrap = wrap_count if wrap_count is not None else hdr.get("wrap_count", 0)
text = extract_text(data, wo, wrap > 0)
lines = [ln for ln in text.splitlines() if ln.strip()]
with open(out_path, "w", encoding="utf-8", newline="\n") as f:
f.write(
f"# K1 log decode magic_ok={hdr.get('valid')} ver={hdr.get('ver')} "
f"boot={hdr.get('boot_count')} write_off={wo} wrap={wrap} "
f"line_count={hdr.get('line_count')} decoded_lines={len(lines)}\n"
)
for ln in lines:
f.write(ln.rstrip("\r") + "\n")
print(f"decoded {len(lines)} lines -> {out_path}")
def main():
ap = argparse.ArgumentParser()
ap.add_argument("bin")
ap.add_argument("-o", "--out", default="problem.log")
ap.add_argument("--write-off", type=int, default=None)
ap.add_argument("--wrap", type=int, default=None)
args = ap.parse_args()
decode_file(args.bin, args.out, args.write_off, args.wrap)
if __name__ == "__main__":
main()