CANoe——CAPL

一、CAPL

CAPL(Communication Access Programming Language)基于C语言开发的,专门用于CANalyzer和CANoe工具环境。

二、语法

CAPL程序的结构包含了头文件、全局变量、事件函数、自定义函数

头文件:(CAPL Include File)

(1)功能函数

注释:
/*                     
Function,value      函数名称
description         函数描述
called  everthing   函数被调用
calls               函数内包含其他函数
return              函数返回值
parameter           函数参数(输入)
*/

(2)文件路径保存→Node文件

 includes{ }                           头文件是对其他文件及dll文件的包含说明

variables{ }                           是对全局变量的声明定义

char letter_a = “a”; 
int number_days_in_year = 365; 
message 0x003 xxx;
timer one_second; 
int j, k = 2; 
double x = 33.7; 
char p;

工程中用到的各类事件

on start{ }

on timer{ }            对应报文周期相关

流程:

(1)Pre-Start

(2)Start(闪电的按键)

(3)各类事件结构(message ; signal ; key)

(4)Pre-Stop

(5)Stop(esc退出的按键)

(1)注释

1. /* 注释内容 */ 
2. /* 注释内容 
      注释内容*/
3. /* 
 注释内容
 */ 
4. // 注释内容

(2)变量名称

A.变量名、函数名和数组名可以由字母和数字和下划线组成,但是首字母不能是数字

B.对于用户定义的变量,小写字母和大写字母是不同的变量

C.CAPL支持的关键字是不区分大小写

(3)运算符

(4) 数据类型

A.整型

类型有/无符号 长度描述语法结构
byteunsigned1B字节,8位,无符号
wordunsigned2B字,16位,无符号
dwordunsigned4B双字,32位,无符号
qwordunsigned8B整型,64位,无符号
int signed2B短整型,16位

int value = 20;         十进制

int value2 = 0x14;   十六进制

longsigned4B长整型,32位
int64signed8B整型,64位

B.浮点型

类型长度描述语法结构
float8B单精度float value = 0.23
double8B双精度

B.字符

类型长度语法结构
char1B

(1)单引号:

char value = ‘B’; char value2 = ‘8’; char value3 = ‘?’;

(2)支持使用ASCII字符集:

char value = 0x42; char value2 = 0x38; char value3 = 0x3F;

(3)字符串

char value[30] = “Here’s a string in C and CAPL”;

C.复合类型

类型语法结构
结构struct

struct Data {

                       int age;

                       long hight;

                       char name[50];

                  };

枚举enum

enum Colors { Red, Green, Blue }; // 默认 从 0开始,每个元素+1

enum State { State_Off = -1, State_On = 1 }; //可以指定值

数组array

(1)

char alphabet[27] = “ABCDEFGHIJK”;

alphabet[0] = ‘A’

(2)整形或者浮点型数组

int sample_data[4] = { 100, 300, 500, 600 };

(3)二维数组

int M[4][5] = {
{ 10, 5, -3, 17, 82 },
{ 9, 0, 0, 8, -7 },
{ 32, 20, 1, 0, 14 },
{ 0, 0, 8, 7, 6 }
};

多维数组elCount(数组名)

D.特殊类型

类型描述代码
报文使用关键字message来声明一个报文变量

message 0xA m1;

message EngineDate m3;

诊断报文

DiagRequest ServiceQualifier request;//诊断请

DiagResponse ServiceQualifier response;//诊断响应

系统变量
定时器

msTimer myTimer; //声明一个毫秒定时器myTimer   单位:ms

timer myTimer;//声明一个秒定时器myTimer   单位:s

(5)关键字

breakcasecharcontinuedefaultdodoubleelsefloatforif
longreturnswitchwhlieenumstructautoconstexterngotoregister
signedsizeofstatictypedefunionunsignedvolatileintshortthismessage
dbMsg*signal*

service

singnal*

diag

Request

sysval*

diag

Response

timertestcase

this用法:

1.在普通方法中,this代表该方法运行所创建的那个对象;

2.在构造方法中,this代表该方法运行所创建的那个对象;

write用法:

(1)打印输出

void用法:

1.不返回任何格式 (有返回值时,不能用该关键词)

return用法 

1.返回值

