CANoe教程 | CAPL编程 - 数据类型

CAPL是一种类C语言,CAPL数据类型的定义很多C语言类似,但也有很多独特的地方。 CAPL数据类型包括基本类型、结构体、枚举、关联类型和对象类型。变量的数据类型决定了变量存储占用的空间。

1 基本类型

2 枚举

枚举变量的定义和使用同C语言:

enum State { State_Off = -1, State_On = 1 };

如果枚举成员的值未定义,那么第一个成员默认值为1,之后的成员按顺序依次加1.

枚举变量的定义和使用

variables
{enum { Apple, Pear, Banana } fruit = Apple;enum Colors { Red, Green, Blue };enum Colors color;
}enum Colors NextColor(enum Colors c)
{if (c == Blue) return Red;else return (enum Colors) (c + 1);
}

3 关联类型

CAPL支持一种类似Python字典和C++ Map的关联类型(Associative Fields),关联类型的元素是键值对(key value pairs)。 关联类型定义格式如下,左边是value类型,右边[ ]内是key类型:

int m[float];         // maps floats to ints
float x[int64];       // maps int64s to floats
char[30] s[ char[] ]  // maps strings (of unspecified length) to strings of length < 30

example 1:关联浮点型

float m[float];
m[4.1] = 5.5; //key is 4.1 (float)  and value is 5.5 (float)
m[5.3] = 6.6;
write ("4.1 is mapped to %2.2lf", m[4.1]);
write ("5.3 is mapped to %2.2lf", m[5.3]);
for (float mykey : m)
{write("%2.2lf is mapped to %2.2lf.", mykey, m[mykey]);
}

example 2:关联字符串

char[30] namen[char []];
strncpy(namen["Max"], "Mustermann", 30);
strncpy(namen["Vector"], "Informatik", 30);for (char[] mykey : namen)
{write("%s is mapped to %s", mykey, namen[mykey]);
}

4 结构体

结构的定义和使用同C:

variables
{struct Point{int x;int y;};struct Point myPoint;struct Point allPoints[50];
}
on start
{myPoint.x = 7;myPoint.y = 2;allPoints[3].x = 1;allPoints[3].y = 5;
}

注意: CAPL中结构体默认按8字节对齐,可以在结构体定义前加_align来改变结构体对齐方式。

example:

struct Point {   // note: default _align(8)
byte x;          // offset 0, size 1
byte y;          // alignment 1, offset 1, size 1, padding before: 0
};               // size 2, alignment (of the struct) 1struct LongPoint {   // note: default _align(8)
byte x;              // offset 0, size 1
qword y;             // alignment 8, offset 8, size 8, padding before: 7
};                   // size 16, alignment (of the struct) 8_align(2) struct Point2 {
byte x;    // offset 0, size 1, (alignment 1)
qword y;   // alignment 2, offset 2, size 8, padding before: 1
};         // size 10, alignment (of the struct) 2struct Points {   // note: _align(8) per default
struct Point p1;  // offset 0, size 2, (alignment 1)
byte x;           // alignment 1, offset 2, size 1, padding before: 0
struct Point2 p2; // alignment 2, offset 4, size 10, padding before: 1
};                // size 14, alignment (of the struct) 2

可以使用如下函数获取结构体大小(size)、对齐方式(alignment )和偏移量(offset )信息:

example:

struct Points {   // note: _align(8) per default
Point p1;         // offset 0, size 2, (alignment 1)
byte x;           // alignment 1, offset 2, size 1, padding before: 0
Point2 p2;        // alignment 2, offset 4, size 10, padding before: 1
};                // size 14, alignment (of the struct) 2__size_of(struct Points);         // returns 14
__alignment_of(struct Points);    // returns 2
__offset_of(struct Points, p1);   // returns 0
__offset_of(struct Points, x);    // returns 2
__offset_of(struct Points, p2);   // returns 4

5 对象类型

除了以上介绍的基础数据类型,CAPL还提供了一些CANoe特有的对象类型来帮助用户快速完成仿真测试功能的开发。

CAN messages

CAPL提供了各种网络对应的报文类。本文以CAN message为例进行介绍。 报文变量定义格式:

message + message ID/message name + variable

使用message关键字来声明一个报文变量,message后是message ID或CANoe工程导入DBC后的message name,然后是在CAPL程序中要使用的报文变量名。

message 0xA m1;                                //定义一个ID为0xA的报文变量m1
message 100x m2;                              //定义一个ID为100的扩展帧报文变量m2,ID后的x后缀表示这是一个扩展帧
message EngineData m3;                  //定义一个在DBC中message name为EngineData的报文变量m3
...
output(m1);
output(m2);
output(m3);

CAPL提供了一系列的选择器(Selectors)来设置或读取CAN message的属性,例如:

example:

message 0x100 msg;  //定义一个ID为0x100的message变量msg
msg.CAN = 1;        //将msg的通道设置为1
msg.DLC = 2;        //将msg的DLC设置为2
msg.BYTE(0) = 0xAA; //给msg报文数据段的第一个byte赋值为0xAA;
msg.BYTE(1) = 0xBB; //给msg报文数据段的第二个byte赋值为0xBB;
output(msg);       //将定义好的msg发送到总线中

