From c6ca57a20497d424f4c0ac9601215da34f88d241 Mon Sep 17 00:00:00 2001 From: lnk Date: Thu, 14 May 2026 16:16:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=A3=85=E7=BD=AE=E9=87=8D?= =?UTF-8?q?=E5=90=AF=E5=8A=9F=E8=83=BD=E5=92=8C=E6=8E=A7=E5=88=B6=E4=BD=8D?= =?UTF-8?q?=E5=86=99=E5=85=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cfg_parse/cfg_parser.cpp | 28 +++ json/create_json.cpp | 7 + json/save2json.cpp | 247 ++++++++++++++----- log4cplus/log4.h | 4 +- mms/db_interface.h | 1 + mms/mms_process.c | 5 +- mms/mmsclient.c | 506 +++++++++++++++++++++++++++++++-------- mms/rdb_client.h | 38 ++- 8 files changed, 664 insertions(+), 172 deletions(-) diff --git a/cfg_parse/cfg_parser.cpp b/cfg_parse/cfg_parser.cpp index 1d22c78..cec7368 100644 --- a/cfg_parse/cfg_parser.cpp +++ b/cfg_parse/cfg_parser.cpp @@ -4204,6 +4204,18 @@ int terminal_ledger_web(QMap* terminal_dev_map, return 0; // 确保函数有返回值 } +static void init_oper_type_cache(ied_usr_t *ied_usr) +{ + if (ied_usr == NULL) + return; + + ied_usr->oper_type_cache.inited = SD_FALSE; + + ied_usr->oper_type_cache.ledrs_oper_type_id = -1; + ied_usr->oper_type_cache.reboot_oper_type_id = -1; + ied_usr->oper_type_cache.reset_oper_type_id = -1; +} + int parse_device_cfg_web() { std::cout << "parse_device_cfg_web" << endl; @@ -4437,6 +4449,10 @@ int parse_device_cfg_web() apr_snprintf(ied_usr->dev_key, sizeof(ied_usr->dev_key), "%s", "");//DEV_Key cout << "defalut dev_key:" << ied_usr->dev_key << endl; } + + //lnk20260512 + init_oper_type_cache(ied_usr); + //lnk20260304 ied_usr->log_level = log_level;//日志等级 cout << "ied_usr->log_level:" << ied_usr->log_level << endl; @@ -5600,6 +5616,15 @@ int DownloadFileWeb(const std::string& strUrl, return -1; } + if (chmod(localpath, 0777) != 0) + { + std::cerr << "chmod 777 failed: " << localpath << std::endl; + } + else + { + std::cout << "chmod 777 success: " << localpath << std::endl; + } + return 0; } @@ -5733,6 +5758,9 @@ int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_i chnl_usr->m_state = CHANNEL_DISCONNECTED; chnl_usr->m_ClosedMsTime = NEXT_CONNECT_TIME * (-1); + //lnk20260512 + init_oper_type_cache(ied_usr); + // 将 monitorData 中的数据写入到 LD_info 中 int count_real_monitor = 0; //遍历监测点台账的计数器 int j; diff --git a/json/create_json.cpp b/json/create_json.cpp index 87eb850..0f59948 100644 --- a/json/create_json.cpp +++ b/json/create_json.cpp @@ -166,6 +166,7 @@ public: QString WavePhasicB; QString WavePhasicC; QString TypeOfData; //闪变和统计是否合并 0-分开 1-合并 + QString IEDControl; //例:LD0 lnk2026-5-13 QString UnitOfTimeUnit; //暂态事件持续事件单位:0 - 毫秒 1 - 秒 lnk20260127 QString ValueOfTimeUnit; //上送值的时间:UTC-UTC时间 beijing-北京时间 QString WaveTimeFlag; //录波文件的时间:UTC-UTC时间 beijing-北京时间 @@ -384,6 +385,7 @@ bool get_xml_config_by_dev_type(const char* dev_type, XmlConfigC* out_cfg) { strncpy(out_cfg->TypeOfData, cfg.TypeOfData.toUtf8().constData(), sizeof(out_cfg->TypeOfData) - 1); out_cfg->TypeOfData[sizeof(out_cfg->TypeOfData) - 1] = '\0';//lnk20260127 strncpy(out_cfg->ValueOfTimeUnit, cfg.ValueOfTimeUnit.toUtf8().constData(),sizeof(out_cfg->ValueOfTimeUnit) - 1); strncpy(out_cfg->WaveTimeFlag, cfg.WaveTimeFlag.toUtf8().constData(), sizeof(out_cfg->WaveTimeFlag) - 1); + strncpy(out_cfg->IEDControl, cfg.IEDControl.toUtf8().constData(), sizeof(out_cfg->IEDControl) - 1);//lnk2026-5-13 strncpy(out_cfg->IEDname, cfg.IEDname.toUtf8().constData(), sizeof(out_cfg->IEDname) - 1); strncpy(out_cfg->LDevicePrefix, cfg.LDevicePrefix.toUtf8().constData(), sizeof(out_cfg->LDevicePrefix) - 1); @@ -1036,6 +1038,10 @@ bool ParseXMLConfig2(int xml_flag, XmlConfig *cfg, list *ctopiclist,QSt cfg->WaveTimeFlag.append(e.attribute("WaveTimeFlag")); } + if ("IEDControl" == strTag) + { + cfg->IEDControl.append(e.attribute("name")); + } if ("IED" == strTag) { cfg->IEDname.append(e.attribute("name")); @@ -1255,6 +1261,7 @@ int transfer_json_block_data(char v_wiring_type[], json_block_data *data) //json printf("TypeOfData = '%s'\n", cfg1.TypeOfData); printf("ValueOfTimeUnit = '%s'\n", cfg1.ValueOfTimeUnit); printf("WaveTimeFlag = '%s'\n", cfg1.WaveTimeFlag); + printf("IEDControl = '%s'\n", cfg1.IEDControl); printf("IEDname = '%s'\n", cfg1.IEDname); printf("LDevicePrefix = '%s'\n", cfg1.LDevicePrefix); printf("=====================================\n"); diff --git a/json/save2json.cpp b/json/save2json.cpp index e79481f..641bc89 100644 --- a/json/save2json.cpp +++ b/json/save2json.cpp @@ -91,10 +91,18 @@ extern "C" { extern ST_RET mms_mvla_fdelete (MVL_NET_INFO *net_info,ST_CHAR *file_to_delete,int iTimeout); - extern ST_RET write_ledrs_oper(MVL_NET_INFO* netInfo,//netInfo:客户端和 MMS 服务器之间的网络连接信息 - ST_CHAR* domName, //域名 iedname+0 - ST_INT oper_type_id, //数据类型 这里是boolean - ST_INT timeOut); //响应时长 + extern ST_RET write_common_oper(chnl_usr_t *chnl_usr, + ST_CHAR *domName, + const char *ctlName, + ST_INT oper_type_id, + ST_INT timeOut); + extern ST_RET write_mod_stval(chnl_usr_t *chnl_usr, + ST_CHAR *domName, + ST_INT timeOut); + + extern ST_RET mms_conclude_disconnect(MVL_NET_INFO *net_info, ST_INT timeOut); + + extern int BuildResetDomName(ied_usr_t *ied_usr, char *domName, size_t domNameSize); extern pt61850app_t *g_pt61850app; @@ -2225,7 +2233,7 @@ static int BuildTempLocalPath(char* outPath, const char* fileName = GetFileNameOnly(remotePath); if (fileName == NULL || fileName[0] == '\0') - fileName = "tmp_file.dat"; + fileName = "tmp_file"; const char* ipStr = chnl_usr->ip_str; if (ipStr == NULL || ipStr[0] == '\0') @@ -2235,7 +2243,7 @@ static int BuildTempLocalPath(char* outPath, SafePathName(ipStr, safeIp, sizeof(safeIp)); char dirPath[512] = {0}; - snprintf(dirPath, sizeof(dirPath), "/tmp/%s", safeIp); + snprintf(dirPath, sizeof(dirPath), "/FeProject/dat/filetodevice/%s", safeIp); /* 目录不存在则创建 */ if (MakeDirRecursive(dirPath) != 0) @@ -2244,8 +2252,16 @@ static int BuildTempLocalPath(char* outPath, return -1; } - snprintf(outPath, outSize, "%s/%s", dirPath, fileName); - return 0; + int n = snprintf(outPath, outSize, "%s/%s", dirPath, fileName); + if (n < 0 || (size_t)n >= outSize) + { + printf("BuildTempLocalPath path too long, outSize=%zu, dir=%s, fileName=%s\n", + outSize, dirPath, fileName); + outPath[0] = '\0'; + return -1; + } + + return 0; } static int HandleTypeDownloadAndUpload(chnl_usr_t* chnl_usr, @@ -2347,7 +2363,7 @@ static int HandleTypeTransferToDevice(chnl_usr_t* chnl_usr, if (chnl_usr == NULL || req == NULL || chnl_usr->net_info == NULL) return -1; - char localpath[512] = {0}; + char localpath[1024] = {0}; if (BuildTempLocalPath(localpath, sizeof(localpath), chnl_usr, req->remote_path) != 0) { DIY_ERRORLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL, @@ -2451,6 +2467,163 @@ static int HandleDeleteFileInDevice(chnl_usr_t* chnl_usr, return 0; } +/* +============================================================================== +TYPE ID DUMP +------------------------------------------------------------------------------ + +[TYPE] id=0 name=RTYP_BOOL size=1 num_rt=1 +[TYPE] id=1 name=RTYP_BTIME6 size=8 num_rt=1 +[TYPE] id=2 name=RTYP_BSTR6 size=1 num_rt=1 +[TYPE] id=3 name=RTYP_BSTR8 size=1 num_rt=1 +[TYPE] id=4 name=RTYP_BSTR9 size=2 num_rt=1 +[TYPE] id=5 name=RTYP_BVSTR6 size=3 num_rt=1 +[TYPE] id=6 name=RTYP_BVSTR8 size=3 num_rt=1 +[TYPE] id=7 name=RTYP_BVSTR10 size=4 num_rt=1 +[TYPE] id=8 name=RTYP_INT8U size=1 num_rt=1 +[TYPE] id=9 name=RTYP_INT16U size=2 num_rt=1 +[TYPE] id=10 name=RTYP_OSTR8 size=8 num_rt=1 +[TYPE] id=11 name=RTYP_VSTR32 size=33 num_rt=1 +[TYPE] id=12 name=RTYP_VSTR65 size=66 num_rt=1 +[TYPE] id=13 name=RTYP_INT32U size=4 num_rt=1 + +------------------------------------------------------------------------------ +自定义/业务类型 +------------------------------------------------------------------------------ + +[TYPE] id=14 name=I16 size=2 num_rt=1 +[TYPE] id=15 name=U32 size=4 num_rt=1 +[TYPE] id=16 name=UTF8VSTRING13 size=28 num_rt=1 + +------------------------------------------------------------------------------ +复杂结构体类型 +------------------------------------------------------------------------------ + +[TYPE] id=17 name=phv_type size=312 num_rt=152 +[TYPE] id=18 name=phsx_type size=52 num_rt=25 + +------------------------------------------------------------------------------ +LEDRs Oper 动态创建结果 +------------------------------------------------------------------------------ +例如: +[CTRL_INIT] success dom=PQPQLD0 type_id=19*/ +/////////////////////////////控制类消息处理 + + +static int HandleTypeControlDevice(chnl_usr_t *chnl_usr, + ied_usr_t *ied_usr, + file_dir_req_t *req, + std::string &jsonString) +{ + if (chnl_usr == NULL || chnl_usr->net_info == NULL || + ied_usr == NULL || req == NULL) + { + jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1); + return -1; + } + + char domName[256] = {0}; + BuildResetDomName(ied_usr, domName, sizeof(domName)); + + const char *controlName = NULL; + ST_INT operTypeId = -1; + ST_RET ret = SD_FAILURE; + + if (strcmp(req->path, "return") == 0) + { + controlName = "CO$LEDRs$Oper"; + operTypeId = ied_usr->oper_type_cache.ledrs_oper_type_id; + + if (ied_usr->oper_type_cache.inited != SD_TRUE || operTypeId < 0) + { + jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1); + DIY_ERRORLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL, + "【ERROR】控制操作失败,LEDRs Oper type_id 未初始化 terminal_id=%s type_id=%d", + req->devid, operTypeId); + return -1; + } + + printf("[CONTROL] before write_common_oper control=%s type_id=%d\n", + controlName, operTypeId); + + ret = write_common_oper(chnl_usr, + domName, + controlName, + operTypeId, + g_pt61850app->mmsOpTimeout); + + printf("[CONTROL] after write_common_oper control=%s ret=0x%X\n", + controlName, ret); + } + else if (strcmp(req->path, "reboot") == 0) + { + controlName = "CO$Reboot$Oper"; + operTypeId = ied_usr->oper_type_cache.reboot_oper_type_id; + + if (ied_usr->oper_type_cache.inited != SD_TRUE || operTypeId < 0) + { + jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1); + DIY_ERRORLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL, + "【ERROR】控制操作失败,Reboot Oper type_id 未初始化 terminal_id=%s type_id=%d", + req->devid, operTypeId); + return -1; + } + + printf("[CONTROL] before write_common_oper control=%s type_id=%d\n", + controlName, operTypeId); + + ret = write_common_oper(chnl_usr, + domName, + controlName, + operTypeId, + g_pt61850app->mmsOpTimeout); + + printf("[CONTROL] after write_common_oper control=%s ret=0x%X\n", + controlName, ret); + } + else if (strcmp(req->path, "reset") == 0) + { + controlName = "ST$Mod$stVal"; + + printf("[CONTROL] before write_mod_stval control=%s\n", controlName); + + ret = write_mod_stval(chnl_usr, + domName, + g_pt61850app->mmsOpTimeout); + + printf("[CONTROL] after write_mod_stval ret=0x%X\n", ret); + + if (ret == SD_SUCCESS) + { + ST_RET discRet = mms_conclude_disconnect(chnl_usr->net_info, + g_pt61850app->mmsOpTimeout); + + printf("[CONTROL] disconnect after reset ret=0x%X\n", discRet); + } + } + else + { + printf("[CONTROL] unknown path=%s\n", req->path); + jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1); + return -1; + } + + if (ret == SD_SUCCESS) + { + jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, 0); + DIY_WARNLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL, + "【WARN】控制操作成功 terminal_id=%s path=%s", req->devid, req->path); + return 0; + } + + jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1); + DIY_ERRORLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL, + "【ERROR】控制操作失败 terminal_id=%s path=%s ret=0x%X", + req->devid, req->path, ret); + + return -1; +} + void HandleFileDirReqForChannel(chnl_usr_t *chnl_usr) { if (chnl_usr == NULL) { @@ -2480,12 +2653,12 @@ void HandleFileDirReqForChannel(chnl_usr_t *chnl_usr) return; } - std::cout << "[FILEDIR] checking req for terminal_id=" + if(DEBUGOPEN)std::cout << "[FILEDIR] checking req for terminal_id=" << ied_usr->terminal_id << std::endl; file_dir_req_t *req = PopMatchedFileDirReq(ied_usr->terminal_id); if (req == NULL) { - std::cout << "[FILEDIR] no matched request, terminal_id=" + if(DEBUGOPEN)std::cout << "[FILEDIR] no matched request, terminal_id=" << ied_usr->terminal_id << std::endl; return; } @@ -2541,54 +2714,10 @@ void HandleFileDirReqForChannel(chnl_usr_t *chnl_usr) handleRet = HandleDeleteFileInDevice(chnl_usr, req, jsonString); } else if (req->type == 4){ //复位 - char domName[256] = {0}; //构造ied+0的domName - - // 取第一个 LD - if (ied_usr->LD_info && - ied_usr->LD_info[0].LD_name) - { - snprintf(domName, - sizeof(domName), - "%s", - ied_usr->LD_info[0].LD_name); - - // 把末尾数字改成0 - int len = strlen(domName); - - if (len > 0 && isdigit(domName[len - 1])) - { - domName[len - 1] = '0'; - } - } - else //没取到则使用默认的domName "PQMonitorPQM0" - { - strcpy(domName, "PQMonitorPQM0"); - std::cout << "use default domName=PQMonitorPQM0" - << std::endl; - DIY_ERRORLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL, - "【ERROR】未取到 LD 信息,使用默认 domName=%s terminal_id=%s", - domName, req->devid); - } - - std::cout << "[CTRL] domName=" - << domName - << std::endl; - - handleRet = write_ledrs_oper(chnl_usr->net_info, - domName, - g_rpt_typeids.mmsbool, //数据类型,使用全局配置的mmsbool类型 - g_pt61850app->mmsOpTimeout); - - if(handleRet == 0){ - jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, 0); - DIY_WARNLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL, - "【WARN】复位操作成功 terminal_id=%s", req->devid); - } - else{ - jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1); - DIY_ERRORLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL, - "【ERROR】复位操作失败 terminal_id=%s ret=0x%X", req->devid, handleRet); - } + handleRet = HandleTypeControlDevice(chnl_usr, + ied_usr, + req, + jsonString); } else { diff --git a/log4cplus/log4.h b/log4cplus/log4.h index a8ec818..9dd3175 100644 --- a/log4cplus/log4.h +++ b/log4cplus/log4.h @@ -113,12 +113,12 @@ extern LOG_TLS int g_log_code_tls; // 声明为 TLS 变量,定义见 log4.cpp int __old_code__ = g_log_code_tls; \ g_log_code_tls = (int)(CODE_INT); \ \ - char __msg_buf__[256]; \ + char __msg_buf__[512]; \ format_log_msg(__msg_buf__, sizeof(__msg_buf__), __VA_ARGS__); \ \ const char* __key_raw__ = (KEY); \ \ - char __key_buf__[256]; \ + char __key_buf__[512]; \ switch ((int)(KEY_TYPE)) { \ case 0: \ snprintf(__key_buf__, sizeof(__key_buf__), "process"); \ diff --git a/mms/db_interface.h b/mms/db_interface.h index f983361..32d72c8 100644 --- a/mms/db_interface.h +++ b/mms/db_interface.h @@ -165,6 +165,7 @@ typedef struct { char TypeOfData[64]; char ValueOfTimeUnit[64]; char WaveTimeFlag[64]; + char IEDControl[64]; char IEDname[64]; char LDevicePrefix[64]; } XmlConfigC; diff --git a/mms/mms_process.c b/mms/mms_process.c index 04576f9..47008dd 100644 --- a/mms/mms_process.c +++ b/mms/mms_process.c @@ -32,7 +32,7 @@ extern apr_pool_t* g_cfg_pool; extern apr_pool_t* g_init_pool; extern int g_DevFlag; //日志配置中读取的参数,暂无特定使用lnk20250121 - +extern bool DEBUGOPEN;//调试开关,控制是否输出调试日志,默认关闭 extern int IED_COUNT; extern int RECALL_ONLY_FLAG; //lnk20260309添加一个全局变量,标志是否只运行补招程序 @@ -1531,7 +1531,8 @@ void CheckAllConnectedChannel() if(chnl_usr->m_state == CHANNEL_CONNECTED) { if(g_node_id == THREE_SECS_DATA_BASE_NODE_ID) { - printf("[FILEDIR] enter HandleFileDirReqForChannel"); + InitLedrsOperTypeForChannel(chnl_usr);//写特殊控制的初始化 + if(DEBUGOPEN)printf("[FILEDIR] enter HandleFileDirReqForChannel"); HandleFileDirReqForChannel(chnl_usr);//文件目录请求 } diff --git a/mms/mmsclient.c b/mms/mmsclient.c index 0488dd8..c037f29 100644 --- a/mms/mmsclient.c +++ b/mms/mmsclient.c @@ -80,6 +80,9 @@ #include //lnk20241119 #include "../cfg_parse/custom_printf.h"//lnk20250225 + +#include "../log4cplus/log4.h" + extern uint32_t g_node_id; extern char subdir[128]; unsigned int g_no_auth = 0; @@ -132,6 +135,8 @@ IDENT_RESP_INFO identify_response_info = /************************************************************************/ +extern pt61850app_t *g_pt61850app; + extern TP0_CONN *tp0_conn_arr; /* ptr to array of "max_num_conns" structs */ static ST_VOID disc_ind_fun (MVL_NET_INFO *cc, ST_INT discType); @@ -269,12 +274,25 @@ MY_CONTROL_INFO my_control_info; ST_INT mms_var_type_id_create (MVL_NET_INFO *clientNetInfo, ST_INT scope, ST_CHAR *dom_name, ST_CHAR *var_name, int iTimeOut) { -MVL_REQ_PEND *reqCtrl; +//MVL_REQ_PEND *reqCtrl; +//reqCtrl 必须初始化为 NULL,防止 mvla_getvar 失败后释放野指针 + MVL_REQ_PEND *reqCtrl = NULL; GETVAR_REQ_INFO getvar_req; ST_INT type_id = -1; /* start with invalid type id */ ST_RET ret; +//参数合法性检查 + if (clientNetInfo == NULL || dom_name == NULL || var_name == NULL) + { + printf("[GETVAR] invalid arg netInfo=%p dom=%p var=%p\n", + clientNetInfo, dom_name, var_name); + return -1; + } + + //结构体清零,避免未初始化字段导致异常 + memset(&getvar_req, 0, sizeof(getvar_req)); + /* Get the type of this "Oper" attribute & create type. */ /* Would be more efficient to do this just once before this function.*/ getvar_req.req_tag = GETVAR_NAME; @@ -283,19 +301,53 @@ ST_RET ret; if (scope == DOM_SPEC) getvar_req.name.domain_id= dom_name; getvar_req.name.obj_name.vmd_spec = var_name; + + //增加调试打印,确认崩溃点 + printf("[GETVAR] start dom=%s var=%s\n", dom_name, var_name); ret = mvla_getvar (clientNetInfo, &getvar_req, &reqCtrl); - if (ret == SD_SUCCESS) + + //打印 mvla_getvar 返回值和 reqCtrl + printf("[GETVAR] mvla_getvar ret=0x%X reqCtrl=%p\n", ret, reqCtrl); + + if (ret == SD_SUCCESS){ ret = waitReqDone (reqCtrl, iTimeOut); - if (ret != SD_SUCCESS) + //打印 waitReqDone 返回值 + printf("[GETVAR] wait ret=0x%X\n", ret); + } + + if (ret != SD_SUCCESS){ echo_warn2 ("Error getting type of variable '%s' in domain '%s'\n", var_name, dom_name); + } else { /* Don't care about name so pass NULL. */ - type_id = mvl_type_id_create (NULL, reqCtrl->u.getvar.resp_info->type_spec.data, - reqCtrl->u.getvar.resp_info->type_spec.len); + //type_id = mvl_type_id_create (NULL, reqCtrl->u.getvar.resp_info->type_spec.data, + // reqCtrl->u.getvar.resp_info->type_spec.len); + //严格检查 resp_info/type_spec,避免空指针崩溃 + if (ret == SD_SUCCESS && + reqCtrl != NULL && + reqCtrl->u.getvar.resp_info != NULL && + reqCtrl->u.getvar.resp_info->type_spec.data != NULL && + reqCtrl->u.getvar.resp_info->type_spec.len > 0) + { + type_id = mvl_type_id_create( + NULL, + reqCtrl->u.getvar.resp_info->type_spec.data, + reqCtrl->u.getvar.resp_info->type_spec.len); + + printf("[GETVAR] create type_id=%d len=%d\n", + type_id, + reqCtrl->u.getvar.resp_info->type_spec.len); + } + else + { + printf("[GETVAR] failed dom=%s var=%s ret=0x%X\n", + dom_name, var_name, ret); + } } - mvl_free_req_ctrl (reqCtrl); /* Done with request struct */ + //只有 reqCtrl 非空才释放 + if (reqCtrl != NULL)mvl_free_req_ctrl (reqCtrl); /* Done with request struct */ return (type_id); } @@ -1683,20 +1735,20 @@ static ST_VOID *my_realloc_err (ST_VOID *old, ST_UINT size) } ///////////////////////////////////////////////////////////////////////// -//#define MAX_FILE_HANDLE_NUM (256) -//static FILE *fp_arr[MAX_FILE_HANDLE_NUM]; -//static ST_INT32 cur_handle = 0; -//ST_INT32 set_file_pointer( FILE *fp) -//{ -// ST_INT32 the_handle = cur_handle; -// fp_arr[cur_handle++] = fp; -// cur_handle %= MAX_FILE_HANDLE_NUM; -// return the_handle; -//} -//FILE* get_file_pointer(ST_INT32 handle) -//{ -// return fp_arr[handle]; -//} +#define MAX_FILE_HANDLE_NUM (256) +static FILE *fp_arr[MAX_FILE_HANDLE_NUM]; +static ST_INT32 cur_handle = 0; +ST_INT32 set_file_pointer( FILE *fp) +{ + ST_INT32 the_handle = cur_handle; + fp_arr[cur_handle++] = fp; + cur_handle %= MAX_FILE_HANDLE_NUM; + return the_handle; +} +FILE* get_file_pointer(ST_INT32 handle) +{ + return fp_arr[handle]; +} /////////////////////////////////////////////////////////////////////// #if (MMS_FOPEN_EN & RESP_EN) @@ -1705,39 +1757,39 @@ static ST_VOID *my_realloc_err (ST_VOID *old, ST_UINT size) /************************************************************************/ ST_VOID u_mvl_fopen_ind (MVL_IND_PEND *indCtrl) { -//FILE *fp; -//FOPEN_RESP_INFO resp_info; -//struct stat stat_buf; +FILE *fp; +FOPEN_RESP_INFO resp_info; +struct stat stat_buf; - //fp = fopen (indCtrl->u.fopen.filename, "rb"); /* CRITICAL: use "b" flag for binary transfer*/ - //if (fp == NULL) - // { - // _mplas_err_resp (indCtrl,11,6); /* File-access denied */ - // return; - // } - //if (fseek (fp, indCtrl->u.fopen.init_pos, SEEK_SET)) - // { - // _mplas_err_resp (indCtrl,11,5); /* Position invalid */ - // return; - // } + fp = fopen (indCtrl->u.fopen.filename, "rb"); /* CRITICAL: use "b" flag for binary transfer*/ + if (fp == NULL) + { + _mplas_err_resp (indCtrl,11,6); /* File-access denied */ + return; + } + if (fseek (fp, indCtrl->u.fopen.init_pos, SEEK_SET)) + { + _mplas_err_resp (indCtrl,11,5); /* Position invalid */ + return; + } - ///* WARNING: this only works if (FILE *) is a 32-bit pointer. */ - //resp_info.frsmid = set_file_pointer(fp); //(ST_INT32) fp; + /* WARNING: this only works if (FILE *) is a 32-bit pointer. */ + resp_info.frsmid = set_file_pointer(fp); //(ST_INT32) fp; - //if (fstat (fileno (fp), &stat_buf)) - // { /* Can't get file size or time */ - // _mplas_err_resp (indCtrl,11,0); /* File Problem, Other */ - // return; - // } - //else - // { - // resp_info.ent.fsize = stat_buf.st_size; - // resp_info.ent.mtimpres = SD_TRUE; - // resp_info.ent.mtime = stat_buf.st_mtime; - // } + if (fstat (fileno (fp), &stat_buf)) + { /* Can't get file size or time */ + _mplas_err_resp (indCtrl,11,0); /* File Problem, Other */ + return; + } + else + { + resp_info.ent.fsize = stat_buf.st_size; + resp_info.ent.mtimpres = SD_TRUE; + resp_info.ent.mtime = stat_buf.st_mtime; + } - //indCtrl->u.fopen.resp_info = &resp_info; - //mplas_fopen_resp (indCtrl); + indCtrl->u.fopen.resp_info = &resp_info; + mplas_fopen_resp (indCtrl); } #endif /* MMS_FOPEN_EN & RESP_EN */ @@ -1748,31 +1800,31 @@ ST_VOID u_mvl_fopen_ind (MVL_IND_PEND *indCtrl) /************************************************************************/ ST_VOID u_mvl_fread_ind (MVL_IND_PEND *indCtrl) { -//FILE *fp; -//ST_UCHAR *tmp_buf; -//MVLAS_FREAD_CTRL *fread_ctrl = &indCtrl->u.fread; -//FREAD_RESP_INFO resp_info; +FILE *fp; +ST_UCHAR *tmp_buf; +MVLAS_FREAD_CTRL *fread_ctrl = &indCtrl->u.fread; +FREAD_RESP_INFO resp_info; - //fp = get_file_pointer(fread_ctrl->req_info->frsmid);// (FILE *) fread_ctrl->req_info->frsmid; - ///* Do NOT read more than "max_size". */ - //tmp_buf = (ST_UCHAR *) chk_malloc (fread_ctrl->max_size); + fp = get_file_pointer(fread_ctrl->req_info->frsmid);// (FILE *) fread_ctrl->req_info->frsmid; + /* Do NOT read more than "max_size". */ + tmp_buf = (ST_UCHAR *) chk_malloc (fread_ctrl->max_size); - //resp_info.fd_len = fread (tmp_buf, 1, fread_ctrl->max_size, fp); - //if (resp_info.fd_len == 0 && ferror (fp)) - // { - // _mplas_err_resp (indCtrl, 3, 0); - // return; - // } + resp_info.fd_len = fread (tmp_buf, 1, fread_ctrl->max_size, fp); + if (resp_info.fd_len == 0 && ferror (fp)) + { + _mplas_err_resp (indCtrl, 3, 0); + return; + } - //resp_info.filedata = tmp_buf; - //if (resp_info.fd_len == fread_ctrl->max_size) - // resp_info.more_follows = SD_TRUE; - //else - // resp_info.more_follows = SD_FALSE; + resp_info.filedata = tmp_buf; + if (resp_info.fd_len == fread_ctrl->max_size) + resp_info.more_follows = SD_TRUE; + else + resp_info.more_follows = SD_FALSE; - //fread_ctrl->resp_info = &resp_info; - //mplas_fread_resp (indCtrl); - //chk_free (tmp_buf); /* Temporary buffer */ + fread_ctrl->resp_info = &resp_info; +mplas_fread_resp (indCtrl); + chk_free (tmp_buf); /* Temporary buffer */ } #endif /* #if (MMS_FREAD_EN & RESP_EN) */ @@ -1782,15 +1834,15 @@ ST_VOID u_mvl_fread_ind (MVL_IND_PEND *indCtrl) /************************************************************************/ ST_VOID u_mvl_fclose_ind (MVL_IND_PEND *indCtrl) { -//FILE *fp; -//MVLAS_FCLOSE_CTRL *fclose_ctrl = &indCtrl->u.fclose; +FILE *fp; +MVLAS_FCLOSE_CTRL *fclose_ctrl = &indCtrl->u.fclose; - //fp = get_file_pointer(fclose_ctrl->req_info->frsmid);//(FILE *) fclose_ctrl->req_info->frsmid; + fp = get_file_pointer(fclose_ctrl->req_info->frsmid);//(FILE *) fclose_ctrl->req_info->frsmid; - //if (fclose (fp)) - // _mplas_err_resp (indCtrl, 11, 0); /* File problem, other */ - //else - // mplas_fclose_resp (indCtrl); + if (fclose (fp)) + _mplas_err_resp (indCtrl, 11, 0); /* File problem, other */ + else + mplas_fclose_resp (indCtrl); } #endif /* #if (MMS_FCLOSE_EN & RESP_EN) */ @@ -1946,44 +1998,294 @@ MVL_REQ_PEND *reqCtrl; } //lnk20260508添加重启装置函数 -ST_RET write_ledrs_oper(MVL_NET_INFO* netInfo,//netInfo:客户端和 MMS 服务器之间的网络连接信息 - ST_CHAR* domName, //域名 iedname+0 - ST_INT oper_type_id, //数据类型 这里是boolean - ST_INT timeOut) //响应时长 +int BuildResetDomName(ied_usr_t *ied_usr, char *domName, size_t domNameSize) { + if (ied_usr == NULL || domName == NULL || domNameSize == 0) + return -1; + + domName[0] = '\0'; + + XmlConfigC cfg1; + memset(&cfg1, 0, sizeof(cfg1)); + + if (get_xml_config_by_dev_type(ied_usr->dev_type, &cfg1)) + { + printf("========== XmlConfigC dump ==========\n"); + printf("IEDControl = '%s'\n", cfg1.IEDControl); + printf("IEDname = '%s'\n", cfg1.IEDname); + printf("LDevicePrefix = '%s'\n", cfg1.LDevicePrefix); + printf("=====================================\n"); + + if (cfg1.IEDControl[0] != '\0') + { + snprintf(domName, domNameSize, "%s", cfg1.IEDControl); + printf("[RESET] use cfg1.IEDControl=%s\n", domName); + return 0; + } + } + + if (ied_usr->LD_info && ied_usr->LD_info[0].LD_name) + { + snprintf(domName, domNameSize, "%s", ied_usr->LD_info[0].LD_name); + + int len = strlen(domName); + if (len > 0 && isdigit(domName[len - 1])) + domName[len - 1] = '0'; + + printf("[RESET] use LD_name domName=%s\n", domName); + + DIY_WARNLOG_CODE(ied_usr->terminal_id, 1, LOG_CODE_FILE_CONTROL, + "【WARN】未取到 IEDControl 信息,使用 LD_name=%s terminal_id=%s", + domName, ied_usr->terminal_id); + + return -2; + } + + snprintf(domName, domNameSize, "%s", "PQMonitorPQM0"); + printf("[RESET] use default domName=%s\n", domName); + DIY_ERRORLOG_CODE(ied_usr->terminal_id, 1, LOG_CODE_FILE_CONTROL, + "【ERROR】未取到 LD 信息,使用默认 domName=%s terminal_id=%s", + domName, ied_usr->terminal_id); + return -1; +} + +static ST_INT ledrs_var_type_create(MVL_NET_INFO* net_info, + OBJECT_NAME* varObj, + ST_INT timeOut) +{ + MVL_REQ_PEND* reqCtrl; + GETVAR_REQ_INFO getvar_req; + VAR_ACC_TSPEC* type_spec; + ST_INT type_id = -1; ST_RET ret; + + memset(&getvar_req, 0, sizeof(getvar_req)); + + getvar_req.req_tag = GETVAR_NAME; + getvar_req.name = *varObj; + + ret = mvla_getvar(net_info, &getvar_req, &reqCtrl); + + if (ret == SD_SUCCESS) + ret = waitReqDone(reqCtrl, timeOut); + + if (ret == SD_SUCCESS) + { + type_spec = &reqCtrl->u.getvar.resp_info->type_spec; + + type_id = mvl_type_id_create(NULL, + type_spec->data, + type_spec->len); + } + + if (reqCtrl) + mvl_free_req_ctrl(reqCtrl); + + return type_id; +} +static ST_INT create_oper_type_id(MVL_NET_INFO *net_info, + ST_CHAR *domName, + const char *ctlName, + ST_INT timeOut) +{ + OBJECT_NAME obj; ST_CHAR varName[MAX_IDENT_LEN + 1]; - LEDRs_Oper_t oper; - memset(&oper, 0, sizeof(oper)); + if (net_info == NULL || domName == NULL || ctlName == NULL) + return -1; - oper.ctlVal = SD_TRUE; //618050抓包显示为true - - oper.origin.orCat = 3; //61850抓包显示为3 - oper.origin.orIdent[0] = '\0'; //618050抓包显示为missing - - oper.ctlNum = 1; //618050抓包显示为1 - - u_get_current_utc_time(&oper.T);//618050抓包显示为当前时间 - - oper.Test = SD_FALSE; //618050抓包显示为false - oper.Check[0] = 0x00; //618050抓包显示为bitstring 00 + memset(&obj, 0, sizeof(obj)); apr_snprintf(varName, sizeof(varName), - "LLN0$CO$LEDRs$Oper"); //61850抓包显示为LLN0$CO$LEDRs$Oper + "LLN0$%s", + ctlName); - ret = mms_named_var_write(netInfo, - varName, //itemid - DOM_SPEC, //统一使用DOM_SPEC作为域名标识符 - domName, - oper_type_id, - (ST_CHAR*)&oper, //数据源 这里是封装好的LEDRs_Oper_t结构体 - timeOut); + obj.object_tag = DOM_SPEC; + obj.domain_id = domName; + obj.obj_name.vmd_spec = varName; + + printf("[CTRL_INIT] create type dom=%s var=%s\n", + domName, varName); + + return ledrs_var_type_create(net_info, &obj, timeOut); +} +void InitLedrsOperTypeForChannel(chnl_usr_t *chnl_usr) +{ + printf("[CTRL_INIT] enter\n"); + + if (chnl_usr == NULL || chnl_usr->chnl == NULL || + chnl_usr->chnl->ied == NULL || chnl_usr->net_info == NULL) + { + printf("[CTRL_INIT] invalid chnl_usr\n"); + return; + } + + ied_t *ied = chnl_usr->chnl->ied; + ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); + + if (ied_usr == NULL || ied_usr->LD_info == NULL) + { + printf("[CTRL_INIT] invalid ied_usr or LD_info\n"); + return; + } + + printf("[CTRL_INIT] current inited=%d ledrs=%d reboot=%d reset=%d\n", + (int)ied_usr->oper_type_cache.inited, + ied_usr->oper_type_cache.ledrs_oper_type_id, + ied_usr->oper_type_cache.reboot_oper_type_id, + ied_usr->oper_type_cache.reset_oper_type_id); + + if (ied_usr->oper_type_cache.inited == SD_TRUE) + { + printf("[CTRL_INIT] already inited\n"); + return; + } + + char domName[256] = {0}; + + BuildResetDomName(ied_usr, + domName, + sizeof(domName)); + + printf("[CTRL_INIT] final dom=%s\n", domName); + + ied_usr->oper_type_cache.ledrs_oper_type_id = + create_oper_type_id(chnl_usr->net_info, + domName, + "CO$LEDRs$Oper", + g_pt61850app->mmsOpTimeout); + + printf("[CTRL_INIT] LEDRs type_id=%d\n", + ied_usr->oper_type_cache.ledrs_oper_type_id); + + ied_usr->oper_type_cache.reboot_oper_type_id = + create_oper_type_id(chnl_usr->net_info, + domName, + "CO$Reboot$Oper", + g_pt61850app->mmsOpTimeout); + + printf("[CTRL_INIT] Reboot type_id=%d\n", + ied_usr->oper_type_cache.reboot_oper_type_id); + + ied_usr->oper_type_cache.reset_oper_type_id = + create_oper_type_id(chnl_usr->net_info, + domName, + "ST$Mod$stVal", + g_pt61850app->mmsOpTimeout); + + printf("[CTRL_INIT] Reset type_id=%d\n", + ied_usr->oper_type_cache.reset_oper_type_id); + + /* 无论成功失败,都不再重复初始化 */ + ied_usr->oper_type_cache.inited = SD_TRUE; + + printf("[CTRL_INIT] finish inited=%d\n", + (int)ied_usr->oper_type_cache.inited); +} + + +ST_RET write_common_oper(chnl_usr_t *chnl_usr, + ST_CHAR *domName, + const char *ctlName, + ST_INT oper_type_id, + ST_INT timeOut) +{ + if (chnl_usr == NULL || + chnl_usr->net_info == NULL || + domName == NULL || + ctlName == NULL || + oper_type_id < 0) + { + printf("[OPER_WRITE] invalid param\n"); + return SD_FAILURE; + } + + ST_CHAR varName[MAX_IDENT_LEN + 1]; + apr_snprintf(varName, + sizeof(varName), + "LLN0$%s", + ctlName); + + Control_Oper_t oper; + memset(&oper, 0, sizeof(oper)); + + oper.ctlVal = SD_TRUE; + oper.origin.orCat = 3; + oper.origin.orIdent.len = 0; + oper.ctlNum = 1; + u_get_current_utc_time(&oper.T); + oper.Test = SD_FALSE; + oper.Check[0] = 0x00; + oper.Check[1] = 0x00; + + if ((int)sizeof(Control_Oper_t) != + mvl_type_ctrl[oper_type_id].data_size) + { + printf("[OPER_WRITE] SIZE MISMATCH ctl=%s local=%d runtime=%d\n", + ctlName, + (int)sizeof(Control_Oper_t), + mvl_type_ctrl[oper_type_id].data_size); + return SD_FAILURE; + } + + printf("[OPER_WRITE] dom=%s var=%s type_id=%d\n", + domName, varName, oper_type_id); + + return mms_named_var_write(chnl_usr->net_info, + varName, + DOM_SPEC, + domName, + oper_type_id, + (ST_CHAR *)&oper, + timeOut); +} + +ST_RET mms_conclude_disconnect(MVL_NET_INFO *net_info, ST_INT timeOut) +{ + MVL_REQ_PEND *reqCtrl = NULL; + ST_RET ret; + + if (net_info == NULL) + return SD_FAILURE; + + printf("[RESET] before mvl_concl\n"); + + ret = mvl_concl(net_info, &reqCtrl); + + printf("[RESET] after mvl_concl ret=0x%X reqCtrl=%p\n", + ret, reqCtrl); + + if (ret == SD_SUCCESS && reqCtrl != NULL) + { + ret = waitReqDone(reqCtrl, timeOut); + + printf("[RESET] conclude wait ret=0x%X\n", ret); + } + + if (reqCtrl != NULL) + mvl_free_req_ctrl(reqCtrl); return ret; } +ST_RET write_mod_stval(chnl_usr_t *chnl_usr, + ST_CHAR *domName, + ST_INT timeOut) +{ + ST_CHAR varName[MAX_IDENT_LEN + 1]; + ST_INT16 value = 88; + + apr_snprintf(varName, sizeof(varName), "LLN0$ST$Mod$stVal"); + + return mms_named_var_write(chnl_usr->net_info, + varName, + DOM_SPEC, + domName, + 14, //int + (ST_CHAR *)&value, + timeOut); +} /************************************************************************/ /* init_log_cfg */ diff --git a/mms/rdb_client.h b/mms/rdb_client.h index 1bcbec0..60b1cd5 100644 --- a/mms/rdb_client.h +++ b/mms/rdb_client.h @@ -320,6 +320,17 @@ struct LD_info_t{ //录波 }; +//装置控制初始化 +typedef struct +{ + ST_BOOLEAN inited; + + ST_INT ledrs_oper_type_id; + ST_INT reboot_oper_type_id; + ST_INT reset_oper_type_id; + +} MMS_OPER_TYPE_CACHE; + struct ied_usr_t{ LD_info_t *LD_info; /**< LD数组 */ int dev_idx; /**< 设备序号 */ @@ -346,6 +357,8 @@ struct ied_usr_t{ bool lastconnectstat;//lnk20250704 bool has_logged_disconnect;//lnk20250704 + + MMS_OPER_TYPE_CACHE oper_type_cache; }; @@ -533,24 +546,35 @@ int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info,long long trig_tm); void HandleFileDirReqForChannel(chnl_usr_t *chnl_usr); +void InitLedrsOperTypeForChannel(chnl_usr_t *chnl_usr); //lnk20250508添加重启装置函数 //根据抓包显示oper的data结构有6个item -typedef struct +typedef struct { - ST_BOOLEAN ctlVal; //0:不重启 1:重启 + ST_BOOLEAN ctlVal; struct { - ST_INT8 orCat; - ST_CHAR orIdent[1]; // 空字符串 + ST_INT16 orCat; + + struct + { + ST_INT16 len; + ST_UINT8 data[64]; + } orIdent; + } origin; - ST_UINT8 ctlNum; + ST_UINT32 ctlNum; + MMS_UTC_TIME T; + ST_BOOLEAN Test; - ST_UCHAR Check[1]; // bit-string 00 -} LEDRs_Oper_t; + + ST_UCHAR Check[2]; + +} Control_Oper_t; //////////////////////////////////////////////////////////////////