如何将CAPL文件应用到Busmaster上进行测试
1、CAPL概述
做汽车电子软件CAN开发的小伙伴应该都用过Canoe,Canalyzer此类Vector系列工具,Canoe自带的二次开发工具CAPL Browser真的是很方便,通过CAPL的编程,我们可以在节点上完成更为复杂的功能需求,CAPL是一种类C语言,熟悉C语言的小伙伴应该都很容易上手,而且CAPL Browser可以直接调用DBC及CDD信号接口,这样做CAN应用测试和诊断测试就大大提升了效率。
在Simuilation菜单界面添加Network Node 或者CAPL Test Module,此处建议添加前者,后面注意事项会有提到。
2、Busmaster软件概述
实际工作中,有Canoe那当然是很好的,但是很多时候Canoe很少,我们只能用Kvaser、PCAN这类CAN工具,这时候开源免费的Busmaster软件我们可能用的就比较多,Busmaster软件功能蛮多的,基础功能就不细叙了,几个特殊的用途如下:
- 记录log,存为.log文件,然后可以转化为Canoe支持的asc格式,在Canoe软件上进行回放,分析;
- 将DBC文件转化为自身支持的DBF文件格式;
- 将CAPL Browser编写的CAPL文件转化为自身支持的CPP文件,进行同样功能的测试;
本文主要介绍第三种功能;
3、软件环境准备
- 安装Canoe软件,做车载软件开发的基本都有(没有就在某鱼上淘一个),要求支持CAPL Browser;
- 安装Busmaster软件;
- 打开Busmaster Help菜单 View Help搜索GCC,按照指示安装GCC;
我自己电脑装的是 tdm64-gcc-5.1.0-2,可供参考;
4、应用举例一:诊断10服务测试(详细叙述步骤)
这个测试很简单,就是不断发诊断10服务请求,监测ECU响应,如果在规定时间内没有收到响应,就打印错误提示,然后终止测试;
- 打开Canoe CAPL Browser编写CAPL文件
variables
{
msTimer Timer100ms;
msTimer Timer1s;
message 0x732 Message_732;
byte ReceiveTimeoutFlag = 0;
}
on timer Timer100ms
{
if( 1 == ReceiveTimeoutFlag)
{
Message_732.dlc = 8;
Message_732.byte(0) = 0x02;
Message_732.byte(1) = 0x10;
Message_732.byte(2) = 0x03;
Message_732.byte(3) = 0x00;
Message_732.byte(4) = 0x00;
Message_732.byte(5) = 0x00;
Message_732.byte(6) = 0x00;
Message_732.byte(7) = 0x00;
output(Message_732);
setTimer(Timer1s,1000);
ReceiveTimeoutFlag = 0;
}
}
on timer Timer1s
{
if( 1 != ReceiveTimeoutFlag)
{
write("接收超时,终止测试");
}
}
on Start
{
Message_732.dlc = 8;
Message_732.byte(0) = 0x02;
Message_732.byte(1) = 0x10;
Message_732.byte(2) = 0x03;
Message_732.byte(3) = 0x00;
Message_732.byte(4) = 0x00;
Message_732.byte(5) = 0x00;
Message_732.byte(6) = 0x00;
Message_732.byte(7) = 0x00;
output(Message_732);
setTimer(Timer100ms,100);
write("开始测试");
}
on message 0x612
{
setTimer(Timer100ms,100);
cancelTimer(Timer1s);
ReceiveTimeoutFlag = 1;
write("收到诊断响应");
}
编写完成之后,要确认Compile成功,没有错误;
- 将此文件用Busmaster软件中的Format Convert转化为CPP文件
1)选择.can文件
2)生成的.cpp文件名称及位置
3)如果.can文件中运用到了DBC文件中的内容,则此处需要添加DBC文件;
4)如果你没有将DBC文件转化为DBF格式过,此处需要选择上,只要转化一次就够了,DB没有修改就不需要每次都选择;
5)开始转化
此处CAPL文件中没有用到DBC,所以不需要选择dbc;
- 点击Busmaster的Node Simulation,添加Node,选择上述生成的CPP文件;
添加完成之后,点击编译,没有报错,就可以正常使用了;
注意:
编译信息在Output Window
打印信息在Trace Window
5、应用举例二: 诊断测试27服务自动解锁
此处模拟的是诊断27服务自动解锁,测试CAN诊断的时候,很多服务需要在解锁状态下才支持,测试起来很不方便,我们可以做一个脚本实现收到Seed的时候,自动计算Key,发送到总线上,完成解锁;
基本操作步骤跟上面举例一样,此处运用了DBC接口(可以不用):
/*@!Encoding:936*/
variables
{
message DiagPhyReq message_732;
}
/*06 67 03 xx xx xx xx*/
/*06 27 04 xx xx xx xx*/
on message DiagResponse
{
byte seed[4];
byte key[4];
byte level;
level = this.byte(2) +1;
if(((this.byte(1) == 0x67)&&(this.byte(2) == 0x03))||((this.byte(1) == 0x67)&&(this.byte(2) == 0x01)))
{
seed[0] = this.byte(3);
seed[1] = this.byte(4);
seed[2] = this.byte(5);
seed[3] = this.byte(6);
/***************************/
/*********caculate key******/
/***************************/
message_732.byte(0) = 0x06;
message_732.byte(1) = 0x27;
message_732.byte(2) = level;
message_732.byte(3) = key[0];
message_732.byte(4) = key[0];
message_732.byte(5) = key[0];
message_732.byte(6) = key[0];
message_732.byte(7) = 0x00;
output(message_732);
}
else if((this.byte(1) == 0x67)&&(this.byte(2) == 0x04))
{
write("解锁成功");
}
}
注意:
1、DiagPhyReq、DiagResponse是DBC里面的message;
2、转化文件的时候需要加载DBC
6、应用举例三: 模拟车载ECU自动响应
此处模拟的是车身的ECU,收到什么报文信号,反馈什么报文信号,如果不运用的DBC里面直接的信号定义,就得自己去解析信号,所以运用DBC这时候就事半功倍;
直接上代码:
/*@!Encoding:936*/
variables
{
msTimer Timer500;
msTimer Timer1000;
message HS7_VSM_INF_PROFILS Message_260;
message HS7_INFO_IHM Message_268;
message HS7_CDE_LED_PUSH Message_227;
message HS7_ETAT_CLIM_AV Message_350;
message HS7_CDE_IHM_CLIM Message_2AD;
byte LKACounter;
}
on Start
{
Message_260.DISPO_PARAM = 1;
Message_350.DMD_AC = 1;
Message_350.ENTREE_AIR = 2;
Message_350.ETAT_MONO = 0;
Message_350.PULS_AV =5;
Message_2AD.ETAT_ELEC_IHM_CLIM = 2;
Message_2AD.CONS_TEMP_CENT = 3;
setTimer(Timer500,500);
setTimer(Timer1000,1000);
}
/*06 67 03 xx xx xx xx*/
/*06 27 04 xx xx xx xx*/
on message HS7_ECRAN_INFO_PROFILS
{
byte temp;
temp = this.ECLAIRAGE_ACCOM;
//伴我回家
Message_260.ECLAIRAGE_ACCOM = temp;
//伴我回家时间
temp = this.TEMPO_EXT_PHARE;
Message_260.TEMPO_EXT_PHARE = temp;
//迎宾灯
temp = this.ECL_DECONDA;
Message_260.ECL_DECONDA = temp;
//迎宾灯时间
temp = this.TEMPO_ECL_DECONDA;
Message_260.TEMPO_ECL_DECONDA = temp;
//远近光
temp = this.FCT_ECLX_ECL_CAFR;
Message_260.FCT_MENU_ECLX_ECL_CAFR = temp;
//情景照明/氛围灯
temp = this.ECLAI_AMBI;
Message_260.ECLAI_AMBI = temp;
//氛围灯等级
temp = this.NIV_AMBIANCE;
Message_260.NIV_AMBIANCE = temp;
//自动大灯
temp = this.ECLAIRAGE_AUTO;
Message_260.ECLAIRAGE_AUTO = temp;
//紧急制动
temp = this.ARC_SENS;
Message_260.ARC_SENS = temp;
//紧急制动等级
temp = this.ARC_SENS_NIV;
Message_260.ARC_SENS_NIV = temp;
//疲劳驾驶
temp = this.DMD_MENU_DAA_ACTIV;
Message_260.FCT_MENU_DAA_ACTIV = temp;
//泊车辅助
temp = this.AAS_STATUS;
Message_260.AAS_STATUS = temp;
//车门解锁
temp = this.SELEC_OUV_PLIP;
Message_260.SELEC_OUV_PLIP = temp;
//后备箱解锁
temp = this.SELEC_ARRIERE;
Message_260.SELEC_ARRIERE = temp;
//自动后雨刮
temp = this.ESSUI_VIT_MAR;
Message_260.ESSUI_VIT_MAR = temp;
output(Message_260);
}
//message 329
on message HS7_DEMANDES_IVI_2
{
byte temp;
temp = this.DMD_FREIN_ASR_TACT_INHIB;
//牵引力控制系统
if( Message_268.P_INFO_ESP_INHIB_ASR != temp)
{
Message_268.P_INFO_ESP_INHIB_ASR = temp;
output(Message_268);
}
//车道保持辅助
temp = this.ENT_PUSH_LKA;
if(temp)
{
if(LKACounter != 3)//会受到3帧,只处理一帧
{
if(LKACounter == 0)
{
if(Message_227.SORTIE_PUSH_LKA == 0)
{
Message_227.SORTIE_PUSH_LKA = 1;
}
else
{
Message_227.SORTIE_PUSH_LKA = 0;
}
output(Message_227);
}
LKACounter++;
}
else if(LKACounter == 3)
{
LKACounter = 0;
}
}
}
on message HS7_ETAT_PUSH_TACT
{
byte temp;
dword time;
byte SendFlag = 0;
//左温度
temp = this.DMD_NIV_TEMP_AVG;
if( Message_350.VAL_CONS_TEMP_AVG != temp)
{
write("调节左温度");
Message_350.VAL_CONS_TEMP_AVG = temp;
SendFlag = 1;
}
//左温度
temp = this.DMD_NIV_TEMP_AVD;
if( Message_350.VAL_CONS_TEMP_AVD != temp)
{
write("调节右温度");
Message_350.VAL_CONS_TEMP_AVD = temp;
SendFlag = 1;
}
//AC
temp = this.DMD_PUSH_AC;
if(temp)
{
write(" AC Pressed");
if(Message_350.DMD_AC == 1)//open
{
Message_350.DMD_AC = 2;//close
}
else
{
Message_350.DMD_AC = 1;//open
}
SendFlag = 1;
}
//Recycle
temp = this.DMD_ENTREE_AIR;
if(temp)
{
write("Recycle Pressed");
if(Message_350.ENTREE_AIR == 2)//open
{
Message_350.ENTREE_AIR = 3;//close
}
else
{
Message_350.ENTREE_AIR = 2;//open
}
SendFlag = 1;
}
//SYNC
temp = this.DMD_MONO;
if(temp)
{
write("SYNC Pressed");
if(Message_350.ETAT_MONO == 0)//open
{
Message_350.ETAT_MONO = 1;//close
}
else
{
Message_350.ETAT_MONO = 0;//open
}
SendFlag = 1;
}
//blower
temp = this.DMD_NIV_PULSEUR_AV;
if(Message_350.PULS_AV != temp)
{
write("调节风量:%d",temp);
Message_350.PULS_AV = temp;
SendFlag = 1;
}
//blower +
temp = this.DMD_PULSEUR_AV_PLUS;
if(temp)
{
write("Blower + Pressed");
if(Message_350.PULS_AV <9)//open
{
Message_350.PULS_AV++;//close
}
SendFlag = 1;
}
//blower -
temp = this.DMD_PULSEUR_AV_MOINS;
if(temp)
{
write("Blower- Pressed");
if(Message_350.PULS_AV >1)
{
Message_350.PULS_AV--;
}
SendFlag = 1;
}
if(SendFlag)
{
output(Message_350);
SendFlag = 0;
}
}
on timer Timer500
{
output(Message_260);
output(Message_227);
output(Message_350);
output(Message_2AD);
setTimer(Timer500,500);
}
on timer Timer1000
{
output(Message_268);
setTimer(Timer1000,1000);
}
7、注意事项
这个功能最近用下来,其实也不是什么样格式的CAPL都可以直接转化来用,但是一些基本的测试其实都还OK,我把我调试过程中的一些注意事项列出来:
- CAPL 编程不要存在空白区域 例如:
Include
{
/*空白,没有实际代码*/
}
- DBC文件名不要过长,简单就好,例如Test.dbc
- CAPL中应定义 On Start ,不要用On Prestart ,On start 中就是初始化做的事情;
- on message 中 不能直接调用this.signal,否则cpp编译的时候会报错,例如:
on message message1
{
Message0.signal0= this.signal0;
}
应该写成如下格式:
on message message1
{
byte temp;
temp = this.signal0;
Message0.signal0= temp ;
}
- 在Simuilation菜单界面添加Network Node,不要添加CAPL Test Module,二者代码框架不太一样;
7、结尾语
我这些总结有些地方也太片面了,不过总体上步骤没啥问题,有啥问题,欢迎指正;