import os, json, time, subprocess, hashlib, statistics, sys from pathlib import Path root=Path.cwd(); out=root/'docs/evidence/2026-10-04/heartbeat' dll=root/'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' firmware=root/'firmware/build/Release/AMI_Controller.bin' def run(name,args): p=subprocess.run([cli]+args,capture_output=True,timeout=40) (out/(name+'.log')).write_bytes(p.stdout+p.stderr) print(name, p.returncode, p.stdout.decode(errors='replace')[-750:],flush=True) assert p.returncode==0,name return p with can.Bus(interface='pcan',channel='PCAN_USBBUS1',bitrate=500000) as bus: assert bus.reset() if '--capture-only' not in sys.argv: run('flash',['-c','port=SWD','mode=UR','freq=1000','-d',str(firmware),'0x08000000','-v','-rst']) readback=out/'readback.bin' run('readback',['-c','port=SWD','mode=HOTPLUG','freq=1000','-u','0x08000000',str(firmware.stat().st_size),str(readback)]) assert firmware.read_bytes()==readback.read_bytes() while bus.recv(0): pass frames=[];end=time.monotonic()+12 while time.monotonic()=100,'bus_ok':status==0,'format':all(f['dlc']==8 and not f['extended'] and not f['remote'] and bytes.fromhex(f['data'])[:2]==b'\x01\x00' for f in h),'sequence_contiguous':all((b-a)%65536==1 for a,b in zip(seq,seq[1:])),'uptime_100ms':all((b-a)%2**32==100 for a,b in zip(ticks,ticks[1:])),'wire_period_95_to_105ms':bool(intervals) and all(95<=v<=105 for v in intervals)} result={'firmware_bytes':firmware.stat().st_size,'sha256':hashlib.sha256(firmware.read_bytes()).hexdigest(),'flash_readback_identical':True,'bus':'CAN1 500 kbit/s PCAN_USBBUS1','duration_s':12,'heartbeat_count':len(h),'bus_status':status,'interval_ms':{'min':min(intervals),'mean':statistics.mean(intervals),'max':max(intervals)} if intervals else None,'checks':checks,'passed':all(checks.values()),'CAN2_wire_verified':False} (out/'results.json').write_text(json.dumps(result,indent=2));print(json.dumps(result,indent=2))