车载学习(8)——CAPL与诊断相关
CAPL与诊断相关
1.诊断脚本的编程思路
1.创建诊断请求变量
变量成CAPL编程器,右侧的symbol框进行查询。针对不同诊断类型进行选择
2.发送诊断请求
3.等待请求发送完毕、等待接收到响应。
4.获取诊断响应的响应码
2.诊断相关CPAL函数
2.1.创建诊断的请求变量
- CAPL中使用diagRequest关键字声明"诊断请求变量"
- 需使用CDD文件中定义的诊断命令限定名作为数据类型
- 可以在CAPL Browser右侧Symbolics面板中查看并复制诊断命令的限定名。
- 语法示例:
- diagRequest ECU名.诊断命令限定名 变量名;
- diagRequest 诊断命令限定名 变量名;
diagRequest DefaultSession_Start reqDefaultSessin; // 进入默认会话的诊断请求diagRequest ExtendedDiagnosticSession_Start reqExtendedSessin; // 进入扩展会话的诊断请求diagRequest ProgrammingSession_Start reqProgSession; // 进入编程会话的诊断请求
2.2基本流程函数
- diagSetTarget:设置后续诊断请求通讯的目标ECU
long diagSetTarget (char ecuName[])
- diagSendRequest:发送指定的诊断请求
long diagSendRequest (diagRequest obj)
- TestWaitForDiagRequestSent:等待直到指定诊断请求已发送
long TestWaitForDiagRequestSent (diagRequest request, dword timeout);
- TestWaitForDiagResponse:等待直到接收到指定诊断请求的响应
long TestWaitForDiagResponse (diagRequest request, dword timeout);
- diagGetResponseCode:返回指定诊断请求的最后收到响应码
long diagGetLastResponseCode (diagRequest req);
long diagGetLastResponseCode ();
- TestReportWriteDiagResponse:向测试报文中写入诊断响应的信息
TestReportWriteDiagResponse (diagRequest req);
- 一个基础流程的TestCase:
// 创建了一个进入扩展会话的“诊断请求变量”diagRequest DoorFL.ExtendedDiagnosticSession_Start reqExtendedSession;// 创建一个变量代表诊断响应返回的响应码long respCode;// 发送诊断请求diagSendRequest(reqExtendedSession);// 等待请求发送完毕if(testWaitForDiagRequestSent(reqExtendedSession, 1000) == 1){write("进入扩展会话的请求发送完毕");}else{write("进入扩展会话的请求发送失败");return;}// 等待收到诊断响应if(testWaitForDiagResponse(reqExtendedSession, 1000) == 1){write("进入扩展会话的响应已经收到");}else{write("进入扩展会话的响应未收到");return;}// 获取诊断响应的响应码respCode = diagGetLastResponseCode(reqExtendedSession);if(respCode == -1) // 肯定响应{write("进入扩展会话的响应为肯定响应");}else if(respCode == 0) // 未收到响应{write("进入扩展会话的响应还没收到");}else{write("进入会展会话的响应为否定响应,NRC为:0x%02X", respCode);} // 将诊断响应信息写入测试报告testReportWriteDiagResponse(reqExtendedSession);
2.3请求报文数据的设置
- diagSetParameter:设置请求中指定参数的物理值
long diagSetParameter (diagResponse obj, char parameterName[], double newValue)
long diagSetParameter (diagRequest obj, char parameterName[], double newValue)
long diagSetParameter (diagResponse obj, long mode, char parameterName[], double newValue)
long DiagSetParameter (diagRequest obj, long mode, char parameterName[], double newValue)
- diagSetParameterRaw:设置请求中指定参数的原始字节数组
long diagSetParameterRaw (diagResponse obj, char parameter[], byte* buffer, DWORD buffersize)
long diagSetParameterRaw (diagRequest obj, char parameterName[], byte* buffer, DWORD buffersize)
long diagGetParameterRaw (diagResponse obj, char parameterName[], byte* buffer, DWORD buffersize)
long diagGetParameterRaw (diagRequest obj, char parameterName[], byte* buffer, DWORD buffersize)
- diagSetPrimitiveByte:设置请求报文中指定索引索引的单个字节
long diagSetPrimitiveByte( diagRequest request, DWORD bytePos, DWORD newValue);
long diagSetPrimitiveByte( diagResponse response, DWORD bytePos, DWORD newValue);
- diagGetPrimitiveData:设置请求报文的原始字节数组
long diagGetPrimitiveData (diagResponse obj, byte* buffer, DWORD buffersize)
long diagGetPrimitiveData (diagRequest obj, byte* buffer, DWORD buffersize)
long diagSetPrimitiveData (diagResponse obj, byte* buffer, DWORD buffersize)
long diagSetPrimitiveData (diagRequest obj, byte* buffer, DWORD buffersize)
- 向请求报文写指定参数的实例
diagRequest DID_WindowLiftRoughPosition_Write reqWindowLiftWrite; // 声明一个诊断请求变量/*DiagSetPrimitiveByte —— 向诊断请求,设置一个原始字节*/
// DiagSetPrimitiveByte(reqWindowLiftWrite, 0, 0x2E); // 将请求报文中第0个字节设置为0x2E
// DiagSetPrimitiveByte(reqWindowLiftWrite, 1, 0x02); // 将请求报文中第1个字节设置为0x02
// DiagSetPrimitiveByte(reqWindowLiftWrite, 2, 0x01); // 将请求报文中第2个字节设置为0x01
// DiagSetPrimitiveByte(reqWindowLiftWrite, 3, 0x06); // 将请求报文中第3个字节设置为0x06/*DiagSetPrimitiveData —— 向诊断请求,设置一组原始字节*/
// {
// byte primitiveData[4] = {0x2E, 0x02, 0x01, 0x08};
// DiagSetPrimitiveData(reqWindowLiftWrite, primitiveData, 4);
// }/*DiagSetParameter —— 设置诊断请求中指定参数的值*/// diagSetParameter(reqWindowLiftWrite, "WindowLiftRoughPosition", 0x06);// diagSetParameter(reqWindowLiftWrite, "WindowLiftRoughPosition", "43,75%");/*DiagSetParameterRaw —— 设置诊断请求中指定的参数的原始字节数组*/{byte position[1] = {0x07};diagSetParameterRaw(reqWindowLiftWrite, "WindowLiftRoughPosition", position, 1);}// 发送诊断请求diagSendRequest(reqWindowLiftWrite);
2.4 响应报文数据的获取
- diagGetRespParameter:获取响应中指定参数的物理值
double diagGetRespParameter (diagRequest req, char parameterName[]);
double diagGetRespParameter (diagRequest req, long mode, char parameterName[]);
- diagGetRespParameterRaw:获取响应中指定参数的原始字节数组
long diagGetRespParameterRaw (diagRequest req, char parameterName[], byte buffer[], dword bufferLen);
- diagGetRespPrimitiveSize:获取响应报文的字节个数
long diagGetRespPrimitiveSize( diagRequest request);
- diagGetRespPrimitiveByte:获取响应报文的原始字节数组
long diagGetRespPrimitiveByte( diagRequest request, DWORD bytePos);
- diagGetIterationCount:获取响应中指定的复合参数的值的个数
long diagGetIterationCount( diagRequest obj, char complexParamQualifier[]);
long diagGetIterationCount( diagResponse obj, char complexParamQualifier[]);
long diagGetRespIterationCount( diagRequest obj, char complexParamQualifier[]);
- diagGetComplexRespParameter:获取响应中指定的复合参数中指定索引的参数值
long diagGetComplexRespParameter (diagRequest req, char parameterName[], dword iteration, char subParameter[], byte buffer[], dword bufferLen);
double diagGetComplexRespParameter (diagRequest req, char parameterName[], dword iteration, char subParameter[]);
double diagGetComplexRespParameter (diagRequest req, long mode, char parameterName[], dword iteration, char subParameter[]);
- 一个获取普通响应数据的测试Case
diagRequest ExtendedDiagnosticSession_Start reqExtendedSession; // 创建一个诊断请求变量long respCode; // 创建一个响应码变量diagSendRequest(reqExtendedSession); // 发送诊断请求if(1 != testWaitForDiagResponse(reqExtendedSession, 1000)) { // 等待收到诊断响应write("进入扩展会话的诊断请求,未收到响应!");return;}respCode = diagGetLastResponseCode(reqExtendedSession);if(-1 != respCode){write("进入扩展会话的诊断请求,收到了否定响应,否定响应码为0x%02X", respCode);return;}write("进入扩展会话的诊断请求收到了肯定响应");/*diagGetRespParameter —— 获取诊断响应中指定参数的值(数值、字符串)*/
// {
// int sessionType; // 诊断响应中返回的当前会话类型
// int p2; // 诊断响应中返回的常规超时时间(P2 Server Time)
// int p2ex; // 诊断响应中返回的特殊超时时间(P2 extended Server Time)
//
// sessionType = diagGetRespParameter(reqExtendedSession, 1, "DiagSessionType");
// p2 = diagGetRespParameter(reqExtendedSession, 1, "P2");
// p2ex = diagGetRespParameter(reqExtendedSession, 1, "P2Ex");
// write("当前的会话类型为:%d", sessionType);
// write("P2时间为:%dms", p2);
// write("P2Ex时间为:%dms", p2ex);
// }/*diagGetRespParameterRaw —— 获取诊断响应中指定参数的原始字节数组*/
// {
// byte p2[2];
// int i;
//
// diagGetRespParameterRaw(reqExtendedSession, "P2", p2, elCount(p2));
// for(i=0; i < elCount(p2); i++)
// {
// write("诊断响应中参数P2的第%d个字节的值为:0x%02X", i, p2[i]);
// }
// }/*DiagGetRespPrimitiveSize —— 获取诊断响应中的原始报文的字节数量DiagGetRespPrimitiveByte —— 获取诊断响应中的原始报文中的指定索引上的字节*/{int primitiveSize;int i;primitiveSize = DiagGetRespPrimitiveSize(reqExtendedSession);write("诊断响应的报文原始字节数量为:%d", primitiveSize);for(i = 0; i < primitiveSize; i++){byte b;b = DiagGetRespPrimitiveByte(reqExtendedSession, i);write("诊断响应的原始报文中第%d个字节为0x%02X", i, b);}}
- 获取响应复合数据的例子(诊断19 02 服务)
diagRequest DoorFL.FaultMemory_ReadAllIdentified reqReadDTC; // 创建一个诊断请求变量int respCode; // 创建一个诊断响应的响应码变量// 设置读取故障码请求的故障码状态掩码参数值为0x01diagSetParameter(reqReadDTC, "DTCStatusMask", 0x01);// 发送诊断请求diagSendRequest(reqReadDTC);// 等待直到收到诊断的响应if(1 != testWaitForDiagResponse(reqReadDTC, 1000)){write("读取故障码列表的诊断请求,未收到响应!");return;}// 获取诊断响应的响应码respCode = diagGetLastResponseCode(reqReadDTC);if(-1 != respCode){write("进入扩展会话的诊断请求,收到了否定响应,否定响应码为0x%02X", respCode);return;}{int dtcCount;int i;// 获取诊断响应中的指定的符合参数的参数值的个数dtcCount = diagGetRespIterationCount(reqReadDTC, "ListOfDTC");write("读取故障码请求的响应报文中,返回的故障信息的数量:%d", dtcCount);// 获取诊断响应中的每一组故障信息的参数值for(i = 0; i < dtcCount; i++){char dtcText[100];long dtc;int status;diagGetComplexRespParameter(reqReadDTC, "ListOfDTC", i, "DTC", dtcText, elCount(dtcText));dtc = diagGetComplexRespParameter(reqReadDTC, "ListOfDTC", i, "DTC");status = diagGetComplexRespParameter(reqReadDTC, "ListOfDTC", i, "StatusOfDTC");write("读取到的第%d个故障信息的故障码码值为:0x%06X,故障文本为:%s,状态码为:0x%02X", i, dtc, dtcText, status);}}
2.5 根据获取的种子计算key的函数
- diagGenerateKeyFromSeed:根据种子值计算key依赖于dll文件
long diagGenerateKeyFromSeed ( byte seedArray[], dword seedArraySize, dword securityLevel, char variant[], char ipOption[], byte keyArray[], dword maxKeyArraySize, dword& keyActualSize); // form 1
long DiagGenerateKeyFromSeed(char ecuQualifier[], byte seedArray[] , dword seedArraySize, dword securityLevel, char variant[], char option[] , byte keyArray[], dword maxKeyArraySize, dword& keyActualSizeOut); // form 2
- 一个获取ECU权限的Case:
/*进入到扩展会话*/{diagRequest DoorFL.ExtendedDiagnosticSession_Start reqExtendSession;diagSendRequest(reqExtendSession); // 发送“进入扩展会话”的诊断请求testWaitForDiagResponse(reqExtendSession, 1000); // 等到收到诊断的响应if(diagGetLastResponseCode() != -1){write("进入扩展会话的诊断请求,未收到肯定响应");return;}}/*申请安全种子 --> 根据种子计算出Key -->发送Key来解锁ECU*/{diagRequest SeedLevel_0x01_Request reqGetSeed; // 获取种子的请求diagRequest KeyLevel_0x01_Send reqSendKey; // 发送Key的请求byte seedArray[2];byte keyArray[255];dword keyActualSize;int i;diagSendRequest(reqGetSeed); // 发送“获取安全种子”请求testWaitForDiagResponse(reqGetSeed, 1000); // 等待收到诊断的响应if(diagGetLastResponseCode() != -1){write("获取安全种子的诊断请求,未收到肯定响应");return;}// 获取响应中返回的种子的字节数组diagGetRespParameterRaw(reqGetSeed, "SecuritySeed", seedArray, elCount(seedArray));write("获取到的安全种子的字节为:0x%02X 0x%02X", seedArray[0], seedArray[1]);// 根据种子计算出KeydiagGenerateKeyFromSeed(seedArray, elCount(seedArray), 1, "", "", keyArray, elCount(keyArray), keyActualSize);write("生成的Key的字节数:%d", keyActualSize);write("生成的Key的字节为:");for(i = 0; i < keyActualSize; i++){write("\t0x%02X", keyArray[i]);}// 给“发送Key”的请求设置参数(SecurityKey)diagSetParameterRaw(reqSendKey, "SecurityKey", keyArray, keyActualSize);// 发送key的请求diagSendRequest(reqSendKey);}
3.诊断小项目
3.1 0x10服务(切换会话功能)的测试
- 切换到默认会话
- 从默认会话切换到拓展会话
- 从拓展会话切换到编程会话
CAPL测试代码:
/*@!Encoding:936*/
includes
{}variables
{int respCode; // 诊断响应码diagRequest DefaultSession_Start reqDefaultSessin; // 进入默认会话的诊断请求diagRequest ExtendedDiagnosticSession_Start reqExtendedSessin; // 进入扩展会话的诊断请求diagRequest ProgrammingSession_Start reqProgSession; // 进入编程会话的诊断请求
}MainTest()
{diagSetTarget("DoorFL");testModuleTitle("DoorFL ECU 诊断功能的测试");testGroupBegin("ECU会话状态的切换", "切换到:默认会话、扩展会话、编程会话");TC1_DefaultSession();TC2_ExtendedSession();TC3_ProgrammingSession();testGroupEnd();
}testcase TC1_DefaultSession()
{testCaseTitle("TC1", "测试用例1:切换到默认会话");diagSendRequest(reqDefaultSessin); // 发送诊断请求testWaitForDiagResponse(reqDefaultSessin, 1000); // 等待收到诊断的响应respCode = diagGetLastResponseCode(reqDefaultSessin); // 获取诊断的响应码if(respCode == -1){int P2, P2Ex;testStepPass("进入默认会话", "进入默认会话成功,返回了肯定响应");P2 = diagGetRespParameter(reqDefaultSessin, 1, "P2");P2Ex = diagGetRespParameter(reqDefaultSessin, 1, "P2Ex");if(P2 == 150){testStepPass("常规超时时间参数P2", "P2时间符合预期值150ms");}else{testStepFail("常规超时时间参数P2", "P2时间不符合预期值150ms");}if(P2Ex == 2000){testStepPass("特殊超时时间参数P2Ex", "P2Ex时间符合预期值2000ms");}else{testStepFail("特殊超时时间参数P2Ex", "P2Ex时间不符合预期值2000ms");}}else if(respCode == 0){testStepFail("进入默认会话", "进入默认会话失败,未收到响应");}else{testStepFail("进入默认会话", "进入默认会话失败,返回了否定响应");}testReportWriteDiagResponse(reqDefaultSessin); // 将响应信息写入测试报告
}testcase TC2_ExtendedSession()
{testCaseTitle("TC2", "测试用例2:切换到扩展会话");diagSendRequest(reqExtendedSessin); // 发送诊断请求testWaitForDiagResponse(reqExtendedSessin, 1000); // 等待收到诊断的响应respCode = diagGetLastResponseCode(reqExtendedSessin); // 获取诊断的响应码if(respCode == -1){int P2, P2Ex;testStepPass("进入扩展会话", "进入扩展会话成功,返回了肯定响应");P2 = diagGetRespParameter(reqExtendedSessin, 1, "P2");P2Ex = diagGetRespParameter(reqExtendedSessin, 1, "P2Ex");if(P2 == 150){testStepPass("常规超时时间参数P2", "P2时间符合预期值150ms");}else{testStepFail("常规超时时间参数P2", "P2时间不符合预期值150ms");}if(P2Ex == 2000){testStepPass("特殊超时时间参数P2Ex", "P2Ex时间符合预期值2000ms");}else{testStepFail("特殊超时时间参数P2Ex", "P2Ex时间不符合预期值2000ms");}}else if(respCode == 0){testStepFail("进入扩展会话", "进入扩展会话失败,未收到响应");}else{testStepFail("进入扩展会话", "进入扩展会话失败,返回了否定响应");}testReportWriteDiagResponse(reqExtendedSessin); // 将响应信息写入测试报告
}testcase TC3_ProgrammingSession()
{testCaseTitle("TC3", "测试用例3:切换到编程会话");diagSendRequest(reqProgSession); // 发送诊断请求testWaitForDiagResponse(reqProgSession, 1000); // 等待收到诊断的响应respCode = diagGetLastResponseCode(reqProgSession); // 获取诊断的响应码if(respCode == -1){int P2, P2Ex;testStepPass("进入编程会话", "进入编程会话成功,返回了肯定响应");P2 = diagGetRespParameter(reqProgSession, 1, "P2");P2Ex = diagGetRespParameter(reqProgSession, 1, "P2Ex");if(P2 == 150){testStepPass("常规超时时间参数P2", "P2时间符合预期值150ms");}else{testStepFail("常规超时时间参数P2", "P2时间不符合预期值150ms");}if(P2Ex == 2000){testStepPass("特殊超时时间参数P2Ex", "P2Ex时间符合预期值2000ms");}else{testStepFail("特殊超时时间参数P2Ex", "P2Ex时间不符合预期值2000ms");}}else if(respCode == 0){testStepFail("进入编程会话", "进入编程会话失败,未收到响应");}else{testStepFail("进入编程会话", "进入编程会话失败,返回了否定响应");}testReportWriteDiagResponse(reqProgSession); // 将响应信息写入测试报告
}
- 跟踪窗口
- testmodule 结果
3.2 完成写入、读取ECU序列号的诊断功能的测试
- 切换到拓展会话,解锁ECU
- 写入ECU序列号
- 读取ECU序列号并验证
- 实际CAPL测试代码
/*@!Encoding:936*/
includes
{}variables
{int respCode; // 诊断响应码diagRequest ExtendedDiagnosticSession_Start reqExtendedSession; // 进入扩展会话的诊断请求diagRequest DoorFL.KeyLevel_0x01_Send reqKeyLevel_0x01; // 发送秘钥的诊断请求diagRequest DoorFL.SeedLevel_0x01_Request reqSeedLevel_0x01; //获取种子的诊断请求diagRequest DoorFL.SerialNumber_Write reqSerialNumber_W; // 写序列号diagRequest DoorFL.SerialNumber_Read reqSerialNumber_R; // 读序列号
}Maintest()
{diagSetTarget("DoorFL"); // 设置诊断目标ECUtestModuleTitle("ECU序列号的诊断功能测试");testModuleDescription("ECU序列号写入、读取,主要涉及诊断0x22、0x2E服务");TC1_Ecu_SerialNum_RW();}testcase TC1_Ecu_SerialNum_RW()
{byte seedArray[2];byte keyArray[8];dword keybyteSize;dword Serialnum;dword SerialnumRead;int i;testCaseTitle("TC1","测试用例1:ECU序列号读写诊断测试");// 进入到拓展会话diagSendRequest(reqExtendedSession);// 等待收到诊断的响应testWaitForDiagResponse(reqExtendedSession, 1000); // 获取诊断响应的响应码if(diagGetLastResponseCode() != -1){write("进入拓展会话的诊断请求,未收到肯定响应");testStepFail("进入拓展会话失败");}else{write("进入拓展会话的诊断请求,收到肯定响应");testStepPass("成功切换为拓展会话");}// 申请安全种子diagSendRequest(reqSeedLevel_0x01); // 等待收到诊断的响应testWaitForDiagResponse(reqSeedLevel_0x01, 1000); // 获取诊断响应的响应码if(diagGetLastResponseCode() != -1){write("申请安全种子的诊断请求,未收到肯定响应");testStepFail("申请安全种子失败");}else{write("申请安全种子的诊断请求,收到肯定响应");testStepPass("成功申请安全种子");}// 获取响应中返回的种子的字节数组diagGetRespParameterRaw(reqSeedLevel_0x01,"SecuritySeed",seedArray,elCount(seedArray));write("获取到的安全种子的字节为:0x%02X 0x%02X", seedArray[0], seedArray[1]);// 根据种子计算出keydiagGenerateKeyFromSeed(seedArray,elCount(seedArray),1,"","",keyArray,elCount(keyArray),keybyteSize);write("生成的Key的字节数:%d", keybyteSize);write("生成的Key的字节为:");for(i = 0;i < keybyteSize; i++){write("\t0x%02X", keyArray[i]);}// 给发送Key请求设置key参数diagSetParameterRaw(reqKeyLevel_0x01,"SecurityKey",keyArray,keybyteSize);// 发送Key的请求diagSendRequest(reqKeyLevel_0x01);// 等待收到诊断的响应testWaitForDiagResponse(reqKeyLevel_0x01, 1000); // 获取诊断响应的响应码if(diagGetLastResponseCode() != -1){write("发送key的诊断请求,未收到肯定响应");testStepFail("解锁ECU失败");}else{write("发送key的诊断请求,收到肯定响应");testStepPass("成功解锁ECU");}// 写入ECU序列号Serialnum = 0x11223344;diagSetParameter(reqSerialNumber_W, "SerialNumber", Serialnum);diagSendRequest(reqSerialNumber_W);// 等待收到诊断的响应testWaitForDiagResponse(reqSerialNumber_W, 1000); // 获取诊断响应的响应码if(diagGetLastResponseCode() != -1){write("写ECU序列号的诊断请求,未收到肯定响应");testStepFail("写ECU序列号请求失败");}else{write("写ECU序列号的诊断请求,收到肯定响应");testStepPass("写ECU序列号请求成功");}// 读取ECU序列号diagSendRequest(reqSerialNumber_R);// 等待收到诊断的响应testWaitForDiagResponse(reqSerialNumber_R, 1000); // 获取诊断响应的响应码if(diagGetLastResponseCode() != -1){write("读ECU序列号的诊断请求,未收到肯定响应");testStepFail("读ECU序列号请求失败");}else{write("读ECU序列号的诊断请求,收到肯定响应");testStepPass("读ECU序列号请求成功");}SerialnumRead = diagGetRespParameter(reqSerialNumber_R,"SerialNumber");write("读取的ECU序列号0x%x",SerialnumRead);if(SerialnumRead != Serialnum){write("读写ECU序列号失败");testStepFail("读写ECU序列号失败");}else{write("读写ECU序列号成功");testStepPass("读写ECU序列号成功");} }
- trace:
- testreport
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/254760.html
如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!