Loading...
墨滴

jasonj333

2021/07/08  阅读:77  主题:红绯

capl-信息、类的实例化、数组、结构体、枚举、关联字段

获取工程信息

  • %NODE_NAME%

仿真节点名称

举例

on key 'a'
{
  write("the node name: %NODE_NAME%");
}  

打印的结果

获取的节点名称是

  • %CHANNEL%

仿真节点分配的通道

举例

on key 'a'
{
  write("the channel: %CHANNEL%");
}  

打印的结果

获取的通道是

  • %NETWORK_NAME%

仿真节点分配的网络名称

举例

on key 'a'
{
  write("the network name: %NETWORK_NAME%");
}  

打印的结果

获取的网络名称是

  • %FILE_NAME%

源文件名称

举例

on key 'a'
{
  write("the source file name: %FILE_NAME%");
}  

打印的结果

获取的源文件名称是

  • %FILE_NAME_NO_EXT%

源文件名称(没有扩展名)

  • %BASE_FILE_NAME%

编译的文件名称

举例

on key 'a'
{
  write("the compiled file name: %BASE_FILE_NAME%");
}  

打印的结果

获取的编译的文件名称是

  • %BASE_FILE_NAME_NO_EXT%

编译的文件名称(没有扩展名)

  • %BUS_TYPE%

仿真节点分配的通道的总线类型

举例

on key 'a'
{
  write("the bus type: %BUS_TYPE%");
}  

打印的结果

获取的总线类型是

%FILE_NAME%获取源文件的名称,%BASE_FILE_NAME%获取编译的文件名称,这两者有何区别?

对于网络节点,只有加载的capl文件才是主文件,而这个capl文件又可能引用多个capl文件

%FILE_NAME%是获取所在文件的名称,而%BASE_FILE_NAME%只会获取主文件的名称

类的实例化

capl虽然无法自定义类,然后通过实例化的方式调用类中的方法

但是,可以对capl中预定义的类进行实例化,然后调用里面的方法

使用方法和其他语言相通

  • 先对类进行实例化,创建一个类的对象

类名 对象名;

  • 然后用这个对象调用函数

对象名.函数名(参数1,参数2,...)

  • Timer, MsTimer

这两个类用于定期执行特定的功能,其中,Timer以秒为单位,MsTimer以毫秒为单位

  • File

这个类用于读取或写入文件

  • TcpSocket

这个类用于实现tcp网络通信

  • UdpSocket

这个类用于实现udp网络通信

  • TestCheck

这个类是与测试序列或模拟节点并行运行,目的是持续检查是否遵守指定条件

  • TestStimulus

这个类可以为信号或环境变量生成特定值模式以刺激设备

  • DiagRequest

这个类表示诊断请求

  • DiagResponse

这个类表示诊断响应

  • Associative fields

关联字段

  • CAN

提供对总线指定信息的访问

  • Classes of CAN Disturbance Interface

CAN干扰接口的类

  • Classes of Scope

范围类

数组

和其他编程语言一样,capl也有数组类型,需要注意的是,字符串是CHAR类型的数组,另外也支持多维数组

举例

int num1[5] = {1, 2, 3, 4, 5}; 
byte num2[3] = {0x01, 0x02, 0x03};
int num3[2][2] = {{1, 2}, {3, 4}};//二维数组
char str[6] = "hello";  

对于char类型的数组,数组长度要是字符串字符个数加1,因为默认还有一个换行符,也算一个字符

消息可以使用id或dbmsg来定义并进行初始化

message 0x5c0 msg_wakeup = {dlc = 8, byte(0) = 0x11, byte(1) = 0x22, byte(2) = 0x33, byte(3) = 0x44, byte(4) = 0x55, byte(5) = 0x66, byte(6) = 0x77, byte(7) = 0x88};  
message IgnitionOn msg_wakeup = {dlc = 8, byte(0) = 0x11, byte(1) = 0x22, byte(2) = 0x33, byte(3) = 0x44, byte(4) = 0x55, byte(5) = 0x66, byte(6) = 0x77, byte(7) = 0x88};  

如果是多个消息的集合,可以用message *

message * msgArray[4] = {msgABSdata, motbus::EngineData, msgGearBoxInfo, {dlc = 8}};   

数组元素个数可以用elcount()获取

除了下标来获取数组的元素以外,还可以用访问数据的选择器来获取

举例来说

on key 'a'
{
  byte num1[4] = {0x11, 0x22, 0x33, 0x44};
  write("value1: 0x%2x", num1.byte(0));
  write("value2: 0x%4x", num1.word(2));
  write("value3: 0x%8x", num1.dword(0));
}  

