<修改> 1、添加变化上送时的品质与时间;2、调整解析icd文件肿获取报告下的配置数据;3、调试事件报告控制块,实现客户端使能后上送变化数据

This commit is contained in:
ypc 2026-06-08 14:02:03 +08:00
parent 7c18f5ee9d
commit cd61e8e27b
5 changed files with 73 additions and 13 deletions

View File

@ -44,6 +44,33 @@ LOCAL IedServer gp_iedServer = NULL;
LOCAL bool g_dbg_switch = false; LOCAL bool g_dbg_switch = false;
/** SIGINT 信号处理:通知后台线程退出 */ /** SIGINT 信号处理:通知后台线程退出 */
/* RCB event handler for monitoring client report subscriptions */
LOCAL void rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError)
{
const char* name = ReportControlBlock_getName(rcb);
char* rptId = ReportControlBlock_getRptID(rcb);
char* dataSet = ReportControlBlock_getDataSet(rcb);
switch (event)
{
case RCB_EVENT_ENABLE: LOG_I("RCB %s ENABLED rptId=%s datSet=%s trigOps=0x%x", name, rptId, dataSet, rcb->trgOps); break;
case RCB_EVENT_DISABLE: LOG_I("RCB %s DISABLED", name); break;
case RCB_EVENT_RESERVED: LOG_I("RCB %s RESERVED", name); break;
case RCB_EVENT_UNRESERVED:LOG_I("RCB %s UNRESERVED", name); break;
case RCB_EVENT_GI: LOG_I("RCB %s GI triggered", name); break;
case RCB_EVENT_SET_PARAMETER:
LOG_I("RCB %s SET param=%s err=%d trigOps=0x%x (before)", name, parameterName ? parameterName : "?", serviceError, rcb->trgOps);
if (parameterName && strcmp(parameterName, "TrgOps") == 0) {
rcb->trgOps |= 0x01;
LOG_I("RCB %s forced dchg, trigOps=0x%x", name, rcb->trgOps);
}
break;
case RCB_EVENT_GET_PARAMETER: LOG_I("RCB %s GET param=%s err=%d", name, parameterName ? parameterName : "?", serviceError); break;
default: LOG_I("RCB %s event=%d", name, event); break;
}
free(rptId);
free(dataSet);
}
LOCAL void sigint_handler(int signum) LOCAL void sigint_handler(int signum)
{ {
g_running = 0; g_running = 0;
@ -268,6 +295,7 @@ int mms_s_init(const char *icd_path, int port)
param_init(gp_iedServer, *gp_icd); param_init(gp_iedServer, *gp_icd);
file_init(gp_iedServer); file_init(gp_iedServer);
IedServer_setRCBEventHandler(gp_iedServer, rcbEventHandler, NULL);
IedServer_start(gp_iedServer, port); IedServer_start(gp_iedServer, port);

View File

@ -182,10 +182,10 @@ LOCAL int parse_ReportControl_TrgOps(XMLElement *ele_reportControl, stru_TrgOps
return -1; return -1;
} }
trgOps.dchg = (ele_trgOps->Attribute(key_dchg) == nullptr ? "false" : ele_trgOps->Attribute(key_dchg)) == "true"; trgOps.dchg = (ele_trgOps->Attribute(key_dchg) == nullptr ? false : strcmp(ele_trgOps->Attribute(key_dchg), "true") == 0);
trgOps.qchg = (ele_trgOps->Attribute(key_qchg) == nullptr ? "false" : ele_trgOps->Attribute(key_qchg)) == "true"; trgOps.qchg = (ele_trgOps->Attribute(key_qchg) == nullptr ? false : strcmp(ele_trgOps->Attribute(key_qchg), "true") == 0);
trgOps.dupd = (ele_trgOps->Attribute(key_dupd) == nullptr ? "false" : ele_trgOps->Attribute(key_dupd)) == "true"; trgOps.dupd = (ele_trgOps->Attribute(key_dupd) == nullptr ? false : strcmp(ele_trgOps->Attribute(key_dupd), "true") == 0);
trgOps.period = (ele_trgOps->Attribute(key_period) == nullptr ? "false" : ele_trgOps->Attribute(key_period)) == "true"; trgOps.period = (ele_trgOps->Attribute(key_period) == nullptr ? false : strcmp(ele_trgOps->Attribute(key_period), "true") == 0);
return 0; return 0;
} }
@ -211,12 +211,12 @@ LOCAL int parse_ReportControl_OptFields(XMLElement *ele_reportControl, stru_OptF
return -1; return -1;
} }
optFields.seqNum = (ele_optFields->Attribute(key_seqNum) == nullptr ? "false" : ele_optFields->Attribute(key_seqNum)) == "true"; optFields.seqNum = (ele_optFields->Attribute(key_seqNum) == nullptr ? false : strcmp(ele_optFields->Attribute(key_seqNum), "true") == 0);
optFields.timeStamp = (ele_optFields->Attribute(key_timeStamp) == nullptr ? "false" : ele_optFields->Attribute(key_timeStamp)) == "true"; optFields.timeStamp = (ele_optFields->Attribute(key_timeStamp) == nullptr ? false : strcmp(ele_optFields->Attribute(key_timeStamp), "true") == 0);
optFields.reasonCode = (ele_optFields->Attribute(key_reasonCode) == nullptr ? "false" : ele_optFields->Attribute(key_reasonCode)) == "true"; optFields.reasonCode = (ele_optFields->Attribute(key_reasonCode) == nullptr ? false : strcmp(ele_optFields->Attribute(key_reasonCode), "true") == 0);
optFields.dataRef = (ele_optFields->Attribute(key_dataRef) == nullptr ? "false" : ele_optFields->Attribute(key_dataRef)) == "true"; optFields.dataRef = (ele_optFields->Attribute(key_dataRef) == nullptr ? false : strcmp(ele_optFields->Attribute(key_dataRef), "true") == 0);
optFields.entryID = (ele_optFields->Attribute(key_entryID) == nullptr ? "false" : ele_optFields->Attribute(key_entryID)) == "true"; optFields.entryID = (ele_optFields->Attribute(key_entryID) == nullptr ? false : strcmp(ele_optFields->Attribute(key_entryID), "true") == 0);
optFields.configRef = (ele_optFields->Attribute(key_configRef) == nullptr ? "false" : ele_optFields->Attribute(key_configRef)) == "true"; optFields.configRef = (ele_optFields->Attribute(key_configRef) == nullptr ? false : strcmp(ele_optFields->Attribute(key_configRef), "true") == 0);
return 0; return 0;
} }

