CANOpen生命守护机制
生活随笔
收集整理的這篇文章主要介紹了
CANOpen生命守护机制
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
CanOpen提供兩種監(jiān)視節(jié)點在線的機制,一種叫做生命保護機制,一種叫心跳機制。兩種機制都是基于NMT報文進行實現(xiàn)的。
心跳機制:從站每隔一段時間上報一次自己的當前狀態(tài)。主站對每個從站進行倒計時,一旦在規(guī)定時間內(nèi)從站沒有上報狀態(tài),則認為其掉線。
/* 初始化心跳報文:主站為所有使用心跳包的從站配置入口,從站沒有在規(guī)定時間內(nèi)上報心跳包,主站將從站狀態(tài)置為掉線 */ void heartbeatInit(CO_Data *d) {UNS8 index;/* 注冊字典索引號0x1017和子索引號0x00的回調(diào)函數(shù)為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);/* 注冊一個定時事件,在規(guī)定時間內(nèi)沒有收到心跳包,主站將從站置為離線 */if(time){d->ConsumerHeartBeatTimers[index] = SetAlarm(d, index, &ConsumerHeartbeatAlarm, MS_TO_TIMEVAL(time), 0);}}/* 生產(chǎn)者(從站)注冊一個定時事件,在規(guī)定時間內(nèi)上報心跳包 */if(*d->ProducerHeartBeatTime){TIMEVAL time = *d->ProducerHeartBeatTime;d->ProducerHeartBeatTimer = SetAlarm(d, 0, &ProducerHeartbeatAlarm, MS_TO_TIMEVAL(time), MS_TO_TIMEVAL(time));} } /* 消費者(主站)心跳包入口定時事件回調(diào)函數(shù) */ void ConsumerHeartbeatAlarm(CO_Data* d, UNS32 id) {/* 從消費者(主站)心跳包入口(從站)中取出節(jié)點ID */UNS8 nodeId = (UNS8)(((d->ConsumerHeartbeatEntries[id]) & (UNS32)0x00FF0000) >> (UNS8)16);/* 將該消費者(主站)心跳包入口(從站)定時器句柄置為空,表示定時事件關閉 */d->ConsumerHeartBeatTimers[id] = TIMER_NONE;/* 將該節(jié)點狀態(tài)置為離線 */d->NMTable[nodeId] = Disconnected;/* 調(diào)用心跳錯誤回調(diào)函數(shù),通過字典可以配置 */(*d->heartbeatError)(d, nodeId); } /* 處理節(jié)點守護報文 */ void proceedNODE_GUARD(CO_Data *d, Message *m) {UNS8 nodeId = (UNS8) GET_NODE_ID((*m));if(m->rtr == 1){} /* 如果是遠程幀,表示該幀為響應運行狀態(tài) */else{/* 從報文中取出節(jié)點運行狀態(tài) */e_nodeState newNodeState = (e_nodeState)((*m).data[0] & 0x7F);MSG_WAR(0x3110, "Received NMT nodeId : ", nodeId);/* 將節(jié)點壽命值恢復滿 */d->nodeGuardStatus[nodeId] = *d->LifeTimeFactor;/* 更新節(jié)點狀態(tài),并調(diào)用回調(diào)函數(shù) */if(d->NMTable[nodeId] != newNodeState){(*d->post_SlaveStateChange)(d, nodeId, newNodeState);d->NMTable[nodeId] = newNodeState;}/* MNT報文是從站發(fā)送的bootup報文,調(diào)用回調(diào)函數(shù) */if(d->NMTable[nodeId] == Initialisation){MSG_WAR(0x3100, "The NMT is a bootup from node : ", nodeId);(*d->post_SlaveBootup)(d, nodeId);}/* 如果該節(jié)點上報過來的不是未知狀態(tài),則要對該節(jié)點進行重新倒計時 */if(d->NMTable[nodeId] != Unknown_state) {UNS8 index, ConsumerHeartBeat_nodeId;/* 遍歷消費者(主站)的所有心跳包入口(從站) */for(index = (UNS8)0x00; index < *d->ConsumerHeartbeatCount; index++){/* 從消費者(主站)心跳包入口(從站)中取出節(jié)點ID */ConsumerHeartBeat_nodeId = (UNS8)(((d->ConsumerHeartbeatEntries[index]) & (UNS32)0x00FF0000) >> (UNS8)16);/* 如果報文發(fā)送節(jié)點的id和入口id吻合,則對該節(jié)點重新進行倒計時 */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);}}}} }
生命保護機制:主站為每個從站設定一個生命值。每隔一段時間詢問一次從站當前狀態(tài),并將生命值減一。收到從站回復,則將生命值復位。否則當生命值減到0的時候,判斷其為掉線。
/* 節(jié)點守護報文初始化主站每隔一段時間發(fā)送守護報文,如果規(guī)定次數(shù)沒有回復,則認定從站離線 */ void nodeguardInit(CO_Data *d) {/* 注冊字典索引號0x100C和子索引號0x00的回調(diào)函數(shù)為OnNodeGuardUpdate */RegisterSetODentryCallBack(d, 0x100C, 0x00, &OnNodeGuardUpdate);/* 注冊字典索引號0x100D和子索引號0x00的回調(diào)函數(shù)為OnNodeGuardUpdate */RegisterSetODentryCallBack(d, 0x100D, 0x00, &OnNodeGuardUpdate);/* 判斷字典中是否配置時間和次數(shù) */if(*d->GuardTime && *d->LifeTimeFactor) {UNS8 i;/* 取出發(fā)送守護報文的間隔時間 */TIMEVAL time = *d->GuardTime;/* 注冊一個定時事件,在規(guī)定時間發(fā)送守護報文 */d->GuardTimeTimer = SetAlarm(d, 0, &GuardTimeAlarm, MS_TO_TIMEVAL(time), MS_TO_TIMEVAL(time));MSG_WAR(0x0, "GuardTime: ", time);/* 初始化所有節(jié)點壽命為滿值 */for(i = 0; i < NMT_MAX_NODE_ID; i++){/* 如果節(jié)點狀態(tài)正常并且節(jié)點號不是本身 */if(d->NMTable[i] != Unknown_state && i != *d->bDeviceNodeId){d->nodeGuardStatus[i] = *d->LifeTimeFactor;}}MSG_WAR(0x0, "Timer for node-guarding startet", 0);} } /* 發(fā)送節(jié)點守護報文 */ UNS8 masterSendNMTnodeguard(CO_Data *d, UNS8 nodeId) {Message m;/* MNT報文(數(shù)據(jù)幀表示響應,遠程幀表示請求) */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);/* 發(fā)送該幀 */return canSend(d->canHandle,&m); }/* 處理節(jié)點守護報文 */ void proceedNODE_GUARD(CO_Data *d, Message *m) {/* 從數(shù)據(jù)包中獲取節(jié)點id */UNS8 nodeId = (UNS8) GET_NODE_ID((*m));/* 如果是遠程幀,表示該幀為請求上報運行狀態(tài) */if(m->rtr == 1){/* 如果節(jié)點id和自身匹配,則上報 */if(nodeId == *d->bDeviceNodeId){Message msg;/* MNT報文(數(shù)據(jù)幀表示響應,遠程幀表示請求) */UNS16 tmp = *d->bDeviceNodeId + 0x700;/* cob-id */msg.cob_id = UNS16_LE(tmp);/* 長度 */msg.len = (UNS8)0x01;/* 數(shù)據(jù)幀:響應 */msg.rtr = 0;/* 節(jié)點狀態(tài) */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);/* 發(fā)送報文 */canSend(d->canHandle, &msg);}}else{} }
總結(jié)
以上是生活随笔為你收集整理的CANOpen生命守护机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 书还可以这样做?3分钟扒光这本变态级作品
- 下一篇: STM32之串口DMA例程