当前位置: 代码迷 >> 综合 >> CANoe DLL编程(四)—— CANoe中的SendKey的响应机制
  详细解决方案

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制

热度:79   发布时间:2023-09-20 13:13:34.0

? 相关文章

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制

  • ?CANoe DLL编程(一)—— Visual Studio 创建DLL以及动态调用

  • ?CANoe DLL编程(二)—— 创建CANoe适用的DLL以及调用

  • ?CANoe DLL编程(三)——DLL和回调函数

  • ?CANoe DLL编程(五)——通过VS 生成 SendKey.dll

  • ?CANoe DLL编程(六)—— DLL 的二次封装

  • ?本章节内容演示源码下载,点击跳转?


?前言

  • 每个在使用CANoe的同学,都绕不开Sendkey 的,这一节,我们先不讲dll怎么制作和生成,我们还是先结合帮助文档和官方示例来弄明白,seedkey的响应机制,然后在下章节再讲解怎么创建 SendKey DLL

  • 本节文章基于仿真节点测试(无真实ECU)

  • 阅读本文请有点耐心哈

  • 软件环境:
    win10 x64
    visual studio 2019
    CANoe 11 x64

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制

文章目录

  • ? 相关文章
  • ?前言
  • ? CANoe官方示例解读
  • ? 通过诊断控制台看seedkey响应机制
  • ? 通过 `Network Node CAPL`脚本 看`seedkey`响应机制
  • ? 通过 seedkey的回调函数看响应机制
  • ? 通过`XML Test Node CAPL`脚本 看`seedkey`响应机制
  • ?总结

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制

? CANoe官方示例解读

1?? 我们先把C:\Users\Public\Documents\Vector\CANoe\Sample Configurations 11.0.55\CAN\Diagnostics\UDSSystem 这个工程拷贝一份,不要破坏源码

  • 下图是打开示例工程,我们先看下DLL在哪里加载进来的

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


? 通过诊断控制台看seedkey响应机制


2?? 打开 DoorFL - Diagnostic console,顺序执行下面的指令看下输出结果,是能够正常解锁的

  1. 进入拓展会话 10 03
  2. 请求种子 27 01
  3. 发送密钥 27 02

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


3?? DoorFL是仿真节点,这里没有实物ECU,所有诊断的响应都是仿真实现的。

  • 我们看DoorFL.can 里面定义了很多的 on diagRequest XXX ,当我们在 DoorFL - Diagnostic console 发送方诊断的时候,就会触发这些on diagRequest 然后做出response

  • 下面我把DoorFL.can 中对seed key的诊断响应代码贴出来,并且添加了一些打印信息,方便我们理解和观察

  • 当我们从 DoorFL - Diagnostic console发送了 27 01请求种子的指令后,on diagRequest DoorFL.SeedLevel_0x01_Request事件会触发,然后下面代码会生成一个随机种子反回给 DoorFL - Diagnostic console,诊断控制台会根据seedkey.dll自动计算key,然后自动填写到27 02 xx xx xx ,等待用户发送。这是诊断控制台自己的机制

on diagRequest DoorFL.SeedLevel_0x01_Request
{
    diagResponse this resp;write("****** (27 01 reponse) is 11111 step exec ******");refreshS3Timer();if (ExtendedSession==@sysvar::%NODE_NAME%::CurrentSession || ProgrammingSession==@sysvar::%NODE_NAME%::CurrentSession) {
    gLastSecuritySeedLevel1=random(0x10000);write("****** return Seed is 0x%x ******",gLastSecuritySeedLevel1);diagSetParameter(resp, "SecuritySeed", gLastSecuritySeedLevel1); // Use 2-byte random value as seeddiagSendPositiveResponse(resp);}else {
    ResetSession();diagSendNegativeResponse(this, cNRC_ConditionsNotCorrectOrRequestSequenceError); }
}

4?? 在上一步用户 发送了 27 02 xx xx xx 后,on diagRequest DoorFL.KeyLevel_0x01_Send事件会触发,然后check key是否正确,正确就postival response 否则NRC

