CAPL语言的基本使用

CAPL语言的.can文件的搭建

image.png

创建一个Nodes文件夹,把我们的.can文件存储到这;
这样创建的这个capl文件,是在工程运行后,如果触发了某些条件,会运行里面的某些功能代码;所以说capl是一门事件驱动型语言;

CAPL语言中的一些基本数据类型

int age; 
  int num = 30; 
  float tall = 1.72;
  const float myPI = 3.14;
  
  //枚举,默认值是 0, 可以设置
  enum Gender {
    MALE = 1,
    FEMALE
  };
  
  //结构体
  struct Humen{
    char name[100];
    byte age;
    float tall;
    enum Gender sex;
  };
  struct point{
    int x;
    int y;
  };
  
  struct point mypoint1 = {34,56};
  struct point mypoint2 = {
    x=34,
    y=56
  };
    //声明一个毫秒级定时器, 需要绑定事件,如果需要开启和关闭;
  msTimer t1;
  msTimer t2;
  msTimer t3;//报文的指定发送次数
  int t3count = 0;
  int t1Count = 0; //执行的次数
  //这个是秒级的   timer t;
  
  
  int i = 0;
  int j = 0;
  
  //定义AEBlog日志是否开启记录;
  int LoggingAEB_Start = 0;
  
  int EngineMsgCount = 0;//记录引擎的报文触发次数;
  int LoggingHeadLightStarted = 0; //车灯的当前状态记录
  char LoggingHeadLight[50] = "LoggingHeadLight";
  
  int currMaxSpeed = 0;//当前的发动机最高转速;
  
  int speedFileHandle = 0;//存储转速的文件句柄;

下面是对定义的数据类型的一些使用

on key 'w'{
  byte count1;
  byte count2;
  
  enum Gender zsySex = FEMALE;
  // 定义Position类型的同时,声明一个Position变量veh1,并赋值为Left
  enum Position { Front=1, Rear=2, Left=3, Right=4} veh1 = Left;
  // 使用Position声明一个变量veh2,并赋值为Front
  enum Position veh2 = Front;
  
  
  char gender = 'F'; //char在C语言中占一个字节
  char nameStr[5] = "ABCD"; //还有一个隐藏的/0,所以最多4个字符
  char nameStr2[100] = "zhaungshaoyun"; //这个就是一般的字符串的写法,C中没有字符串的定义,只有字符数组;
  
  char numStr1 = 'B';
  int num2 = 2;
  char numStr3 ;
  
  //声明数组Array  
  int intArray[10] = {1,2,3,4,5};
  //这个是字符数组,但是不是字符串
  char strArray[10] = {'a','b','c','d','a'};
  // name2是字符串的字符数组,必须以'\0'结尾
  char name2[6] = {'S', 'm', 'i', 't', 'h', '\0'};
  
  //二维数组
  int scores[2][3] = {
    {1,2,3},
    {4,5,6}
  };
  char currTime[100];
  
  //计算字符串,数组的长度
  write("%d-----%d------%d------%d",elCount(nameStr),elCount(nameStr2),elCount(strArray),elCount(scores));
  //5--------100----------10------------2 ,二维的是计算行,列应该要明确固定写死。
  
  
  numStr3 = numStr1+'!'; // 字符可以进行运算,因为有对应的ASCII
  // B = 66  ! = 33   , = 99 是小写的c
  
  write("字符相加:%c , %c",numStr3 , (char)(numStr1 + num2) );
  write("%c",gender);
  
  write("%d",zsySex);
  count1 = 5;
  count2 = -5;
  write("byte占一个字节,超出范围会截取:%d , %d",count1,count2);
  
  //随机数 [0;100]
  writeDbgLevel(5,"随机数:%d",random(100));
  write("7.32四舍无入:%d", _round(7.32));
  
  getLocalTimeString(currTime);
  write("当前时间:%s", currTime);
  write("30度角的正弦值为:%.2f", sin(30 * pi / 180));
}

//结构体
On key 's'{
  struct Humen Jame = {
     name = "jame",
     age = 18,
     tall = 1.77,
     sex = FEMALE
  };
  
  struct Humen mery;
  
  
 // mery.name = "jame";
  //CAPL中是没有 字符串 这种明确的数据类型的,结构中的name的数据类型是char[],也就是char的数组。
  //数组一旦初始化,不能重新整体赋值,只能访问其中的元素;
  //所以上面重新进行赋值的操作是行不通的,只能对数组单个元素操作,比如mery.name[0] = 'j';
  
  mery.age = 19;
  mery.tall = 1.53;
  mery.sex = MALE;
  
  write("name = %s",Jame.name);
  write("name = %s",mery.name);
  
}

下面是定时器的使用

