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 conditionA
if(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 data
output(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 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);//移除测试条件
}
四、报文长度检测
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;
}
版权归原作者 汽车人——EEA 所有, 如有侵权,请联系我们删除。