封装了几个CAPL发送诊断相关函数,具有较高的可复用性
Posted 蚂蚁小兵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了封装了几个CAPL发送诊断相关函数,具有较高的可复用性相关的知识,希望对你有一定的参考价值。
- 🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用
- 🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】
- 🍅 玩转CANoe,博客目录大全,点击跳转👉
📘前言
- 🍅 诊断相关的CAPL函数绝对是日常写测试用例用的最多的,但是由于这些函数重载的非常多,什么场景下改用什么格式的,初学者常常混淆不清,本节就通过测试实例来帮大家弄清楚它们
- 🍅 考虑到内容还是比较多,打算分两个文章,本文,主要集中讲解下
发送诊断时
用到的相关函数,而且我将他们进一步封装了,具备较高的可复用性。 - 🍅 演示软硬件环境
Windows11 x64
;CANoe 11 SP2 x64
,Python 3.8 x64
目录
📙 诊断发送相关函数
通过下面的内容,你会掌握下面这些诊断函数的实战用法
diagSetTarget
TestReportWriteDiagObject
DiagSendRequest
TestWaitForDiagRequestSent
DiagGetLastResponseCode
diagSetParameter(数值)
diagSetParameter(数值字符串)
diagSetParameterRaw (byte数组)
DiagSetPrimitiveByte
diagSetPrimitiveData
diagSetTarget (设置诊断对象)
在CAPL code 的代码中如果要发送诊断就需要先设置诊断目标ECU,在(CDD/ODX).等诊断数据库中定义
long diagSetTarget (char ecuName[])
:设置tester 要对哪个ECU进行诊断通信
如果你有很多项目,又想要代码通用,可以使用
diagGetTargetCount
和diagGetTargetQualifier
函数组合,可以获取到该工程下的诊断目标ECU的名字,然后再进行设置
testcase TC_013()
long i;
char ecuQual[100];
i = diagGetTargetCount();
while( i-- > 0)
diagGetTargetQualifier( i, ecuQual, elcount(ecuQual));
write( "Target %d: %s", i, ecuQual);
封装了三个诊断发送函数
参数是diagrequest
Send_DiagRequest_diag(diagrequest *DiagReq)
是一个相对简单的封装函数,发送诊断,并且期望响应positival
,否则就failed
,这一个函数使用了下面的capl 函数:
-
diagSetTarget :发送诊断前,要先设置诊断ECU的名字(CDD/ODX).
-
TestReportWriteDiagObject: 打印发送诊断信息到测试报告
-
DiagSendRequest:发送诊断
-
TestWaitForDiagRequestSent:等待诊断发送完毕
-
TestReportWriteDiagResponse:诊断的响应内容打印到测试报告
-
TestWaitForDiagResponse :等待诊断响应完毕,这个函数的返回值需要只有特别注意:
0,在指定时间内没有响应 ;
1,在指定时间内给出了响应(不管时正相应还是负响应);
<0 ,诊断出现错误,可能是TP层,具体要看help文档 -
DiagGetLastResponseCode :读取最后一次诊断的响应码,
TestReportWriteDiagResponse
只能判断有没有响应,但是无法判断是postival还是NRC,所以还需要DiagGetLastResponseCode
函数来判断
-1 :positival
0 : 没响应
大于0 : NRC,比如NRC12,13,31等等
//发送诊断,并判断是否是正响应
// 参数是diagrequest类型
void Send_DiagRequest_diag(diagrequest *DiagReq)
char tempStr[100];
long retVal,lastCode;
// 下面两个参数应该是个全局变量
const long SendTimeout = 100;//ms
const long ReceiveTimeout = 1000;//ms
TestReportWriteDiagObject(DiagReq); //打印发送诊断
DiagSendRequest(DiagReq);
if (TestWaitForDiagRequestSent(DiagReq, SendTimeout)== 1)
//等待诊断响应
retVal = TestWaitForDiagResponse( DiagReq, ReceiveTimeout);
TestReportWriteDiagResponse(DiagReq); //打印诊断接收
if(retVal == 1) // 有响应
retVal = DiagGetLastResponseCode(DiagReq);
if(retVal == -1)//有正响应
TestStepPass("Positival response received, as expected.");
else
TestStepFail("Expected Positival response, But Not.");
else
TestStepFail("Expected Positival response, But Not.");
else
TestStepFail("Request could not be sent!");
- testcase 代码:
testcase TC_001()
diagRequest DefaultSession_Start DefaultSession_Start; //1001
diagRequest ProgrammingSession_Start ProgrammingSession_Start; //1002
diagSetTarget("xxx");// xxx是ECU节点名称
Send_DiagRequest_diag(DefaultSession_Start);
Send_DiagRequest_diag(ProgrammingSession_Start);
- xml 代码
<testmodule title="诊断函数测试" version="1.1">
<externalref type="url" title="CSDN蚂蚁小兵">
https://blog.csdn.net/qq_34414530
</externalref>
<testgroup title="TestGroup_1">
<capltestcase name="TC_001" title="TC_001"/>
</testgroup>
</testmodule>
- 测试报告:
参数是byte 数组
参数是diagrequest可能更需要依赖cdd数据库中的定义,有时候,我们不需要cdd数据库啊文件,希望传递时要发送的数据数组
- diagrequest *DiagReq ; 这样定义可以自定义诊断
- diagResize :重新设置要发送发送诊断报文的大小
- DiagSetPrimitiveByte :将byte数组循环赋值给诊断
//发送诊断,并判断是否是正响应
//参数是诊断Byte数组
void Send_DiagRequest_arrary(byte diag_data[])
char tempStr[100];
long retVal,lastCode;
int i ;
diagrequest *DiagReq ;
// 下面两个参数应该是个全局变量
const long SendTimeout = 100;//ms
const long ReceiveTimeout = 1000;//ms
diagResize(DiagReq,elCount(diag_data));
for(i=0;i<elCount(diag_data);i++)
DiagSetPrimitiveByte(DiagReq,i,diag_data[i]);
TestReportWriteDiagObject(DiagReq); //打印发送诊断
DiagSendRequest(DiagReq);
if (TestWaitForDiagRequestSent(DiagReq, SendTimeout)== 1)
//等待诊断响应
retVal = TestWaitForDiagResponse( DiagReq, ReceiveTimeout);
TestReportWriteDiagResponse(DiagReq); //打印诊断接收
if(retVal == 1) // 有响应
retVal = DiagGetLastResponseCode(DiagReq);
if(retVal == -1)//有正响应
TestStepPass("Positival response received, as expected.");
else
TestStepFail("Expected Positival response, But Not.");
else
TestStepFail("Expected Positival response, But Not.");
else
TestStepFail("Request could not be sent!");
- testcase 代码:
testcase TC_002()
byte ReadECUVersion[3]=0x22,0x47,0x03; //1002
diagSetTarget("xxx");
Send_DiagRequest_arrary(ReadECUVersion);
- xml 代码:
<testmodule title="诊断函数测试" version="1.1">
<externalref type="url" title="CSDN蚂蚁小兵">
https://blog.csdn.net/qq_34414530
</externalref>
<testgroup title="TestGroup_1">
<capltestcase name="TC_001" title="TC_001"/>
<capltestcase name="TC_002" title="TC_002"/>
</testgroup>
</testmodule>
- 测试结果
参数是diagrequest的功能完善版
-
上面的两个函数,比较简单,只能对正相应做出判断,所以我设计了下面这个稍微复杂点的诊断发送函数,可以通过参数ExpResCode来判断期望的响应,SendType参数可以用来指定物理/功能寻址
-
不再重复说明,后面封装的函数参数都是 diagrequest类型。
-
特别要注意理解
TestWaitForDiagResponse
和DiagGetLastResponseCode
的区别,不清楚的向上翻翻
// @DiagReq :发送诊断
// @ExpResCode:可以对诊断响应进行判断,可以期望正响应,NRC,或者没响应
// @SendType :可以指定物理请求还是功能请求
void Send_DiagRequest_diag(diagrequest *DiagReq, long ExpResCode,byte SendType)
char tempStr[100];
long retVal,lastCode;
// 下面两个参数应该是个全局变量
const long SendTimeout = 100;//ms
const long ReceiveTimeout = 1000;//ms
const long NoResponse = 0;
const long PostitiveResponse = -1;
const long NrcResponse_12 = 12;
const long NrcResponse_13 = 13;
TestReportWriteDiagObject(DiagReq); //打印发送诊断
if (SendType == 1) //功能寻址
DiagSendFunctional(DiagReq);
else //物理寻址
DiagSendRequest(DiagReq);
if (TestWaitForDiagRequestSent(DiagReq, SendTimeout)== 1)
//等待诊断响应
retVal = TestWaitForDiagResponse( DiagReq, ReceiveTimeout);
TestReportWriteDiagResponse(DiagReq); //打印诊断接收
switch( retVal)
case 0: // Timeout: The ECU did not respond .
if(ExpResCode == NoResponse)
TestStepPass("No response received,as expected.");
else
TestStepFail("Response was received when no response was expected.");
break;
case 1: // response received
lastCode = DiagGetLastResponseCode(DiagReq);
switch( lastCode)
case -1: // postival response
if(ExpResCode == PostitiveResponse)
TestStepPass("Positival response received, as expected.");
else
snprintf(tempStr,elcount(tempStr),"positival response was received when NRC 0x%x was expected.",ExpResCode);
TestStepFail(tempStr);
break;
default: // NRC response
if(ExpResCode == lastCode)
snprintf(tempStr,elcount(tempStr),"NRC 0x%x was received, as expected.",ExpResCode);
TestStepPass(tempStr);
else
snprintf(tempStr,elcount(tempStr),"NRC 0x%x was received when Positival response was expected.",lastCode);
TestStepFail(tempStr);
break;
default: // error
snprintf(tempStr,elcount(tempStr),"there a Error code received = %.",retVal);
TestStepFail(tempStr);
- testcase 代码:
testcase TC_003()
const long NoResponse = 0;
const long PostitiveResponse = -1;
const long NrcResponse_7E = 0x7E;
const long phy_diagRequest = 0;
diagRequest DefaultSession_Start DefaultSession_Start; //1001
diagRequest ProgrammingSession_Start ProgrammingSession_Start; //1002
diagSetTarget("xxx");
Send_DiagRequest_diag(DefaultSession_Start, PostitiveResponse , phy_diagRequest);
Send_DiagRequest_diag(ProgrammingSession_Start,NrcResponse_7E,phy_diagRequest);
- xml 代码:
<testmodule title="诊断函数测试" version="1.1">
<externalref type="url" title="CSDN蚂蚁小兵">
https://blog.csdn.net/qq_34414530
</externalref>
<testgroup title="TestGroup_1">
<capltestcase name="TC_001" title="TC_001"/>
<capltestcase name="TC_002" title="TC_002"/>
<capltestcase name="TC_003" title="TC_003"/>
</testgroup>
</testmodule>
- 测试结果
diagSetParameter函数
diagSetParameter: 对发送的诊断服务,设置其cdd中定义的parameter的值
主要有几种方法实现:
diagSetParameter(数值)
diagSetParameter(数值字符串)
diagSetParameterRaw (byte数组)
diagSetPrimitiveData :对整个诊断报文进行赋值
DiagSetPrimitiveByte(一个字节一个字节的设置)
diagSetParameter(数值)
- 下面用19 04 读snapshot 服务,说下 diagSetParameter 的使用方法 ,我们在发送诊断之前,可以对诊断的parameter重新赋值,
testcase TC_008()
byte resData[256];
int64 resValue;
diagRequest FaultMemory_Read_snapshot_record FaultMemory_Read_snapshot_record; //1904
diagSetTarget(ECU_Name);
diagSetParameter(FaultMemory_Read_snapshot_record,"DTC",0x540297); //0x540297 高压DTC
Send_DiagRequest_diag(FaultMemory_Read_snapshot_record);
diagSetParameter(字符串)
- 下面用19 04 读snapshot 服务,说下 diagSetParameter 的使用方法 ,我们在发送诊断之前,可以对诊断的parameter重新赋值,
- diagSetParameter 两种用法,参数可以是数值0x540297,也可以是数值字符串"0x540297"
testcase TC_009()
byte resData[256];
int64 resValue;
diagRequest FaultMemory_Read_snapshot_record FaultMemory_Read_snapshot_record; //1904
diagSetTarget(ECU_Name);
diagSetParameter(FaultMemory_Read_snapshot_record,"DTC","0x540297"); //0x540297 高压DTC
Send_DiagRequest_diag(FaultMemory_Read_snapshot_record);
diagSetParameterRaw (字节数组)
- diagSetParameterRaw 算是diagSetParameter函数的一个变种吧,可以通过byte数组进行设置,当写的参数很多的时候,这种方式很方便
testcase TC_010()
byte dtc[3]= 0x54,0x02,0x97;
int64 resValue;
diagRequest FaultMemory_Read_snapshot_record FaultMemory_Read_snapshot_record; //1904
diagSetTarget(ECU_Name);
diagSetParameterRaw (FaultMemory_Read_snapshot_record,"DTC",dtc,elCount(dtc)); //0x540297 高压DTC
Send_DiagRequest_diag(FaultMemory_Read_snapshot_record);
DiagSetPrimitiveByte (诊断报文的字节设置)
- 上面都是对cdd诊断文件中的Parameter的重新赋值,有时候cdd写的很烂,参数定义的乱七八糟,parameter不可用,那我 就可以用DiagSetPrimitiveByt可以对诊断的指定位置进行赋值
testcase TC_011()
byte dtc[3]= 0x54,0x02,0x97;
int64 resValue;
diagRequest FaultMemory_Read_snapshot_record FaultMemory_Read_snapshot_record; //1904
diagSetTarget(ECU_Name);
DiagSetPrimitiveByte(FaultMemory_Read_snapshot_record,2,dtc[0]);
DiagSetPrimitiveByte(FaultMemory_Read_snapshot_record,3,dtc[1]);
DiagSetPrimitiveByte(FaultMemory_Read_snapshot_record,4,dtc[2]);
diagSetParameterRaw (FaultMemory_Read_snapshot_record,"DTC",dtc,elCount(dtc)); //0x540297 高压DTC
Send_DiagRequest_diag(FaultMemory_Read_snapshot_record);
diagSetPrimitiveData (整个诊断报文)
-
上面的几种设置诊断发送的函数,都是针对某一个parameter或者某一个byte ,而diagSetPrimitiveData 就是对整个诊断报文进行赋值
-
diagSetPrimitiveData :对整个诊断进行赋值
-
diagGetPrimitiveData :读取整个诊断的值
-
DiagGetPrimitiveSize:返回整个诊断的字节数
testcase TC_012()
byte diaSendData[6]= 0x19,0x04,0x54,0x02,0x97,0x01;
byte diaSendData_2[6];
long i ;
diagRequest FaultMemory_Read_snapshot_record FaultMemory_Read_snapshot_record; //1904
diagSetTarget(ECU_Name);
// 设置诊断发送的数据
diagSetPrimitiveData (FaultMemory_Read_snapshot_record,diaSendData,elCount(diaSendData));
Send_DiagRequest_diag(FaultMemory_Read_snapshot_record);
🌎总结
-
🍅 本节就重点讲解了诊断发送相关,诊断接收在下篇点击跳转👉诊断想用接收函数
-
🍅 网盘脚本路径:CANoe学习资料›CANoe学习资料›CANoe演示工程代码›CAPL Scripts>诊断函数
- 🚩要有最朴素的生活,最遥远的梦想,即使明天天寒地冻,路遥马亡!
- 🚩如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。
以上是关于封装了几个CAPL发送诊断相关函数,具有较高的可复用性的主要内容,如果未能解决你的问题,请参考以下文章