CAPL编程 - 实用CAPL代码片段

1 周期消息发送

无论是Simulation Setup中的仿真节点还是Test Setup中的Test Module所关联的CAPL脚本在做仿真或测试时都经常需要向总线模拟发送周期消息。

点击键盘按键 'a' 后向总线发送周期为20ms的can 消息msg:

variables
{ 
    msTimer myTimer;
    message 100 msg;
}
on key 'a' {
    setTimer(myTimer,20);
}
on timer myTimer {
    output(msg);
    setTimer(myTimer,20);
}

2 应用报文REQUEST/RESPONSE测试

ECU通常都有很多请求/应答式的功能,比如BCM可以接收用户点击车窗、雨刮、遮阳帘等车身相关硬件的控制按钮向总线发出的开关请求(Request),然后由BCM向总线发出响应消息,并控制车窗、雨刮、遮阳帘等做出相应的反馈动作(Response)。

下面以测试BCM雨刮开关功能为例进行Request/Response测试。

DBC定义:

参考代码:

variables
{
    message BCM_Request  tBCM_Request;
    message BCM_Response tBCM_Response;
    int result   = 0;
    int waitTime = 1000;
}
 
void MainTest()
{
   TestModuleTitle ("Test BCM Features");
   TestModuleDescription ("Check all features in BCM.");
 
   TestGroupBegin("BCM Wiper Feature", "Check the perfomance of Wiper");
     Check_Wiper_Feature(0,0);   //测试雨刮关闭功能
     Check_Wiper_Feature(1,1);   //测试雨刮开启功能
   TestGroupEnd();  
}
//Wiper Feature testcase
testcase Check_Wiper_Feature(int request, int response )
{
    tBCM_Request.WiperRequest.phys = request;
    output(tBCM_Request);
    //测试请求发出去后1000ms内是否收到BCM的响应信号。
    result = TestWaitForSignalMatch(BCM_Response::WiperResponse,response,waitTime);
    passResult(result,request,response);
}
void passResult(long result,int request,int response)
{
    switch(result){
        case  1: TestStepPass("1.0","Test Pass     - request : %d expect response : %d ",request,response);break;
        case  0: TestStepFail("1.0","Timeout       - request : %d expect response : %d ",request,response);break;
        case -1: TestStepFail("1.0","General error - request : %d expect response : %d ",request,response);break;
        case -2: TestStepFail("1.0","Signal is not valid");break;
        default:break;
    }
}

3 检测总线中周期报文的发送周期是否在给定范围内

TSL提供了两组函数用于测试周期报文:

一组使用相对时间因子,当周期小于 (aMinRelCycleTime * GenMsgCycleTime)或大于(aMaxRelCycleTime* GenMsgCycleTime)时产生事件。

函数原型:

dword ChkCreate_MsgRelCycleTimeViolation (Message aObservedMessage, double aMinRelCycleTime, double aMaxRelCycleTime, Callback aCallback);
 
dword ChkStart_MsgRelCycleTimeViolation (Message aObservedMessage, double aMinRelCycleTime, double aMaxRelCycleTime, Callback aCallback);

另一组使用绝对时间参数,当周期小于 aMinCycleTime 或大于 aMaxCycleTime 时产生事件。

dword ChkCreate_MsgAbsCycleTimeViolation (Message aObservedMessage, duration aMinCycleTime, duration aMaxCycleTime, char[] aCallback);
 
dword ChkStart_MsgAbsCycleTimeViolation (Message aObservedMessage, duration aMinCycleTime, duration aMaxCycleTime, char[] aCallback);

参考代码:

 

testcase CheckMsgEngineData()
{
  float aMinRelCycleTime = 0.9;  
  float aMaxRelCycleTime = 1.1;  
 
  // Information for test report.
  TestCaseTitle("TC 4", "Check cycle time of message EngineData");
 
  // checks the cycle time of the message
  gCycCheckId = ChkStart_MsgRelCycleTimeViolation (EngineData, aMinRelCycleTime , aMaxRelCycleTime );
  TestAddCondition(gCycCheckId);
  // sequence of different actions and waiting conditions
  TestWaitForTimeout(1000);
  TestRemoveCondition(gCycCheckId);
}

测试报告中设置的命令如下,请您自行查阅CANoe帮助文档,或者查找自带的模板。

TestModuleTitle ("Test BCM Features");\\测试报告标题。
   TestModuleDescription ("Check all features in BCM.");\\测试报告描述。

输出的测试报告如下图所示:

如上图所示,测试报告展示了错误事件产生的次数以及错误事件所处的事件范围。

 

4 统一诊断测试(UDS)

诊断测试经常需要进行切换session,22/2E读写等request/response式的操作,CANoe Demo工程UDSBasic.cfg中Simulation Setup窗口里的TestModule节点关联的CAPL脚本为我们提供了一个很好的参考模板:

参考代码:

/*@!Encoding:1252*/
// --------------------------------------------------
// Simple test module for automated tests.
// For the sake of simplicity, this example omits 
// security access mechanisms, especially for the
// write services. In some cases, return parameters
// are not checked.
//
// CANoe 10.0 and higher
// --------------------------------------------------
 
includes
{
  // As this is a test module, neither including the CAPL callback interface nor adding
  // the corresponding transport protocol node layer DLL is necessary, because in this case,
  // the "built-in" diagnostic channel of CANoe can be used.
}
 
