#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import hashlib, json, pathlib, re, struct, subprocess, sys
elf, binary, map_file = map(pathlib.Path, sys.argv[1:4])
map_text = map_file.read_text(errors='replace')
dis = subprocess.check_output(['arm-none-eabi-objdump','-d',str(elf)],text=True)
sections = subprocess.check_output(['arm-none-eabi-objdump','-h',str(elf)],text=True)
data = binary.read_bytes()
sp, reset = struct.unpack_from('<II',data)
required = ['drill_safe_boot','drill_foc_probe_math','mfoc_init','mfoc_step','main']
missing = [s for s in required if not re.search(r'\b'+re.escape(s)+r'\b',map_text)]
if missing: raise SystemExit('missing linked symbols: '+','.join(missing))
if sp != 0x20005800: raise SystemExit(f'bad initial SP: {sp:#x}')
if not (reset & 1) or not (0x08000000 <= (reset & ~1) < 0x08020000): raise SystemExit('invalid reset vector')
if '.isr_vector' not in sections or '.text' not in sections: raise SystemExit('missing vector/text section')
for s in ('drill_safe_boot','drill_foc_probe_math','mfoc_init','mfoc_step'):
    if s not in dis: raise SystemExit('missing disassembly symbol '+s)
size_line=subprocess.check_output(['arm-none-eabi-size',str(elf)],text=True).splitlines()[-1].split()
result={'status':'LINKED_DIAGNOSTIC_IMAGE_STATIC_CHECK_PASS','target':'STM32G431CBT6 Cortex-M4','flash_bytes':len(data),'flash_capacity_bytes':131072,'ram_bytes':int(size_line[1])+int(size_line[2]),'ram_capacity_bytes':22528,'initial_sp':hex(sp),'reset_vector':hex(reset),'linked_symbols':required,'foc_math_linked':True,'foc_probe_invoked_from_main':True,'diagnostic_numeric_config_is_product_calibration':False,'tim1_or_motor_outputs_enabled':False,'motor_power_enabled':False,'charge_enabled':False,'physical_runtime_test':False,'physical_gpio_levels_verified':False,'sha256_bin':hashlib.sha256(data).hexdigest(),'sha256_elf':hashlib.sha256(elf.read_bytes()).hexdigest()}
print(json.dumps(result,ensure_ascii=False,indent=2))
