• 前言
  • 确认模拟节点
  • 发送机制
  • 节点排序
  • 节点加入并建环
  • 节点丢失
  • 节点跳过
  • 测试例子
  • 总结
    ————————————————
    闲暇之际,听到不知名网友呼我关于OSEK的建环机制用CAPL怎么做?
    我会的有以下三种:
  1. 利用.dll调用,这得看函数解析,对新手不太友好。

  2. 建立network node仿真节点,每个仿真节点都有一个完整的OSEK机制,即相互独立运作建环,睡眠唤醒等;编写测试用例简单;这得有开发基础及逻辑清晰的头脑,再花费亿点点时间(小七用的这种)。

  3. 只满足基本的建环与丢失,代码量少,需要迎合测试用例(推荐)。

今天讲第3种。

新建工程,Insert CAPL Test Module > osek.can

确认模拟节点

  • 以0x604为ECU节点,0x601,0x605,0x603,0x650,0x67F为模拟节点。
variables{dword   ecu_node_id = 0x604;//ECU节点dword   node_id[5] = {0x601,0x605,0x603,0x650,0x67f};//模拟节点5个}

发送机制

  • 初步模拟出ECU节点运行,直到跛行状态持续
variables{message 0x001 g_Tx = {dlc=0x08};dword   ecu_node_cycle = 0;//周期msTimer TsingleNode;//模拟osek管理发送机制int     rxLimit_sum = 4,rxLimit_n = 0;
}
on timer TsingleNode//模拟ECU节点的定时器
{if(ecu_node_cycle == 0){ecu_node_cycle = 100;g_Tx.byte(1) = 0x01;}else if(ecu_node_cycle == 100){ecu_node_cycle = 260;g_Tx.byte(1) = 0x02;}else if(ecu_node_cycle == 260 || ecu_node_cycle == 1000){rxLimit_n++;if(rxLimit_n >= rxLimit_sum + 1){ecu_node_cycle = 1000;g_Tx.byte(1) = 0x04;}else{if(rxLimit_n == rxLimit_sum){ecu_node_cycle = 1000;g_Tx.byte(1) = 0x01;}else{ecu_node_cycle = 100;g_Tx.byte(1) = 0x01;}}}g_Tx.id = ecu_node_id;g_Tx.byte(0) = ecu_node_id - node_id_min;output(g_Tx);setTimer(TsingleNode,ecu_node_cycle);
}
  • 效果

节点排序

  • 声明变量数组按ID大小,从小到大存储当前模拟节点及ECU 节点
void alignNodes(byte sim_node_n, byte node_behavior)//排列节点id大小,只有加入和丢失两种操作。
{dword value;int Tempi,Tempj,Tempk;if(node_behavior != gSim_on && node_behavior != gSim_out)//加入和丢失两种操作return;if(sim_node_n != 0xFF)//单个节点{if(node_behavior == gSim_on)//模拟节点加入,要重新排列发送顺序{for (Tempi = 0; Tempi < cur_node_id_sum; Tempi++){if(cur_node_id[Tempi] == node_id[sim_node_n - 1])//加入时,要排除当前节点数组是否有待加入的IDreturn;}
//            writeEx(-3,0,"0x%x节点加入",node_id[sim_node_n-1]);cur_node_id[cur_node_id_sum++] = node_id[sim_node_n - 1];if(cur_node_id_sum == 1)//有一个节点时就先增加进去,防止每次增加节点时都增加一个ECU IDcur_node_id[cur_node_id_sum++] = ecu_node_id;//获取当前所有节点ID}else if(node_behavior == gSim_out)//丢失,要重新排列发送顺序{for (Tempi = 0; Tempi < cur_node_id_sum; Tempi++){if(cur_node_id[Tempi] == node_id[sim_node_n - 1])//丢失时判断,找到要丢失模拟节点在cur_node_id里位置{//                    writeEx(-3,0,"0x%x节点丢失",node_id[sim_node_n-1]);for(Tempj = Tempi+1; Tempj < cur_node_id_sum; Tempj++)//遍历Tempi后面的模拟节点{cur_node_id[Tempi] = cur_node_id[Tempj];//把后一位模拟节点向前移}cur_node_id[cur_node_id_sum - 1] = 0x00;//最后一位置0cur_node_id_sum--;if(cur_node_id[Tempi] < ecu_node_id)//前节点,发送时要往左移。后节点不用管。cur_node_id_n--;if(cur_node_id_sum == 1)//最后只剩下ECU的节点时,清空cur_node_id和当前节点总个数{cur_node_id_sum = 0;cur_node_id_n = 0;}break;}}}for (Tempi = 0; Tempi < cur_node_id_sum; Tempi++)  //冒泡排序,ID从小到大排序{for (Tempj = Tempi+1; Tempj < cur_node_id_sum; Tempj++){if (cur_node_id[Tempi] > cur_node_id[Tempj]){value = cur_node_id[Tempi];cur_node_id[Tempi] = cur_node_id[Tempj];cur_node_id[Tempj] = value;}}}}else//所有节点都需要操作{for (Tempk = 1; Tempk <= elCount(node_id); Tempk++)alignNodes(Tempk,node_behavior);}
}
void nodeBehavior(byte sim_node_n, byte node_behavior)//模拟节点行为
{//sim_node_n:node_id数组里的节点;以1为起始,1表示第一个节点;0xFF表示所有节点//node_behavior:代表模拟节点的行为int Tempi,Tempk;if(sim_node_n != 0xFF)//单个节点{if(node_behavior == gSim_on)//加入{sendAlive(sim_node_n);//单个节点加入,先声明,发送AlivesendRing(sim_node_n,gNMStateCode_Ring);//再发送ring}else if(node_behavior == gSim_out)//丢失{if(cur_node_id_sum <= 1)//丢失完以后,停止发送cancelTimer(TringOperation);}else if(node_behavior == gSim_sleep){gNMStateCode = gNMStateCode_sleepInd;//建环时,满足睡眠条件时ind置1}else if(node_behavior == gSim_awake){gNMStateCode = gNMStateCode_Ring;//建环时,满足睡眠条件->不满足睡眠条件}}else//所有节点{for (Tempk = 1; Tempk <= elCount(node_id); Tempk++)nodeBehavior(Tempk,node_behavior);}
}
void nodeSwitch(byte sim_node_n, byte node_behavior)//模拟节点开关
{int Tempi;alignNodes(sim_node_n,node_behavior);//重组模拟节点if(cur_node_id_sum >= 2)//包含ECU 在内的节点{write("当前所有节点[%d] %x",cur_node_id_sum,cur_node_id[0]);for (Tempi = 1; Tempi < cur_node_id_sum; Tempi++)writeEx(1,0," %x",cur_node_id[Tempi]);}elsewrite("当前所有节点[0] ");nodeBehavior(sim_node_n,node_behavior);
}
  • 效果
  • CAPL声明:
  • CAPL打印:

节点加入并建环

  • 先声明模拟节点存在,发送Alive报文
  • 按排序后从小到大依次发送
  • 发送最大节点ID时,后继节点变为最小节点ID

节点建环图示:

void sendAlive(byte sim_node_n)//alive报文
{//sim_node_n:node_id数组里的节点;以1为起始,1表示第一个节点;0xFF表示所有节点g_Tx.id = node_id[sim_node_n-1];g_Tx.byte(0) = node_id[sim_node_n-1] - node_id_min;g_Tx.byte(1) = gNMStateCode_Alive;output(g_Tx);
}
void sendRing(byte sim_node_n, byte msg_type)//ring报文
{gNMStateCode = msg_type;if(msg_type == gNMStateCode_sleepAck)//模拟节点发送置1的ack位/32{cancelTimer(TringOperation);g_Tx.id = node_id[sim_node_n-1];g_Tx.byte(0) = desNodeAddress(node_id[sim_node_n-1]);g_Tx.byte(1) = gNMStateCode;output(g_Tx);}else//02/12/{if(cur_node_id_sum <= 2)//已建环时不能重启定时器,周期会出错setTimer(TringOperation,100);}
}
on timer TringOperation//ring报文 模拟节点周期发送
{if(cur_node_id_n >= cur_node_id_sum)//后继节点移位cur_node_id_n = 0;g_Tx.id = cur_node_id[cur_node_id_n];//idg_Tx.byte(0) = desNodeAddress(cur_node_id[cur_node_id_n]);//后继节点g_Tx.byte(1) = gNMStateCode;//ring报文类型outputNode();cur_node_id_n++;setTimer(TringOperation,100);
}
  • 效果

节点丢失

  • 效果

节点跳过

  • 根据OsekVDX NM 2.5.2规范,节点需要具有监测自身是否被跳过的能力,如果检测到被跳过,则重新发送alive报文

如下图:

  • 效果

测试例子

  • 关注公众号【总线网络】代码自取
void MainTest ()
{NewTestCase0();//ECU节点发送机制NewTestCase1();//所有节点建环并丢失NewTestCase2();//单个节点建环并丢失NewTestCase3();//三个节点建环并丢失后继节点NewTestCase4();//三个节点建环跳过ECU节点testWaitForMeasurementEnd(10);stop();
}

总结

选择合适自己的写脚本的方式,能事半功倍!祝福各位学习CANoe的同学能早日毕业!
有不完善的地方欢迎留言或加我vx补充。
请输入公众号:总线网络。关注我,获取汽车网络开发及测试方面资料,更新干货!
分享总线开发知识
分享CAN/CANFDLIN/ETH等网络资料
分享CANoe/TSMaster/PCAN等设备工具使用
分享UDS/NM/Bootloader测试用例等
一起来学习,进步,交流吧!

手撸CAPL(二)——OSEK网络管理N个节点建环机制(包含节点建环/丢失/跳过等)代码自取相关推荐

  1. 科普系列:AUTOSAR与OSEK网络管理比较(下)

    在上篇中我们分别在状态机和报文格式方面对OSEK和AUTOSAR网络管理进行了简单介绍,感兴趣的小伙伴请移步至文章<科普系列:AUTOSAR与OSEK网络管理比较(上)>. 三.OSEK与 ...

  2. 在用安全框架前,我想先让你手撸一个登陆认证

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 转自:RudeCrab, 链接:blog.csdn.net ...

  3. ​.NET手撸2048小游戏

    前言 2048是一款益智小游戏,得益于其规则简单,又和 2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎" FlysEngine,从空白窗口 ...

  4. 99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!|建议收藏

    世界上只有一种英雄主义,就是看清生活的真相之后依然热爱生活. 对于 Lombok 我相信大部分人都不陌生,但对于它的实现原理以及缺点却鲜为人知,而本文将会从 Lombok 的原理出发,手撸一个简易版的 ...

  5. 99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!|建议收藏!!!...

    世界上只有一种英雄主义,就是看清生活的真相之后依然热爱生活. 对于 Lombok 我相信大部分人都不陌生,但对于它的实现原理以及缺点却鲜为人知,而本文将会从 Lombok 的原理出发,手撸一个简易版的 ...

  6. 以鶸ice为例,手撸一个解释器(一)明确目标

    代码地址 # HelloWorld.ice print("hello, world") 前言(废话) 其实从开始学习编译原理到现在已经有快半年的时间了,但是其间常常不能坚持看下去龙 ...

  7. 手撸一个Switch开关组件

    一.前言 手撸系列又来了,这次咱们来撸一个Switch开关组件,废话不多说,咱们立刻发车. 二.使用效果 三.实现分析 首先我们先不想它的这个交互效果,我们就实现"不合格"时的一个 ...

  8. php 六边形 属性图 能力数值图,详解基于 Canvas 手撸一个六边形能力图

    一.前言 六边形能力图如下,由 6 个 六边形组成,每一个顶点代表其在某一方面的能力.这篇文章我们就来看看如何基于 canvas 去绘制这么一个六边形能力图.当然,你也可以基于其他开源的 js 方案来 ...

  9. 手撸架构,MyBatis 面试42问

    技术栈 传送门 JAVA 基础 手撸架构,Java基础面试100问_vincent-CSDN博客 JAVA 集合 手撸架构,JAVA集合面试60问_vincent-CSDN博客 JVM 虚拟机 手撸架 ...

  10. 手撸架构,Nginx 面试40问

    技术栈 传送门 JAVA 基础 手撸架构,Java基础面试100问_vincent-CSDN博客 JAVA 集合 手撸架构,JAVA集合面试60问_vincent-CSDN博客 JVM 虚拟机 手撸架 ...

最新文章

  1. 磁盘文件目录罗列和list控件的使用
  2. 第三章、一文告诉你FastDFS分布式如何部署
  3. java的面向对象的四大特征
  4. LSMW批处理使用方法(02)_步骤1
  5. C/Cpp / #include
  6. laravel8 模型自定义方法_Laravel 8.14.0 发布,PHP Web 开发框架
  7. LeetCode 1691. 堆叠长方体的最大高度(排序+最大上升子序DP)
  8. Redis为什么默认16个数据库,干什么用?
  9. layui弹出层:使用icon图标小结
  10. Matplotlib 中文用户指南 5.1 指定颜色
  11. Android成企业安全主要威胁的十大原因
  12. java servlet 视频_Servlet开发的理论提升视频教程 - JavaWeb - Java - 私塾在线 - 只做精品视频课程服务...
  13. matlab如何使用random函数,random函数
  14. python选择题题库百度文库_(完整版)Python题库
  15. 五险一金,这篇就够了
  16. linux中权限设置,Linux 权限设置chmod
  17. vue3中添加elementui插件
  18. 酷狗音乐模仿还在继续
  19. 【软件工程】------软件开发
  20. 卧槽!微信又更新了新功能,快来尝鲜!!

热门文章

  1. IC基础知识7-数据选择器
  2. html如何定义mime类型的作用,自定义mime类型、mime类型介绍
  3. 教师管理系统_ER图_功能图_数据字典_数据库脚本
  4. 通过热透镜聚焦的高斯光束
  5. Python-科比投篮预测
  6. java获取世界各国地址,获取世界各国、全国省份、城市、县
  7. oppo系统android版本下载,oppo手机助手
  8. udp 消息转发 服务器,UDP消息发送
  9. dbv oracle驱动,Oracle的DBV工具
  10. mysql随机抽样方法_MySQL中随机抽样