6 定时器变量

CAPL提供两种定时器变量: timer:基于秒(s)的定时器 msTimer:基于毫秒(ms)的定时器 example:点击键盘'a'后以20ms为周期发送id为100的报文

msTimer myTimer;        //定义一个ms定时器myTimer
message 100 msg;
...
on key 'a' {setTimer(myTimer,20); //点击键盘'a'将定时器myTimer设置为20ms,并开始计时
}
...
on timer myTimer {       //响应定时器事件myTimer,将msg发送到总线,output(msg);setTimer(myTimer,20); //重新设置定时器myTimer为20ms
}

CANoe教程 | CAPL编程-运算符/流程控制

CAPL中算数运算符、逻辑运算符、位运算以及流程控制语句和C语言一致。

1 运算符

2 流程控制

CANoe教程 | CAPL编程 - 事件驱动

1 事件概述

CAPL是一种面向过程、由事件驱动的类C语言。

事件驱动针对于顺序执行,其区别如下:

顺序执行:顺序执行流程中,子例程或过程函数按照代码编写顺序逐句执行。

事件驱动:CAPL程序由事件驱动,工程运行过程中发生指定的事件时才会运行相应的事件处理函数。

顺序执行VS事件驱动

在CAPL中添加事件处理函数:

重要的事件处理函数:

事件总览: [3]

2 事件详解

事件起始关键字 on

on后加某种事件,工程运行时条件触发,则执行函数体内的语句。

关键字this

系统变量、环境变量或CAN报文事件中,可以用this关键字访问其指代的数据内容,如:

on envvar Switch {
// Declare a CAN message to be transmitteed
message Controller msg;// Read out the value of the switch
// Assign to the signal Stop
msg.Stop = getvalue(this);
// Output the message on the bus
output(msg);
}

系统事件

系统事件主要用于处理CANoe测量系统的控制功能,主要有on start、on preStart、onstopMeasurement、on preStop、on key<newKey>以及on timer


系统事件Example:

//on preStart procedureon preStart
{write("Measurement started!");msg_Count = 0;
}//on start procedureon start
{write("start Node A");setTimer(cycTimer,20);CallAllOnEnvVar(); // CANoe only
}//on preStop procedureon preStop
{message ShutdownReq m;output(m);DeferStop(1000);
}//on stopMeasurement procedureon stopMeasurement
{write("Message 0x%x received: %d", msg.id, msg_Count);
}

CAN控制器事件

当CAN控制器或错误计数器状态变化时调用CAN控制器事件。

CAN控制器事件Example:

//on errorPassive procedure
on errorPassive {...write("CAN Controller is in errorPassive state")write(" errorCountTX = %d", this.errorCountTX);write(" errorCountRX = %d", this.errorCountRX);
};//on busOff procedure
on busOff
{int errRxCnt;int errTxCnt;int channel;double timestamp; // [seconds]timestamp = (double)timeNow() / (double)100000;channel = this.can;errRxCnt = this.errorCountRX;errTxCnt = this.errorCountTX;Write("Bus Off: time=%f channel=%d, errRxCnt=%d, errTxCnt=%d",timestamp, channel, errRxCnt, errTxCnt);resetCanEx(channel);
}

CAN报文/信号事件

CAN报文或信号变化时调用报文/信号事件。

CAN报文/信号事件

报文事件:

信号事件:

on signal LightSwitch::OnOff
{v1 = this.raw;v2 = $LightSwitch::OnOff.raw;
}

定时器事件

定义好定时器变量后,由SetTimer函数设置定时器间隔并启动定时器。当定时器运行到设定的时间间隔时触发定时器事件,并执行on timer函数体中的程序。

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

键盘事件

通过定义键盘事件,用户可以在工程运行时通过点击键盘触发预先定义的行为。这在实际开发和测试时非常常用。比如用户可以在任意时刻向总线发送特定的消息、改变信号或系统变量的值或是启动停止测量。

系统变量/环境变量事件

系统变量和环境变量事件分别是对系统变量和环境变量发生变化时的响应。

系统变量事件:

on sysvar IO::DI_0
{
$Gateway::IOValue = @this;
}

环境变量事件

on envvar Switch {
// Declare a CAN message to be transmitteed
message Controller msg;// Read out the value of the switch
// Assign to the signal Stop
msg.Stop = getvalue(this);
// Output the message on the bus
output(msg);
}

CANoe教程 | CAPL编程 - 实用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定义:

Signal Name Message Name Signal Value Description
WiperRequest BCM_Request Off : 0
On : 1
WiperResponse BCM_Response Off : 0
On : 1

参考代码:

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 messagegCycCheckId = ChkStart_MsgRelCycleTimeViolation (EngineData, aMinRelCycleTime , aMaxRelCycleTime );TestAddCondition(gCycCheckId);// sequence of different actions and waiting conditionsTestWaitForTimeout(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 reportword 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 requestif (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 transmissionif (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 responseif (-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。

