CANoe——CAPL案例

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;
}

  • 34
    点赞
  • 306
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汽车人——EEA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值