目录
工程背景
工程目的
报文发送情况
工程实现
工程步骤概述
1 测试方法分析
1-1 检测报文周期
1-2 检测报文长度DLC
1-3?功能测试
1-4?检测未定义报文
2 添加Test Module
2-1创建测试环境
?2-2 插入CAPL Test Module
3?CAPL编写测试用例
?3-1?测试模块入口函数MainTest
3-2 CAPL测试用例——检测报文周期
3-3 CAPL测试用例——检测报文长度DLC
3-4 CAPL测试用例——检测未定义报文undefined msg
3-5 CAPL测试用例——功能测试
4 工程运行测试
?5 故障注入
5-1 系统变量控制报文发送
5-2? IG节点发送自定义报文
?6 测试报告
工程背景
本工程主要目的是: 基于第3个仿真工程, 熟悉CANoe的报文测试功能。
工程目的
本工程将围绕CAN总线中的报文,在Test Module中实现测试功能。主要包括:
- 检测周期性报文的周期
- 检测报文的长度
- 检查网络中是否有未定义的报文
- 简单的功能测试:通过修改相关系统变量的数值,模拟真实测试环境的操作,最后检验总线上的信号数值的改变。
- 生成测试报告
报文发送情况
第3个仿真工程报文发送与接收情况如下:
报文的相关属性整理如下表:
报文中的信号属性如下表:
?
工程实现
工程步骤概述
本章实例基于第12章的仿真工程,为了便于区别,需要将原工程的文件夹复制并 名为Vehicle_System_Simulation_Test, 工程名称也另存为Vehicle_System_CAN_Test.cfg, 在该工程文件夹下创建一个名为Testmodul的文件夹,用于存放相关的测试代码。
接下来,将在此基础上添加测试模块及故障注入面板等。
工程包括以下几个关键步骤:
- 测试方法分析
- 添加Test Module,
- CAPL测试用例编写,
- 运行工程,运行测试用例。
- 故障注入,运行测试用例。
- 查看测试报告。
1 测试方法分析
本工程的目的是分别测试不同报文的发送周期、报文长度DLC;功能测试(检测信号值是否在期望的数值范围内 );未定义报文。
1-1 检测报文周期
检测报文周期的方法是划定某一段特定的时间,选取该时间段中第一条待测报文作为起始时间戳,观察此待测报文后续重复的时间间隔。
TSL函数——检测函数
检测函数1:
ChkStart_MsgAbsCycleTimeViolation ( Message aObservedMessage,duration aMinCycleTime, duration aMaxCycleTime)
函数功能:观察总线周期性报文aObservedMessage的每次出现,如果该报文的间隔不符合规范要求,则会触发一个代表异常出现的特殊事件。
返回值:>0,返回一个IDaCheckedId,即观察待测报文的事件;=0报错。
TSL函数——状态报告函数
状态报告函数1:long ChKQuery_NumEvents(dword aCheckId)?
函数功能:查询该时间段内异常出现的特殊事件的个数
状态报告函数2:double ChkQuery_StatProbeIntervalAvg(dword aCheckId)
返回该时间段内,该报文的平均周期间隔时间
状态报告函数3: double ChkQuery_StatProbeIntervalMin(dword aCheckId)
返回该时间段内,该报文的最小周期间隔时间
状态报告函数4: double ChkQuery_StatProbeIntervalMax(dword aCheckId)
返回该时间段内,该报文的最大周期间隔时间
TSL函数——检测控制函数
检测控制函数1: long ChkControl_Destroy(Check aCheckId)
用于测试结束时,销毁该事件对象aCheckId,释放资源。返回0操作成功,<0报错。
1-2 检测报文长度DLC
函数:
-
状态报告函数 ChkQuery_NumEvents -
检测控制函数 ChkControl_Destroy -
检测函数:dword ChkStart_InconsistentDLC(Message aMessage,char [] aCallback)
-
检测发送到总线上指定报文长度是否与DBC数据库中的定义一致 -
aMessage待测报文;char [] aCallback回调函数名,可选参数 -
返回值:>0:返回一个事件对象aCheckId;=0报错
1-3?功能测试
功能测试用过CAPL程序逻辑来设置某信号的数值,然后使用ChkStart_MsgSignalValueInvalid函数来检测信号值是否在期望的数值范围内。
dword ChkStart_MsgSignalValueInvalid (Signal aObservedSignal,double aMinValue, double aMaxValue, Callback aCallback)
函数参数:待测信号,必须是定在DBC中的信号,最小信号值,最大信号值,回调CAPL函数名,可选。
返回值:返回一个事件对象aCheckId,即检测未定义报文的事件
1-4?检测未定义报文
检测函数:dword ChkStart_UndefinedMessageReceived (char [] CaplCallback)
作用:观察当前总线上是否有未定义的报文
返回值:>0:返回一个事件对象aCheckId,即待观测报文的事件;=0报错。
状态报告函数:long ChkQuery_EventMessageId (dword aCheckId)
作用:返回触发该事件的报文的MessageId
返回值:>0返回触发该事件的报文ID;<0报错。
2 添加Test Module
2-1创建测试环境
创建测试环境,命名为NetworkTester。
?2-2 插入CAPL Test Module
插入CAPL Test Module,并配置此模块Configuration对话框
?配置Module的Name为:Network Tester,在TestModule文件夹下创建CAPL文件NetworkTester.can
3?CAPL编写测试用例
?选中TestModule,右键选中Edit,可以编辑NetworkTester.can 。
?3-1?测试模块入口函数MainTest
CAPL测试模块中can文件要求:-必须包含MainTest函数,所有的测试用例均从此接口进入
- 添加TestModule描述:Title,DisCription。
- 仿真工程初始化,确保报文的正常发送;本工程中为车门开锁,设置CarDriver,并且钥匙位置设置为2.
- 将测试用例分组testGroupBegin,测试用例函数名调用,testGroupEnd。
void MainTest()
{
testModuleTitle("NetworkTester");
testModuleDescription("Message Specification Test and Function Test Demo.");
testGroupBegin("Check msg cycle time","Check the differ mesage cycle time");
Init_Test_Condition();
CheckMsgEngineData();
CheckMsgVehicleData();
CheckMsgGear_Info();
CheckMsgIgnition_Info();
CheckMsgLight_Info();
testGroupEnd();
testGroupBegin("Check msg DLC","Check DLC of a message");
CheckDLCLock_Info();
testGroupEnd();
testGroupBegin("Check undefined msg","Check the undefined message");
CheckUndefinedMessage();
testGroupEnd();
testGroupBegin("Fucntion Test","Check the engine speed after setup");
CheckEngine_Speed();
testGroupEnd();
}
//初始化仿真工程状态,确保各个模块处于Online
Init_Test_Condition()
{
@Vehicle_Key::Unlock_Car = 1;
@Vehicle_Key::Car_Driver = 0;
@Vehicle_Key::Key_State = 2;
testWaitForTimeout(500);
}
3-2 CAPL测试用例——检测报文周期
分别测试EngineData(50),VehicleData(50),Gear_Info(50),Ignition_Info(50) ,Light_Info(500)的报文周期。
以EngineData为例,CAPL程序逻辑如下:
- 先声明检测事件gCycCheckId
- ?定义常量:
- 周期最大最小范围值? :[lCycMinCycleTime,lCycMaxCycleTime] 为 [40,60]
- Light_Info的周期范围区间:[Light_MIN_CYCLE_TIME,Light_MAX_CYCLE_TIME] 为 [490,510]。
- 写测试用例: ?
- 定义测试报告提示信息:用testCaseTitle定义测试报告提示信息,以EngineData为例testCaseTitle("TC-1","TC-1:Check cycle time of msg EngineData");
- ?观测待测报文,周期是否在范围要求内:使用ChkStart_MsgAbsCycleTimeViolation观察待测报文是否在设置的区间范围内。正常返回报文检测事件ID——aCheckedId 。如果aCheckedId大于0代表测试正常运行,如果=0代表测过程有错误。
- 检测测试用例结果,输出测试报告后,销毁测试事件
- ?设定用例测试的时间 KTIMEOUT,在此观测时间段内观测待测报文的周期。
- 将测试用例运行结果aCheckedId 作为test条件——testAddCondition,这意味着将在报告中展示测试用例运行结果
- 等待测试时间结束,
- 观测结束后,统计测试用例中报文的周期平均值、最大值、最小值。
- 根据用例运行结果aCheckedId打印报告,如果aCheckedId的数量大于0,即检测报文周期存在不在范围内的情况,则用snprintf+TestStepFail 描述导致错误的测试步骤,测试用例的判决在此自动设置为失败。否则用snprintf+TestStepPass描述测试结果,报告中将显示按预期执行的测试步骤,顺利通过。
- 最后销毁检测事件gCycCheckId。
其他报文只需在3测试用例部分,改为相应的报文名称即可。1声明检测事件,4用例检测结果,5销毁检测事件都是通用功能。
具体代码示例如下:
variables
{
//TC1
dword gCycCheckId;//声明检测事件的ID
int gUndefinedMsgCheckResult;//声明未定义报文的检测结果
const long kMIN_CYCLE_TIME = 40;//一般最小周期时间常量
const long kMAX_CYCLE_TIME = 60;//一般最大周期时间常量
const long Light_MIN_CYCLE_TIME = 490;//定义报文Light_Info最小周期时间常量
const long Light_MAX_CYCLE_TIME = 510;//定义报文Light_Info最大周期时间常量
const long kTIMEOUT = 4000;//定义测试等待时间常量
//自定义报文——使用IG模块
}
//周期时间检测结果函数
CheckMsgCyc(float aCycMinCycleTime, float aCycMaxCycleTime)
{
long lQueryResultProbeAvg;//声明平均时间
long lQueryResultProbeMin;//声明最小测量时间
long lQueryResultProbeMax;//声明最大测量时间
char lbuffer[100];
testAddCondition(gCycCheckId);//在该函数中添加事件
testWaitForTimeout(kTIMEOUT);//等待测试时间结束
//统计平均时间
lQueryResultProbeAvg = ChkQuery_StatProbeIntervalAvg(gCycCheckId);
//统计min时间
lQueryResultProbeMin = ChkQuery_StatProbeIntervalMin(gCycCheckId);
//统计max时间
lQueryResultProbeMax = ChkQuery_StatProbeIntervalMax(gCycCheckId);
if(ChkQuery_NumEvents(gCycCheckId)>0)
{
//统计异常次数//打印报告
snprintf(lbuffer,elCount(lbuffer),"Valid values %.0fms - %.0fms",aCycMinCycleTime,aCycMaxCycleTime);
testStepFail("",lbuffer);
snprintf(lbuffer,elCount(lbuffer),"Average cycle time: %dms",lQueryResultProbeAvg);
testStepFail("",lbuffer);
snprintf(lbuffer,elCount(lbuffer),"Min cycle time: %dms",lQueryResultProbeMin);
testStepFail("",lbuffer);
snprintf(lbuffer,elCount(lbuffer),"Average cycle time: %dms",lQueryResultProbeMax);
testStepFail("",lbuffer);
}
else
{
snprintf(lbuffer,elCount(lbuffer),"Valid values %.0fms - %.0fms",aCycMinCycleTime,aCycMaxCycleTime);
testStepPass("",lbuffer);
snprintf(lbuffer,elCount(lbuffer),"Average cycle time: %dms",lQueryResultProbeAvg);
testStepPass("",lbuffer);
snprintf(lbuffer,elCount(lbuffer),"Min cycle time: %dms",lQueryResultProbeMin);
testStepPass("",lbuffer);
snprintf(lbuffer,elCount(lbuffer),"Average cycle time: %dms",lQueryResultProbeMax);
testStepPass("",lbuffer);
}
ChkControl_Destroy(gCycCheckId);//销毁事件
}
//TC1:Check Cycle time of msg EngineData
testcase CheckMsgEngineData()
{
float lCycMinCycleTime;//声明最小周期时间
float lCycMaxCycleTime;//声明最大周期时间
lCycMinCycleTime = kMIN_CYCLE_TIME;//赋值
lCycMaxCycleTime = kMAX_CYCLE_TIME;
//测试报告提示信息
testCaseTitle("TC-1","TC-1:Check cycle time of msg EngineData");
//开始观察待测报文
gCycCheckId = ChkStart_MsgAbsCycleTimeViolation(EngineData,lCycMinCycleTime,lCycMaxCycleTime);
CheckMsgCyc(lCycMinCycleTime,lCycMaxCycleTime);//周期时间检测结果函数
testRemoveCondition(gCycCheckId);//移除测试条件
}
//TC-2:Check Cycle time of msg VehicleData
testcase CheckMsgVehicleData()
{
float lCycMinCycleTime;
float lCycMaxCycleTime;
lCycMinCycleTime = kMIN_CYCLE_TIME;
lCycMaxCycleTime = kMAX_CYCLE_TIME;
testCaseTitle("TC-2","TC-2:Check cycle time of msg VehicleData");
gCycCheckId = ChkStart_MsgAbsCycleTimeViolation(VehicleData,lCycMinCycleTime,lCycMaxCycleTime);
CheckMsgCyc(lCycMinCycleTime,lCycMaxCycleTime);
testRemoveCondition(gCycCheckId);
}
//TC-3:Check Cycle time of msg Gear_Info
testcase CheckMsgGear_Info()
{
float lCycMinCycleTime;
float lCycMaxCycleTime;
lCycMinCycleTime = kMIN_CYCLE_TIME;
lCycMaxCycleTime = kMAX_CYCLE_TIME;
testCaseTitle("TC-3","TC-3:Check cycle time of msg Gear_Info");
gCycCheckId = ChkStart_MsgAbsCycleTimeViolation(Gear_Info,lCycMinCycleTime,lCycMaxCycleTime);
CheckMsgCyc(lCycMinCycleTime,lCycMaxCycleTime);
testRemoveCondition(gCycCheckId);
}
//TC-4:Check Cycle time of msg Ignition_Info
testcase CheckMsgIgnition_Info()
{
float lCycMinCycleTime;
float lCycMaxCycleTime;
lCycMinCycleTime = kMIN_CYCLE_TIME;
lCycMaxCycleTime = kMAX_CYCLE_TIME;
testCaseTitle("TC-4","TC-4:Check cycle time of msg Ignition_Info");
gCycCheckId = ChkStart_MsgAbsCycleTimeViolation(Ignition_Info,lCycMinCycleTime,lCycMaxCycleTime);
CheckMsgCyc(lCycMinCycleTime,lCycMaxCycleTime);
testRemoveCondition(gCycCheckId);
}
//TC-5:Check Cycle time of msg Light_Inf
testcase CheckMsgLight_Info()
{
float lCycMinCycleTime;
float lCycMaxCycleTime;
lCycMinCycleTime = kMIN_CYCLE_TIME;
lCycMaxCycleTime = kMAX_CYCLE_TIME;
testCaseTitle("TC-5","TC-5:Check cycle time of msg Light_Info");
gCycCheckId = ChkStart_MsgAbsCycleTimeViolation(Light_Info,lCycMinCycleTime,lCycMaxCycleTime);
CheckMsgCyc(lCycMinCycleTime,lCycMaxCycleTime);
testRemoveCondition(gCycCheckId);
}
3-3 CAPL测试用例——检测报文长度DLC
//TC6:DLC 报文长度测试
testcase CheckDLCLock_Info()
{
dword checkId;
//测试报告提示信息
testCaseTitle("TC-6","TC-6:Check msg DLC of Lock_Info");
//管事观测报文Lock_Info的DLC
checkId = ChkStart_InconsistentDlc(Lock_Info);
testAddCondition(checkId);
//等待测试时间结束
testWaitForTimeout(kTIMEOUT);
testRemoveCondition(checkId);
}
3-4 CAPL测试用例——检测未定义报文undefined msg
//TC-7:检测未定义信号
testcase CheckUndefinedMessage()
{
long lEventUndefineMessageId;//声明未定义报文Id
char lbuffer[100];
gUndefinedMsgCheckResult = 0;//?初始化未定义报文数量为0
testCaseTitle("TC-7","TC-7:Check CAN channel for undefined message");
//开始观测当前总线
gCycCheckId = ChkStart_UndefinedMessageReceived("UndefinedMsgCallback");
//延时,即测量该时间段
testWaitForTimeout(kTIMEOUT);
switch(gUndefinedMsgCheckResult)
{
case 1:
write("undefined message detected!");
//获取未定义报文ID
lEventUndefineMessageId = ChkQuery_EventMessageId(gCycCheckId);
snprintf(lbuffer,elCount(lbuffer),"Undefined message detected: Id 0x%x",lEventUndefineMessageId);
testStepFail("",lbuffer);
break;
default:
write("Iamdefault");
testStepPass("","No undefined message detected!");
break;
}
ChkControl_Destroy(gCycCheckId);//销毁事件
}
UndefinedMsgCallback(dword aCheckId)
{
//回调函数,检测到未定义报文时调用
write("Test: undefined message finded");
ChkQuery_EventStatusToWrite(aCheckId);
gUndefinedMsgCheckResult=1;//将未定义报文个数置为1
}
3-5 CAPL测试用例——功能测试
testcase CheckEngine_Speed()
{
dword checkId;
testCaseTitle("TC-8","TC-8:Check Engine Speed Value");
@Vehicle_Key::Unlock_Car = 1;
@Vehicle_Key::Car_Driver = 0;
@Vehicle_Key::Key_State = 2;
@Vehicle_Control::Eng_Speed = 2000;
//开始观测,信号值是否在范围内
checkId = ChkStart_MsgSignalValueInvalid(EngineData::EngSpeed,1900,2100);
testWaitForTimeout(kTIMEOUT);
if(ChkQuery_EventSignalValue(checkId))
{
testStepPass("","Correct Engine Speed Value");
}
else
{
testStepFail("","Incorrect Engine Speed Value");
}
}
4 工程运行测试
运行工程后,运行测试。
测试用例运行结果如图所示,Light_Info的报文周期检测报错。
——查看CANdb,发现只有报文Light_Info的报文周期为500,代码中使用的检测范围为40-60,将周期范围更改为Light_MIN_CYCLE_TIME和Light_MAX_CYCLE_TIME,如下示例:
//TC-5:Check Cycle time of msg Light_Info
testcase CheckMsgLight_Info()
{
float lCycMinCycleTime;
float lCycMaxCycleTime;
//lCycMinCycleTime = kMIN_CYCLE_TIME;//kMIN_CYCLE_TIME=40==>Light_MIN_CYCLE_TIME=490
//lCycMaxCycleTime = kMAX_CYCLE_TIME;//kMAX_CYCLE_TIME=60==>Light_MAX_CYCLE_TIME=510
lCycMinCycleTime = Light_MIN_CYCLE_TIME;
lCycMaxCycleTime = Light_MAX_CYCLE_TIME;
testCaseTitle("TC-5","TC-5:Check cycle time of msg Light_Info");
gCycCheckId = ChkStart_MsgAbsCycleTimeViolation(Light_Info,lCycMinCycleTime,lCycMaxCycleTime);
CheckMsgCyc(lCycMinCycleTime,lCycMaxCycleTime);
testRemoveCondition(gCycCheckId);
}
再次运行测试用例,全部通过。
?5 故障注入
为了验证测试用例的正确性,可以使用多种故障注入方法实现故障注入,常见的有:使用故障注入函数,采用网络节点CAPL编程,以及使用IG节点。
书中制作了一个面板: Msg_Switch和Custom_Msg,分别控制报文的发送和关闭,以及发送自定义报文。
?我自己尝试使用Panel模块实现这个面板:创建系统变量,将面板复选框关联系统变量,再在CAPL编程中读取系统变量,根据变量值控制对应的报文函数。
但最后,使用Panel只实现了Msg_Switch部分。Custom_Msg没有找到对应的未定义报文创建方法,有实现的小伙伴欢迎分享。最后使用IG节点实现了未定义报文的发送。
5-1 系统变量控制报文发送
创建系统变量,将面板复选框关联系统变量,再在CAPL编程中读取系统变量,根据变量值控制对应的报文函数。
测试用例涉及7个报文,因而创建7个系统变量创建如下:
?以Gateway_EngineData_off为例,系统变量创建过程如下。
先建立一个Value Table共同使用。因为7个系统变量具有相同的数值解释:勾选为1代表停止报文发送,不勾选为0代表报文正常发送。使用相同的ValueTable可以统一管理。
?Panel创建过程如下:
先添加一个Panel面板,命名为NetworkTest.
添加复选框组件,修改名称并,关联对应的系统变量,下图示例为EngineData,其余报文控制根据名称一一对应即可。
?Panel创建完毕后,在NetworkTest.can中添加变量监听事件,控制相应的报文发送。
以EngineData为例,CAPL编程如下:
on sysvar_update TestSysVar::Gateway_EngineData_off
{
if (@this==1)
{
testDisableMsg(EngineData);
write("Test: disable EngineData");
//testDisableMsg(Cluster_Info);
// ILDisableMsg("Cluster_Info");
}
else{
testEnableMsg(EngineData);
write("Test: enable EngineData");
}
}
控制报文发送和终止的函数不止有testDisableMsg和testEnableMsg,其它函数可以参考此文(完善后放链接)。
5-2? IG节点发送自定义报文
IG节点可分为?CAN IG和IG,区别是CANIG只支持CAN报文,而IG可支持CAN、LIN、MOST等其他报文。此外还有IG和PDU IG的区别,PDU IG可以支持任意网络协议,包括CAN以及Ethernet 、FlexRay。
?5-2-1 创建IG节点
在Simulation Setup总线上创建CAN IG 模块,CAN IG模块允许用户发送自定义的CAN报文。
5-2-2 添加自定义报文,并配置
?如上图添加了3个自定义报文Msg_01,Msg_02,Msg_03,并按下图定义相关属性
?5-2-3 运行
保存后,启动工程,启动测试用例,发送自定义报文。
测试结果显示检测到了未定义报文。
?6 测试报告
测试报告有2种格式:①CANoe TestReport Viewer(推荐)②XML/HTML格式(以前的)
可如下图所示,修改为自己所需的格式:
?测试报告的打开位置如下
①CANoe TestReport Viewer(推荐)
?②XML/HTML格式(以前的)
?
END?
|