之前項目中使用到libiec61850庫,都是服務端開發。這次新的需求要接收服務端的遙測數據,這就涉及到客戶端開發了。 客戶端開發沒搞過啊,挑戰不少,但是人不就是通過戰勝困難才成長的嘛。
通過查看libiec61850的客戶端API發現,它支持兩種模式,一種同步阻塞模式,另一種是異步回調模式。由于我沒有打算采用多線程,那就選異步回調模式吧。
首先 ,創建鏈接,并connect,安裝鏈接回調函數。
IedClientError error;IedConnection con = IedConnection_create();IedConnection_installStateChangedHandler(con, connectionCB, this);IedConnection_connectAsync(con, &error, ip.c_str(), port);
接著,在鏈接回調函數中,判斷如果連接成功的話,就獲取rcb屬性。因為客戶端一個很重要的功能就是接收服務端的rcb(報告控制塊),然后從rcb中解析出服務端更新了哪個字段。
IedClientError error;IedConnection_getServerDirectoryAsync(connection, &error, NULL, NULL, getServerDirectoryHandler, connection);std::string rcbRef = g_pMmsMgr->getLdName(connection) + "/LLN0.RP.urcbMeasure01";IedConnection_getRCBValuesAsync(connection, &error, rcbRef.c_str(), NULL, getRCBValuesCB, connection);
getServerDirectoryHandler這個回調函數,實現的是獲取邏輯設備名稱,這個在注冊獲取rcb屬性回調函數時會用到。
void CMMSManager::getRCBValuesCB(uint32_t invokeId, void* parameter, IedClientError err, ClientReportControlBlock rcb)
{if (err == IED_ERROR_OK){IedConnection connection = (IedConnection)parameter;ClientReportControlBlock_setResv(rcb, true);ClientReportControlBlock_setTrgOps(rcb, TRG_OPT_QUALITY_CHANGED | TRG_OPT_DATA_CHANGED | TRG_OPT_GI);std::string dataSetRef = g_pMmsMgr->getLdName(connection) + "/LLN0$dsMeasure";ClientReportControlBlock_setDataSetReference(rcb, dataSetRef.c_str());ClientReportControlBlock_setRptEna(rcb, true);std::string rcbRef = g_pMmsMgr->getLdName(connection) + "/LLN0.RP.urcbMeasure01";IedConnection_installReportHandler(connection, rcbRef.c_str(),ClientReportControlBlock_getRptId(rcb), reportCB, parameter);/* Write RCB parameters and enable report */IedConnection_setRCBValuesAsync(connection, &err, rcb, RCB_ELEMENT_RESV | RCB_ELEMENT_DATSET | RCB_ELEMENT_TRG_OPS| RCB_ELEMENT_RPT_ENA | RCB_ELEMENT_GI, true, genericServiceCB, parameter);}
}
最開始時,我的客戶端無論如何都收不到服務斷的報告控制塊,就是這個getRCBValuesCB回調函數里的邏輯沒寫對。
碰到困難時,一定不要怕,多看libiec61850中關于client的例子,再加上不斷嘗試,這樣基本的功能框架就實現了。