通过Canoe CAPL发送报文和诊断
前言
canoe可以通过IG面板添加报文进行发送,为什么还需要通过节点的CAPL发送报文,从我个人的使用感受上来说,以下2种情况需要通过CAPL发送报文:
1.需要在接收到什么报文,或者什么条件触发之后在限定的时间内发送什么报文,这个时候通过IG面板,时间上来不及。
2.有的报文是带有校验位的,比如MAC校验,CRC校验,E2E校验等,通过IG面板发的是固定数据的报文,当某个信号改变之后,校验位也是要改变的,通过CAPL则比较容易实现。
1、怎么导入DBC和CDD文件
当测试工程导入DBC文件后,CAPL中就可以直接用DBC里的报文描述定义报文。
导入CDD以后,CAPL可以直接调用CDD里的诊断。
由于CDD文件的制作需要购买硬件license,这里随便拷贝安装目录下的示例用的DBC和CDD,路径如下。
导入DBC
导入CDD
2、通过Canoe CAPL发送报文
2.1CAPL的main函数在哪里
CAPL的是没有main函数的,或者说有但是被隐藏了,无法编辑修改,至少初学者不用考虑这个。
CAPL不是面向过程也不是面向对象的编程语言,它是面向事件触发的,真实的实现原理我也不懂,但是可以理解为,发生了什么样的事情就会触发一个函数,比如检测到按键’a’按下会触发一个函数
on key 'a'
{
/*Do what you want to do*/
}
如果非要找一个类似与main的入口函数,如下2个,这两个我感觉作用一致,我常用第二个on start,就是说工程开始运行的时候,开始运行这个事件就触发了on start这个函数,可以理解为函数入口,但是如果CAPL里同时出现类似于on key ‘a’这个函数,没有在on start函数里调用,当按下键盘’a’的时候,on key ‘a’依然会触发。
就是说on start和on key是同等级的,都是事件处理函数,就看发生了哪个事件就会跳转到哪里去
on prestart
{
}
on start
{
}
on key 'a'
{
/*Do what you want to do*/
}
2.2定义一条报文
报文是一种类似于int,unsigned char的数据类型,使用关键字message来定义声明一条报文。
当在CAPL的variables里写message后选中message,按F1快捷键,可以查看帮助文档里,介绍怎么定义一条报文
手册里的0xA时报文ID的十六进制表达,100时报文ID的十进制表达。
前面讲过当导入DBC以后,可以根据DBC里报文的描述来定义报文,
比如这里我们想发送DBC里的 DOOR_I(0x1F0),这条报文
在variables里敲完message后空格,编辑器会自动匹配DBC里定义的报文,选择我们想要的DOOR_I,命名为Msg_Tx_Test_0x1F0;
message DOOR_l Msg_Tx_Test_0x1F0;
message 0xB Msg_Tx_Test_0x0B;
message 100 Msg_Tx_Test_0x64;//Dec 100
还有一种情况就是,需要定义一个报文ID可变的报文,比如说,很多ECU休眠以后需要接收到唤醒报文才能激活,但是唤醒报文的ID不是固定的,而是一个连续的范围,比如说ECU接收到从0x700-0x800的报文以后唤醒,我们想测试ECU有没有满足这个功能要求,不可能定义0x700-0x800这么多条报文去测试。
最好是能声明一个ID不确定的报文,在使用的时候再给ID赋值。定义方式如下:
message * Msg_Test_Wakeup;
2.3发送一条报文
发送报文的方式比较简单,output(Msg),Msg就是定义报文的名称。
一般在发送报文之前,要对报文的属性做配置,这里假设我们检测到按键’a’以后发送0xB这条报文,前面我们定义0xB报文名称为Msg_Tx_Test_0x1F0,那在函数里编辑完这个名字后,按‘.’,编辑器会提示有各种配置项目可选
常见的有dlc来确定报文发送的长度。
FDF配置是否为canfd
byte()配置要发送的各个字节的数据
其他配置项,可以自己试着选择配置下,不配置的话都有个默认项。
on key 'a'
{
Msg_Tx_Test_0x0B.dlc=6;//定义报文长度,默认为0
Msg_Tx_Test_0x0B.can=1;//定义报文发送在哪条can线上,默认为1
Msg_Tx_Test_0x0B.byte(0)=0x05;//定义报文的第一个字节数据,默认为0
output(Msg_Tx_Test_0x0B);//发送报文
}
在trace窗口里可以看到,当按下键a后,总线上出现一条报文0xB
发送没有定义具体ID的报文则是在这些配置项的基础上加一个id的配置
on key 'b'
{
Msg_Test_Wakeup.id=0x555;
Msg_Test_Wakeup.dlc=8;
output(Msg_Test_Wakeup);
}
当发送DBC里定义的报文的时候,属性里有个特别的,就是DBC报文里定义的信号,可以在这里直接作为一个属性直接配置,这个还是挺好用的,假设这个信号在dbc报文里占据2.5个byte,就不用把这个数据做拆分再分别赋值给byte0,1,2,可以直接通过赋值信号,一步完成。当然这里是只占一个byte。大家以后用到的时候就能体会到这个的方便之处了。
2.4周期发送一条报文
实际应用中,只发单帧是不够的,很多报文都是需要周期发送的。
CAPL里实现周期发送报文的方式是通过定时器。
定义一个定时器,设置一个时间,假设是100ms,那从设置开始100ms,会触发一个定时器时间函数。
定时器的关键字是timer单位是s,还有mstimer 单位是ms。
1.定义声明定时器
msTimer Timer_TxMsg_0xB;
2.在工程运行的时候设置定时器的时间为100ms,设置定时器时间的函数是:void setTimer(msTimer t, long duration);
on start
{
setTimer(Timer_TxMsg_0xB,100);
}
3.100ms后触发的事件函数为on timer Timer_TxMsg_0xB,值得注意的是,定时器运行完之后就结束了,反映在这里就是,当这个事件触发处理完之后就结束了,只发了一帧报文,需要在最后重新设置定时器时机为100ms,这样就能实现周期发送的目的了。
on timer Timer_TxMsg_0xB
{
Msg_Tx_Test_0x64.dlc=8;
output(Msg_Tx_Test_0x64);
setTimer(Timer_TxMsg_0xB,100);
}