CAPL编程中需要注意的点和事项(总结笔记)

前言:

先说一段废话:对于vector推出CAPL,全称叫做 communcation access program language。

           本人对于它的评价,结构臃肿不堪,这主要集中在两方面 1:其推出了更多的产品,这些新的产品,都需要CAPL不断去兼容。而CANoe又大量采用库函数调用,导致其库函数越积累越多。

甚至出现了一个功能,就有好几个库函数都能实现这种功能。

第二:CAPL自己号称是类C语言。但是又放弃了,c中的一些核心概念,如mian主函数,指针,以及c对内存的直接管理机制。又有类似与c++中函数重载的概念。同时又根据通讯测试中的实时性要求,和易于上手的原因。设置了如,message 以及各种ON事件监测机制。

总之而言,CAPL是想即兼顾代码运行的效率,有想易于上手和学习,同时还想兼顾通讯测试的实时性要求。三方面都想兼顾的情况下。导致CAPL像一个四不像。同时也导致了,代码逻辑上不如C/C++清楚和易于理解。(多说一句CAPL还修改了一些很让人看不懂的操作,如,函数类定义的变量,默认都是static类型变量,这一点来说就让人很不理解,也对很多刚刚接触capl的人来说,这就是一个坑)。

因为如此,写这篇文章,来详细梳理一下,CAPL与C/C++中的不同点。看代码

/*@!Encoding:936*/    /*可以看到CAPL在代码中,添加了一个类似与注释的说明然后,添加@+!Encoding+封号:加一段数字,这个数字的意思,暂时不清楚。
includes      //这里CAPL,使用了一个语法,它把你需要包含的.cin文件。都统一包含在一个大括号中,注意和C/c++中的#include不同,这里不需要#,而且要加一个“s”。暂时不清楚这么做的好处,比如我要添加三个cin文件,我也是需要一个一个写出来。增加了这样一个语法,徒增了代码量。

真是搞不懂,它为什么要这样干。

另外,CAPL语法规定,includes{},只能出现一次,而它包含的#include则能出现很多次
{   

      # include"example.cin" //C/C++中规定的是,有两种模式1:#include<> 2:#include"",但是CAPL语法规定,只能使用 ""。C/C++规定当使用<>是在规定的文件夹下,寻找包含的头文件,所谓的规定文件的相对路径,比如C中的stdio.h/math.h /string.h文件。是在编译器安装时,就固定在莫一个文件夹中了,如都固定存放在一个名为head_h的文件夹中。当编译器编译和连接时,他就会到head_h的文件名中查找。

       当使用#include"xxx"时,"表示首先在当前目录下(这个当前目录:暂时可以理解为.c文件存在的文件夹)搜索要嵌入的文件,如果没有再按照标准方式搜索,对用户自己编写的文件一般采用这种方式。

       理解了C/C++中的逻辑,我们是不是可以理解,CAPL文件也是按照这种方式寻找头文件的。还有需要注意的是,C++的头文件有两种,一种是系统自带头文件,这是在引用时,不需要带.h的后缀名的。如:#include<iostream>。另外一种如用户自定义的文件则是需要带.h的。

最后聊一下两个问题

(1)C及C++中系统自带头文件,系统命名不一致的原因。

答:我们都知道,C++是对C,进行了语法上的优化。而所有优化都是有原因的。原因在于C中的头文件#include" stdio.h"这种形式引用时,一般情况下,是能正常运行的,编译器会现在.C所在的文件夹下寻找。发现没有,再到系统头文件夹下寻找。找啊找,马上就能在系统头文件夹中找到这个头文件。但是如果出现以下情况,我们自定义一个头文件,恰好这个头文件名字就是stdio.h就在.C所在的文件夹下,那么这时,编译器就会把我们自定义的头文件,连接到源代码中去。代码中再去执行printf和scanf。编译器就会报错。这种错误很多资料就叫做头文件覆盖错误。

      有兴趣的,可以自己实操试一试。C++这么做就

   二:cin文件不能简单的和c中的头文件划等号, 

   三: 目前实操发现: #include"xxx.cin"和#include"xxx.can"都是可以包含的,且compile不会报错。C/C++中include只能包含.h的文件(C++系统自带头文件除外)。暂时还不知道,包含.can和.cin的区别和联系到底在哪?

四:对三的补充说明,我在include中添加.can文件时,执行的是以下操作:

1:找到导航栏的

2:鼠标悬停includes,然后右单击鼠标,出现

3:然后就出现了文件悬着弹窗:可以看到弹窗是限定了,导入文件类型为CAPLFile(.can和,cin),我们选定一个can文件,然后单击右下角的确定。

接下来发生了一件很奇怪的事,看截图:

当添加.can文件时,前面会出现一堆//..//..//。感觉是把相对地址给包含中去了。暂时不知道为什么。

      另外,其实CAPL会用到大量的库函数,但是CAPL并没有像,C/C++中那样,需要包含这些库函数的文件。我猜测是编译时,编译器会自行处理,把包含这些库函数的头文件,添加到源代码中去
}

variables  //这里也是variable+s+{},
{

  byte a;   //长度1Byte,类型unsigned 表示范围0~255
  word b; //长度2Byte,类型unsigned 表示范围0~65535
  dword c;//长度4Byte,类型unsigned 表示范围0~4294967295
  qword e;//长度8Byte,类型unsigned 表示范围0~18446744073709551615
  int f;      //长度2Byte,类型unsigned 表示范围0~255
  //short h; //short编辑器能支持,打一半能显示出来,但是编译就会出错
  long g;   //但是long它又选择支持,哎!!搞不懂,这到底是几个意思!!!

//还有就是,capl不支持unsigned 修饰符,也就是说如果我们需要定义一个变量,如温度显示范围//-70-110℃,那么在capl中就只能选择 int类型的变量了。C中一个chart 类型的变量就可以解决,

//但是capl只能用int,非要用到2个Byte。

//另外CAPL的capl,明明是运行在64BIT操作系统上的软件,但是非要把int设置为2Byte
  /*总结,CAPL新定义了,几类基本类型,但是个人感觉也是很鸡肋。如Byte,完全可以用 unsigned char,代替*/