格式输出
“%ld” or “%d”整数十进制格式显示
“%lx” or “%x”整数十六进制格式显示
“%lX” or “%X”整数十六进制格式显示 (字母大写显示)
“%lu” or “%u”无符号整数格式显示
“%lo” or “%o”整数八进制格式显示
“%s”显示字符串
“%g”浮点数显示(最终显示为科学计数法)
“%f”浮点数显示
“%c”显示一个字符
“%I64d” or “%lld”64位整数的十进制格式显示
“%I64x” or “%llx”64位整数的十六进制格式显示
“%I64X” or “%llX”64位整数的十六进制格式显示(字母大写显示)
“%I64u” or “%llu”64位无符号整数的十进制格式显示
“%I64o” or “%llo”64位整数的八进制格式显示
“%%”显示一个%
void WRITE()
{
  write("Hello world");
  write("number = %d",number);
  write("number = %x",number);
  write("number = %X",number);
  write("number = %o",number);
  write("number = %u",number);
  write("str1 = %s",str1);
  write("str = %g",str);
  write("str = %f",str);
  write("str = %5.3f",str);
  write("str = %15.33f",str);
  write("str = %6.8g",str);
  write("str1 = %c",str2);
  write("number = %I64d",number);
  write("number = %I64x",number);
  write("number = %I64X",number);
  write("number = %I64o",number);
  write("number = %I64u",number);
}


/*输出*/
Hello world
number = 160
number = a0
number = A0
number = 240
number = 160
str1 = abcd
str = 1.23457e+008
str = 123456789.987654
str = 123456789.988
str = 123456789.987654330000000000000000000000000
str = 1.2345679e+008
str1 = b
number = 712964571296
number = a6000000a0
number = A6000000A0
number = 12300000000240
number = 712964571296

Message

msg.CAN = 1               /*帧的传输通道*/
msg.ID  = 0x600           /*帧的ID*/
msg.name=Msg1             /*帧的名称*/

/*DIR和RTR结合使用*/
msg.DIR = Tx  / Rx        /*帧的传输方向:Rx(received);Tx(sent)*/
msg.RTR =1                /*帧的传输请求的状态:0(无远程传输请求);1(远程传输请求)*/

msg.type=RXREMOTE         /*TYPE = (RTR << 8) | DIR*/

msg.dlc = 8               /*帧的长度*/

(6)事件类型

类型事件名执行条件语法结构
系统事件preStartCANoe初始化时执行on preStart { . . . }
start测量开始时执行on start { . . . }
stopMeasurement测量结束时执行on stopMeasurement { . . . }
CAN消息事件自定义接受到指定消息时执行on message 自定义名 { . . . }
时间事件定时时间到后执行on timer 自定义名 { . . . }
键盘事件指定按键按下时on key 按键名 { . . . }
CAN控制器事件busoff硬件检测到busoff时执行on busoff { . . . }
errorActive硬件检测到errorActive时执行on errorActive { . . . }
errorPassive硬件检测到errorPassive时执行on errorPassive { . . . }
warningLimit硬件检测到warningLimit时执行on warningLimit { . . . }
错误帧事件errorFrame硬件检测到错误帧时执行on errorFrame { . . . }

系统事件

系统事件的发生顺序依次是:preStart-->start-->preStop-->stopMeasurement

on preStart                   /*系统事件,初始化时执行*/
{
   write("Measurement started!");
   msg_Count = 0;
}
 
 
on start                     /*系统事件,工程开始时执行*/
{
   write("start Node A");
   setTimer(cycTimer,20);
   CallAllOnEnvVar(); // CANoe only
}
 
 
on preStop                  /*系统事件,工程预备停止时执行;发生在stopMeasurement事件前面*/
{
   message ShutdownReq m;
    output(m);
   DeferStop(1000);
}
 
 
on stopMeasurement         /*系统事件,工程停止时执行*/
{
   write("Message 0x%x received: %d", msg.id, msg_Count);
}

 CAN控制器事件

on errorPassive               /*CAN控制器事件:硬件检测到errorPassive时执行*/
{
   ...
   write("CAN Controller is in errorPassive state")
   write(" errorCountTX = %d", this.errorCountTX);
   write(" errorCountRX = %d", this.errorCountRX);
};
 

on busOff                     /*CAN控制器事件:硬件检测到BusOff时执行*/
{
   int errRxCnt;
   int errTxCnt;
   int channel;
   double timestamp; // [seconds]
 
   timestamp = (double)timeNow() / (double)100000;
   channel = this.can;
   errRxCnt = this.errorCountRX;
   errTxCnt = this.errorCountTX;
   Write("Bus Off: time=%f channel=%d, errRxCnt=%d, errTxCnt=%d",
   timestamp, channel, errRxCnt, errTxCnt);
 
   resetCanEx(channel);
}