//定时器的启动
on key 'a'{
  
  setTimer(t1,200);
  setTimer(t2,100);
}
//定时器事件绑定
On timer t1{
 
  write("time定时器启动了");
  
  t1Count++;
  if(t1Count < 10){
    setTimer(t1,200);
  }
  
}
On timer t2{
  sendDoorStateMsg();
}
void sendDoorStateMsg(){
  
  message DoorState msg;
  msg.LeftDoorState = i%2;
  i++;
  output(msg);
  write("发送了一帧报文");
  //开始定时器
  setTimer(t2,100);
  
  //取消定时器
  //cancelTimer(t2);
  
}

下面是定义一个报文

//报文
On key 'b'{
  message DoorState msg1;  //DoorState的 ID = 0x666
  message 0x666 msg2;
   // 访问报文变量msg1的属性
  write("报文的ID:%#x", msg1.id);
  write("报文的名称:%s", msg1.name);
  write("报文的DLC(数据长度):%d", msg1.dlc);
  
  
   write("报文的ID:%#x", msg2.id);
  write("报文的名称:%s", msg2.name);
  write("报文的DLC(数据长度):%d", msg2.dlc);
  
  
  //配置报文的信号值,使用报文变量配置,来着dbc文件;
  msg1.LeftDoorState = 1;
  msg1.RightDoorState = 0;
  msg1.LeftWindowPosition = 50;
  msg1.RightWindowPosition = 73;
 // 使用output函数向总线上输出报文msg1
  
  output(msg1);
  
}

在进行CAPL的报文创建时


image.png

这个DoorState 的报文是车门的报文,来着我们加载的dbc文件:


image.png

下面是log输出的方式和函数的调用方法

On key 'c'{
  // 4 代表输出的位置是 Test page ,0123是信息类型
  writeLineEx(4,0,"一个成功的输出"); 
  writeLineEx(4,1,"一个信息的输出");
  writeLineEx(4,2,"一个警告的输出");
  writeLineEx(4,3,"一个错误的输出");
  
  write("配置了输出登记后的write输出");
  
  
  writeDbgLevel(2,"按照等级输出");
  
  add(1,3);
}

//函数
void add(int a,int b){
  writeDbgLevel(5,"%d",a+b);
}
long addBig(int a,int b){
  return a+b;
}

//以报文为参数的函数
void sendMsg(message * msg,int count){
  //执行一些操作,然后可以发送报文
  //.......
  
  int i;
  for( i=0;i<count ;i++){
    
  }
 
  output(msg);
  
  
}

下面是程序的生命周期函数

//生命周期
//开始启动时调用
On start {
  writeDbgLevel(5,"启动");
  //配置输出的等级,一般是全局配置的,只对writeDbgLevel方法生效;
  setWriteDbgLevel(5);
  
  
  //配置log日志的输出路径和文件名
  setLogFileName("LoggingAEB","ZSYLogging/{LoggingBlock}_{MeasurementStart}.asc");
  
  
  speedFileHandle = openFileWrite("test/EngineSpeedReport.txt",2);
  if(speedFileHandle){
    write("打开存储转速文本成功");
  }else{
    write("打开存储转速文本失败");
  }
  
  
 
}
//结束时调用
On stopMeasurement{
  writeDbgLevel(5,"结束");
  
  //关闭文件
  if(speedFileHandle){
    fileClose(speedFileHandle);
  }
  
}

//结束程序
On key 'd'{
  writeDbgLevel(5,"结束程序");
  stop();
}

通过CAPL控制 LoggingAEB 日志模块的启动和停止

On key 'e'{
  
  //log日志的开启和停止,数据录入到文件中,不会再次创建新的文件,是一个asc文件;
  //如果关闭了刚才重新开始,会生成一个新的日志文件;
  
  if(LoggingAEB_Start == 0){
    LoggingAEB_Start = 1;
    // 启动名为LoggingAEB的日志模块的记录
    startLogging("LoggingAEB");
    
  }else{
    LoggingAEB_Start = 0;
    stopLogging("LoggingAEB");
  }
  
}

如果需要CAPL控制日志的记录,需要如下操作,代码才能生效:


image.png

文件的读写操作

//文件的 数据写入操作,返回文件句柄
int writeSomeMsgToFile(char filePath[]){
  int fh;
  char name[50] = "小庄";
  int age = 18;
  float tall = 1.73;
  char mutStr[100]; //定义一个可变字符串,用于字符串的拼接
  
  // 以覆盖写入文本字符的模式(0)打开文件,返回代表这个文件的句柄
  // 注意:如果使用模式2,则表示追加写入
  fh = openFileWrite(filePath,0);
  if(fh){
    //打开文件成功,进行写入操作
    //1.字符串拼接
    snprintf(mutStr, elCount(mutStr), "我是%s,今年%d岁,我的身高%.2f米。\n", name, age, tall);
    //2.写入数据
    filePutString(mutStr,elCount(mutStr),fh);
    filePutString("XXXXXXXXX",100,fh);
    filePutString("OOOOOO",100,fh);
    //3.关闭文件
    fileClose(fh);
  }
  return fh;
}

