之前项目中使用到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的例子,再加上不断尝试,这样基本的功能框架就实现了。