import json,os,threading,time from pathlib import Path import numpy as np import pyautogui as pg import win32gui,win32con from pywinauto import Desktop from pywinauto.controls.win32_controls import ComboBoxWrapper R=Path(__file__).resolve().parent;P=R.parents[1] DLL=P/'tmp/can1-test-20261002/pcan-basic/x64' os.environ['PATH']=str(DLL)+os.pathsep+os.environ['PATH'];dh=os.add_dll_directory(str(DLL)) import can W=4262948 w=Desktop(backend='win32').window(handle=W);u=Desktop(backend='uia').window(handle=W);w.set_focus() if not u.child_window(title='停止',control_type='Hyperlink').exists(): w.child_window(title='用户MCU输入').click();time.sleep(.3) for c in w.descendants(): if 'COMBOBOX' in c.class_name() and c.is_visible(): combo=ComboBoxWrapper(c.element_info);items=combo.item_texts() if '9600' in items:combo.select('9600') if 'COM4' in items:combo.select('COM4') u.child_window(title='开始',control_type='Hyperlink').invoke();time.sleep(6) canvas_control=next(c for c in w.children() if c.rectangle().width()==720 and c.rectangle().height()==408) canvas=canvas_control.rectangle() def touch(x,y): point=(y<<16)|x win32gui.SendMessage(canvas_control.handle,win32con.WM_LBUTTONDOWN,win32con.MK_LBUTTON,point) time.sleep(.15) win32gui.SendMessage(canvas_control.handle,win32con.WM_LBUTTONUP,0,point) ROIS=[(185,275,445,313),(185,328,445,364),(472,349,705,394)] checks=[];tx=[];errors=[];stop=threading.Event();payload=None def check(name,colors,delay=1.2): time.sleep(delay) shot=pg.screenshot(region=(canvas.left,canvas.top,720,408));shot.save(str(R/f'can-{name}.png')) pixels=np.asarray(shot);counts=[] for (x1,y1,x2,y2),color in zip(ROIS,colors): a=pixels[y1:y2,x1:x2,:3].astype(np.int16);r,g,b=a[:,:,0],a[:,:,1],a[:,:,2] c=[int(((r>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())] assert c[color]>20 and (color==1 or c[1]==0) and (color==2 or c[2]==0),(name,colors,c) counts.append(c) assert bus.status()==0 and not errors,(name,errors) checks.append({'name':name,'colors':colors,'pixel_counts':counts,'passed':True,'screenshot':f'can-{name}.png'}) print(name,'passed',flush=True) with can.Bus(interface='pcan',channel='PCAN_USBBUS1',bitrate=500000) as bus: assert bus.reset() def sender(): try: while not stop.is_set(): msg=payload if msg: bus.send(msg,timeout=.2);tx.append({'id':hex(msg.arbitration_id),'data':msg.data.hex(' ')}) stop.wait(.1) except Exception as exc:errors.append(repr(exc)) t=threading.Thread(target=sender);t.start() def feedback(task,locked,normal,flags=7): global payload payload=can.Message(arbitration_id=0x183,is_extended_id=False,data=bytes([task,locked,normal,flags,0,0,0,1])) try: check('initial-unknown',[0,0,0]) for task in range(7): feedback(task,1,1);check(f'task-{task}',[2 if task==0 else 1,1,1]) feedback(2,0,0);check('unlocked-ebs-fault',[1,2,2]) feedback(2,1,1,5);check('lock-invalid',[1,0,1]) feedback(2,1,1,3);check('ebs-invalid',[1,1,0]) feedback(2,1,1,6);check('task-invalid',[0,1,1]) feedback(2,1,1);check('before-EBS-request',[1,1,1]) while bus.recv(0):pass # Actual mouse press/release invokes the real task and confirm events. touch(75,292);time.sleep(.3) pg.screenshot(region=(canvas.left,canvas.top,720,408)).save(str(R/'can-confirm-EBS-request.png')) print('CONFIRM entered; locate confirm control from screenshot',flush=True) # CONFIRM buttons are placed in the lower half of the page. touch(180,323) request=None;end=time.monotonic()+1 while time.monotonic() STM32 -> USART2 COM4 -> official HMI simulator, not physical panel','checks':checks,'tx':tx,'errors':errors,'counters':counters,'request':request,'passed':True},ensure_ascii=False,indent=2),encoding='utf-8') print(len(checks),'physical CAN/UART/display checks passed',counters,flush=True)