手撸CAPL(二)——OSEK网络管理N个节点建环机制(包含节点建环/丢失/跳过等)代码自取
- 前言
- 确认模拟节点
- 发送机制
- 节点排序
- 节点加入并建环
- 节点丢失
- 节点跳过
- 测试例子
- 总结
————————————————
闲暇之际,听到不知名网友呼我关于OSEK的建环机制用CAPL怎么做?
我会的有以下三种:
利用.dll调用,这得看函数解析,对新手不太友好。
建立network node仿真节点,每个仿真节点都有一个完整的OSEK机制,即相互独立运作建环,睡眠唤醒等;编写测试用例简单;这得有开发基础及逻辑清晰的头脑,再花费亿点点时间(小七用的这种)。
只满足基本的建环与丢失,代码量少,需要迎合测试用例(推荐)。
今天讲第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个节点建环机制(包含节点建环/丢失/跳过等)代码自取相关推荐
- 科普系列:AUTOSAR与OSEK网络管理比较(下)
在上篇中我们分别在状态机和报文格式方面对OSEK和AUTOSAR网络管理进行了简单介绍,感兴趣的小伙伴请移步至文章<科普系列:AUTOSAR与OSEK网络管理比较(上)>. 三.OSEK与 ...
- 在用安全框架前,我想先让你手撸一个登陆认证
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 转自:RudeCrab, 链接:blog.csdn.net ...
- .NET手撸2048小游戏
前言 2048是一款益智小游戏,得益于其规则简单,又和 2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎" FlysEngine,从空白窗口 ...
- 99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!|建议收藏
世界上只有一种英雄主义,就是看清生活的真相之后依然热爱生活. 对于 Lombok 我相信大部分人都不陌生,但对于它的实现原理以及缺点却鲜为人知,而本文将会从 Lombok 的原理出发,手撸一个简易版的 ...
- 99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!|建议收藏!!!...
世界上只有一种英雄主义,就是看清生活的真相之后依然热爱生活. 对于 Lombok 我相信大部分人都不陌生,但对于它的实现原理以及缺点却鲜为人知,而本文将会从 Lombok 的原理出发,手撸一个简易版的 ...
- 以鶸ice为例,手撸一个解释器(一)明确目标
代码地址 # HelloWorld.ice print("hello, world") 前言(废话) 其实从开始学习编译原理到现在已经有快半年的时间了,但是其间常常不能坚持看下去龙 ...
- 手撸一个Switch开关组件
一.前言 手撸系列又来了,这次咱们来撸一个Switch开关组件,废话不多说,咱们立刻发车. 二.使用效果 三.实现分析 首先我们先不想它的这个交互效果,我们就实现"不合格"时的一个 ...
- php 六边形 属性图 能力数值图,详解基于 Canvas 手撸一个六边形能力图
一.前言 六边形能力图如下,由 6 个 六边形组成,每一个顶点代表其在某一方面的能力.这篇文章我们就来看看如何基于 canvas 去绘制这么一个六边形能力图.当然,你也可以基于其他开源的 js 方案来 ...
- 手撸架构,MyBatis 面试42问
技术栈 传送门 JAVA 基础 手撸架构,Java基础面试100问_vincent-CSDN博客 JAVA 集合 手撸架构,JAVA集合面试60问_vincent-CSDN博客 JVM 虚拟机 手撸架 ...
- 手撸架构,Nginx 面试40问
技术栈 传送门 JAVA 基础 手撸架构,Java基础面试100问_vincent-CSDN博客 JAVA 集合 手撸架构,JAVA集合面试60问_vincent-CSDN博客 JVM 虚拟机 手撸架 ...
最新文章
- 磁盘文件目录罗列和list控件的使用
- 第三章、一文告诉你FastDFS分布式如何部署
- java的面向对象的四大特征
- LSMW批处理使用方法(02)_步骤1
- C/Cpp / #include
- laravel8 模型自定义方法_Laravel 8.14.0 发布,PHP Web 开发框架
- LeetCode 1691. 堆叠长方体的最大高度(排序+最大上升子序DP)
- Redis为什么默认16个数据库,干什么用?
- layui弹出层:使用icon图标小结
- Matplotlib 中文用户指南 5.1 指定颜色
- Android成企业安全主要威胁的十大原因
- java servlet 视频_Servlet开发的理论提升视频教程 - JavaWeb - Java - 私塾在线 - 只做精品视频课程服务...
- matlab如何使用random函数,random函数
- python选择题题库百度文库_(完整版)Python题库
- 五险一金,这篇就够了
- linux中权限设置,Linux 权限设置chmod
- vue3中添加elementui插件
- 酷狗音乐模仿还在继续
- 【软件工程】------软件开发
- 卧槽!微信又更新了新功能,快来尝鲜!!