View File

@ -611,7 +611,7 @@ LOCAL int model_DataSet_init(LogicalNode *LLN0, stru_icd &icd, std::map<std::str
for(it_fcda = p_dataset->vec_fcda.begin(); it_fcda != p_dataset->vec_fcda.end(); it_fcda++) // 遍历数据集成员 for(it_fcda = p_dataset->vec_fcda.begin(); it_fcda != p_dataset->vec_fcda.end(); it_fcda++) // 遍历数据集成员
{ {
std::string variable = it_fcda->prefix + it_fcda->lnClass + it_fcda->lnInst + "$" + \ std::string variable = it_fcda->prefix + it_fcda->lnClass + it_fcda->lnInst + "$" + \
it_fcda->fc + "$" + it_fcda->doName + "$" + it_fcda->daName; // 拼装 FCDA 变量名 it_fcda->fc + "$" + it_fcda->doName + (it_fcda->daName.empty() ? "" : "$" + it_fcda->daName); // 拼装 FCDA 变量名
for(int i = 0; i < variable.size(); i++) // 将变量名中所有 '.' 替换为 '$' for(int i = 0; i < variable.size(); i++) // 将变量名中所有 '.' 替换为 '$'
{ {
@ -663,7 +663,9 @@ LOCAL int model_ReportControlBlock_init(LogicalNode *LLN0, stru_icd &icd, std::m
int Options = model_get_rpt_options(rcb.optFields); // 将 OptFields 结构转为位掩码 int Options = model_get_rpt_options(rcb.optFields); // 将 OptFields 结构转为位掩码
int trgOps = model_get_rpt_trgOps(rcb.trgOps); // 将 TrgOps 结构转为位掩码 int trgOps = model_get_rpt_trgOps(rcb.trgOps); // 将 TrgOps 结构转为位掩码
ReportControlBlock_create(it_rcb->c_str(), LLN0, rcb.rptID.c_str(), rcb.buffered, rcb.datSet.c_str(), rcb.confRev, trgOps, Options, rcb.bufTime, rcb.intgPd); // 创建 RCB LOG_I("RCB CREATE: name=%s dchg=%d qchg=%d dupd=%d period=%d -> trgOps=0x%x",
it_rcb->c_str(), rcb.trgOps.dchg, rcb.trgOps.qchg, rcb.trgOps.dupd, rcb.trgOps.period, trgOps);
rcb.Rcb = ReportControlBlock_create(it_rcb->c_str(), LLN0, rcb.rptID.c_str(), rcb.buffered, rcb.datSet.c_str(), rcb.confRev, trgOps, Options, rcb.bufTime, rcb.intgPd);
} }
return 0; return 0;

View File

@ -580,6 +580,9 @@ LOCAL void mms_s_value_update(const char *str_saddr, const char *str_val)
DataAttribute *p_da = (DataAttribute *)p_node; DataAttribute *p_da = (DataAttribute *)p_node;
LOG_I("mms_s_value_update: saddr=%s val=%s da_type=%d da_name=%s",
saddr.c_str(), val.c_str(), p_da->type, p_da->name);
if(g_iec61850s_value_update_cb_map.find(p_da->type) == g_iec61850s_value_update_cb_map.end()) if(g_iec61850s_value_update_cb_map.find(p_da->type) == g_iec61850s_value_update_cb_map.end())
{ {
LOG_E("EnumType %d not found in ICD", p_da->type); LOG_E("EnumType %d not found in ICD", p_da->type);
@ -590,7 +593,34 @@ LOCAL void mms_s_value_update(const char *str_saddr, const char *str_val)
if(NULL != g_iec61850s_value_update_cb_map[p_da->type] && p_ied_server != NULL) if(NULL != g_iec61850s_value_update_cb_map[p_da->type] && p_ied_server != NULL)
{ {
IedServer_lockDataModel(p_ied_server);
g_iec61850s_value_update_cb_map[p_da->type](p_ied_server, p_da, val); g_iec61850s_value_update_cb_map[p_da->type](p_ied_server, p_da, val);
/* 向上查找父级 DO同步更新时间戳(t)和品质(q) */
ModelNode *parent = p_node->parent;
while (parent && parent->modelType != DataObjectModelType)
{
parent = parent->parent;
}
if (parent && parent->modelType == DataObjectModelType)
{
DataAttribute *child = (DataAttribute *)parent->firstChild;
while (child)
{
if (strcmp(child->name, "t") == 0)
{
IedServer_updateUTCTimeAttributeValue(p_ied_server, child, Hal_getTimeInMs());
}
else if (strcmp(child->name, "q") == 0)
{
IedServer_updateQuality(p_ied_server, child, QUALITY_VALIDITY_GOOD);
}
child = (DataAttribute *)child->sibling;
}
}
IedServer_unlockDataModel(p_ied_server);
} }
} }

View File

@ -42,7 +42,7 @@ LOCAL void iec61850s_st_mx_change_callback(std::string saddr, uint8_t data_type,
std::string val = dc_get_signal_val(p_data, data_type); std::string val = dc_get_signal_val(p_data, data_type);
if(val.empty()) if(val.empty())
{ {
LOG_E("val is empty"); LOG_E("val is empty for saddr: %s", saddr.c_str());
return; return;
} }