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生命守护机制相关推荐

  1. TTE系统容错设计(1) ——集中守护机制

    2020年,NASA计划在月球门户(lunar Gateway)空间站的动力和推进系统(PPE:Power and Propulsion Element)中使用TTE技术.由此,我们再次认识到,与目前 ...

  2. 谈谈CANopen协议的机制

    CANopen是基于CAN协议的高级通信协议和设备配置文件规范.该协议是为嵌入式网络应用(如车载网络)开发的.CANopen涵盖了网络编程框架,设备描述,接口定义和应用程序配置文件.CANopen使来 ...

  3. 【Android 应用开发】UI绘制流程 ( 生命周期机制 | 布局加载机制 | UI 绘制流程 | 布局测量 | 布局摆放 | 组件绘制 | 瀑布流布局案例 )

    文章目录 一. 博客相关资料 及 下载地址 1. 代码查看方法 ( ① 直接获取代码 | ② JAR 包替换 ) 2. 本博客涉及到的源码查看说明 二. Activity 生命周期回调机制 1. An ...

  4. Spring 生命周期回调机制

    一.Spring 生命周期回调机制可选方式 Spring官方文档注明从Spring 2.5开始,您可以使用三种方式来控制Bean生命周期行为: InitializingBean和DisposableB ...

  5. 【CANopen】CAN总线的高级协议详解

    目录 简介 CAL(CAN Application layer) CANopen CANopen对象字典(CANopen Object Dictionary) CANopen communicatio ...

  6. CANopen总线的高级协议详解

    目录 简介 CAL(CAN Application layer) CANopen CANopen对象字典(CANopen Object Dictionary) CANopen communicatio ...

  7. CANopen总线的协议详解

    目录 简介 CAL(CAN Application layer) CANopen CANopen对象字典(CANopen Object Dictionary) CANopen communicatio ...

  8. Spring5参考指南:Bean的生命周期管理

    文章目录 Spring Bean 的生命周期回调 总结生命周期机制 startup和Shutdown回调 优雅的关闭Spring IoC容器 Spring Bean 的生命周期回调 Spring中的B ...

  9. Android应用开发—ViewPager FragmentPagerAdapter和FragmentStatePagerAdapter下Fragment的生命周期

    ViewPager配合不同的PagerAdapter,对应Fragment的生命周期有着不同的表现,了解这个生命周期机制对于开发者选择合适的PagerAdapter实现不同的效果,有着很大的帮助. F ...

最新文章

  1. Linux环境下查PG库的慢sql,postgresql慢SQL
  2. 人可以拒绝任何东西,但绝对不可以拒绝成熟
  3. Java并发执行器的懒惰开发人员简介
  4. docker导入镜像 liunx_docker扫盲?面试连这都不会就等着挂吧
  5. jqery获取每个月天数_三年级《年、月、日》单元重要知识点整理汇总,以及难点题型解析...
  6. php实现服务器文件同步,PHPstorm配置同步服务器文件
  7. @kafkalistener中id的作用_SSM框架(十一):Spring框架中的IoC(1)
  8. python 列表list相关知识
  9. Java词汇表(三)L——O
  10. 基于CSS+dIV的网页层,点击后隐藏或显示
  11. 程序员怎样锻炼批判性思维
  12. python高级函数_python高级之函数
  13. 大学物理实验计算机仿真 光电效应,大学物理实验报告模版
  14. 招银网络科技算法面试
  15. Cannot forward to error page for request ......
  16. 使用fsck命令检查并修复linux文件系统
  17. 怎么利用粉丝圈这个微信社区工具做好社群营销?我们是做教育行业
  18. 洛谷 2448 无尽的生命
  19. python程序怎么运行-Python如何运行程序
  20. 责任链模式(Chain of Responsibility Pattern)简介

热门文章

  1. 消除文法左递归-编译原理
  2. 翻领成型器轨迹点MATLAB编程,基于MATLAB的翻领成型器领口曲线的展开及可视化
  3. java爬取网页并保存_第九讲:Python爬取网页图片并保存到本地
  4. SQLite允许向一个integer型字段中插入字符串
  5. 参数 中_理解JavaScript中函数的参数
  6. mmd python error_python_mmdt:一种基于敏感哈希生成特征向量的python库(一)
  7. dnf加物理攻击的卡片有哪些_DNF:节日宝珠之外百分比神器附魔,拍卖行100w,实用不氪金...
  8. 段寄存器中代码段数据段堆栈段附加段
  9. 动态规划 - 最长递增子序列LIS
  10. (王道408考研数据结构)第六章图-第四节2:最小生成树之克鲁斯卡尔算法(思想、代码、演示、答题规范)