CANoe教程:CAPL编程相关推荐

  1. CANoe 之 CAPL编程

    文章目录 CANoe 之 CAPL编程 CAPL 编程语言介绍及操作步骤 CAPL介绍 操作步骤 CAPL语法 CAPL程序的结构 数据结构 事件类型概述 常见函数 CANoe 之 CAPL编程 CA ...

  2. CANoe之CAPL编程(CANoe系列其三)

    CANoe之CAPL编程(CANoe系列其三) 1.CAPL概述 1.1.CAPL语言特性 1.2.CAPL的程序结构 1.3.CAPL的数据类型 1.4.CAPL事件类型概述 2.CAPL事件类型 ...

  3. 【CANoe之CAPL基础学习_如何正常在总线上中发送CAN消息】

    前言 本文适合于新手使用CANoe进行基础CAPL编程.基于CANoe的VN1640在CAN网络上进行发送CAN报文,实现CAN总线报文的控制.本文主要通过使用CANoe模拟发送一条周期型报文.文章内 ...

  4. CANoe 入门 _CAPL编程

    转自:https://www.cnblogs.com/dongdonghuihui/archive/2012/09/26/2704619.html CANOE入门(二) CAPL就是Communica ...

  5. Termux基础教程(无编程基础动图展示版)

    Termux基础教程(无编程基础版) Termux作为一个无需root就能实现很多功能的手机终端软件,它可以实现多种编程功能,其命令与Linux相似,可以为电脑暂时无法满足要求的同学提供一个编程和Li ...

  6. 普林斯顿Stata教程 - Stata编程

    译者:谢作翰 | 连玉君 | (知乎 | 简书 | 码云)   原文链接:Princeton Stata 在线课程 (Princeton University - Stata Tutorial )   ...

  7. C#教程 socket编程

    C#教程 socket编程 编程需要恒心和毅力,最主要的是要有信心,循序渐进的完成任务. 一.socket类用于网络通信 命名空间System.Net.Sockets,完整的类引用System.Net ...

  8. php泡点,PHP数据类型_PHP教程_编程技术

    两相篓儿狗盗棉袄崇兴猛药.馆际麦垅蓝带柔情失密泡点前因信使!小孩女监连山麦道抽筋魔神煤窑,不收莽撞库格祖逖拼版!明艳路单板坯瓯绣供养哩数!轻吹梅树爽利轻贱抛洒年鉴插曲蒙医:北城湿病国税漫坡侧板钳子面嫩 ...

  9. CANoe中用CAPL脚本按特定格式发送报文

    CANoe中用CAPL脚本按特定格式发送报文 需求 实验设备 实验环境 最近学习用CANoe软件测试CAN总线,纯新手,把最近的学习心得分享一下,欢迎大佬指正. 需求 1)仿真开始报文默认以100ms ...

  10. 基于canoe 新建一个lin工程_CANoe教程 | 高级编程 - C Library API

    概述 CANoe/CANalyzer C library 简称CCL,允许用户在Virtual Studio中的的DLL工程中使用C语言开发应用功能,生成dll可以在CANoe/CANalyzer工程 ...

最新文章

  1. 通关制单机器人_2020关务节|“数字供应链与智能通关”论坛——如何打造云上跨境贸易生态圈...
  2. centos7升级自带的php5.4版本到php5.6
  3. ACCESS中如何比较日期和时间,使用DateDiff函数
  4. 原理分析之:从JDBC到Mybatis
  5. zabbix如何监控WEB应用性能
  6. 分享丨10年DBA老司机整理的Oracle学习路线图
  7. 一文详解超参数调优方法
  8. C++全局变量和局部变量有什么区别
  9. 大神手把手教你设计秒杀架构模型
  10. 全新OpenMMLab邀你入伙 共创AI开源世界
  11. 电信烽火2821t虚拟服务器设置,iTV使用指南-烽火智能高清机顶盒装维手册
  12. python的空语句_Python 函数返回空值
  13. 根据银行卡号查询银行名接口目前免费阿里接口
  14. xp系统开机自检很久_XP开机卡在自检不能进入系统的解决办法
  15. flyaway mysql_MySQL open table
  16. python:输出10行的杨辉三角 - 二项式的n次方展开系数
  17. 小周个人博客之恋爱日记
  18. Java代码安装maven jar_Java中Maven项目导出jar包配置的示例代码
  19. OSWatcher的安装使用
  20. 配置文件工具类【ConfigTools】

热门文章

  1. DisplayTag详解
  2. Premiere视频导出格式
  3. Win10易升是什么?如何彻底关闭Windows10易升?
  4. 肌电数据归一化并显示灰度图片
  5. vim命令模式下粘贴内容
  6. 离散数学知识点及错题集合 第七章
  7. python自动登录网银_网银自动充值-登陆联通网站沃支付
  8. 后台数据联调的接口工具 postman和apizza 集成数据
  9. 统计学贾俊平第六版pdf下载|贾俊平统计学第六版pdf下载电子书
  10. 计算机408考研专业课思维导图(计算机组原理、数据结构、操作系统、计算机网络)