CANOpen生命守护机制
CanOpen提供两种监视节点在线的机制,一种叫做生命保护机制,一种叫心跳机制。两种机制都是基于NMT报文进行实现的。
心跳机制:从站每隔一段时间上报一次自己的当前状态。主站对每个从站进行倒计时,一旦在规定时间内从站没有上报状态,则认为其掉线。
/* 初始化心跳报文:主站为所有使用心跳包的从站配置入口,从站没有在规定时间内上报心跳包,主站将从站状态置为掉线 */
void heartbeatInit(CO_Data *d)
{UNS8 index;/* 注册字典索引号0x1017和子索引号0x00的回调函数为OnHeartbeatProducerUpdate */RegisterSetODentryCallBack(d, 0x1017, 0x00, &OnHeartbeatProducerUpdate);/* 同步标志位置0 */d->toggle = 0;/* 遍历消费者(主站)的所有心跳包入口(从站) */for(index = (UNS8)0x00; index < *d->ConsumerHeartbeatCount; index++){/* 从消费者(主站)心跳包入口(从站)中取出定时时间 */TIMEVAL time = (UNS16)((d->ConsumerHeartbeatEntries[index]) & (UNS32)0x0000FFFF);/* 注册一个定时事件,在规定时间内没有收到心跳包,主站将从站置为离线 */if(time){d->ConsumerHeartBeatTimers[index] = SetAlarm(d, index, &ConsumerHeartbeatAlarm, MS_TO_TIMEVAL(time), 0);}}/* 生产者(从站)注册一个定时事件,在规定时间内上报心跳包 */if(*d->ProducerHeartBeatTime){TIMEVAL time = *d->ProducerHeartBeatTime;d->ProducerHeartBeatTimer = SetAlarm(d, 0, &ProducerHeartbeatAlarm, MS_TO_TIMEVAL(time), MS_TO_TIMEVAL(time));}
}
/* 消费者(主站)心跳包入口定时事件回调函数 */
void ConsumerHeartbeatAlarm(CO_Data* d, UNS32 id)
{/* 从消费者(主站)心跳包入口(从站)中取出节点ID */UNS8 nodeId = (UNS8)(((d->ConsumerHeartbeatEntries[id]) & (UNS32)0x00FF0000) >> (UNS8)16);/* 将该消费者(主站)心跳包入口(从站)定时器句柄置为空,表示定时事件关闭 */d->ConsumerHeartBeatTimers[id] = TIMER_NONE;/* 将该节点状态置为离线 */d->NMTable[nodeId] = Disconnected;/* 调用心跳错误回调函数,通过字典可以配置 */(*d->heartbeatError)(d, nodeId);
}
/* 处理节点守护报文 */
void proceedNODE_GUARD(CO_Data *d, Message *m)
{UNS8 nodeId = (UNS8) GET_NODE_ID((*m));if(m->rtr == 1){}
/* 如果是远程帧,表示该帧为响应运行状态 */else{/* 从报文中取出节点运行状态 */e_nodeState newNodeState = (e_nodeState)((*m).data[0] & 0x7F);MSG_WAR(0x3110, "Received NMT nodeId : ", nodeId);/* 将节点寿命值恢复满 */d->nodeGuardStatus[nodeId] = *d->LifeTimeFactor;/* 更新节点状态,并调用回调函数 */if(d->NMTable[nodeId] != newNodeState){(*d->post_SlaveStateChange)(d, nodeId, newNodeState);d->NMTable[nodeId] = newNodeState;}/* MNT报文是从站发送的bootup报文,调用回调函数 */if(d->NMTable[nodeId] == Initialisation){MSG_WAR(0x3100, "The NMT is a bootup from node : ", nodeId);(*d->post_SlaveBootup)(d, nodeId);}/* 如果该节点上报过来的不是未知状态,则要对该节点进行重新倒计时 */if(d->NMTable[nodeId] != Unknown_state) {UNS8 index, ConsumerHeartBeat_nodeId;/* 遍历消费者(主站)的所有心跳包入口(从站) */for(index = (UNS8)0x00; index < *d->ConsumerHeartbeatCount; index++){/* 从消费者(主站)心跳包入口(从站)中取出节点ID */ConsumerHeartBeat_nodeId = (UNS8)(((d->ConsumerHeartbeatEntries[index]) & (UNS32)0x00FF0000) >> (UNS8)16);/* 如果报文发送节点的id和入口id吻合,则对该节点重新进行倒计时 */if(nodeId == ConsumerHeartBeat_nodeId){/* 从消费者(主站)心跳包入口(从站)中取出定时时间 */TIMEVAL time = ((d->ConsumerHeartbeatEntries[index]) & (UNS32)0x0000FFFF);/* 删除消费者(主站)心跳包入口(从站)定时事件 */DelAlarm(d->ConsumerHeartBeatTimers[index]);/* 重新设置消费者(主站)心跳包入口(从站)定时事件 */d->ConsumerHeartBeatTimers[index] = SetAlarm(d, index, &ConsumerHeartbeatAlarm, MS_TO_TIMEVAL(time), 0);}}}}
}
生命保护机制:主站为每个从站设定一个生命值。每隔一段时间询问一次从站当前状态,并将生命值减一。收到从站回复,则将生命值复位。否则当生命值减到0的时候,判断其为掉线。
/* 节点守护报文初始化主站每隔一段时间发送守护报文,如果规定次数没有回复,则认定从站离线 */
void nodeguardInit(CO_Data *d)
{/* 注册字典索引号0x100C和子索引号0x00的回调函数为OnNodeGuardUpdate */RegisterSetODentryCallBack(d, 0x100C, 0x00, &OnNodeGuardUpdate);/* 注册字典索引号0x100D和子索引号0x00的回调函数为OnNodeGuardUpdate */RegisterSetODentryCallBack(d, 0x100D, 0x00, &OnNodeGuardUpdate);/* 判断字典中是否配置时间和次数 */if(*d->GuardTime && *d->LifeTimeFactor) {UNS8 i;/* 取出发送守护报文的间隔时间 */TIMEVAL time = *d->GuardTime;/* 注册一个定时事件,在规定时间发送守护报文 */d->GuardTimeTimer = SetAlarm(d, 0, &GuardTimeAlarm, MS_TO_TIMEVAL(time), MS_TO_TIMEVAL(time));MSG_WAR(0x0, "GuardTime: ", time);/* 初始化所有节点寿命为满值 */for(i = 0; i < NMT_MAX_NODE_ID; i++){/* 如果节点状态正常并且节点号不是本身 */if(d->NMTable[i] != Unknown_state && i != *d->bDeviceNodeId){d->nodeGuardStatus[i] = *d->LifeTimeFactor;}}MSG_WAR(0x0, "Timer for node-guarding startet", 0);}
}
/* 发送节点守护报文 */
UNS8 masterSendNMTnodeguard(CO_Data *d, UNS8 nodeId)
{Message m;/* MNT报文(数据帧表示响应,远程帧表示请求) */UNS16 tmp = nodeId | (NODE_GUARD << 7);/* cob-id */m.cob_id = UNS16_LE(tmp);/* 远程帧,请求 */m.rtr = REQUEST;/* 长度 */m.len = 0;MSG_WAR(0x3503, "Send_NODE_GUARD to node : ", nodeId);/* 发送该帧 */return canSend(d->canHandle,&m);
}
/* 处理节点守护报文 */
void proceedNODE_GUARD(CO_Data *d, Message *m)
{/* 从数据包中获取节点id */UNS8 nodeId = (UNS8) GET_NODE_ID((*m));/* 如果是远程帧,表示该帧为请求上报运行状态 */if(m->rtr == 1){/* 如果节点id和自身匹配,则上报 */if(nodeId == *d->bDeviceNodeId){Message msg;/* MNT报文(数据帧表示响应,远程帧表示请求) */UNS16 tmp = *d->bDeviceNodeId + 0x700;/* cob-id */msg.cob_id = UNS16_LE(tmp);/* 长度 */msg.len = (UNS8)0x01;/* 数据帧:响应 */msg.rtr = 0;/* 节点状态 */msg.data[0] = d->nodeState;/* 同步标志 */if(d->toggle){msg.data[0] |= 0x80;d->toggle = 0;}elsed->toggle = 1;MSG_WAR(0x3130, "Sending NMT Nodeguard to master, state: ", d->nodeState);/* 发送报文 */canSend(d->canHandle, &msg);}}else{}
}
CANOpen生命守护机制相关推荐
- TTE系统容错设计(1) ——集中守护机制
2020年,NASA计划在月球门户(lunar Gateway)空间站的动力和推进系统(PPE:Power and Propulsion Element)中使用TTE技术.由此,我们再次认识到,与目前 ...
- 谈谈CANopen协议的机制
CANopen是基于CAN协议的高级通信协议和设备配置文件规范.该协议是为嵌入式网络应用(如车载网络)开发的.CANopen涵盖了网络编程框架,设备描述,接口定义和应用程序配置文件.CANopen使来 ...
- 【Android 应用开发】UI绘制流程 ( 生命周期机制 | 布局加载机制 | UI 绘制流程 | 布局测量 | 布局摆放 | 组件绘制 | 瀑布流布局案例 )
文章目录 一. 博客相关资料 及 下载地址 1. 代码查看方法 ( ① 直接获取代码 | ② JAR 包替换 ) 2. 本博客涉及到的源码查看说明 二. Activity 生命周期回调机制 1. An ...
- Spring 生命周期回调机制
一.Spring 生命周期回调机制可选方式 Spring官方文档注明从Spring 2.5开始,您可以使用三种方式来控制Bean生命周期行为: InitializingBean和DisposableB ...
- 【CANopen】CAN总线的高级协议详解
目录 简介 CAL(CAN Application layer) CANopen CANopen对象字典(CANopen Object Dictionary) CANopen communicatio ...
- CANopen总线的高级协议详解
目录 简介 CAL(CAN Application layer) CANopen CANopen对象字典(CANopen Object Dictionary) CANopen communicatio ...
- CANopen总线的协议详解
目录 简介 CAL(CAN Application layer) CANopen CANopen对象字典(CANopen Object Dictionary) CANopen communicatio ...
- Spring5参考指南:Bean的生命周期管理
文章目录 Spring Bean 的生命周期回调 总结生命周期机制 startup和Shutdown回调 优雅的关闭Spring IoC容器 Spring Bean 的生命周期回调 Spring中的B ...
- Android应用开发—ViewPager FragmentPagerAdapter和FragmentStatePagerAdapter下Fragment的生命周期
ViewPager配合不同的PagerAdapter,对应Fragment的生命周期有着不同的表现,了解这个生命周期机制对于开发者选择合适的PagerAdapter实现不同的效果,有着很大的帮助. F ...
最新文章
- Linux环境下查PG库的慢sql,postgresql慢SQL
- 人可以拒绝任何东西,但绝对不可以拒绝成熟
- Java并发执行器的懒惰开发人员简介
- docker导入镜像 liunx_docker扫盲?面试连这都不会就等着挂吧
- jqery获取每个月天数_三年级《年、月、日》单元重要知识点整理汇总,以及难点题型解析...
- php实现服务器文件同步,PHPstorm配置同步服务器文件
- @kafkalistener中id的作用_SSM框架(十一):Spring框架中的IoC(1)
- python 列表list相关知识
- Java词汇表(三)L——O
- 基于CSS+dIV的网页层,点击后隐藏或显示
- 程序员怎样锻炼批判性思维
- python高级函数_python高级之函数
- 大学物理实验计算机仿真 光电效应,大学物理实验报告模版
- 招银网络科技算法面试
- Cannot forward to error page for request ......
- 使用fsck命令检查并修复linux文件系统
- 怎么利用粉丝圈这个微信社区工具做好社群营销?我们是做教育行业
- 洛谷 2448 无尽的生命
- python程序怎么运行-Python如何运行程序
- 责任链模式(Chain of Responsibility Pattern)简介
热门文章
- 消除文法左递归-编译原理
- 翻领成型器轨迹点MATLAB编程,基于MATLAB的翻领成型器领口曲线的展开及可视化
- java爬取网页并保存_第九讲:Python爬取网页图片并保存到本地
- SQLite允许向一个integer型字段中插入字符串
- 参数 中_理解JavaScript中函数的参数
- mmd python error_python_mmdt:一种基于敏感哈希生成特征向量的python库(一)
- dnf加物理攻击的卡片有哪些_DNF:节日宝珠之外百分比神器附魔,拍卖行100w,实用不氪金...
- 段寄存器中代码段数据段堆栈段附加段
- 动态规划 - 最长递增子序列LIS
- (王道408考研数据结构)第六章图-第四节2:最小生成树之克鲁斯卡尔算法(思想、代码、演示、答题规范)