variables
{
  enum bool {true=1, false=0};
 
  const cAccessModeNumerical=0;
  const cAccessModePhysical=1;
  const cAccessModeCoded=2;
 
  const test_vehicle_Speed_kmh = 40.0;
  
  // This timeout is used just to force CANoe to continue, i.e. normally a TestWaitForDiag...
  // function will return much earlier due to diagnostic level timing!
  const cApplicationTimeoutMs = 5000; 
  
  char gTestIdStr[10];    // Test step ID for test report
  word gTestCaseIndex=0;
  word gTestStepIndex=0;
 
  char gResultString[200]; // String for temporary test step result outputs  
}
 
// Set and increment test step ID for test report
updateTestIdStr()
{
  snprintf(gTestIdStr, elcount(gTestIdStr), "%d.%d", gTestCaseIndex, gTestStepIndex);
}
 
setTestId(word tcIndex, word tsIndex)
{
  gTestCaseIndex=tcIndex;
  gTestStepIndex=tsIndex;
  updateTestIdStr();
}
 
incTestStepId()
{
  gTestStepIndex++;
  updateTestIdStr();  
}
 
word SendRequestAndWaitForResponse(diagRequest *req, enum bool posResponseExpected)
{
  long ret;
 
  // Trigger sending the request
  if (0 > (ret=req.SendRequest())) { 
    snprintf(gResultString, elcount(gResultString), "Trigger sending the request failed (Return code=%d)!", ret);
    testStepFail(gTestIdStr, gResultString);
    return 0;
  }
  testStepPass(gTestIdStr, "Trigger sending the request succeded.");
 
  incTestStepId();
  // Wait until the complete request has been sent, e.g. in case of long requests which spread over several messages (segmented message)
  if (1!=(ret=testWaitForDiagRequestSent(req, cApplicationTimeoutMs))){ 
    snprintf(gResultString, elcount(gResultString), "Failed to finish sending the request (Return code=%d)!", ret);
    testStepFail(gTestIdStr, gResultString);
    return 0;
  }
  testStepPass(gTestIdStr, "Request was sent successfully.");
 
  incTestStepId();
  // Wait until the complete response has been received, e.g. segmented messages might take some time for transmission
  if (1!=(ret=testWaitForDiagResponse(req, cApplicationTimeoutMs))) {          
    snprintf(gResultString, elcount(gResultString), "Valid response missing or received too late (Return code=%d)!", ret);
    testStepFail(gTestIdStr, gResultString);
    return 0;
  }
  testStepPass(gTestIdStr, "Response received successfully.");
 
  incTestStepId();
  // Check whether the response was a positive response
  if (-1==(ret=diagGetLastResponseCode(req))) {
    if (!posResponseExpected) {
      snprintf(gResultString, elcount(gResultString), "Positive response received although negative response was expected!");
      testStepFail(gTestIdStr, gResultString);
      return 0;
    }
    testStepPass(gTestIdStr, "Positive Response received as expected.");
  }
  else if (ret>0) {
    if (posResponseExpected) {
      snprintf(gResultString, elcount(gResultString), "Negative response received (NRC=0x%02x) although positive response was expected!", ret);
      testStepFail(gTestIdStr, gResultString);
      return 0;
    }
    testStepPass(gTestIdStr, "Negative Response received as expected (NRC=%d).", ret);
  }
  return 1;
}
 
// Check whether writing the vehicle speed parameter is done correctly by reading its value after writing
testcase tcWriteAndReadVehicleSpeed()
{
  diagRequest Door.Variant_Coding_Write req_write;
  diagRequest Door.Variant_Coding_Read req_read;
  double ret;
  word testCaseIndex; 
  
  setTestId(1,1);
  TestStep(gTestIdStr, "Writing variant coding");
  if (0>req_write.SetParameter(cAccessModePhysical, "Codingstring.VehicleSpeedToLockDoor", test_vehicle_Speed_kmh)) {
    testStepFail(gTestIdStr, "Could not set parameter 'VehicleSpeedToLockDoor' in write request!");
  }
  else {
    if (0>req_write.SetParameter("Codingstring.VehicleType", "Sedan")) {
      testStepFail(gTestIdStr, "Could not set parameter 'VehicleType' in write request!");
    }
    else {
      sendRequestAndWaitForResponse(req_write, true);
    }
  }
  incTestStepId();
  TestStep(gTestIdStr, "Reading variant coding");
  if (sendRequestAndWaitForResponse(req_read, true)) {
    incTestStepId();
    ret=req_read.GetRespParameter(cAccessModePhysical, "Codingstring.VehicleSpeedToLockDoor");
    if (test_vehicle_Speed_kmh == ret) {
      testStepPass(gTestIdStr, "VehicleSpeedToLockDoor read as expected!");
    }
    else {
      testStepFail(gTestIdStr, "Read VehicleSpeedToLockDoor value is wrong (value=%f)!", ret);
    }
  }
}
 
void MainTest ()
{
  tcWriteAndReadVehicleSpeed();
}

CANoe提供的Demo工程是学习CANoe最好的资源,熟悉以上示例代码已经能够帮助我们开发出大部分诊断测试case。

版权声明:本文为haokeyu1752558508原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:CANoe教程:CAPL编程_capl教程-CSDN博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>