CANoe学习之通过Python自动控制CANoe工程中的CAPL Test Module测试节点进行测试
参考文献
1-https://mp.weixin.qq.com/s?__biz=MzIwMDgzOTg3Mg==&mid=2247485368&idx=1&sn=fed547154fadc5fc8239f1029e811021&chksm=96f64017a181c901b51a5f5c0a82f45faba14d8a7353f7f673a3935be3269e4361064fe1de06&mpshare=1&scene=1&srcid=07275TD9hE0AG6Sv6NsS4DLH&sharer_sharetime=1640049404966&sharer_shareid=52df95daab17081c7595d8cc4731d29f&exportkey=A60SVSc9LAgF1x12UlWo8Ic%3D&pass_ticket=MhTtat3pZzYUDZ3Dtg1zUGkVI4A%2FxU8KpQaxAnYtdxsmeTJEU23zcAHzvIGqJgsD&wx_header=0#rd
2-CANoe自带Demo: C:UsersPublicdocumentsVectorCANoeSample Configurations 12.0.189ProgrammingPython
代码内容及解释
# -----------------------------------------------------------------------------
# Example: Test Feature Set via Python
#
# This sample demonstrates how to start the test modules and test
# configurations via COM API using a Python script.
# The script uses the included PythonBasicEmpty.cfg configuration but is
# working also with any other CANoe configuration containing test modules
# and test configurations.
#
# Limitations:
# - only the first test environment is supported. If the configuration
# contains more than one test environment, the other test environments
# are ignored
# - the script does not wait for test reports to be finished. If the test
# reports are enabled, they may run in the background after the test is
# finished
# -----------------------------------------------------------------------------
# Copyright (c) 2017 by Vector Informatik GmbH. All rights reserved.
# -----------------------------------------------------------------------------
import time, os, msvcrt #导入时间、操纵系统、输入输出库
from win32com.client import * #导入win32com.client所有模块,Com组件调用
from win32com.client.connect import * #导入win32com.client.connect所有模块,Com组件调用
from datetime import datetime #导入时间计算模块
# -------------------------------------------------------------------------------
# 主线程挂起,等待CANoe测试执行完毕(注:这里用到了pythoncom库里的API - PumpWaitingMessages),测试界面中弹出CANoe相关运行消息。
# 线程等待处理,若条件为假(cond = False),则程序一直等待挂起,若条件为真(cond = True),则程序跳出
# -------------------------------------------------------------------------------
def DoEvents():
pythoncom.PumpWaitingMessages() #在当前线程下弹出所有等待消息
time.sleep(.1) #延时0.1秒,线程挂起
def DoEventsUntil(cond):
while not cond():
DoEvents()
# -------------------------------------------------------------------------------
# 定义CANoe应用
# -------------------------------------------------------------------------------
class CanoeSync(object):
"""Wrapper class for CANoe Application object"""
#定义类变量
Started = False
Stopped = False
ConfigPath = ""
# -------------------------------------------------------------------------------
# 构造方法,Self代表类的示例
# -------------------------------------------------------------------------------
def __init__(self):
app = DispatchEx('CANoe.Application') #创建CANoe应用对象实例
app.Configuration.Modified = False #CANoe 工程加载或者新建时不能被修改
ver = app.Version #CANoe 版本
print('Loaded CANoe version ',
ver.major, '.',
ver.minor, '.',
ver.Build, '...', sep='')
self.App = app
self.Measurement = app.Measurement # 获取CANoe的测量配置
self.Running = lambda : self.Measurement.Running # 获取CANoe的运行状态
self.WaitForStart = lambda: DoEventsUntil(lambda: CanoeSync.Started) # 等待CANoe启动
self.WaitForStop = lambda: DoEventsUntil(lambda: CanoeSync.Stopped) # 等待CANoe停止
WithEvents(self.App.Measurement, CanoeMeasurementEvents) # 等待Measurement事件
# -------------------------------------------------------------------------------
# 加载CANoe工程,cfgPath-相对路径
# -------------------------------------------------------------------------------
def Load(self, cfgPath):
# current dir must point to the script file
cfg = os.path.join(os.curdir, cfgPath) #结合当前工程根目录os.curdir和给定子目录cfgPath
cfg = os.path.abspath(cfg) #获取CANoe工程绝对路径
print('Opening: ', cfg)
self.ConfigPath = os.path.dirname(cfg) #返回CANoe工程的路径名称
self.Configuration = self.App.Configuration #定义CANoe仿真配置
self.App.Open(cfg) #打开CANoe工程
# -------------------------------------------------------------------------------
# 加载Test Module测试配置:对象搜索路径:App – Configuration –TestSetup – TestEnvironments – Add()
# -------------------------------------------------------------------------------
def LoadTestSetup(self, testsetup):
self.TestSetup = self.App.Configuration.TestSetup #返回测试配置
path = os.path.join(self.ConfigPath, testsetup) #路径整合,返回testsetup路径
print("testenv path = ",path)
time.sleep(3)
testenv = self.TestSetup.TestEnvironments.Add(path) #把.tse测量环境Test Environment加入testsetup(注意:工程打开的时候该tse文件不在Test Modules里面)
testenv = CastTo(testenv, "ITestEnvironment2") #ITestEnvironment2属于Vector自定义强制类型
print("testenv Name = ",testenv.Name)
print("Sub Folders Count= ",testenv.Folders.Count)
# TestModules property to access the test modules
self.TestModules = [] #创建TestModule列表
self.TraverseTestItem(testenv, lambda tm: self.TestModules.append(CanoeTestModule(tm))) #Test Module添加到tse中,List末尾添加新对象
# -------------------------------------------------------------------------------
# 加载Test Unit(基于vTESTstudio生成),对象搜索路径:App – Configuration –TestConfigurations - Add()
# -------------------------------------------------------------------------------
def LoadTestConfiguration(self, testcfgname, testunits):
""" Adds a test configuration and initialize it with a list of existing test units """
tc = self.App.Configuration.TestConfigurations.Add() #添加Test Configurations到canoe工程
tc.Name = testcfgname #Test Configurations名称
print("testcfgname= ",testcfgname)
tus = CastTo(tc.TestUnits, "ITestUnits2") #ITestUnits2属于Vector自定义强制类型
for tu in testunits: #遍历所有Test Units,加入到Test Configurations
tus.Add(tu)
print("Test Unit Name= ",tu)
# TestConfigs property to access the test configuration
self.TestConfigs = [CanoeTestConfiguration(tc)]
# -------------------------------------------------------------------------------
# 启动CANoe工程,调用Measurement对象的Start方法
# -------------------------------------------------------------------------------
def Start(self):
if not self.Running(): #若CANoe未启动
self.Measurement.Start() #则启动CANoe
self.WaitForStart() #等待CANoe启动,弹出相关信息
def Stop(self):
if self.Running(): #若CANoe启动
self.Measurement.Stop() #则停止CANoe
self.WaitForStop() #等待CANoe停止,弹出相关信息
# -------------------------------------------------------------------------------
# 启动测试节点,调用TestModule对象的Start方法
# -------------------------------------------------------------------------------
def RunTestModules(self):
""" starts all test modules and waits for all of them to finish"""
# start all test modules
for tm in self.TestModules:
tm.Start()
# wait for test modules to stop
while not all([not tm.Enabled or tm.IsDone() for tm in app.TestModules]): #若当前CANoe工程中的所有TestModules在运行中或未激活,则程序等待
DoEvents()
# -------------------------------------------------------------------------------
# 启动测试单元,调用TestConfiguration对象的Start方法
# -------------------------------------------------------------------------------
def RunTestConfigs(self):
""" starts all test configurations and waits for all of them to finish"""
# start all test configurations
for tc in self.TestConfigs:
tc.Start()
# wait for test modules to stop
while not all([not tc.Enabled or tc.IsDone() for tc in app.TestConfigs]):#若当前CANoe工程中的所有TestModules在运行中或未激活,则程序等待
DoEvents()
# -------------------------------------------------------------------------------
# 循环遍历tse里面的Test Module和子文件
# -------------------------------------------------------------------------------
def TraverseTestItem(self, parent, testf):
for test in parent.TestModules: #遍历tse里面的Test Module
testf(test) #添加到Test Module集合中
for folder in parent.Folders: #遍历tse里面的子文件
found = self.TraverseTestItem(folder, testf) #添加到Test Module集合中
class CanoeMeasurementEvents(object):
"""Handler for CANoe measurement events"""
def OnStart(self):
CanoeSync.Started = True
CanoeSync.Stopped = False
print("< measurement started >")
def OnStop(self) :
CanoeSync.Started = False
CanoeSync.Stopped = True
print("< measurement stopped >")
class CanoeTestModule:
"""Wrapper class for CANoe TestModule object"""
def __init__(self, tm):
self.tm = tm
self.Events = DispatchWithEvents(tm, CanoeTestEvents)
self.Name = tm.Name
self.IsDone = lambda: self.Events.stopped
self.Enabled = tm.Enabled
def Start(self):
if self.tm.Enabled:
self.tm.Start()
self.Events.WaitForStart()
class CanoeTestConfiguration:
"""Wrapper class for a CANoe Test Configuration object"""
def __init__(self, tc):
self.tc = tc
self.Name = tc.Name
self.Events = DispatchWithEvents(tc, CanoeTestEvents)
self.IsDone = lambda: self.Events.stopped
self.Enabled = tc.Enabled
def Start(self):
if self.tc.Enabled:
self.tc.Start()
self.Events.WaitForStart()
class CanoeTestEvents:
"""Utility class to handle the test events"""
def __init__(self):
self.started = False
self.stopped = False
self.WaitForStart = lambda: DoEventsUntil(lambda: self.started)
self.WaitForStop = lambda: DoEventsUntil(lambda: self.stopped)
def OnStart(self):
self.started = True
self.stopped = False
print("<", self.Name, " started >")
def OnStop(self, reason):
self.started = False
self.stopped = True
print("<", self.Name, " stopped >")
# -----------------------------------------------------------------------------
# main
# -----------------------------------------------------------------------------
#创建CanoeSync实例
print("Create CANoe Application")
LoadStartTime = datetime.now()
print("LoadStartTime= ",str(LoadStartTime))
app = CanoeSync()
#调用Application对象的Open方法,打开相关的CANoe工程
# loads the sample configuration
app.Load('Evergrande_CANFD_SwTest.cfg')
LoadFinishTime = datetime.now()
print("LoadFinishTime= ",str(LoadFinishTime))
print("LoadTime= ",(LoadFinishTime-LoadStartTime).seconds,"s")
#加载Test Module
# add test modules to the configuration
print("LoadTestSetup")
app.LoadTestSetup('TestTestEnvironmentdemo.tse')
#加载Test Unit(基于vTESTstudio生成)
# add a test configuration and a list of test units
#print("LoadTestConfiguration")
#app.LoadTestConfiguration('TestConfiguration', ['TestConfigurationEasyTestEasyTest.vtuexe'])
# 启动CANoe工程
# start the measurement
print("Start Application")
app.Start()
#启动测试节点
# runs the test modules
print("Start TestModule")
app.RunTestModules()
#启动测试单元
# runs the test configurations
#app.RunTestConfigs()
#主线程挂起
# wait for a keypress to end the program
#print("Press any key to exit ...")
#while not msvcrt.kbhit():
# DoEvents()
# 停止CANoe工程
# stops the measurement
print("Stop Application")
app.Stop()
操作实例
1-配置CANoe 工程名及该py代码与工程的相对路径
2-配置Test Module及该py代码与加载Test Module的相对路径
3-运行py代码
结果:
调试过程中遇到的问题及解决方法
Otherwise the issue of “pywintypes.com_error: (-2147352567, ‘发生意外。’, (0, None, None, None, 0, -2147467259), None)” will happen!!!
发生情况1:拟打开的CANoe工程正在运行
解决办法:确保拟打开的CANoe工程处于未运行状态
发生情况2:拟加载的Test Module(XX.tse)已经被加载到工程中了
解决办法:确保拟加载的Test Module(XX.tse)未被加载到工程中



