日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CANOpen数据存档文件

發布時間:2025/3/15 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CANOpen数据存档文件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數據存檔文件,用于保存所有從節點的字典配置。

在從節點初始化時,從節點將上報boot_up報文。主節點收到boot_up報文后,將對從節點的字典和數據存檔文件進行對比,如果不匹配,則需要通過sdo報文對從節點字典進行重新配置,并根據配置決定是否命令從節點將新的配置存入非易失性存儲器。

主站可以為每個從站配置一個節點數據存檔文件,節點數據存檔文件的格式如圖:


/* DCF入口 */ typedef struct {UNS16 Index; //索引UNS8 Subindex; //子索引UNS32 Size; //字節數UNS8 *Data; //數據指針 }dcf_entry_t;void SaveNode(CO_Data *d, UNS8 nodeId); static UNS8 read_consise_dcf_next_entry(CO_Data *d, UNS8 nodeId); static UNS8 write_consise_dcf_next_entry(CO_Data *d, UNS8 nodeId); UNS8 init_consise_dcf(CO_Data *d,UNS8 nodeId);#ifdef _MSC_VER #define inline _inline #endif/* 啟動節點 */ void start_node(CO_Data *d, UNS8 nodeId) {/* 節點開始運行 */masterSendNMTstateChange(d, nodeId, NMT_Start_Node);/* 節點進入運行狀態 */d->NMTable[nodeId] = Operational; }/* 該函數被post_SlaveBootup函數調用,檢查是否要獲取數據存檔文件并啟動節點 */ UNS8 check_and_start_node(CO_Data *d, UNS8 nodeId) {/* 如果該節點的數據存檔文件正在初始化,則直接退出 */if(d->dcf_status != DCF_STATUS_INIT)return 0;/* 初始化節點nodeId的數據存檔文件,并讀取該節點的數據存檔文件中配置的所有條目的數據 */if((init_consise_dcf(d, nodeId) == 0) || (read_consise_dcf_next_entry(d, nodeId) == 0)){/* 如果沒有配置該節點數據存檔文件,則直接啟動該節點 */start_node(d, nodeId);return 1;}/* 開始讀取該節點的數據存檔文件后,將狀態設置為讀取檢查 */d->dcf_status = DCF_STATUS_READ_CHECK;return 2; }/* 啟動該節點并檢查是否有節點還未進入運行態 */ void start_and_seek_node(CO_Data *d, UNS8 nodeId) {UNS8 node;/* 啟動該節點 */start_node(d, nodeId);/* 檢查是否有節點還未進入運行態,如果有則檢查是否要獲取數據存檔文件并啟動節點 */for(node = 0; node < NMT_MAX_NODE_ID; node++){if(d->NMTable[node] != Initialisation)continue;/* 檢查是否要獲取數據存檔文件并啟動節點 */if(check_and_start_node(d, node) == 2)return;}/* 所有如果已經有從站進入運行態,則必須將主站設置為運行態 */setState(d, Operational); }/* 檢查數據存檔文件sdo并判斷下一步要做什么動作 */ static void CheckSDOAndContinue(CO_Data *d, UNS8 nodeId) {UNS32 abortCode = 0;UNS8 buf[4], match = 0;UNS32 size = 4;/* 如果狀態為讀取檢查,說明已經開始讀取 */if(d->dcf_status == DCF_STATUS_READ_CHECK){/* 獲取sdo讀取到的結果 */if(getReadResultNetworkDict(d, nodeId, buf, &size, &abortCode) != SDO_FINISHED)goto dcferror;/* 檢查讀取到的大小和本地配置的是否匹配 */if(size == d->dcf_size){match = 1;/* 檢查讀取到的內容和配置的是否匹配 */while(size--){if(buf[size] != d->dcf_data[size])match = 0;}}/* 如果匹配,繼續讀取該節點數據存檔文件中配置的下一個條目 */if(match) {/* 如果已經讀完該節點配置的數據存檔文件中的所有條目 */if(read_consise_dcf_next_entry(d, nodeId) == 0){/* 開始并檢查節點 */start_and_seek_node(d, nodeId);}}/* 如果讀取的數據存檔文件和配置的數據存檔文件不匹配,則將配置數據存檔文件寫到節點字典中 */else {/* 初始化節點nodeId的數據存檔文件,寫數據存檔指針指向的條目數據并將指針偏移到下一個條目 */if((init_consise_dcf(d, nodeId) == 0) || (write_consise_dcf_next_entry(d, nodeId) == 0))goto dcferror; /* 將狀態配置為寫 */d->dcf_status = DCF_STATUS_WRITE;}}/* 如果狀態為寫 */else if(d->dcf_status == DCF_STATUS_WRITE){/* 檢查寫字典結果是否成功 */if(getWriteResultNetworkDict(d, nodeId, &abortCode) != SDO_FINISHED)goto dcferror;/* 寫該節點數據存檔文件中指針指向的條目的數據,并將指針偏移到該節點配置的下一個條目 */if(write_consise_dcf_next_entry(d, nodeId) == 0){ #ifdef DCF_SAVE_NODE/* 所有條目都寫完,通知從站保存字典到非易失性存儲器 */SaveNode(d, nodeId);/* 將狀態設置為保存 */d->dcf_status = DCF_STATUS_SAVED; #else/* 所有條目都寫完,將狀態設置為初始化 */d->dcf_status = DCF_STATUS_INIT;/* 啟動該節點并檢查是否有其它節點還未進入運行態,如果有則檢查是否要獲取數據存檔文件并啟動其它節點 */start_and_seek_node(d,nodeId); #endif}}/* 保存狀態 */else if(d->dcf_status == DCF_STATUS_SAVED){/* 檢查是否寫成功 */if(getWriteResultNetworkDict(d, nodeId, &abortCode) != SDO_FINISHED)goto dcferror;/* 重啟節點 */ masterSendNMTstateChange(d, nodeId, NMT_Reset_Node);/* 如果保存完該節點后,需要將數據存檔入口狀態設置初始化 */d->dcf_status = DCF_STATUS_INIT;/* 因為節點重啟還會boot_up,因此將節點狀態設置為未知狀態 */d->NMTable[nodeId] = Unknown_state;}return;dcferror:MSG_ERR(0x1A01, "SDO error in consise DCF", abortCode);MSG_WAR(0x2A02, "server node : ", nodeId);d->NMTable[nodeId] = Unknown_state; }/* 初始化節點nodeId的數據存檔文件 */ UNS8 init_consise_dcf(CO_Data *d, UNS8 nodeId) {UNS32 errorCode;ODCallback_t *Callback;UNS8 *dcf;/* 查找節點的數據存檔文件入口 */d->dcf_odentry = (*d->scanIndexOD)(0x1F22, &errorCode, &Callback);if(errorCode != OD_SUCCESSFUL)goto DCF_finish;/* 節點號不能大于數據存檔入口配置的條目數 */if(nodeId > d->dcf_odentry->bSubCount) goto DCF_finish;/* 該節點數據存檔入口配置的字節大小,為零說明沒有配置 */if(!d->dcf_odentry->pSubindex[nodeId].size) goto DCF_finish;/* 該節點的數據存檔文件入口配置指針 */dcf = *(UNS8 **)d->dcf_odentry->pSubindex[nodeId].pObject;/* 初始化數據存檔文件條目的偏移指針(數據存檔文件配置的前4字節是條目數) */d->dcf_cursor = dcf + 4;/* 初始化數據存檔文件已初始化條目計數器 */d->dcf_entries_count = 0;/* 數據存檔文件狀態設為初始化 */d->dcf_status = DCF_STATUS_INIT;return 1; DCF_finish: return 0; }/* 獲取該節點數據存檔文件中指針指向的條目的索引、子索引、數據指針、數據大小,并將指針偏移到下一個條目 */ UNS8 get_next_DCF_data(CO_Data *d, dcf_entry_t *dcf_entry, UNS8 nodeId) {UNS8 *dcfend;UNS32 nb_entries;UNS32 szData;UNS8 *dcf;/* DCF入口是否配置 */if(!d->dcf_odentry)return 0;/* 每個節點作為一個子條目存在,節點號不能大于子條目數 */if(nodeId > d->dcf_odentry->bSubCount)return 0;/* 該節點的數據存檔文件配置的字節大小 */szData = d->dcf_odentry->pSubindex[nodeId].size;/* 該節點的數據存檔文件配置指針 */dcf = *(UNS8 **)d->dcf_odentry->pSubindex[nodeId].pObject;/* 該節點的數據數據存檔文件條目數(數據存檔文件配置的前4字節) */nb_entries = UNS32_LE(*((UNS32 *)dcf));/* 該節點數據存檔文件的結束指針 */dcfend = dcf + szData;/* 該節點的數據存檔文件至少包含索引、子索引、和數據大小,共7個字節,并節點的數據存檔文件已初始化條目數小于配置的條目數 */if((UNS8 *)d->dcf_cursor + 7 < (UNS8 *)dcfend && d->dcf_entries_count < nb_entries){ #ifdef CANOPEN_BIG_ENDIANdcf_entry->Index = *(d->dcf_cursor++) << 8 | *(d->dcf_cursor++); #else/* 該條目索引 */memcpy(&dcf_entry->Index, d->dcf_cursor, 2);d->dcf_cursor += 2; #endif/* 該條目子索引 */dcf_entry->Subindex = *(d->dcf_cursor++);#ifdef CANOPEN_BIG_ENDIANdcf_entry->Size = *(d->dcf_cursor++) << 24 | *(d->dcf_cursor++) << 16 | *(d->dcf_cursor++) << 8 | *(d->dcf_cursor++); #else/* 該條目數據存儲區大小 */memcpy(&dcf_entry->Size, d->dcf_cursor, 4);d->dcf_cursor += 4; #endif/* 該條目數據存儲區指針 */d->dcf_data = dcf_entry->Data = d->dcf_cursor;/* 該條目數據存儲區大小 */d->dcf_size = dcf_entry->Size;/* 該節點下一條數據存檔文件條目的指針 */d->dcf_cursor += dcf_entry->Size;/* 該節點的數據存檔文件已初始化條目數加一 */d->dcf_entries_count++;return 1;}return 0; }/* 寫該節點數據存檔文件中指針指向的條目的數據,并將指針偏移到該節點配置的下一個條目 */ static UNS8 write_consise_dcf_next_entry(CO_Data* d, UNS8 nodeId) {UNS8 Ret;dcf_entry_t dcf_entry;/* 獲取該節點數據存檔文件中指針指向的條目的索引、子索引、數據指針、數據大小,并將指針偏移到下一個條目 */if(!get_next_DCF_data(d, &dcf_entry, nodeId))return 0;/* 將數據寫過去 */Ret = writeNetworkDictCallBackAI(d, nodeId, dcf_entry.Index, dcf_entry.Subindex, (UNS8)dcf_entry.Size, 0, dcf_entry.Data, CheckSDOAndContinue, 0, 0);if(Ret)MSG_ERR(0x1A02,"Erreur writeNetworkDictCallBackAI",Ret);return 1; }/* 讀取該節點數據存檔文件中指針指向的條目的數據,并將指針偏移到該節點配置的下一個條目 */ static UNS8 read_consise_dcf_next_entry(CO_Data *d, UNS8 nodeId) {UNS8 Ret;dcf_entry_t dcf_entry;/* 獲取該節點數據存檔文件中指針指向的條目的索引、子索引、數據指針、數據大小,并將指針偏移到下一個條目 */if(!get_next_DCF_data(d, &dcf_entry, nodeId))return 0;/* 讀取該節點數據存放文件中指針指向的條目的數據 */Ret = readNetworkDictCallbackAI(d, nodeId, dcf_entry.Index, dcf_entry.Subindex, 0, CheckSDOAndContinue, 0);if(Ret)MSG_ERR(0x1A03,"Erreur readNetworkDictCallbackAI", Ret);return 1; }/* 通知從站保存字典到非易失性存儲器 */ void SaveNode(CO_Data *d, UNS8 nodeId) {UNS8 Ret;UNS32 data = 0x65766173;Ret = writeNetworkDictCallBackAI(d, nodeId, 0x1010, 1, 4, 0, (void *)&data, CheckSDOAndContinue, 0, 0);if(Ret) MSG_ERR(0x1A04, "Erreur writeNetworkDictCallBackAI", Ret); }

總結

以上是生活随笔為你收集整理的CANOpen数据存档文件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。