CAN报文事件

on message 123         		/*接收到123(10进制)这个ID的报文时执行*/
on message 0x441       		/*接收到0x441(16进制)这个ID的报文时执行*/
on message BCM 	       		/*接收到BCM(工程dbc文件中的报文名)这个报文时执行*/
on message*	      			/*接收到任意报文时都执行(注意*与message之间没有空格)*/
on message 0x300-0x444	 	/*接收到这个范围内的ID报文时执行*/
{
  	write(“Received %x”,this.id);	 /*打印接收到的报文id*/
  	write(“Received Message %d in total!”,count);
}

报文的索引及发送操作(通过报文的信号(msg.VoiceType)去操作)

void TxMsg_VoiceStatus(void) 
{
    message VoiceStatus msg;         /*将工程中dbc中定义的VoiceStatus这条报文取名为msg*/
    msg.VoiceType = @VoiceType;      /*对应赋值给到报文的信号,通过报文别名"msg."调出*/
    msg.VoiceOperation = @VoiceOperation;
    output(msg);                     /*通过output指令发送该报文*/
}

(通过数据类型(msg.byte(0))去操作 

void TxMsg_VoiceStatus(void) 
{
    message VoiceStatus msg;         /*将工程中dbc中定义的VoiceStatus这条报文取名为msg*/
    msg.byte(0) = @VoiceType;        /*报文第1个数据字节*/
    msg.word(1) = @VoiceOperation; ; /*报文从第1个字节开始的一个字(2个字节)*/
    output(msg);                     /*通过output指令发送该报文*/
}

键盘事件

on key ‘a’      	/*在小写输入法下,按下键盘的’A’键时执行*/
on key ‘A’      	/*在大写输入法下,按下键盘的’A’键时执行*/
on key ‘ ’      	/*按下键盘的空格键时执行,注意单引号中间是有空格的*/
on key 0x20     	/*按下键盘的空格键时执行*/
on key F2      	    /*按下键盘的’F2’键时执行*/
on key CtrlF3      	/*同时按下键盘的’Ctrl’键和’F3’键时执行*/
on key*      		/*按下键盘的任意键时都会执行(注意*与key之间没有空格) */
{
  	write(“The Key Is Press”);
}

定时器事件

variables
{
  msTimer Timer1;    		/*在variables中声明一个以ms为单位的定时器变量Timer1*/
}


msTimer myTimer;
message 100 msg;
...
on key 'a' {
   setTimer(myTimer,20);
}
...
on timer myTimer {
   output(msg);
}


on start
{
setTimer(Timer1,100); /将Timer1的定时时间设定为100ms,并启动它/
}

on timer Timer1 /定义的Timer1时间事件,每100ms执行一次/
{
setTimer(Timer1,100); /启动下一个周期循环/
}

on key ‘a‘ /键盘事件,按下键盘’A’键时执行/
{
cancelTimer(Timer1); /停止Timer1这个100ms执行一次的定时器/
}

错误帧事件(在硬件检测到错误帧时执行

on errorFrame       /*错误帧事件:硬件检测到错误帧时执行*/
{
  write("The error has occur"); 
}

系统变量事件

通过”on sysvar”定义系统变量事件;该事件会在指定的系统变量值有新的输入时执行;

注:

系统变量与环境变量差别只在于环境变量是在dbc文件中定义的

on sysvar IO::DI_0
{
$Gateway::IOValue = @this;
}


on sysvar SysVar1	 /*系统变量事件:指定的系统变量值有新的输入时执行*/
{
	 write("The SysVar1 is %d",@SysVar1);
}

环境变量事件

通过”on envVar”定义环境变量事件;该事件会在指定的环境变量值有新的输入时执行

注:

环境变量常常用于关联上一个面板控件,当我们对控件进行操作时,对应改变关联上的环境变量值

on envVar BCM_HightBeamAlarm    /*环境变量事件:指定的环境变量值有输入时执行*/
{
	  byte num=0;
	  num = getValue(this);     /*可以使用getValue(环境变量名/this关键字)获取指定的环境变量的值*/
	  if(num == 1)
	  {
	    write("The envVar is %d",@BCM_HightBeamAlarm);  
	  }
	  else
	  {
	    putValue(this,1);/*使用putValue(环境变量名/this关键字,设定的值)改变指定的环境变量的值;直接赋值的话,格式是@BCM_HightBeamAlarm = 1; */
	    write("Change envVar to %d",@BCM_HightBeamAlarm);
	  }
}

 

(7)函数

函数执行条件语法结构
setTimer()设置开启一个定时器,时间到后关闭setTimer(Timer1,100)
cancelTimer关闭定时器cancelTimer(Timer1)
write()消息输出打印write(“The error has occur”)
output发送报文output(msg)

通用函数:

 计算函数

 字符串函数

 CAN总线函数

 诊断函数

diagResize:

调整诊断对象的大小以匹配指定的参数迭代,或将总线消息的大小设置为给定的字节数

diagRequest  PAS3.*  pasDiagReqst;
dword diagLen;
diagLen = stringToBytes(diagString, rawDiagReqst);
diagResize(pasDiagReqst, diagLen);

diagSetPrimitiveByte:

用于设定诊断对象指定字节的数值 

  for(i=0;i<diagLen;i++)
  {
    diagSetPrimitiveByte(pasDiagReqst, i, diagData[i]);
  }

 diagSetPrimitiveData:
用于设置完整服务原语的原始数据(通过传输协议传输的所有数据)

PrintDiagRequestBytes( diagRequest * req)
{
BYTE primitiveRaw[4095];
long size;
size = DiagGetPrimitiveData( req, primitiveRaw, elcount( primitiveRaw));
if( size > 0)
write( "Request = (%d)[%02x ...]", size, primitiveRaw[0]);
else
write( "Request: error %d", size);
}

TestReportWriteDiagObject / TestReportWriteDiagResponse:
用于在测试报告中增加诊断请求或响应的报文打印 

diagRequest  PAS3.*  pasDiagReqst; 
testReportWriteDiagObject(pasDiagReqst);

 TestWaitForDiagRequestSent:
用于定义在指定时间内将要求的诊断请求发送出去

DiagRequest SerialNumber_Read req;
long result;

DiagSetTarget("Door");
req.SendRequest();
// waits until request is completely sent
if (TestWaitForDiagRequestSent(req, 2000)== 1)
  TestStepPass("Request was sent successfully!");
else
  TestStepFail("Request could not be sent!");
TestWaitForDiagResponse(req, 2000);

 TestWaitForDiagResponse:
用于定义在指定时间内是否收到诊断请求的响应

diagResponse PAS3.*  pasDiagRespd;
const cApplicationTimeoutMs = 5000;
result = testWaitForDiagResponse(pasDiagReqst, cApplicationTimeoutMs)

diagGetLastResponse

用于获取最新的诊断请求响应 

diagResponse PAS3.*  pasDiagRespd;
diagGetLastResponse(pasDiagRespd);

 diagGetPrimitiveData :
用于读取一个诊断服务的原始数据

PrintDiagRequestBytes( diagRequest * req)
{
BYTE primitiveRaw[4095];
long size;
size = DiagGetPrimitiveData( req, primitiveRaw, elcount( primitiveRaw));
if( size > 0)
write( "Request = (%d)[%02x ...]", size, primitiveRaw[0]);
else
write( "Request: error %d", size);
}

diagGetPrimitiveByte :

用于读取诊断服务中的某一字节的数据 

diagIsPositiveResponse / diagIsNegativeResponse:
用于判断回复的诊断相应是否为正/负响应,如果是则返回一个不为0的数值 

on diagResponse *
{
  // Handle the ambiguity of neg responses by treating them as '*'
  if( diagIsNegativeResponse ( this ) )
  {
    write( "Received negative response for service 0x%x, code 0x%x",
    (long) diagGetParameter( this, "SIDRQ_NR" ),
    (long) diagGetParameter( this, "NRC" ) );
  }
}

(8)流程控制

控制类型执行条件语法结构
if 

if 括号内的表达式为真,或者非0,则执行if 下面的语句

if (speed > 60)

{

  //花括号内的语句都会执行

   write("line 1");

   write("line 2");

}

如果没有花括号,则只执行if下面的第一行语句

if (speed > 60)

write("line 1");//这一行语句受if语句控制

write("line 2");//这一行语句不受if语句控制

if else如果下面表达式为真或者非0,则执行语句块1,否则执行语句块2

if (speed > 60)

   write("line 1");

}

else if(speed > 80)

  write("line 2");

}