打印结果

可以看出

byte(i)、word(i)、dword(i)、int(i)、double(i)等传入的参数i代表的是从第i个byte开始,所以能调用它们的数组也只能是byte数组

byte(i)是从第i个byte开始的一个byte值

word(i)是从第i个byte开始的一个word值

dword(i)是从第i个byte开始的一个dword值

这里还要注意

byte数组是存入的window电脑,采用的是小端存储,那么低位下标的值表示低位,高位下标的值表示高位,所以0x33,0x44才会变成4433

对于消息来说,它里面的值也是以byte为单位的,所以也可以用这些选择器获取索引值

msg_wakeup.byte(0) = 0x01;
msg_wakeup.word(1) = 0x1234;

由于网络传输采用的是大端存储,那么低位下标的值表示高位,高位下标的值表示低位,所以0x33,0x44就会写成3344

结构体

结构类型以关键字struct+结构体名定义,简单数据类型、枚举类型和其他结构和这些类型的字段都可以用作结构体内的元素

结构类型也是一个变量类型,所以它可以在任何可以声明变量的地方定义

定义一个结构体

struct Data {
int type;
long l;
char name[50];
};  

注意:中括号的后面需要有分号

定义了结构体后,还需要声明这个结构体变量

struct Data data;

然后用这个结构体变量调用里面的元素,比如data.type

你会发现结构体从定义到使用,都和类的实例化比较像

反过来想,其实类的实例化也是声明变量类型的一种形式

对类的实例化,其实就是声明这个类的类型的变量

而声明变量也是类的实例化的表现,比如声明一个int类型的变量,其实也是对int类实例化一个对象,所以很多时候,可以直接用变量调用某些方法,这些方法其实就是变量类型的类里的方法

结构体的常见用法是可以定义协议头部里的各种字段,而对结构体里的元素赋值后,需要把报头以数组的形式发出去,结构体和数组的转换,在capl中也是提供了方法的

计算机系统为了简化处理器与内存之间的传输,以及提升读取数据的速度,对数据在内存中的存储的位置进行了限制,要求是某个数k的倍数,这就是所谓的内存对齐

结构体中的元素由于大小不一,就需要设置这个k值

capl中用_align()来设置对齐方式,只允许使用值1、2、4、8,默认是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) 2

上面的例子,x放在0这个位置的内存上,它只占有一个字节,y如果紧挨着它,放在了1的位置上,就不行了,因为1不是2的倍数,所以它只能放在2的位置上,1的位置就需要空着

设置对齐方式,并不意味着结构体的长度/大小发生了变化,可以用__size_of(struct Data)来获取结构体长度,注意传入的参数是结构体而非结构体变量

枚举

结构体类型是对不同变量的定义,而枚举类型是对不同值的定义

怎么说,举个例子

某校统计学生信息,各班报上来的信息有

名字:xxx
年级:xxx

姓名:xxx
年龄:xxx

称呼:xxx
岁数:xxx

这样统计到一起时会显得杂乱无序

聪明的校长想到了可以用结构体来定义各信息的变量名

struct INFO
{
  char name[10];
  int age;
};  

这样我在统一的时候只需要声明这个结构体变量,然后调用里面的元素变量即可实现统一

虽然解决了变量的统一,但是对于有些值又可能造成不统一,比如在统计性别时,有的班级用男/女,有的班级用公/母,有的班级用雌/雄,这又要如何统一呢?

就可以用枚举类型,把值固定

enum GENDER
{
  male = 1,
  female = 0
};  

用关键字enum定义枚举,枚举可以赋值,也可以不赋值,如果不赋值,则第一个元素默认0值,后面依次加1

这里有个注意点,里面的元素用逗号隔开,最后一个元素后面不需要符号

枚举里的值可以直接使用,无需声明枚举变量后调用,这点貌似和C#不同

比如

int i;
i = male;  

关联字段

在capl中叫Associative Fields,我大概的了解了下,和字典类型相似,也是通过键值对的方式,快速访问值

int m[float];
m[3.1] = 2;
m[4.3] = 5;

键的数据类型可以是long、int64、float、double、字符换和枚举,值的数据类型就是简单的数据类型都可以,包括枚举和结构体

关联字段的大小可以动态增加或减小,你也可以在声明时指定初始大小

int m[float, 30];  //为30个元素保留的初始空间

当然,它也提供了几种方法


jasonj333

2021/07/08  阅读:77  主题:红绯

作者介绍

jasonj333