on diagRequest DoorFL.KeyLevel_0x01_Send
{
    diagResponse this resp;long securityKey, receivedKey;byte seedArray[2];byte keyArray[2];dword keyArraySize;write("****** (27 02 reponse) is 33333 step exec ******");  refreshS3Timer();if (ExtendedSession==@sysvar::%NODE_NAME%::CurrentSession || ProgrammingSession==@sysvar::%NODE_NAME%::CurrentSession) {
    seedArray[0]=(gLastSecuritySeedLevel1>>8)&0xFF;seedArray[1]=gLastSecuritySeedLevel1&0xFF;diagGenerateKeyFromSeed(seedArray, 2, 17, "", "", keyArray, 2, keyArraySize); // Use 2-byte random value as seedsecurityKey=keyArray[0];securityKey=(securityKey<<8) + keyArray[1];receivedKey=diagGetParameter(this, "SecurityKey");if (securityKey==receivedKey) {
    @sysvar::%NODE_NAME%::SecurityStatus=Unlocked;@sysvar::%NODE_NAME%::SecurityLevel=Unlocked_Level_1;diagSendPositiveResponse(resp);return;}}ResetSession();diagSendNegativeResponse(this, cNRC_InvalidKey); 
}

5?? 下面的打印结果是DoorFL.can中我们添加的打印信息。对比代码理解下。

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


? 通过 Network Node CAPL脚本 看seedkey响应机制

1?? 看下图创建一个节点TesterPanel ,我们不用诊断控制台发送诊断,我们在CAPL文件TesterPanelControl.can文件中通过诊断SendRequest() 发送种子请求,并在这个文件中处理 响应和生成key,并把key发送出去。

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


2?? 下面我们再把27 服务的整个响应机制写下来,具体代码,上一步骤贴出来过的,在这就拿掉了。

  • 当我们在TesterPanelControl.can发送了 27 01请求种子的指令后, DoorFL.can:on diagRequest DoorFL.SeedLevel_0x01_Request事件会触发,然后把种子reponse 回来,Door作为仿真ECU,这和上面的处理是一致的。
  • 限于篇幅,具体内容就补贴出来了,可以参考源码
on diagRequest DoorFL.SeedLevel_0x01_Request
{
    
}

3?? Door仿真ECU返回种子后,会触发TesterPanelControl.can:on diagResponse 事件,代码在这里通过 diagGenerateKeyFromSeed 函数生成key,然后以 27 02 xx xx xx 发送出去

on diagResponse DoorFL.SeedLevel_0x01_Request
{
    diagRequest DoorFL.KeyLevel_0x01_Send reqKeySend;diagRequest DoorFL.Variant_Coding_Write reqCodingWrite;word seed;word securityKey;byte seedArray[2];byte keyArray[2];dword keyActualSizeOut;seed=this.GetParameter("SecuritySeed");seedArray[1]=(seed>>8)&0xFF;seedArray[0]=seed&0xFF;diagGenerateKeyFromSeed(gECU, seedArray , 2, 1, "", "" , keyArray, elcount(keyArray), keyActualSizeOut); securityKey=(((word)keyArray[1])<<8) | keyArray[0];write("****** create key (27 02 send) is 22222 step exec ******");write("****** create key is 0x%x ******",securityKey);reqKeySend.SetParameter("SecurityKey", securityKey);// Checking on return values indicating an error when sending the requests or when receiving the responses was omitted here to simplify the examplereqKeySend.SendRequest();
}

4?? DoorFL.can: 收到发送了 27 02 xx xx xx 后,下面的事件会触发,然后check key 是否正确,正确就postival response 否则NRC,

  • 限于篇幅,具体内容就补贴出来了,可以参考源码
on diagRequest DoorFL.KeyLevel_0x01_Send
{
    
}

5?? 我们在 TesterPanelControl.can: 文件中再添加 on key ‘a’,把种子请求诊断发出去,对比看下打印结果。

On key 'a' // unlock
{
    diagRequest DoorFL.SeedLevel_0x01_Request rqRequestSeed;rqRequestSeed.SendRequest();
}

6?? 对比代码, 看下打印结果。

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


? 通过 seedkey的回调函数看响应机制

1?? 上面的两种方式其实同属一种类型,都是通过调用函数diagGenerateKeyFromSeed来生成的key。下面CANoe还提供了另外一种函数DiagStartGenerateKeyFromSeed当执行了这个函数,就会调用_Diag_GenerateKeyResult回调函数,携带这key

  • 对比下面两个函数长得不同

  • diagGenerateKeyFromSeed

  • DiagStartGenerateKeyFromSeed

  • 我们把TesterPanelControl.can:文件中的 on diagResponse DoorFL.SeedLevel_0x01_Request 注释掉,添加下面的回到函数代码:

on diagResponse DoorFL.SeedLevel_0x01_Request
{
    char gECU[20]="DoorFL";BYTE seed[2];int count;write("****** create key (27 02 send) is 22222 step exec ******");count = this.GetParameterRaw( "SecuritySeed", seed, elcount(seed));// _Diag_GetError is called when an error occursDiagStartGenerateKeyFromSeed( gECU,seed, elcount( seed), 1);
}_Diag_GenerateKeyResult( long result, BYTE computedKey[])
{
    diagRequest DoorFL.KeyLevel_0x01_Send reqKeySend;write("******* callback function is exec *******");if( 0 != result){
    write( "Error: computing key returned %d", result);return;}// Success, i.e. a key was computed, so send it to the ECUreqKeySend.SetParameterRaw( "SecurityKey", computedKey, elcount( computedKey));reqKeySend.SendRequest();
}
_Diag_GetError (char buffer[])
{
    //called if error in DiagGenerateKeyFromSeed occurswrite("Diagnostic Error: %s", buffer);
}On key 'a' // unlock
{
    diagRequest DoorFL.SeedLevel_0x01_Request rqRequestSeed;rqRequestSeed.SendRequest();
}

2?? 按键‘a’,对比代码观察打印结果,_Diag_GenerateKeyResult回调函数被执行了

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


3?? 这两个长得像的函数还有点不同点

  • diagGenerateKeyFromSeed 返回值非0的时候 就会自动触发 回调函_Diag_GetError
    DiagStartGenerateKeyFromSeed 报错的话,不会触发 _Diag_GetError
  • 下面我们把DiagStartGenerateKeyFromSeed 相关代码在注释掉,把 on diagResponse DoorFL.SeedLevel_0x01_Request 代码放出来。
  • 把按照下面贴图更改,改成1,

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


4?? -点击 按键‘a’测试看下结果, 根据打印结果我们看到,程序进入了_Diag_GetError 函数中。

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


? 通过XML Test Node CAPL脚本 看seedkey响应机制

1?? 恰好这个工程跟也有个XML Test Node ,我就图个简单,在原来的case中直接修改,添加我们自己的seedkey 代码

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


2?? 添加的seedkey 代码如下,也添加一些打印信息,方便理解

export testcase TCSendDiagnosticRequest(int tcId)
{
    diagRequest DoorFL.SeedLevel_0x01_Request  rqRequestSeed;diagRequest  DoorFL.ExtendedDiagnosticSession_Start reqExtSession;diagRequest DoorFL.KeyLevel_0x01_Send reqKeySend;word seed;word securityKey;byte seedArray[2];byte keyArray[2];dword keyActualSizeOut;char gECU[20]="DoorFL";dword keyArraySize;DiagSendRequest(reqExtSession);TestWaitForDiagResponse(reqExtSession,100);rqRequestSeed.SendRequest();TestWaitForDiagResponse(rqRequestSeed,100);seed = diagGetRespParameter (rqRequestSeed,"SecuritySeed");  write("*********Get Response seed :%x *********",seed);seedArray[0]=(seed>>8)&0xFF;seedArray[1]=seed&0xFF;diagGenerateKeyFromSeed(gECU,seedArray, 2, 1, "", "", keyArray, 2, keyArraySize); // Use 2-byte random value as seedsecurityKey=keyArray[0];securityKey=(securityKey<<8) + keyArray[1];write("*********create key :%x *********",securityKey);reqKeySend.SetParameter("SecurityKey", securityKey);// Checking on return values indicating an error when sending the requests or when receiving the responses was omitted here to simplify the examplereqKeySend.SendRequest();}

3?? ,观察打印结果
CANoe DLL编程(四)—— CANoe中的SendKey的响应机制


CANoe DLL编程(四)—— CANoe中的SendKey的响应机制

End

?总结

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制

CANoe DLL编程(四)—— CANoe中的SendKey的响应机制

? 这节文章写的不好,内容有点多,而且有点绕了,小伙伴多担待哈。

? 有需要演示中所用demo工程的,可以关注下方公众号网盘自取啦,感谢阅读。
CANoe DLL编程(四)—— CANoe中的SendKey的响应机制

  • ?要有最朴素的生活,最遥远的梦想,即使明天天寒地冻,路遥马亡!

  • ? 有手机的小伙伴可以加下交流群,在车载诊断领域的一个小小圈子,群里有网盘资料源码,可能有你需要的呢,平时可以交流技术,聊聊工作机会啥的。

  • ?如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。
    CANoe DLL编程(四)—— CANoe中的SendKey的响应机制