else

{

  write("line 3");

}

switchswitch ( operator ) 

 case ‘+’: result = value1 + value2; 
 break; 
 case ‘-’: result = value1 – value2; 
 break;
 case ‘*’: result = value1 * value2; 
 break; 
 default: write (“Unknown operator.”); 
 break; 
while循环

while( a < 20 )

{

  write("a 的值: %d\n", a);

  a++;

}

do…while

循环

当条件为 true 时执行循环。 当条件为 false 时,退出循环

注:

do…while 循环与 while 循环类似,但是 do…while 循环会确保至少执行一次循环

/* do 循环执行,在条件被测试之前至少执行一次 */

do

{    write("a 的值: %d\n", a);

     a = a + 1;

}while( a < 20 );

for循环

/* for 循环执行 */

for( a = 10; a < 20; a = a + 1 )

{   write("a 的值: %d\n", a);

}

/* for 循环执行 */

for( ; a < 20; )//第1,3个表达式为空

{

   write("a 的值: %d\n", a);

   a = a + 1;

}

break

当 break 语句出现在一个循环内时,循环会立即终止

嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环

continue
return

不带参数的return也可以退出循环语句

用来在函数中,返回一个值或者值的表达式

while( a < 20 )
   {
      write("a 的值: %d\n", a);
      a++;
      if( a > 15)
      {
         /* 使用 break 语句终止循环 */
          return;
      }
   }