message 0x110 Msg_1;

/*  1meaage 是定义CAN/LIN的报文,是CAPL特有的一种数据结构,其基本声明结构为:Meaage( 关键字)+报文ID[ID书写格式兼容十六进制和十进制]或DBC数据库中的报文名+客户自定义的报文变量名。

     message 默认是定义成CAN(准确的来说是是标准CAN),message 100x msg2;表示的是定义了扩展帧格式的CAN报文。

    那么如果我们想定义一个CANfd帧,那么该将如何操作?只能在message定义变量时,直接初始化,并给它的一个参数FDF设置为1,

如:

message 0x22 msg_4=

{FDF=1,

BRS=1};

有相关经验的工程师和同学,一眼就看出来了,这个FDF就是CAN_FD帧的标志位,FDF=1,表示是CAN_FD,而BRS则是速率切换标志位。

这里,又有一个问题?就是如下:

  message 0x23x msg_4=
  {  FDF=0,
     BRS=1
    
  };

我们设置了,FDF=0,但是BRS=1。我们晓得,BRS存在的必要条件就是FDF=1。但是编译竟然通过,我们试一试能不能将这个报文发送出来

但是发出来的报文,是CAN拓展帧(暂时确实还看不出来是不是拓展帧,有知道怎么看的,除了直接用示波器或者逻辑分析仪看的)。

此外,如果我们还想定义lin报文,那么将该如何定义,CAPL中使用:linframe 0x23 msg_5;这里需要注意的一点,就是老版本的CAPL中使用的是linmessage,新版本的CAPL现阶段依然是兼容这个关键字的,但是不建议继续使用,原因也很简单,谁又知道VECTOR在哪一个版本又不支持了喃?

暂时可以理解为C中的结构体 ,但是其本身与结构体差别还是很大的 。我之前又想过把他比喻成C++中的class,但是发现message和class也有很大不同。

如果把message 比喻成一个已经定义好的struct类型。

Typedef struct Message

{

   char dir[20];

   int ID;

   int DLC;

  char CAN;

   unsigned char Byte(0);

   。。。。。

}message;

那我们在利用message 声明新的实例对象时,按照C的语法,message msg_1,

但是message却可以在声明的时候,同时声明ID,并且ID后面加x还能定义为拓展帧,这一点就很特殊。

我们知道c中结构体变量(实例)是可以在定义时,直接赋初值的,message是直接继承了这一特性。

message 0x345 msg_module1=

{CAN=1,

dir="TX",

....

}

但是注意:结构体一般情况下,在初始化时,是直接写值的,按照定义的顺序直接依次赋值。不需要写结构体内元素的名字。

但是这种写法其实很不直观。因为如果结构体内部定义了很多成员,我一个一个赋值,很容易出错。于是C99和C11推出了,结构体的初始化器。

#include <stdio.h>
#include <stdlib.h>
struct message
{
  int ID;
  char dir[20];
  int can;
  int byte1;
  int byte2;
};

int main()
{
    struct message Msg_1={.byte1=40,.can=2};
    printf("Hello world!\n");
    return 0;
}

就是可以采用这种方式来初始化,“.+结构体成员名”

CAPL有一种类似的方法,但是不需要,在结构体成员名前加上.点成员名。另外结构体中的单独赋值,CAPL也是支持的,使用方法和结构体非常相似。

message 0x123 msg_2;  //先定义一个message类型变量

msg_2.DLC =8;    //再单独为每一个元素,赋值。

msg_2.CAN=2;     //再单独为每一个元素,赋值。每一个都是单独的赋值语句

以上写了这么多,并且CAPL中message和c中的结构体作比较。其实不是多此一举,而是为了更加深入的了解message这种特殊的,capl特有的数据结构。

接下来。我们看看一些常见的message常见的“成员变量的属性”,这里我用了成员变量这个名字,可能不太准确,但是我也没有更好的称谓来描述。只能借用结构体struct或class中的成员变量来称呼了。

message结构数据成员变量(属性表格)
成员                           说明数据类型访问权限补充说明
CAN(全大写)此成员说明了,Message对应的逻辑通道word
(1-32)
可读/可写这两点属性,我建议是不要同时写。因为,我们在配置工程时已经将逻辑通道和canoe上的物理进行映射。建立工程或测试用例时,我们已经将不同的测试部件,映射到不同的逻辑通道上去了,而且有时候,我们在设置工程的阶段还会设置虚拟通道。
MsgChannel此成员说明了,Message对应的物理通道,也就是CANoe上的通道word
(1-32)
可读/可写
IDCAN 帧的IDdword可读可写但是又有一个新问题,如果我在声明阶段已经定义过了,我又在这里重新定义了一下,那么会实际发出来的报文,又会采用哪一个喃?
nameDBC文件的名字char[]只读这个名称是基于DBC文件
DIR传输方向,类型为Tx和Rx与TXREQUEST,一共三种类型。byte只读注意,这个变量应该只是一个只读变量,这个变量,是以
DLC报文数据段长度byte可读可写数据段长度,这里也有一个知识点,当我们定义的帧是CAN帧时,
RTR远程帧标志位(CANfd中取消了,远程帧)byte
FDFCANfd帧的标志位byte
BRSCANFD帧的数据段切换标志位byte这里必须声明一下,CANFD数据段是有两种不同速率发送的,第一种:就是以帧头的速率传送,第二种是以速率的部分发送,两个速率是在CANoe Hardwork->NetworkHarawork中设置的。
TYPEDIR和RTR的组合word只读TYPE=(RTR<<8)|DIR
Time时间戳信息(单位10ms)longint类型只读
SIMULATED由模拟节点发送只读

0:代表真实节点

1:代表控制节点

on message 0x*
{
 
  write("this.id = %x",this.id);//获取报文ID
  write("this.name = %s",this.name);//获取报文名字
  write("this.can = %d",this.can);//获取当前报文在哪路can上
  write("this.dir = %d",this.dir);//获取当前报文是TX还是RX
  write("this.dlc = %d",this.dlc);//获取当前报文的报文长度
  write("this.Byte0 = %x",this.Byte(0));//获取当前报文的第一个字节
  write("this.Byte1 = %x",this.QWord(0));//获取当前报文的第二个字节
}

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值