
本文记录一下学习DTC测试的一些基础知识与canoe配置在这个过程中遇到的一些问题一、什么是IL有什么作用参考文档1.CAN Interaction Layer (谈谈我对交互层的理解)_蚂蚁小兵-CSDN博客_interaction layer2.总线仿真还可以这样玩_怿星科技的博客-CSDN博客3.CANoe DLL 导入与使用-CSDN博客1.IL的理解IL层在message发送到总线上之前默认情况下IL层的参数是在DBC文件中定义的。IL层定义message 和signal的行为方式比如什么时候发发送周期是多少。2.常见的函数1long ILControlInit () 初始化 IL 这个函数只能在 on preStart中使用 目的是阻止 IL自动启动 IL 是默认生效的 2long ILControlStart 和 ILControlStop 开始和停止IL层 开启时发送相关的报文 3long ILSetMsgEvent (dbMessage msg) 直接向总线上发送一帧报文 4long ILFaultInjectionDisableMsg (dbMsg msg)停止发送某一帧报文 5long ILFaultInjectionEnableMsg (dbMsg msg);恢复报文的发送 6long ILFaultInjectionSetMsgCycleTime (dbMsg msg, double value)更改报文的周期 7long ILFaultInjectionResetMsgCycleTime(dbMsg msg);恢复报文的周期 8long ILNodeControlStop(char aNodeName[])停止指定仿真节点的交互层节点所有报文停发 9long ILNodeControlStart(char aNodeName[]);重启指定仿真节点的交互层 10dword appILTxPending(long aId, dword aDlc, byte data[]); IL 准备往总线发送任意一帧报文之前每帧发送前都会进入这个回调。 可以直接修改data[]数组下发到总线的就是改后数据 回调内部禁止使用 setSignal 系列函数会反复触发 IL 发送逻辑造成无限循环、总线风暴。注只能在IL节点上调用测试工程才能调用上面这些函数才能正常的停发报文3. CANOEILNLVECTOR.DLL是 Vector CANoe 自带的 Interaction Layer Node Layer 库属于官方库。它的作用可以简单理解成给仿真节点提供“基于 DBC 的报文交互能力”依赖 CANoe 的 IL 机制按数据库做这些事按 DBC 的周期、初值、发送类型自动发报文支持 setSignal() 改信号后自动映射到对应报文支持 testEnableMsg() / testDisableMsg() 这类基于 IL 的停发/使能维护消息更新、信号打包等基础行为常见配合方式有两种纯 IL只改信号IL 自动发整帧IL CAPLIL 先正常发CAPL 再拦截或二次加工二、创建与配置工程1.创建两个can通道右键重命名2.在CAN2上添加节点配置为IL节点自动发送dbc里面的报文参考链接1CANoe DLL 导入与使用-CSDN博客1在对应的总线上添加dbc2右键选择节点3右键节点Configuration查看节点配置4右键节点- Open IL Configuration勾选需要发送发送的报文跟DTC相关的报文3. 创建测试环境详情可参考: 使用Canoe写CAPL自动化脚本_canoe自动化测试脚本-CSDN博客三、测试思路及代码1.故障类型报文丢失整个节点丢失CRC 错误Rolling Counter 错误信号失效/越界2.测试思路先清空 ECU 当前 DTC。通过停发报文、修改 CRC、固定 rolling counter、修改信号值等方式制造故障。用 UDS 0x19 周期性读 DTC。记录“首次读到当前故障”的时间判断是否落在规范时间窗口内。去掉故障。再周期性读 DTC判断是否在规定时间内从“当前故障”变成“历史故障”。3.测试代码简略不全DTC_test.can /*!Encoding:936*/ includes { #include ../Include/IniConfig.cin #include ../Include/UDS_DiagServices.cin #include ../Include/E2E for SDA-S.cin #include ../Include/Common.cin #include ../Include/ReportAndLog.cin } variables { dword Channel_CAN1 65537; dword Channel_CAN2 63338; int LostMsgRsflg0; dword LostMsgID0; int E2EMsgERflg0;//E2E错误标志 int E2EMsgRsflg0;//E2E恢复标志 int E2EMsgRstime0; dword E2EMsgID0; float E2Etime0; float restime0; } on message CAN1.* { if(LostMsgRsflg1 this.id LostMsgID) {//报文丢失恢复标志为1并且当前报文是丢失的报文说明恢复了发送 testSupplyTextEvent (messagesend); restimetimeNow ()/100000.000;//恢复时间 LostMsgRsflg0; write(报文0x%03X恢复发送%.3f,LostMsgID,restime); } } //在诊断响应里面查找指定DTC int CheckDTC(dword dtcWord,byte status) { int res; byte dtc[4]; dtc[0] 0xFF (dtcWord 16);//取DTC的高8位第3字节 dtc[1] 0xFF (dtcWord 8);// 取DTC的中间8位第2字节 dtc[2] 0xFF dtcWord; dtc[3] status; return bytesIndexOf(DiagRxBuf, DiagRxBufLen, dtc, 4);//在本次恢复DiagRxBuf里面找DTC } /// DiagrRes /* 周期读取DTC然后调用CheckDTC去查找有没有读到读到DTC记录时间 在规定观察窗口内找到目标 DTC 第一次出现的时间点。testtime1s1000 */ float CheckDTCForPeriod(float starttime,float testtime,dword MsgDTC,int DTCStatus) { float endtime; float temptime; int res; endtime0; /*timenow获取时间 timeNow() / 100000.0 → 秒 (s) timeNow() / 100.0 → 毫秒 (ms) timeNow() * 10 → 微秒 (μs) */ while((timenow()/100.0-starttime)testtime*10){ Service19_ReadDTC(PhyRequest ,2,9);//读取当前DTC resCheckDTC(MsgDTC,DTCStatus); if(res0){ continue; } else if(res0){ endtimetimenow()/100.000; break; } } return endtime;//ms } void SignalValidValueSet()//初始化所有失效故障的信号值 { int i; for(i0;i50;i){ if(!SigOverRange[i].MsgDTC) { break;}//如果DTC为0就停止配置表常见结束写法 // 把名字叫 SAS_SteeringAngleValid 的信号设成正常值 0 setSignal (SigOverRange[i].signalname,SigOverRange[i].CorrContext);//将信号设置为正常值 } } long DisableSingleMsg(long msgid) { SetBusContext( 65538);//切到CAN2上 canOnline(3);//确保节点在线 testDisableMsg(msgid);//停发指定报文 testWaitForTimeout (5); SetBusContext( 65537);//切回can1 canOnline(3); return 0; } /// ILControl long EnableSingleMsg(long msgid) { SetBusContext( 65538); canOnline(3); testEnableMsg(msgid); testWaitForTimeout (5); SetBusContext( 65537); canOnline(3); return 0; } testfunction SystemInitialization() { //将本节点的bus channel设置为CAN1。注CAN2是63338 //需要注意的是本节点的bus channel设置为CAN1后就不能对CAN2上节点里的报文做停发或发送处理除非再次设置为CAN2但不影响修改信号值 SetBusContext( 65537); canOnline(3); InitReportAndLog(网络DTC测试);//初始化报告和log InitConfig();//初始化TP配置 SignalValidValueSet();//将信号初始化为正常值 testWaitForTimeout (6000); } testfunction DesystemInitialization() { } testcase MsgLostDtc_Test() { int i; float starttime; float endtime; int res; long ILret; loggingStart (MsgLostDtc); for(i0;i20;i)//先只执行1次 { res0; Service14_ClearDTC(PhyRequest,0xFFFFFF); testWaitForTimeout(300); if(!lostmsglist[i].MsgID) {//0x180 teststep(测试结束,所有报文丢失测试完毕); break; }//如果报文ID为0意味着测试结束 frllcnt[lostmsglist[i].MsgID]0;//关闭E2E fCRC[lostmsglist[i].MsgID]0;//关闭E2E关闭 E2E 正常计算影响避免报文丢失测试混入 CRC/rolling counter 变量。 LostMsgIDlostmsglist[i].MsgID;//设置当前丢失报文ID teststep(,%d.1 测试报文0x%03X超时时间,i1,lostmsglist[i].MsgID); DisableSingleMsg(lostmsglist[i].MsgID);//停发到can2上停发切回can1 TestSetMsgEvent(lostmsglist[i].MsgID);//让测试系统关注该报文事件。 write(停发报文%03X成功, LostMsgID); starttimetimenow()/100.0;//周期性读取DTC是否产生当前故障09单位ms teststep(,%d.2 最后一帧0x%03X报文的时间是%.3f,i1,lostmsglist[i].MsgID,starttime/100.0); endtime CheckDTCForPeriod(starttime,lostmsglist[i].Losttime,lostmsglist[i].MsgDTC,9);//读到就返回 write(%d.3 首次读到当前故障 0x%06X的时间是%.3f,i1,lostmsglist[i].MsgDTC,endtime/1000.000); teststep(,%d.3 首次读到当前故障 0x%06X的时间是%.3f,i1,lostmsglist[i].MsgDTC,endtime/1000.000);//ms 转成 s if(endtime 0) { testStepFail(,%d.4 报文0x%03X超时最大时间%.0fms后仍不产生报文丢失DTC,i1,lostmsglist[i].MsgID,lostmsglist[i].Losttime*10); continue ; } else if ((endtime-starttime)lostmsglist[i].Losttime*0.9 (endtime-starttime)lostmsglist[i].Losttime*1.1) {//在超时事件内产生了DTC write(%d.4 报文0x%03X超时时间为%.0fms在规范要求范围%.0f~%.0fms内,i1,lostmsglist[i].MsgID,endtime-starttime,lostmsglist[i].Losttime*0.9,lostmsglist[i].Losttime*1.1); testStepPass (,%d.4 报文0x%03X超时时间为%.0fms在规范要求范围%.0f~%.0fms内,i1,lostmsglist[i].MsgID,endtime-starttime,lostmsglist[i].Losttime*0.9,lostmsglist[i].Losttime*1.1); } else testStepFail (,%d.4 报文0x%03X超时时间为%.0fms不在规范要求范围%.0f~%.0fms内,i1,lostmsglist[i].MsgID,endtime-starttime,lostmsglist[i].Losttime*0.9,lostmsglist[i].Losttime*1.1); teststep(,%d.5 测试报文0x%03X超时恢复时间,i1,lostmsglist[i].MsgID); testWaitForTimeout (100); LostMsgRsflg1;//恢复标志 testWaitForTimeout (100); EnableSingleMsg(lostmsglist[i].MsgID);//DTC读取成功恢复报文发送 while(LostMsgRsflg1)//等待总线上收到恢复的报文将标志置为0退出循环 { testWaitForTimeout(lostmsglist[i].Resumetime);//1mscan1上抓到回复的报文之后LostMsgRsflg0 } write(%d.6 恢复发送的首帧0x%03X报文的时间是%.3f,i1,lostmsglist[i].MsgID,restime); teststep(,%d.6 恢复发送的首帧0x%03X报文的时间是%.3f,i1,lostmsglist[i].MsgID,restime);//恢复on message can1记录时间 testWaitForTimeout (10); starttimerestime; if(lostmsglist[i].Resumetime1)//逻辑诊断调查表上是恢复1帧立马检查有些是恢复一定的时间 {//恢复次数恢复一帧后立即检查是否变成历史故障 Service19_ReadDTC(PhyRequest ,2,8);//读取当前故障获取回复 endtimeCheckDTC(lostmsglist[i].MsgDTC,8);//在回复里面去找历史故障 if(endtime0) {//找到了故障 write(%d.8 报文0x%03X恢复发送1帧后DTC0x%06X变为历史故障,i1,lostmsglist[i].MsgID,lostmsglist[i].MsgDTC); testStepPASS(,%d.8 报文0x%03X恢复发送1帧后DTC0x%06X变为历史故障,i1,lostmsglist[i].MsgID,lostmsglist[i].MsgDTC); } else testStepFail (,%d.8 报文0x%03X恢复发送1帧后DTC0x%06X仍为当前故障,i1,lostmsglist[i].MsgID,lostmsglist[i].MsgDTC); } else {//不是恢复一帧才算恢复持续一段时间根据诊断调查表去看 endtimeCheckDTCForPeriod(starttime,lostmsglist[i].Resumetime,lostmsglist[i].MsgDTC,8); if(endtime0) { testStepFail(,%d.8 报文0x%03X恢复发送最大时间%.0fms后DTC仍为当前故障,i1,lostmsglist[i].MsgID,lostmsglist[i].Resumetime*10); } else if ((endtime-starttime)lostmsglist[i].Resumetime*0.9 (endtime-starttime)lostmsglist[i].Resumetime*1.1) { testStepPass (,%d.8 报文0x%03X丢失DTC0x%06X恢复时间为%.0fms在规范要求范围%.0f~%.0fms内,i1,lostmsglist[i].MsgID,lostmsglist[i].MsgDTC,endtime-starttime,lostmsglist[i].Resumetime*0.9,lostmsglist[i].Resumetime*1.1); } else testStepFail (,%d.8 报文0x%03X丢失DTC0x%06X恢复时间为%.0fms不在规范要求范围%.0f~%.0fms内,i1,lostmsglist[i].MsgID,lostmsglist[i].MsgDTC,endtime-starttime,lostmsglist[i].Resumetime*0.9,lostmsglist[i].Resumetime*1.1); } starttime0; endtime0; frllcnt[lostmsglist[i].MsgID]0xFF;//开启E2E fCRC[lostmsglist[i].MsgID]0xFF;//开启E2E testWaitForTimeout (100); } } testcase NodeLostDTC_Test() { float starttime; float endtime; int res; loggingStart (NodeLostDTC_Test); teststep(,1 测试mADC节点超时时间); DisableSingleMsg(0x180); DisableSingleMsg(0x15D); DisableSingleMsg(0x1B1); DisableSingleMsg(0x1C2); DisableSingleMsg(0x161); DisableSingleMsg(0x152); TestSetMsgEvent(0x152); teststep(,2 最后一帧0x152报文的时间是%.3f,timenow()/100000.000); starttimetimenow()/100.0; endtimeCheckDTCForPeriod(starttime,1000,0xDA8587,9); teststep(,3 首次读到当前故障 0x%06X的时间是%.3f,0xDA8587,endtime/1000.000); if(endtime0){ testStepFail(,4 mADC节点超时最大时间%.0fms后仍不产生报文丢失DTC,10000); return ; } else if ((endtime-starttime-40)900 (endtime-starttime-40)1100){ testStepPass (,4 mADC节点超时时间为%.0fms在规范要求范围%.0f~%.0fms内,endtime-starttime-40,900.0,1100.0); } else testStepFail (,4 mADC节点超时时间为%.0fms不在规范要求范围%.0f~%.0fms内,endtime-starttime-40,900.0,1100.0); teststep(,5 测试mADC节点超时恢复时间); LostMsgID0x152; testWaitForTimeout (100); LostMsgRsflg1; testWaitForTimeout (100); EnableSingleMsg(0x152); while(LostMsgRsflg1){ testWaitForTimeout(10); } teststep(,6 恢复发送的首帧0x152报文的时间是%.3f,restime); testWaitForTimeout (10); starttimerestime; Service19_ReadDTC(PhyRequest ,2,8); endtimeCheckDTC(0xDA8587,8); if(endtime0){ testStepPASS(,7 mADC节点恢复发送1帧后DTC0x%06X变为历史故障,0xDA8587); } else testStepFail (,7 mADC节点恢复发送1帧后DTC0x%06X仍为当前故障,0xDA8587); EnableSingleMsg(0x180); EnableSingleMsg(0x15D); EnableSingleMsg(0x1B1); EnableSingleMsg(0x1C2); EnableSingleMsg(0x161); starttime0; endtime0; loggingStop(); } testcase CRCDTC_Test() { int i; float starttime; float endtime; int res; loggingStart (CRCDTC); for(i0;i50;i){ Service14_ClearDTC(PhyRequest,0xFFFFFF); if(!CRCMsgList[i].MsgID) { teststep(测试结束,所有CRC故障测试完毕); break;}//如果报文ID为0意味着测试结束 E2EMsgIDCRCMsgList[i].MsgID; Service14_ClearDTC(PhyRequest,0xFFFFFF); teststep(,%d.1 测试0x%03X报文CRC故障产生时间,i1,CRCMsgList[i].MsgID); testWaitForTimeout (100); E2EMsgERflg1;//E2E错误标志 fCRC[CRCMsgList[i].MsgID]0;//注入CRC故障 testWaitForTimeout(5); TestSetMsgEvent(CRCMsgList[i].MsgID); starttimetimenow()/100.0; //testWaitForTimeout (CRCMsgList[i].Losttime/5); //starttimeE2Etime; teststep(,%d.2 首帧CRC故障的0x%03X报文发送时间为%.3f,i1,CRCMsgList[i].MsgID,timenow()/100000.000); endtimeCheckDTCForPeriod(starttime,CRCMsgList[i].Losttime,CRCMsgList[i].MsgDTC,9); teststep(,%d.3 首次读到当前故障 0x%06X的时间是%.3f,i1,CRCMsgList[i].MsgDTC,endtime/1000.000); if(endtime0){ testStepFail(,%d.4 0x%03X报文CRC故障产生最大时间%.0fms后仍不产生DTC 0x%06X,i1,CRCMsgList[i].MsgID,CRCMsgList[i].Losttime*10,CRCMsgList[i].MsgDTC); continue ; } else if ((endtime-starttime)CRCMsgList[i].Losttime*0.9 (endtime-starttime)CRCMsgList[i].Losttime*1.1){ testStepPass (,%d.4 0x%03X报文CRC故障DTC 0x%06X产生时间为%.0fms在规范要求范围%.0f~%.0fms内,i1,CRCMsgList[i].MsgID,CRCMsgList[i].MsgDTC,endtime-starttime,CRCMsgList[i].Losttime*0.9,CRCMsgList[i].Losttime*1.1); } else testStepFail (,%d.4 0x%03X报文CRC故障DTC 0x%06X产生时间为%.0fms不在规范要求范围%.0f~%.0fms内,i1,CRCMsgList[i].MsgID,CRCMsgList[i].MsgDTC,endtime-starttime,CRCMsgList[i].Losttime*0.9,CRCMsgList[i].Losttime*1.1); teststep(,%d.5 测试0x%03X报文CRC故障恢复时间,i1,CRCMsgList[i].MsgID); testWaitForTimeout (100); E2EMsgRsflg1;//恢复标志 fCRC[CRCMsgList[i].MsgID]0xFF;//移除CRC故障 testWaitForTimeout(5); TestSetMsgEvent(CRCMsgList[i].MsgID); starttimetimenow()/100.0; // testWaitForTimeout (CRCMsgList[i].Resumetime/2); // starttimeE2Etime; teststep(,%d.6 首帧CRC正常的0x%03X报文发送时间为%.3f,i1,CRCMsgList[i].MsgID,timenow()/100000.000); endtimeCheckDTCForPeriod(starttime,CRCMsgList[i].Resumetime,CRCMsgList[i].MsgDTC,8); teststep(,%d.7 故障 0x%06X的转为历史故障的时间是%.3f,i1,CRCMsgList[i].MsgDTC,endtime/1000.000); if(endtime0){ testStepFail(,%d.8 0x%03X报文CRC故障移除最大时间%.0fms后DTC仍为当前故障DTC 0x%06X,i1,CRCMsgList[i].MsgID,CRCMsgList[i].Resumetime*10,CRCMsgList[i].MsgDTC); } else if ((endtime-starttime)CRCMsgList[i].Resumetime*0.9 (endtime-starttime)CRCMsgList[i].Resumetime*1.1){ testStepPass (,%d.8 0x%03X报文CRC故障DTC 0x%06X恢复时间为%.0fms在规范要求范围%.0f~%.0fms内,i1,CRCMsgList[i].MsgID,CRCMsgList[i].MsgDTC,endtime-starttime,CRCMsgList[i].Resumetime*0.9,CRCMsgList[i].Resumetime*1.1); } else testStepFail (,%d.8 0x%03X报文CRC故障DTC 0x%06X恢复时间为%.0fms不在规范要求范围%.0f~%.0fms内,i1,CRCMsgList[i].MsgID,CRCMsgList[i].MsgDTC,endtime-starttime,CRCMsgList[i].Resumetime*0.9,CRCMsgList[i].Resumetime*1.1); starttime0; endtime0; testWaitForTimeout (100); } loggingStop(); } testcase RllcntDTC_Test() { int i; float starttime; float endtime; int res; loggingStart (RllcntDTC); for(i0;i50;i){ Service14_ClearDTC(PhyRequest,0xFFFFFF); testWaitForTimeout(50); if(!RllCtMsgList[i].MsgID) { teststep(测试结束,所有RollingCounter故障测试完毕); break;}//如果报文ID为0意味着测试结束 E2EMsgIDRllCtMsgList[i].MsgID; Service14_ClearDTC(PhyRequest,0xFFFFFF); teststep(,%d.1 测试0x%03X报文Rollingcounter故障产生时间,i1,RllCtMsgList[i].MsgID); E2EMsgERflg1; frllcnt[RllCtMsgList[i].MsgID]0;//注入rolling counter故障 testWaitForTimeout(5); TestSetMsgEvent(RllCtMsgList[i].MsgID); starttimetimenow()/100.0; // testWaitForTimeout (RllCtMsgList[i].Losttime/5); // starttimeE2Etime; teststep(,%d.2 首帧Rollingcounter故障的0x%03X报文发送时间为%.3f,i1,RllCtMsgList[i].MsgID,timenow()/100000.000); endtimeCheckDTCForPeriod(starttime,RllCtMsgList[i].Losttime,RllCtMsgList[i].MsgDTC,9); teststep(,%d.3 首次读到当前故障 0x%06X的时间是%.3f,i1,RllCtMsgList[i].MsgDTC,endtime/1000.000); if(endtime0){ testStepFail(,%d.4 0x%03X报文Rollingcounter故障产生最大时间%.0fms后仍不产生DTC 0x%06X,i1,RllCtMsgList[i].MsgID,RllCtMsgList[i].Losttime*10,RllCtMsgList[i].MsgDTC); continue ; } else if ((endtime-starttime)RllCtMsgList[i].Losttime*0.9 (endtime-starttime)RllCtMsgList[i].Losttime*1.1){ testStepPass (,%d.4 0x%03X报文Rollingcounter故障DTC 0x%06X产生时间为%.0fms在规范要求范围%.0f~%.0fms内,i1,RllCtMsgList[i].MsgID,RllCtMsgList[i].MsgDTC,endtime-starttime,RllCtMsgList[i].Losttime*0.9,RllCtMsgList[i].Losttime*1.1); } else testStepFail (,%d.4 0x%03X报文Rollingcounter故障DTC 0x%06X产生时间为%.0fms不在规范要求范围%.0f~%.0fms内,i1,RllCtMsgList[i].MsgID,RllCtMsgList[i].MsgDTC,endtime-starttime,RllCtMsgList[i].Losttime*0.9,RllCtMsgList[i].Losttime*1.1); teststep(,%d.5 测试0x%03X报文Rollingcounter故障恢复时间,i1,RllCtMsgList[i].MsgID); testWaitForTimeout (100); E2EMsgRsflg1; frllcnt[RllCtMsgList[i].MsgID]0xFF;//移除rolling counter故障 testWaitForTimeout(5); TestSetMsgEvent(RllCtMsgList[i].MsgID); starttimetimenow()/100.0; // testWaitForTimeout (RllCtMsgList[i].Resumetime/2); // starttimeE2Etime; teststep(,%d.6 首帧Rollingcounter正常的0x%03X报文发送时间为%.3f,i1,RllCtMsgList[i].MsgID,timenow()/100000.000); endtimeCheckDTCForPeriod(starttime,RllCtMsgList[i].Resumetime,RllCtMsgList[i].MsgDTC,8); teststep(,%d.7 故障 0x%06X的转为历史故障的时间是%.3f,i1,RllCtMsgList[i].MsgDTC,endtime/1000.000); if(endtime0){ testStepFail(,%d.8 0x%03X报文Rollingcounter故障移除最大时间%.0fms后DTC仍为当前故障DTC 0x%06X,i1,RllCtMsgList[i].MsgID,RllCtMsgList[i].Resumetime*10,RllCtMsgList[i].MsgDTC); } else if ((endtime-starttime)RllCtMsgList[i].Resumetime*0.9 (endtime-starttime)RllCtMsgList[i].Resumetime*1.1){ testStepPass (,%d.8 0x%03X报文Rollingcounter故障DTC 0x%06X恢复时间为%.2fms在规范要求范围%.0f~%.0fms内,i1,RllCtMsgList[i].MsgID,RllCtMsgList[i].MsgDTC,endtime-starttime,RllCtMsgList[i].Resumetime*0.9,RllCtMsgList[i].Resumetime*1.1); } else testStepFail (,%d.8 0x%03X报文Rollingcounter故障恢DTC 0x%06X恢复时间为%.2fms不在规范要求范围%.0f~%.0fms内,i1,RllCtMsgList[i].MsgID,RllCtMsgList[i].MsgDTC,endtime-starttime,RllCtMsgList[i].Resumetime*0.9,RllCtMsgList[i].Resumetime*1.1); starttime0; endtime0; testWaitForTimeout (100); } loggingStop(); } /*将有效值和无效值都配置好然后更改值参考诊断调查表*/ testcase SigOverRangeDTC_Test() { int i; float starttime; float endtime; int res; loggingStart (SigOverRangeDTC); for(i0;i50;i){ Service14_ClearDTC(PhyRequest,0xFFFFFF); testWaitForTimeout(50); if(!SigOverRange[i].MsgDTC) { teststep(测试结束,所有信号超范围故障测试完毕); break;}//如果DTC为0意味着测试结束 teststep(,%d.1 测试信号%s失效故障产生时间,i1,SigOverRange[i].signalname); setSignal (SigOverRange[i].signalname,SigOverRange[i].ErrContext);//之后改信号一直是这个值除非再次改变 testWaitForTimeout(5); TestSetMsgEvent(SigOverRange[i].MsgID); teststep(,%d.2 首帧0x%03X报文信号%s失效的发送时间为%.3f,i1,SigOverRange[i].MsgID,SigOverRange[i].signalname,timenow()/100000.000); starttimetimenow()/100.0; endtimeCheckDTCForPeriod(starttime,SigOverRange[i].Losttime,SigOverRange[i].MsgDTC,9); teststep(,%d.3 首次读到当前故障 0x%06X的时间是%.3f,i1,SigOverRange[i].MsgDTC,endtime/1000.000); if(endtime0){ testStepFail(,%d.4 信号%s失效故障产生最大时间%.0fms后仍然不产生DTC,i1,SigOverRange[i].signalname,SigOverRange[i].Losttime*10); continue ; } else if ((endtime-starttime)SigOverRange[i].Losttime*0.9 (endtime-starttime)SigOverRange[i].Losttime*1.1){ testStepPass (,%d.4 信号%s失效故障产生时间为%.0fms在规范要求范围%.0f~%.0fms内,i1,SigOverRange[i].signalname,endtime-starttime,SigOverRange[i].Losttime*0.9,SigOverRange[i].Losttime*1.1); } else testStepFail (,%d.4 信号%s失效故障产生时间为%.0fms不在规范要求范围%.0f~%.0fms内,i1,SigOverRange[i].signalname,endtime-starttime,SigOverRange[i].Losttime*0.9,SigOverRange[i].Losttime*1.1); testWaitForTimeout (100); teststep(,%d.5 测试信号%s失效故障恢复时间,i1,SigOverRange[i].signalname); setSignal (SigOverRange[i].signalname,SigOverRange[i].CorrContext); testWaitForTimeout(5); TestSetMsgEvent(SigOverRange[i].MsgID); teststep(,%d.6 首帧0x%03X报文信号%s有效的发送时间为%.3f,i1,SigOverRange[i].MsgID,SigOverRange[i].signalname,timenow()/100000.000); starttimetimenow()/100.0; endtimeCheckDTCForPeriod(starttime,SigOverRange[i].Resumetime,SigOverRange[i].MsgDTC,8); teststep(,%d.7 故障 0x%06X转为历史故障的时间是%.3f,i1,SigOverRange[i].MsgDTC,endtime/1000.000); if (endtime!0 (endtime-starttime)SigOverRange[i].Resumetime*0.9 (endtime-starttime)SigOverRange[i].Resumetime*1.1){ testStepPass (,%d.8 信号%s失效故障恢复时间为%.0fms在规范要求范围%.0f~%.0fms内,i1,SigOverRange[i].signalname,endtime-starttime,SigOverRange[i].Resumetime*0.9,SigOverRange[i].Resumetime*1.1); } else if(endtime0) testStepFail(,%d.8 信号%s失效故障移除最大时间%.0fms后DTC仍为当前故障,i1,SigOverRange[i].signalname,SigOverRange[i].Resumetime*10); else testStepFail (,%d.8 信号%s失效故障恢复时间为%.0fms不在规范要求范围%.0f~%.0fms内,i1,SigOverRange[i].signalname,endtime-starttime,SigOverRange[i].Resumetime*0.9,SigOverRange[i].Resumetime*1.1); starttime0; endtime0; testWaitForTimeout (100); } loggingStop(); }iniConfig.cin/*!Encoding:936*/ // WMG 2026.7.15 // 功能用于读写ini配置信息 variables { word MsgIdTag[long];//用于写入E2E的MsgID long rllcntMax256;//rollingcounter最大值1 long frllcnt[long];//每条报文的rollingcounter开关置0时rollingcounter为0 long fCRC[long];//每条报文的CRC开关置0时CRC为0 /*报文相关的信息*/ struct DTCMsgList { long MsgID; dword MsgDTC;//报文关联的DTC float Losttime; float Resumetime; }; /*信号相关的信息*/ struct DTCSignalList { char signalname[200];//信号名模板为“signalname”,注意总线上该信号名必须唯一 dword MsgDTC;//信号关联的DTC dword ErrContext;//错误信号数值 dword CorrContext;//正确信号数值 float Losttime; float Resumetime; long MsgID; }; struct DTCMsgList lostmsglist[20];//丢失报文、丢失报文DTC、丢失时间、恢复时间 struct DTCMsgList CRCMsgList[50]; struct DTCMsgList RllCtMsgList[50]; struct DTCSignalList SigOverRange[50];//有50个结构体对象 } void InitConfig() { int i; char tempname[100]; //rllcnt和CRC开关初始化默认开启 for(i0;i0xFFF;i) { frllcnt[i]0xFF; fCRC[i]0xFF; } //报文丢失DTC,报文和DTC绑定 lostmsglist[0].MsgID0x180; lostmsglist[0].MsgDTC0xDA8187; lostmsglist[0].Losttime1000;//丢失时间 lostmsglist[0].Resumetime1;//恢复次数 lostmsglist[1].MsgID0x15D; lostmsglist[1].MsgDTC0xDA8287; lostmsglist[1].Losttime1000; lostmsglist[1].Resumetime1; lostmsglist[2].MsgID0x1B1; lostmsglist[2].MsgDTC0xDA8387; lostmsglist[2].Losttime1000; lostmsglist[2].Resumetime1; lostmsglist[3].MsgID0x1C2; lostmsglist[3].MsgDTC0xDA8487; lostmsglist[3].Losttime1000; lostmsglist[3].Resumetime1; lostmsglist[4].MsgID0x152; lostmsglist[4].MsgDTC0xDA8787; lostmsglist[4].Losttime1000; lostmsglist[4].Resumetime1; lostmsglist[5].MsgID0x161; lostmsglist[5].MsgDTC0xDA8887; lostmsglist[5].Losttime2500; lostmsglist[5].Resumetime1; lostmsglist[6].MsgID0x288; lostmsglist[6].MsgDTC0xDA8687; lostmsglist[6].Losttime1000; lostmsglist[6].Resumetime1; //Checksum DTC CRCMsgList[0].MsgID0x180; CRCMsgList[0].MsgDTC0xDA8183; CRCMsgList[0].Losttime1000; CRCMsgList[0].Resumetime1000; CRCMsgList[1].MsgID0x15D; CRCMsgList[1].MsgDTC0xDA8283; CRCMsgList[1].Losttime1000; CRCMsgList[1].Resumetime1000; CRCMsgList[2].MsgID0x1B1; CRCMsgList[2].MsgDTC0xDA8383; CRCMsgList[2].Losttime1000; CRCMsgList[2].Resumetime1000; CRCMsgList[3].MsgID0x1C2; CRCMsgList[3].MsgDTC0xDA8483; CRCMsgList[3].Losttime1000; CRCMsgList[3].Resumetime1000; CRCMsgList[4].MsgID0x161; CRCMsgList[4].MsgDTC0xDA8883; CRCMsgList[4].Losttime1000; CRCMsgList[4].Resumetime1000; CRCMsgList[5].MsgID0x288; CRCMsgList[5].MsgDTC0xDA8683; CRCMsgList[5].Losttime1000; CRCMsgList[5].Resumetime1000; //Rollcounter DTC RllCtMsgList[0].MsgID0x180; RllCtMsgList[0].MsgDTC0xDA8182; RllCtMsgList[0].Losttime1000; RllCtMsgList[0].Resumetime1000; RllCtMsgList[1].MsgID0x15D; RllCtMsgList[1].MsgDTC0xDA8282; RllCtMsgList[1].Losttime1000; RllCtMsgList[1].Resumetime1000; RllCtMsgList[2].MsgID0x1B1; RllCtMsgList[2].MsgDTC0xDA8382; RllCtMsgList[2].Losttime1000; RllCtMsgList[2].Resumetime1000; RllCtMsgList[3].MsgID0x1C2; RllCtMsgList[3].MsgDTC0xDA8482; RllCtMsgList[3].Losttime1000; RllCtMsgList[3].Resumetime1000; RllCtMsgList[4].MsgID0x161; RllCtMsgList[4].MsgDTC0xDA8882; RllCtMsgList[4].Losttime1000; RllCtMsgList[4].Resumetime1000; RllCtMsgList[5].MsgID0x288; RllCtMsgList[5].MsgDTC0xDA8682; RllCtMsgList[5].Losttime1000; RllCtMsgList[5].Resumetime1000; //报文信号失效DTC snprintf (SigOverRange[0].signalname,200,EpsSasSteerAgVld); SigOverRange[0].MsgDTC0xDA8186; SigOverRange[0].ErrContext1; SigOverRange[0].CorrContext0; SigOverRange[0].Losttime1000; SigOverRange[0].Resumetime1000; SigOverRange[0].MsgID0x180; snprintf (SigOverRange[1].signalname,200,ESP_LatAccelValid); SigOverRange[1].MsgDTC0xDA8286; SigOverRange[1].ErrContext2; SigOverRange[1].CorrContext1; SigOverRange[1].Losttime1000; SigOverRange[1].Resumetime1000; SigOverRange[1].MsgID0x15D; snprintf (SigOverRange[2].signalname,200,ESP_LongAccelValid); SigOverRange[2].MsgDTC0xDA8286; SigOverRange[2].ErrContext2; SigOverRange[2].CorrContext1; SigOverRange[2].Losttime1000; SigOverRange[2].Resumetime1000; SigOverRange[2].MsgID0x15D; snprintf (SigOverRange[3].signalname,200,ESP_YawRateValid); SigOverRange[3].MsgDTC0xDA8286; SigOverRange[3].ErrContext2; SigOverRange[3].CorrContext1; SigOverRange[3].Losttime1000; SigOverRange[3].Resumetime1000; SigOverRange[3].MsgID0x15D; snprintf (SigOverRange[4].signalname,200,VcuVehGearPosnVld); SigOverRange[4].MsgDTC0xDA8386; SigOverRange[4].ErrContext1; SigOverRange[4].CorrContext0; SigOverRange[4].Losttime1000; SigOverRange[4].Resumetime1000; SigOverRange[4].MsgID0x1B1; snprintf (SigOverRange[5].signalname,200,EspVehSpdVld); SigOverRange[5].MsgDTC0xDA8486; SigOverRange[5].ErrContext1; SigOverRange[5].CorrContext0; SigOverRange[5].Losttime1000; SigOverRange[5].Resumetime1000; SigOverRange[5].MsgID0x1C2; snprintf (SigOverRange[6].signalname,200,VIU_PassengerADEDSts); SigOverRange[6].MsgDTC0xDA8A87; SigOverRange[6].ErrContext1; SigOverRange[6].CorrContext0; SigOverRange[6].Losttime1000; SigOverRange[6].Resumetime1000; SigOverRange[6].MsgID0x288; snprintf (SigOverRange[7].signalname,200,VIU_DriverADEDSts); SigOverRange[7].MsgDTC0xDA8A87; SigOverRange[7].ErrContext1; SigOverRange[7].CorrContext0; SigOverRange[7].Losttime1000; SigOverRange[7].Resumetime1000; SigOverRange[7].MsgID0x288; snprintf (SigOverRange[8].signalname,200,ESP_AEBAvailable); SigOverRange[8].MsgDTC0xDA8B87; SigOverRange[8].ErrContext0; SigOverRange[8].CorrContext1; SigOverRange[8].Losttime1000; SigOverRange[8].Resumetime1000; SigOverRange[8].MsgID0x161; snprintf (SigOverRange[8].signalname,200,VcuAccrPedlPosnVld); SigOverRange[8].MsgDTC0xDA8C87; SigOverRange[8].ErrContext1; SigOverRange[8].CorrContext0; SigOverRange[8].Losttime1000; SigOverRange[8].Resumetime1000; SigOverRange[8].MsgID0x1B1; snprintf (SigOverRange[10].signalname,200,IbBrkPedlStsGbVld); SigOverRange[10].MsgDTC0xDA8D87; SigOverRange[10].ErrContext0; SigOverRange[10].CorrContext1; SigOverRange[10].Losttime1000; SigOverRange[10].Resumetime1000; SigOverRange[10].MsgID0x17A; //TP配置 gCommunicationParameter.phyTxID0x7B2; gCommunicationParameter.funTxID0x7DF; gCommunicationParameter.rxID 0x7BA; gCommunicationParameter.p2ClientTimeout150; gCommunicationParameter.p2EnhanceClientTimeout5000; gCommunicationParameter.diagRequestTimeout50; gCommunicationParameter.flowControlFlag1; gCommunicationParameter.STmin10; gCommunicationParameter.blockSize0; gCommunicationParameter.Ar_ms70; gCommunicationParameter.As_ms70; gCommunicationParameter.Br_ms150; gCommunicationParameter.Bs_ms150; gCommunicationParameter.CANFDMode1; gCommunicationParameter.Cr_ms150; gCommunicationParameter.Cs_ms150; gCommunicationParameter.maxCANFDFrameLength64; gCommunicationParameter.maxRxLength4095;//影响流控帧中的overflow (FC.Ovflw) gCommunicationParameter.bitRateSwitch 1; canTpInitial(); }四、用到的基础函数1.总线上下文切换 前言 1CANoe 工程存在多 CAN 通道 / 多总线CAN/LIN/Ethernet/IBUS 时canOnline()、canOffline()、output()、报文收发这类无通道号的通用 CAPL 函数会默认在当前总线上下文执行。 2Bus Context 本质是总线通道唯一标识 ID每个总线 / 通道对应一个专属 context 数值 3不切换上下文时函数只会操作默认通道 dword SetBusContext( dword context );手动切换当前代码块的总线上下文通道让后续总线 API 作用到指定通道。 dword GetBusNameContext(char name[])获取该总线的context值 dword GetBusContext()读取当前正在执行的执行的context值 dword canOnline(dword flags); 返回值 1仅激活CAPL脚本 2仅激活NodeLayer DLL信号层数据库节点仿真依赖它 3同时激活 CAPL NodeLayer如果该节点配置了诊断 ECU 仿真一并挂载到总线网络 把仿真节点Simulation Node 恢复到总线在线状态。 配套函数 canOffline() 是断连总线调用 canOnline() 后节点才能正常通过 output() 往总线发报文。 2.控制交互层周期报文的自动发送 long TestEnableMsg (dbMessage aMessage);//dbc报文名字 long TestEnableMsg (dword aMessageId);//can ID long TestDisableMsg (dbMessage aMessage); long TestDisableMsg (dword aMessageId);//can ID long TestSetMsgEvent (dbMessage aMessage); long TestSetMsgEvent (dword aMessageId);强制发一帧报文到总线上无论报文当前是禁用/启用 void setSignal(Signal aSignal, double aValue);设置信号的物理值五、遇到的问题1.报告里面一直有测试框架自动加进去的 Resume reason这些无关信息导致测试报告不简洁解决方法补充tse文件DTC_test.tse 本质上是 CANoe Test Setup 的“测试环境配置文件”主要描述这个测试模块叫什么绑定哪个 .vxt用哪个 CAPL 库报告怎么生成报告里显示哪些内容当前测试环境窗口布局和一些控制器状态