Files
onur 1dbd1b5151 Merge tdk_new and Ti375 Efinity support
Keep the current GPS software and Genesys2/VCU118 flows while integrating Ti375C529 Efinity, flash, programming, and debug support. Add board-specific SPI NOR profiles and persistent GPS flash layouts across all three boards.
2026-08-13 01:28:46 +03:00

127 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""Build Efinity raw-HEX images for Ti375C529 persistent Rocket boot."""
import argparse
import hashlib
import json
import re
from pathlib import Path
HEX_BYTE = re.compile(r"[0-9a-fA-F]{2}")
def parse_int(value):
return int(value, 0)
def read_raw_hex(path):
data = bytearray()
with path.open() as source:
for line_number, line in enumerate(source, 1):
value = line.strip()
if not HEX_BYTE.fullmatch(value):
raise SystemExit(
f"{path}:{line_number}: expected one hexadecimal byte per line"
)
data.append(int(value, 16))
return bytes(data)
def write_raw_hex(path, chunks):
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w") as output:
for chunk in chunks:
for value in chunk:
output.write(f"{value:02X}\n")
def sha256(data):
return hashlib.sha256(data).hexdigest()
def main():
parser = argparse.ArgumentParser(
description="Combine an Efinity configuration HEX and Rocket app image"
)
parser.add_argument("--config-hex", type=Path, required=True)
parser.add_argument("--app-bin", type=Path, required=True)
parser.add_argument("--app-offset", type=parse_int, required=True)
parser.add_argument("--flash-size", type=parse_int, default=0x04000000)
parser.add_argument("--nav-context-offset", type=parse_int, required=True)
parser.add_argument("--ephemeris-offset", type=parse_int, required=True)
parser.add_argument("--combined-hex", type=Path, required=True)
parser.add_argument("--app-hex", type=Path, required=True)
parser.add_argument("--manifest", type=Path, required=True)
args = parser.parse_args()
config = read_raw_hex(args.config_hex)
app = args.app_bin.read_bytes()
app_end = args.app_offset + len(app)
if args.app_offset & 0xFFFF:
raise SystemExit("application offset must be aligned to a 64-KiB sector")
if len(config) > args.app_offset:
raise SystemExit(
f"configuration image (0x{len(config):x} bytes) overlaps application "
f"at 0x{args.app_offset:x}"
)
if app_end > args.flash_size:
raise SystemExit(
f"application ends at 0x{app_end:x}, beyond flash size 0x{args.flash_size:x}"
)
reserved_size = 2 * 0x10000
if args.nav_context_offset + reserved_size > args.ephemeris_offset:
raise SystemExit("navigation context overlaps ephemeris flash region")
if args.ephemeris_offset + reserved_size > args.flash_size:
raise SystemExit("ephemeris flash region exceeds device capacity")
if app_end > args.nav_context_offset:
raise SystemExit(
f"application ends at 0x{app_end:x}, overlapping persistent data at "
f"0x{args.nav_context_offset:x}"
)
padding_size = args.app_offset - len(config)
write_raw_hex(args.app_hex, (app,))
write_raw_hex(args.combined_hex, (config, bytes([0xFF]) * padding_size, app))
manifest = {
"format": "Efinity raw HEX (one byte per line)",
"flash": "Ti375C529 lower SPI NOR (U47)",
"flash_size": f"0x{args.flash_size:08x}",
"configuration": {
"source": str(args.config_hex),
"offset": "0x00000000",
"size": len(config),
"sha256": sha256(config),
},
"application": {
"source": str(args.app_bin),
"offset": f"0x{args.app_offset:08x}",
"size": len(app),
"sha256": sha256(app),
},
"navigation_context": {
"offset": f"0x{args.nav_context_offset:08x}",
"size": reserved_size,
},
"ephemeris_cache": {
"offset": f"0x{args.ephemeris_offset:08x}",
"size": reserved_size,
},
"combined": {
"image": str(args.combined_hex),
"programmed_length": app_end,
},
}
args.manifest.parent.mkdir(parents=True, exist_ok=True)
args.manifest.write_text(json.dumps(manifest, indent=2) + "\n")
print(f"configuration: 0x00000000..0x{len(config) - 1:08x}")
print(f"application: 0x{args.app_offset:08x}..0x{app_end - 1:08x}")
print(f"combined HEX: {args.combined_hex}")
if __name__ == "__main__":
main()