import json, os, re, struct, subprocess, threading, time from pathlib import Path import numpy as np import pyautogui from pywinauto import Desktop ROOT=Path(__file__).resolve().parent PROJECT=ROOT.parents[1] DLL=PROJECT/'tmp/can1-test-20261002/pcan-basic/x64' os.environ['PATH']=str(DLL)+os.pathsep+os.environ['PATH'] handle=os.add_dll_directory(str(DLL)) import can CLI=r'D:\STM32CubeCLT_1.19.0\STM32CubeProgrammer\bin\STM32_Programmer_CLI.exe' NM=r'D:\STM32CubeCLT_1.19.0\GNU-tools-for-STM32\bin\arm-none-eabi-nm.exe' nm=subprocess.check_output([NM,'-n',str(PROJECT/'firmware/build/Release/AMI_Controller.elf')]).decode().replace('\r','') symbols={n:int(a,16) for a,k,n in re.findall(r'^(\w+)\s+(\w)\s+(\w+)$',nm,re.M)} (ROOT/'symbols.json').write_text(json.dumps(symbols,indent=2),encoding='utf-8') names=['sdc_gpio_state','sdc_gpio_changed','sdc_gpio_timestamp_ms','display_state','can_port_last_rx_ms','can_rx_error_count','uart_rx_error_count'] base=min(symbols[n] for n in names)&~3 length=((symbols['display_state']+56-base+3)//4)*4 MAP=[0,5,2,6,7,1,3,4,8,9,10,11,12,13,14] ROIS={0:[(15,82,165,118)],1:[(374,82,525,118),(555,146,706,185)],2:[(555,82,706,118)],3:[(374,146,525,185)],4:[(195,146,345,185)],5:[(15,241,225,272)],6:[(255,241,465,272)],7:[(495,241,705,272)],8:[(15,311,165,341)],9:[(195,311,345,341)],10:[(375,311,525,341)],11:[(555,311,705,341)],12:[(15,375,165,405)],13:[(195,375,345,405)],14:[(375,375,525,405)],15:[(555,375,705,405)]} window=Desktop(backend='win32').window(handle=2034542) window.set_focus() canvas=next(c.rectangle() for c in window.children() if c.rectangle().width()==720 and c.rectangle().height()==408) rows=[] tx=[] errors=[] heartbeat=True stop=threading.Event() def memory(name): result=subprocess.run([CLI,'-c','port=SWD','mode=HOTPLUG','freq=1000','-r32',hex(base),str(length)],capture_output=True,timeout=15) (ROOT/f'{name}_ram.log').write_bytes(result.stdout+result.stderr) assert result.returncode==0 mem={} for address,words in re.findall(r'0x([0-9A-Fa-f]+)\s*:\s*((?:[0-9A-Fa-f]{8}\s*)+)',result.stdout.decode(errors='replace')): addr=int(address,16) for word in words.split(): for i,b in enumerate(struct.pack('75)&(r<180)&(abs(r-g)<8)&(abs(r-b)<8)).sum()),int(((g>180)&(r<80)&(b<80)).sum()),int(((r>180)&(g<80)&(b<80)).sum())] matching.append(counts[state]>20 and (state==1 or counts[1]==0) and (state==2 or counts[2]==0)) rows.append({'name':name,'expected':target,'snapshot':values,'hmi_color_match':all(matching),'screenshot':f'{name}.png','pcan_status':hex(bus.status())}) (ROOT/'mapping-results.json').write_text(json.dumps({'map':MAP,'normal_level':0,'checks':rows,'tx':tx},indent=2),encoding='utf-8') print(json.dumps({'name':name,'mcu_passed':True,'hmi_color_match':all(matching)}),flush=True) try: check('heartbeat_before_sample',None,0,0,[0]*16) check('all_normal',0,0x7fff,1000) for bit in range(15): check(f'PD{bit}_high_fault',1<