//文件的 数据读取操作,返回文件句柄
int readSomeMsgToFile(char filePath[]){
  int fh;//文件句柄
  char msg[100];
  fh = openFileRead(filePath,0);
  if(fh){
    
    while(fileGetString(msg,elCount(msg),fh)){
      write("读取的每一行的内容:%s",msg);
    }
    fileClose(fh);
    
  }
  
  return fh;
}

//文件的读写
On key 'f'{
  
  /*
    这里如果是直接读取文件内已经存在的信息,
    没办法设置读取的encode,导致可能乱码,这
    个应该修改txt的文本格式;
  */
  
  char filePath[50] = "test/zsyMsg.txt"; //文件地址,必须带文件后缀名
  
   if(writeSomeMsgToFile(filePath)){
    writeDbgLevel(5,"写入成功");
  }else{
    writeDbgLevel(5,"写入失败");
  }
  
  
  if(readSomeMsgToFile(filePath)){
    writeDbgLevel(5,"读取成功");
  }else{
    writeDbgLevel(5,"读失败");
  }

}
image.png

通过timer来实现多次执行某一件事情

On timer t3{
  t3count++;
  writeDbgLevel(5,"执行 了%d次",t3count); //可以把这个log换成报文发送
  if(t3count < 10){
    setTimer(t3,50);
  }
}

On key 'g'{
  setTimer(t3,50);
  
}

报文的监测

// 当总线上监测到了EngineState报文的时候触发
On message EngineState {
  
    write("第%d次检测到%s[%#x]报文,报文的传输方向[%d], 引擎的开关[%d], 引擎的转速[%d], 报文的长度[%d],报文的字节[%#X]", 
    ++EngineMsgCount, this.name, this.id, this.dir, this.OnOff, this.EngineSpeed,this.dlc, this.word(0));
  
}

// 监测LightState报文的出现(每次监测到报文出现,就触发一次
On message LightState{
  //writeDbgLevel(5,"监测到LightState报文");
  if(this.HeadLight == 1 && LoggingHeadLightStarted == 0){
    //已开灯 + 未记录日志
    startLogging(LoggingHeadLight);
    LoggingHeadLightStarted = 1;
     writeDbgLevel(1, "开始记录LoggingHeadLight的日志");
  }else if(this.HeadLight == 0 && LoggingHeadLightStarted == 1){
    stopLogging(LoggingHeadLight);
    LoggingHeadLightStarted = 0;
     writeDbgLevel(1, "停止记录LoggingHeadLight的日志");
  }
  
}


报文中的信号的监测 (发生了改变,比如从0到1了,才会触发)

//监测报文下面的信号的变化
On signal HeadLight {
   write("信号HeadLight发生了变化,信号的值为:%d", (int)this);
  
  write("引擎的开关%d",(int)$OnOff);
  write("引擎的转速%d",(int)$EngineSpeed);
  write("引擎的值%d",(int)$EngineSpeed);
  write("引擎的物理量%d",(int)$EngineSpeed.phys);
  write("引擎的原始值%d",(int)$EngineSpeed.raw);
  
  //这个方法直接监测信号值控制开启关闭,比上面的更直接;
  if(this == 1){
    startLogging(LoggingHeadLight);
    writeDbgLevel(1, "开始记录LoggingHeadLight的日志");
  }else if(this == 0){
     stopLogging(LoggingHeadLight);
     writeDbgLevel(1, "停止记录LoggingHeadLight的日志");
  }
  
}

监测信号值的更新,其实就是报文上报收到了,就触发的意思

On signal_update HeadLight{
  //这个信号50毫秒上报一次,所以这个打印50毫秒触发一次;
  write("接收到了头灯的信号:%d",(int)this);
}

信号变化的简单使用示例:

需求:检测EngineState报文中的信号的变化,每次变化判定是否是本次乘车过程中的最高转速;
EngineState报文中,有开关信号OnOff,和转速信号EngineSpeed;
如果是最高转速,写入报告文件;

On start {
  
  speedFileHandle = openFileWrite("test/EngineSpeedReport.txt",2);
  if(speedFileHandle){
    write("打开存储转速文本成功");
  }else{
    write("打开存储转速文本失败");
  }
  
}
//结束时调用
On stopMeasurement{
  writeDbgLevel(5,"结束");
  
  //关闭文件
  if(speedFileHandle){
    fileClose(speedFileHandle);
  }
  
}

On signal EngineSpeed
{
  char info[200]; //存储的转速信息
  char currentTime[200];//当前时间
  char pattern[100] = "[%s] 出现了目前的最高转速 [%d]\n"; //一个待用的拼接字符串
  if(this > currMaxSpeed){
    getLocalTimeString(currentTime);
    currMaxSpeed = (int)this;
    snprintf(info,elCount(info),pattern,currentTime,currMaxSpeed);
    //文件的打开和关闭操作,放在了程序的启动和关闭上了
    filePutString(info,elCount(info),speedFileHandle);
  }
  
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容