————————————————
for (i = 1; i <= y; i++)

result *= x;

return result;

 三、案例

(1)周期消息发送

 仿真或测试时向总线模拟发送周期消息

variables
{ 
    msTimer myTimer;
    message 100 msg;
}
on key 'a' {
    setTimer(myTimer,20);
}
on timer myTimer {
    output(msg);
    setTimer(myTimer,20);
}

(2)应用报文Request/Response

 ECU请求/应答式的功能

variables
{
    message BCM_Request  tBCM_Request;   //请求报文
    message BCM_Response tBCM_Response;  //响应报文
    int result   = 0;
    int waitTime = 1000;
}
 
void MainTest()
{
   TestModuleTitle ("Test BCM Features");
   TestModuleDescription ("Check all features in BCM.");
 
   TestGroupBegin("BCM Wiper Feature", "Check the perfomance of Wiper");
     Check_Wiper_Feature(0,0);   //测试雨刮关闭功能
     Check_Wiper_Feature(1,1);   //测试雨刮开启功能
   TestGroupEnd();  
}

//自定义函数
testcase Check_Wiper_Feature(int request, int response )
{
    tBCM_Request.WiperRequest.phys = request;// 报文名称.信号.信号值
    output(tBCM_Request);
    //测试请求发出去后1000ms内是否收到BCM的响应信号。
    result = TestWaitForSignalMatch(BCM_Response::WiperResponse,response,waitTime);
    passResult(result,request,response);
}
void passResult(long result,int request,int response)
{
    switch(result){
        case  1: TestStepPass("1.0","Test Pass     - request : %d expect response : %d ",request,response);break;
        case  0: TestStepFail("1.0","Timeout       - request : %d expect response : %d ",request,response);break;
        case -1: TestStepFail("1.0","General error - request : %d expect response : %d ",request,response);break;
        case -2: TestStepFail("1.0","Signal is not valid");break;
        default:break;
    }
}

(3)检测总线中周期报文的发送周期

dword ChkCreate_MsgRelCycleTimeViolation (Message aObservedMessage, double aMinRelCycleTime, double aMaxRelCycleTime, Callback aCallback);
 
dword ChkStart_MsgRelCycleTimeViolation (Message aObservedMessage, double aMinRelCycleTime, double aMaxRelCycleTime, Callback aCallback);

dword ChkCreate_MsgAbsCycleTimeViolation (Message aObservedMessage, duration aMinCycleTime, duration aMaxCycleTime, char[] aCallback);
 
dword ChkStart_MsgAbsCycleTimeViolation (Message aObservedMessage, duration aMinCycleTime, duration aMaxCycleTime, char[] aCallback);


案例:

testcase CheckMsgEngineData()
{
  float aMinRelCycleTime = 0.9;  
  float aMaxRelCycleTime = 1.1;  
 
  // Information for test report.
  TestCaseTitle("TC 4", "Check cycle time of message EngineData");
 
  // checks the cycle time of the message
  gCycCheckId = ChkStart_MsgRelCycleTimeViolation (EngineData, aMinRelCycleTime , aMaxRelCycleTime );
  TestAddCondition(gCycCheckId);
  // sequence of different actions and waiting conditions
  TestWaitForTimeout(1000);
  TestRemoveCondition(gCycCheckId);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

汽车人——EEA

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

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

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

打赏作者

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

抵扣说明:

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

余额充值