封装了几个CAPL发送诊断相关函数,具有较高的可复用性

Posted 蚂蚁小兵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了封装了几个CAPL发送诊断相关函数,具有较高的可复用性相关的知识,希望对你有一定的参考价值。


📘前言

  • 🍅 诊断相关的CAPL函数绝对是日常写测试用例用的最多的,但是由于这些函数重载的非常多,什么场景下改用什么格式的,初学者常常混淆不清,本节就通过测试实例来帮大家弄清楚它们
  • 🍅 考虑到内容还是比较多,打算分两个文章,本文,主要集中讲解下发送诊断时用到的相关函数,而且我将他们进一步封装了,具备较高的可复用性。
  • 🍅 演示软硬件环境 Windows11 x64CANoe 11 SP2 x64Python 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进行诊断通信


如果你有很多项目,又想要代码通用,可以使用

  • diagGetTargetCountdiagGetTargetQualifier 函数组合,可以获取到该工程下的诊断目标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类型。

  • 特别要注意理解TestWaitForDiagResponseDiagGetLastResponseCode的区别,不清楚的向上翻翻

// @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); 


🌎总结

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

  • 🚩如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。

以上是关于封装了几个CAPL发送诊断相关函数,具有较高的可复用性的主要内容,如果未能解决你的问题,请参考以下文章

封装了几个CAPL发送诊断相关函数,具有较高的可复用性

接收诊断响应的相关CAPL函数,具有较高的可复用性

接收诊断响应的相关CAPL函数,具有较高的可复用性

接收诊断响应的相关CAPL函数,具有较高的可复用性

CAPL 封装了的SeedKey解锁函数,高复用性

CAPL 封装了的SeedKey解锁函数,高复用性