on signal:信号发生变化是触发代码
on signal_update:信号每一帧都触发代码
一、发送报文
(1)周期发送
includes{}variables{ message 0x11 msg1;//定义要发送的报文 msTimer timer1;//定义定时器}on start{ setTimer(timer1,100);//运行canoe程序,启动定时器}on timer timer1{ msg1.dlc = 8;//定义该报文的属性 msg1.byte(0)=0x11;//定义byte(0)字节的数值 output(msg1); //输出该报文到CAN总线 setTimer(timer1,100); //重置定时器}
(2)按键触发发送
variables{message 0x555 msg1 = {dlc=1};} on key 'b'{msg1.byte(0)=0xAA;output(msg1);}
(3)按键触发后周期发送
variables{message 0x400 msgA = {dlc=1};mstimer timerA;int conditionA = 0; //初始化 conditionA =off} on key 'a'{conditionA = !conditionA; //toggle conditionAif(conditionA == 1) //如果条件满足:按下A按键{setTimer(timerA,200); //计时器触发启动}} on timer timerA{if(conditionA == 1) //if conditionA is still true{setTimer(timerA,200); //then continue timer}msgA.byte(0)=msgA.byte(0)-1; //change the dataoutput(msgA); //输出该报文到CAN总线}
(3)打印并赋值
write输出的内容在CANoe的write界面显示
on message ABSdata, EngineData{message WheelInfo wMsg; //定义新的报文write("Message %LX received on CAN %ld",this.ID,this.CAN); //打印报文output(wMsg); //发送报文}
(4)监听报文
variables{ message 0x11 msg1;//定义要发送的报文 msTimer timer1;//定义定时器}on start{ setTimer(timer1,100);//运行canoe程序,启动定时器}/*监听总线报文0x11*/on message 0x11{ msg1.byte(0)=this.byte(0); //将总线上的报文信息赋值到新的报文}/*发送报文至总线*/on timer timer1{ msg1.dlc = 8;//定义该报文的属性 output(msg1); //输出该报文到CAN总线 setTimer(timer1,100); //重置定时器}
二、报文接收
当从CAN总线接收到消息并为该消息定义了事件过程时,才会发生消息接收过程
on message ABSdata{if (this.DIR == RX){write(“Message ID = %d is received from channel %d”, this.ID, this.CAN);write(“The signal value of car speed is %d”, this.CarSpeed);}
将从CAN通道1接收到的ABSdata消息发送到CAN通道2
on message CAN1.ABSdata{message * gatewayMsg;gatewayMsg = this;gatewayMsg.CAN = 2;output(gatewayMsg);} or on message CAN1.ABSdata{message CAN2.* gatewayMsg;gatewayMsg = this;output(gatewayMsg);}
三、周期检测
//周期时间检测结果函数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 EngineDatatestcase 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);//移除测试条件}
四、报文长度检测
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);}
五、自动化测试
includes{ }variables{ message * req,resp;}void Maintest(){ write("运行开始"); testWaitForTimeout(1000); req.id = 0x720; req.dlc = 8; req.byte(0) = 0x02; req.byte(1) = 0x10; req.byte(2) = 0x01; output(req); write("运行结束"); resp.id = 0x730; if (testWaitForMessage(resp.id,5100)) { testGetWaitEventMsgData(resp); write ("在5.1s内,收到0x730的报文"); write ("报文为:%x %x %x %x %x %x %x %x",resp.byte(0),resp.byte(1),resp.byte(2),resp.byte(3), resp.byte(4),resp.byte(5),resp.byte(6),resp.byte(7)); }}
五、循环码(Cycle)和校验码(CRC)校验
(1)循环码模拟发送
on signal_update LightCycle{ tempCycle++; tempCycle=tempCycle%16; //循环码:0~15 if(@sysvar::MyNameSpace::CheckCycle==1) //面板触发 { $MSG::LightCycle=tempCycle; } else { $MSG::LightCycle=1; }}on errorFrame{ ErrorCount++; @MyNameSpace::ErrorCount=ErrorCount; write("%d is errorcount",ErrorCount);}
(2)循环码校验
int tempSwitchCycle=5;on signal_update LightCycle{ tempSwitchCycle++; write("cycle is %d",tempSwitchCycle); tempSwitchCycle=tempSwitchCycle%16; if($LightCycle==tempSwitchCycle) { write("lightcycle is pass"); } else { write("lightcycle is fail"); } tempSwitchCycle=$MSG::LightCycle; //为保证模拟与真实值同步}
六、总线负载率
on timer MyTimer{ setTimer(MyTimer,1000); write("Busload is %d",@sysvar::_Statistics::CAN1::Busload);}
七、测量CAN周期
variable{ message 0x1cd FrameOutput={dlc=4}; msTimer MyTimer; long tempPeriod1; long tempPeriod2;}on start{ setTimer(MyTimer,200); //初始值}on timer MyTimer{ setTimer(MyTimer,@sysvar::MyNameSpace::Timer); FrameOutput.byte(1)=0x1a; output(FrameOutput);}on meaasge 0x1cd{ foat temp; tempPeriod2=timenow(); //记录当前时间 @sysvar::MyNameSpace::Period=(tempPeriod2-tempPeriod1)/100.0;//在Panel中显示周期Period write("time is %f",temp); tempPeriod1=tempPeriod2;}
八、CRC校验码(信道中是否存在错误)
CRC校验函数byte CRC(byte buffer[]){ int i; int j; Byte crc8; Byte poly;//多项式 crc8=0x00; poly=0x1d; for(i=0;1<elcount(buffer);i++) { crc8=crc8^buffer[i]; for(j=0;j<8;j++) { if(crc8 & 0x80) { crc8=crc8<<1; crc8=crc8^poly; } else { crc8=crc8<<1; } } } crc8=crc8^0x00; return(crc8);}
存储一个节点的多条报文dword appllLTxPending(long aId,dword aDlc,byte data[]){ int tempcycle=0; if (aId==0x1ab) { tempcycle=tempcycle%15; data[6]=tempcycle; tempcycle++; FrameData[1]=data[0]; FrameData[2]=data[1]; FrameData[3]=data[2]; FrameData[4]=data[3]; FrameData[5]=data[4]; FrameData[6]=data[5]; FrameData[7]=data[6]; data[7]=CRC(FrameData); } else { write("Error") } return 1;}
九、通过触发发送固定帧数报文(触发发送3帧报文)
on message MSG{ int i=0; //计数 if (@sysvar::MyNameSpace::trigger==1) //触发按键“开” { write("active"); //调试 i++; if (i<=3) { write("less than 3"); //调试 @sysvar::MyNameSpace::trigger=1; $Light1=1; //MSG.Light1报文信号赋值 } else { @sysvar::MyNameSpace::trigger=0; } } if (@sysvar::MyNameSpace::trigger==0) { write("inactive"); //调试 $Light=0; i=0; }}
十、创建自动化脚本
(1)Test Module → 创建Test Environment → 右击插入测试节点insert Network Node
→ 右击Edit 编辑测试用例(CAPL节点) →运行(先点击外面的闪电,再右击Execution执行)
十一、创建UDS
添加CDD文件
物理寻址和功能寻址ID设置
UDS——27服务Seed与Key之间的转换 (dll文件)
CDD文件创建
DD文件(定义CAN总线通信方式一种)
CDD Template文件(可定义多种通信方式)
10服务
(1)UDS功能指定模块
on start{ DiagSetTarget("ABS"); //指定节点}
on sysvar sysvar::~NameSpace::DefaultSession{ diagRequest IPC.DefaultSession_Start req; if(@this==1) { SendRequestAndCheckReturnvalue(req); //请求 write("default"); }}
variables{ byte P2[2]={0x12,0x34};}on diagRequest IPC.DefaultSession_Start{ diagResponse this resp; resp.SetParameterRaw("P2",P2,elcount(P2)); resp.SendPositiveResponse();//正反馈}on diagRequest IPC.ECU_Manufacturing_Date_Read{ diagResponse this resp; resp.SendNegativeResponse(0x7e);//负反馈 write("diagrequest");}
十二、Log函数
void WriteLOG(char NameSpace[],char Variable[],long value){ char TimeStamp[25]; //时间戳 下面定义的时间戳变量 char FinalLOG[200]; strncpy(FinalLOG,"",elCount(FinalLOG)); //字符串取空 GetCurrentTime(TimeStamp); //时间戳函数 strncat(FinalLOG,TimeStamp,25); //输入时间戳参数 write(FinalLOG); snprintf(LOG,elCount(LOG)," %s::%s==%d",~NameSpace,Variable,value);//系统变量名称 write(LOG); strncat(FinalLOG,LOG,elCount(LOG)); write(FinalLOG); putValueToControl("LOG","LOG",FinalLOG)}
十三、时间戳
void GetCurrentTime(char TimeStamp[]) //TimeStamp:时间戳{ long time[9]; getLocalTime(time); snprintf(TimeStamp,elcount(TimeStamp),"\r\n %02d:%02d%:02d",time[2],time[1],time[0]); // “\r”:换行;“\n”:回车}
十四、网络路由(网关)创建及测试
十五、输出CAN Statistic中的某个数据(不能直接输出)
(1)创建CPAL节点
on sysvar sysvar::_Statistics::can1::FramesPerBurst{ @sysvar::~NameSpace::FramePerBurst=@this; //系统变量}on message * //trace界面输出所有报文{ output(this);}
(2)write窗口输出
on sysvar sysvar::NameSpace::DefaultSession //按下Default按钮进入下面操作{ write("%d is test",@sysvar::~NameSpace::FramePerBurst);}
十六、Logging文件大小设置
十七、字符串——ACS码
打印字符串on key "a"{ long time[9]; char target[100]; snprintf(target,elcount(target),"%f action1",timenow()/100000.0); write(target); getlocaltime(time); snprintf(target,elcount(target),"%02d:%02d:%04d action2",time[2],time[1],time[0]); // 输出字符串:12:10:0005 write(target); snprintf(target,elcount(target),"channel=%d,value=%d",1,2); write(target); strncat(target,"append value",elcount(target)); //字符串拼接 write(target);}提取字符串中的数值on key "b"{ char Log[50]="this is channel 5, Value is 3";//字符串内容 char channel[5];//提取字符串 if ( (strstr_regex(Log,"[0-9]") > 0)&&( strstr_regex(Log,"[A-Z]") >0)) //根据字符串特征判定 是否字符串格式 { substr_cpy(channel,Log,strstr_regex_off(Log,0,"[0-9]"),2,elcount(channel)); //确定字符串位置,并截取字符串 2:“5,” write(channel); if(strstr(channel,",")>0) //判断是否为字符串格式 strstr与strstr_regex作用一样 { write("less than 10"); str_replace(channel,",","");//字符串替换 “5,” 转换为 “5” write(channel); } @sysvar::~NameSpace::Channel=atol(channel); //字符串转数字 }else { write("error"); }}
十八、文件解析
on sysvar sysvar::MyNamespace::File{ char path[100];//定义数组 char Data[100];//定义数组 byte Address[10];//定义数组 //初始化 long FileRef=0; long index=0; long i=0; long DataLength=0; dword Log[100]; byte CRC=0; sysGetVariableString("MyNamespace","Path",path,elcount(path)); // (类,系统变量名称,系统变量,数组长度)字符串path 转换为 数组 //读取文档: //(1)产生一个引用 //(2)读取或写入 //(3)释放引用 FileRef=openFileRead(patn,0);// 0:读 ACSII码; 1:写 二进制 while(fileGetString(Data,elcount(Data),FileRef)!=0) //对TXT文档进行一行一行读取 { if(strstr(Data,"S3")!=-1) //根据表头header 判断是否正确 每一行相同的前几位 { write("%d x",CharToByte(Data[5])); DataLength=CharToByte(Data[2])*0x10+chartobyte(Data[3]);//十六进制转换为十进制 write("%d datalength",DataLength); write("%d address[0]",( CharToByte(Data[5]) * 0x10 )+(CharToByte(Data[6]))); i=0; while(i<4) { Address[i]=(CharToByte(Data[2*i+4]))*0x10 +(CharToByte(Data[2*i+5])); i++; }i=0; write("%d A %d B %d C %d",Address[0],Address[1],Address[2],Address[3]); CRC=CharByte(Data[strlen(Data)-2])*0x10+CharByte(Data[strlen(Data)-1]); while(i<DataLength) { Log[i]=CharToByte(Data[12+1*2])*0x10+CharToByte(Data[13+1*2]); i++; } } }}ACSII码(char)转十六进制(十六进制:0~F 十进制:0~15)byte CharToByte(chaar ch){ byte val=0; if(ch >'0' && ch <'9') { val=ch-'0'; //ACSII码:0 对应十进制:48 }else if(ch >'a' && ch< 'f') { val=(ch-'a') + 10; //ACSII码:a 对应十进制:97 }else if(ch >'A' && ch< 'F') { val=(ch-'A') + 10; //ACSII码:A 对应十进制:65 } return val;}
ACSII码转十进制(十六进制:0~F 十进制:0~15)byte CharToByte(chaar ch){ byte val=0; if(ch >'0' && ch <'9') { val=ch-'0'; //ACSII码:0 对应十进制:48 }else if(ch >'a' && ch< 'f') { val=(ch-'a') + 10; //ACSII码:a 对应十进制:97 }else if(ch >'A' && ch< 'F') { val=(ch-'A') + 10; //ACSII码:A 对应十进制:65 } return val;}