/** * @file: $RCSfile: rdb_ext_utils.c,v $ * @brief: $ rdb 利用usr_ext扩充的结构的一些工具函数 * * @version: $Revision: 1.11 $ * @date: $Date: 2018/12/23 12:39:52 $ * @author: $Author: lizhongming $ * @state: $State: Exp $ * * @latest: $Id: rdb_ext_utils.c,v 1.11 2018/12/23 12:39:52 lizhongming Exp $ */ #include #include "rdb_client.h" #include "xmltools.h" #include "db_interface.h" #include "../cfg_parse/custom_printf.h"//lnk20250225 #include "../log4cplus/log4.h"//lnk添加log4 //extern rdb_t* g_rdb ; extern node_t* g_node ; extern char g_my_conf_fname[256]; extern apr_pool_t* g_init_pool; extern apr_pool_t* g_run_pool; extern pt61850app_t* g_pt61850app; //extern int g_sysfile_appid; //extern char *g_sysfile_filedir; //int my_index =0; //extern ied_info_t *my_info; //extern byte_t g_file_name_len; //extern byte_t g_file_time_from; ////////////////////////str 辅助函数////////////////////////// char* str_trim_both(char* temp,const char* pattern) { // pattern such as " \t" or " \t\'" unsigned int i,j; for(i=0;i=0;j--) { if ( strchr(pattern,temp[j]) ) temp[j] = 0; else break; } return(temp); } ////////////////////////rdb 61850扩充结构 辅助函数////////////////////////// ied_usr_t* GET_IEDEXT_ADDR(ied_t *ied) { assert(ied); return (ied_usr_t* )ied->usr_ext; } element_usr_t* GET_DOTEXT_ADDR(element_t *elem) { element_usr_t *elem_usr; assert(elem); if (elem->usr_ext == NULL) { elem_usr = apr_pcalloc(g_init_pool,sizeof(element_usr_t)); elem_usr->last_soe_status = 99; elem->usr_ext = elem_usr; } return (element_usr_t* )elem->usr_ext; } LD_info_t* find_LD_from_cpuCount_and_LEDRs(ied_t* ied, byte_t cpuCount) { LD_info_t *LD_info = NULL; element_t *elem = NULL; LD_info = & (GET_IEDEXT_ADDR(ied)->LD_info[cpuCount]); elem = apr_hash_get(LD_info->ht_fcd, "LLN0$CO$LEDRs", APR_HASH_KEY_STRING); if (elem) return LD_info; else return NULL; } LD_info_t* find_LD_from_cpuId(ied_t* ied,byte_t cpuId) { int cpuno; LD_info_t* LD_info = NULL; assert(ied); for(cpuno=0 ; cpunocpucount; cpuno++) { if ( ied->cpuinfo[cpuno].addr != cpuId ) continue; LD_info = & (GET_IEDEXT_ADDR(ied)->LD_info[cpuno]) ; } return LD_info; } LD_info_t* find_LD_from_IEDLDName(ied_t* ied, char *IEDLDName) { int cpuno; LD_info_t* LD_info = NULL; assert(ied); for(cpuno=0 ; cpunocpucount; cpuno++) { LD_info = & (GET_IEDEXT_ADDR(ied)->LD_info[cpuno]) ; if(LD_info->LD_name){ if (strcmp(LD_info->LD_name, IEDLDName)==0) return LD_info; } } return NULL; } LD_info_t* find_LD_from_IEDLDName_in_report(ied_t* ied, char *IEDLDName) { ST_CHAR * DomName; LD_info_t* LD_info = NULL; DomName = IEDLDName; //strtok (DataReference, "/");/* extract domain name */ LD_info = find_LD_from_IEDLDName(ied, DomName); assert(LD_info); return LD_info; } LD_info_t* find_LD_from_element(element_t* elem) { return find_LD_from_cpuId(elem->ied, (elem->grp->id>>8)&0xff ) ; } RCB_INFO* FindRcbInfo(MVL_NET_INFO *net_info,ST_CHAR *dom_name, ST_CHAR *rcb_name) { ied_t *ied; ied_usr_t *ied_usr; chnl_usr_t *chnl_usr; LD_info_t *LD_info; rptinfo_t *rptinfo = NULL; int cpuno,rpt_no; char rpt_inst_name[65]; chnl_usr = net_info->user_ext; ied = chnl_usr->chnl->ied; ied_usr = GET_IEDEXT_ADDR(ied); for(cpuno=0 ; cpunocpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); if (!LD_info->LD_name) continue; if ( strcmp(LD_info->LD_name,dom_name)!=0 ) continue; for(rpt_no=0 ; rpt_norptcount; rpt_no++) { rptinfo = LD_info->rptinfo[rpt_no]; get_rpt_inst_name(rptinfo,rpt_inst_name); if ( strcmp(rpt_inst_name,rcb_name)==0 ) { if (rptinfo->rpt_registered) return rptinfo->m_rcb_info; else return NULL; } } } return NULL; } //////////////////////////////////////// //WW 2023-08-29 由于rcb_info和dev_type绑定不是和监测点绑定,这里修改规则,保留报告名称匹配 rptinfo_t* find_rptinfo_from_net_rpt_info_name(MVL_NET_INFO *net_info, RCB_INFO *rcb_info) { ied_t *ied; ied_usr_t *ied_usr; chnl_usr_t *chnl_usr; LD_info_t *LD_info; rptinfo_t *rptinfo = NULL; int cpuno,rpt_no; chnl_usr = net_info->user_ext; ied = chnl_usr->chnl->ied; ied_usr = GET_IEDEXT_ADDR(ied); for(cpuno=0 ; cpunocpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); for(rpt_no=0 ; rpt_norptcount; rpt_no++) { rptinfo = LD_info->rptinfo[rpt_no]; printf("%d rptinfo %s,rcbinfo %s ", rpt_no, rptinfo->rptID, rcb_info->RptID); if (strcmp(rcb_info->RptID,rptinfo->rptID)==0)//WW 修改为匹配字符串 return rptinfo; } } return NULL; } //WW 2023-08-29 注释 //////////////////////////////////////// //////////////////////////////////////// //WW 2023-08-29 注释 rptinfo_t* find_rptinfo_from_net_rcb_info(MVL_NET_INFO *net_info,RCB_INFO *rcb_info) { ied_t *ied; ied_usr_t *ied_usr; chnl_usr_t *chnl_usr; LD_info_t *LD_info; rptinfo_t *rptinfo = NULL; int cpuno,rpt_no; chnl_usr = net_info->user_ext; ied = chnl_usr->chnl->ied; ied_usr = GET_IEDEXT_ADDR(ied); for(cpuno=0 ; cpunocpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); for(rpt_no=0 ; rpt_norptcount; rpt_no++) { rptinfo = LD_info->rptinfo[rpt_no]; if (rcb_info==rptinfo->m_rcb_info) return rptinfo; } } return NULL; } //////////////////////////////////////// //WW 2023-08-29 注释 end void get_rpt_inst_name(rptinfo_t *rptinfo, char * rpt_inst_name ) { strcpy(rpt_inst_name,rptinfo->rptID); if (rptinfo->instanceNeedSuffix) { char rpt_suffix_str[8]; apr_snprintf(rpt_suffix_str,sizeof(rpt_suffix_str),"%02d",rptinfo->m_curRptSuffix); strcat(rpt_inst_name,rpt_suffix_str); } } void strip_file_name_tail_to_ms(char *fileName) { char *p = NULL; assert(fileName); assert(strlen(fileName)<128); assert(strlen(fileName)>0); p = fileName; while(*p != '.') { p++; } while((p>fileName)&&(*p<0x30 || *p>0x39)) { p--; } *++p = '\0'; } static void _cut_file_name(char *fileName, byte_t len) { size_t full_len = strlen(fileName); if (full_len<=len) return; else { memmove(fileName, fileName+(full_len-len), len); *(fileName+len) = '\0'; } } //////////////////////////////////////////////////////////////////////////////////////////////////// ied_t* find_ied_from_dev_idx(int dev_idx) { ied_t *ied = NULL; int iedno; ied_usr_t *ied_usr = NULL; for(iedno=0; iednon_clients; iedno++) { ied = g_node->clients[iedno]; ied_usr = (ied_usr_t*)ied->usr_ext; if (ied_usr && ied_usr->dev_idx == dev_idx ) return ied; } return NULL; } ied_t* find_ied_from_dev_code(char dev_idx[]) { ied_t* ied = NULL; int iedno; ied_usr_t* ied_usr = NULL; for (iedno = 0; iedno < g_node->n_clients; iedno++) { ied = g_node->clients[iedno]; ied_usr = (ied_usr_t*)ied->usr_ext; if (ied_usr && strcmp(ied_usr->terminal_code, dev_idx) == 0) { return ied; } } return NULL; } //lnk20250114新增通过终端id查找终端 ied_t* find_ied_from_terminal_id(char terminal_id[]) { ied_t* ied = NULL; int iedno; ied_usr_t* ied_usr = NULL; for (iedno = 0; iedno < g_node->n_clients; iedno++) { ied = g_node->clients[iedno]; ied_usr = (ied_usr_t*)ied->usr_ext; if (ied_usr && strcmp(ied_usr->terminal_id, terminal_id) == 0) { return ied; } } return NULL; } //lnk20250121找不使用的ied空间 ied_t* find_ied_unused() { ied_t* ied_find_unused = NULL; int iedno; ied_usr_t* ied_usr_find_unused = NULL; for (iedno = 0; iedno < g_node->n_clients; iedno++) { ied_find_unused = g_node->clients[iedno]; ied_usr_find_unused = (ied_usr_t*)ied_find_unused->usr_ext; if (ied_usr_find_unused && ied_usr_find_unused->dev_flag == UNUSED) { return ied_find_unused;//找到第一个就返回 } } return NULL; } LD_info_t* find_LD_info_from_line_id(ied_t* ied, int line_id) { LD_info_t *LD_info = NULL; ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); int cpuno; for(cpuno=0 ; cpunocpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); if (LD_info && LD_info->line_id==line_id) return LD_info; } return NULL; } LD_info_t* find_LD_info_only_from_line_id(int line_id) { ied_t *ied = NULL; int iedno; LD_info_t *LD_info = NULL; for(iedno=0; iednon_clients; iedno++) { ied = g_node->clients[iedno]; if (ied) { LD_info = find_LD_info_from_line_id(ied,line_id); if (LD_info) return LD_info; } } return NULL; } LD_info_t* find_LD_info_from_mp_id(ied_t* ied, char* mp_id) { LD_info_t* LD_info = NULL; ied_usr_t* ied_usr = GET_IEDEXT_ADDR(ied); int cpuno; for (cpuno = 0; cpuno < ied->cpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); if (LD_info && strcmp(LD_info->mp_id, mp_id) == 0) return LD_info; } return NULL; } LD_info_t* find_LD_info_only_from_mp_id(char* mp_id) { ied_t* ied = NULL; int iedno; LD_info_t* LD_info = NULL; for (iedno = 0; iedno < g_node->n_clients; iedno++) { ied = g_node->clients[iedno]; if (ied) { LD_info = find_LD_info_from_mp_id(ied, mp_id); if (LD_info) return LD_info; } } return NULL; } void clear_all_LD_real_soe_report_shoud_register() { ied_t *ied = NULL; int iedno; ied_usr_t *ied_usr = NULL; LD_info_t *LD_info = NULL; int cpuno; for(iedno=0; iednon_clients; iedno++) { ied = g_node->clients[iedno]; ied_usr = (ied_usr_t*)ied->usr_ext; for(cpuno=0 ; cpunocpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); if (LD_info ) { LD_info->real_data = 0; LD_info->soe_data = 0; } } } } void clear_one_LD_real_soe_report_shoud_register(int dev_index,int line_index) { ied_t *ied; LD_info_t *LD_info; ied = find_ied_from_dev_idx(dev_index); if (!ied) return; LD_info = find_LD_info_from_line_id(ied,line_index); if (!LD_info) return; if (LD_info ) { LD_info->real_data = 0; LD_info->soe_data = 0; } } void clear_rpt_counter_by_trigger(trigger_t *trigger) { ied_t *ied; LD_info_t *LD_info; int rpt_no; rptinfo_t *rptinfo = NULL; trigger->count = 0; ied = find_ied_from_dev_idx(trigger->dev_idx); if (!ied) return; LD_info = find_LD_info_from_line_id(ied,trigger->line_id); if (!LD_info) return; LD_info->count = 0; for(rpt_no=0 ; rpt_norptcount; rpt_no++) { rptinfo = LD_info->rptinfo[rpt_no]; rptinfo->count = 0; } } int get_real_report_count(LD_info_t *LD_info) { int rpt_no; rptinfo_t *rptinfo = NULL; for(rpt_no=0 ; rpt_norptcount; rpt_no++) { rptinfo = LD_info->rptinfo[rpt_no]; //if (rptinfo->report_PQ_type & REPORT_TYPE_REAL)//遍历所有报告判断报告类型 if (rptinfo->report_PQ_type)//上层已判断实时数据,不需要再判断 return rptinfo->count; } return 0; } //////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////电压波动处理///////////////////////////// void processQVVR_start(LD_info_t* LD_info) { int i; for (i=0;iqvvr[i].used_status==QVVR_DATA_NOT_USED) { LD_info->qvvr_idx = i; //这个点没使用,使用这个点 break; } } if (i>=QVVR_NUM) { //已经使用到了最后一个点 uint32_t timestamp = LD_info->qvvr[0].timestamp;//第一个点的时间 LD_info->qvvr_idx = 0;//从第一个点开始记录 echo_warn1("QVVR data memory is full,to replace the oldest,line_id=%d \n",LD_info->line_id); for (i=1;iqvvr[i].timestampqvvr_idx = i; timestamp = LD_info->qvvr[i].timestamp; } } } LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_RECEIVED;//这个点标记为收到暂态数据 LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 0; //类型未定 LD_info->qvvr[LD_info->qvvr_idx].timestamp = apr_time_sec(apr_time_now());//记录当前时间 printf("\n~~~~~~~~~~~~~~~~~ processQVVR_start: line_id=%d \n",LD_info->line_id); } void processQVVR_time(LD_info_t* LD_info, long long Time) { LD_info->qvvr[LD_info->qvvr_idx].QVVR_time = Time; printf("\n~~~~~~~~~~~~~~~~~ processQVVR_time: line_id=%d ,Time=%lld \n",LD_info->line_id,Time);//这里是报告上送的时间 } void processQVVR_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v) { if ( strstr(FULL_FCDA_Name,"VarStr$stVal") ) { LD_info->qvvr[LD_info->qvvr_idx].QVVR_start = (v>0.99) ? 1:0; } else if ( strstr(FULL_FCDA_Name,"VVaTm$mag$f") ) LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime = (float)v; else if ( strstr(FULL_FCDA_Name,"VVa$mag$f") ) LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg = (float)v; else { if ( strstr(FULL_FCDA_Name,"DipStr$stVal") && (v>0.99) ) //电压暂降 LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1210002;//按照接口修改 else if ( strstr(FULL_FCDA_Name,"SwlStr$stVal") && (v>0.99) ) //电压暂升 LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1210001; else if ( strstr(FULL_FCDA_Name,"IntrStr$stVal") && (v>0.99) ) //电压中断 LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1210004; } if (strstr(FULL_FCDA_Name, "QVVR")) { apr_snprintf(LD_info->qvvr[LD_info->qvvr_idx].QVVR_Rptname, sizeof(LD_info->qvvr[LD_info->qvvr_idx].QVVR_Rptname), "%s", FULL_FCDA_Name);//terminal_code } printf("\n~~~~~~~~~~~~~~~~~ processQVVR_data: line_id=%d ,mms_str=%s,v=%f \n",LD_info->line_id,FULL_FCDA_Name,v); } void processQVVR_end(LD_info_t* LD_info) { //lnk20241227lnk添加暂态事件直接上报,等录波事件上来后,那边会再上报一次更新文件路径,这里不更新文件路径 ied_t *ied = LD_info->ied; ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); int ret; //////////////////////////////////////////////////////////////////////////////////////////////////////////// int find_paired = FALSE; int i; if (LD_info->qvvr[LD_info->qvvr_idx].QVVR_start)//波动数据处理时FCDA包含VarStr$stVal,QVVR_start为1,退出处理 return; //获取时间类型lnk20250520 printf("~~~~~~~this dev type is %s~~~~~~~",ied_usr->dev_type); XmlConfigC cfg; if (get_xml_config_by_dev_type(ied_usr->dev_type, &cfg)) { printf("UnitOfTimeUnit = %s\n", cfg.UnitOfTimeUnit); printf("ValueOfTimeUnit = %s\n", cfg.ValueOfTimeUnit); } else { printf("读取失败,未找到 dev_type\n"); } double s_or_ms; long long utc_or_beijing; if(strcmp(cfg.UnitOfTimeUnit, "1") == 0){//持续时间上送的是秒1还是毫秒0 s_or_ms = 0.001; //DIY_WARNLOG_CODE(LD_info->mp_id,2,LOG_CODE_TRANSIENT,"【WARN】监测点:%s - id:%s上送的暂态持续时间单位是秒,监测点对应装置型号:%s",LD_info->name,LD_info->mp_id,ied_usr->dev_type); } else{ s_or_ms = 1.0; //DIY_WARNLOG_CODE(LD_info->mp_id,2,LOG_CODE_TRANSIENT,"【WARN】监测点:%s - id:%s上送的暂态持续时间单位是毫秒,监测点对应装置型号:%s",LD_info->name,LD_info->mp_id,ied_usr->dev_type); } if(strcmp(cfg.ValueOfTimeUnit, "utc") == 0){//上送的是utc还是北京 utc_or_beijing = 0;//61850库已经转换过了,八小时毫秒数28800000; } else{ utc_or_beijing = 0; } for (i=0;iqvvr_idx) //跳过监测点当前波动位置,不会和自己做匹配。第一次记录波形后,第一次的第一个事件会让0号点为QVVR_DATA_RECEIVED, //第二次qvvr_idx=1,1号中为QVVR_DATA_RECEIVED,QVVR_start=0,会和0点做匹配 { printf("skip this index\n"); continue; } if (LD_info->qvvr[i].used_status != QVVR_DATA_RECEIVED)//跳过没有收到波动的位置 { printf("qvvr %d is not received\n",i); continue; } //添加时间判断lnk20250311,当前的时间减去找到的时间应该等于持续时间 if (fabs((LD_info->qvvr[LD_info->qvvr_idx].QVVR_time - LD_info->qvvr[i].QVVR_time)/1.0 //判断秒还是毫秒 - LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime/s_or_ms) > 1.0){ printf("~~~~~~~fail in pair qvvr node %f~~~~~~~~~~ \n",fabs((LD_info->qvvr[LD_info->qvvr_idx].QVVR_time - LD_info->qvvr[i].QVVR_time)/1.0 - LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime/s_or_ms)); continue; } //其他某位置的波动也没有定义类型/这个位置的波动类型和当前位置的波动类型一致,暂降事件一次会发三个报告,启动和上值和结束 if ( (LD_info->qvvr[i].QVVR_type==0)||(LD_info->qvvr[i].QVVR_type==LD_info->qvvr[LD_info->qvvr_idx].QVVR_type) ) { //long long end_tm = (long long)(LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime*1000) + LD_info->qvvr[i].QVVR_time;//结束时间是持续时间加最初的触发时间,毫秒 long long end_tm = (long long)(LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime/s_or_ms) + LD_info->qvvr[i].QVVR_time;//结束时间是持续时间加最初的触发时间,毫秒 //调试用 printf("\n~~~~~~~now qvvr node type before record is %d~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].QVVR_type); printf("~~~~~~~now qvvr node QVVR_PerTime before record is %f~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime); printf("~~~~~~~now qvvr node QVVR_Amg before record is %f~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg); printf("~~~~~~~now qvvr node QVVR_time before record is %lld~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].QVVR_time); printf("~~~~~~~now qvvr node used_status before record is %d~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].used_status); printf("~~~~~~~now qvvr node QVVR_start before record is %d~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].QVVR_start); printf("~~~~~~~now qvvr node timestamp before record is %d~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].timestamp); LD_info->qvvr[i].used_status = QVVR_DATA_PAIRED; //匹配上了 LD_info->qvvr[i].QVVR_type = LD_info->qvvr[LD_info->qvvr_idx].QVVR_type; LD_info->qvvr[i].QVVR_PerTime = LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime;//存在内存的还是原始读出的数据 LD_info->qvvr[i].QVVR_Amg = LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg; //记录当前这个点的波动数据到找到的点位置上,确保记录的是最新的相同类型的事件 LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //当前这个点位置释放 find_paired = TRUE; //调试用 printf("~~~~~~~this qvvr node QVVR_PerTime after record is %f~~~~~~~~~~ \n",LD_info->qvvr[i].QVVR_PerTime); printf("~~~~~~~this qvvr node QVVR_Amg after record is %f~~~~~~~~~~ \n",LD_info->qvvr[i].QVVR_Amg); printf("~~~~~~~this qvvr node used_status after record is %d~~~~~~~~~~ \n",LD_info->qvvr[i].used_status); printf("~~~~~~~this qvvr node QVVR_type after record is %d~~~~~~~~~~ \n",LD_info->qvvr[i].QVVR_type); printf("~~~~~~~this qvvr node QVVR_time after record is %lld~~~~~~~~~~ \n",LD_info->qvvr[i].QVVR_time); printf("~~~~~~~this qvvr node timestamp before record is %d~~~~~~~~~~ \n",LD_info->qvvr[i].timestamp); printf("~~~~~~~this qvvr node QVVR_start before record is %d~~~~~~~~~~ \n",LD_info->qvvr[i].QVVR_start); //匹配后再发qvvr,起始时间要填暂态触发的时间,就是第一次事件上送时只有时间没有值的那个时间 //mq日志 DIY_WARNLOG_CODE(LD_info->mp_id,2,LOG_CODE_TRANSIENT,"【WARN】监测点%s - id:%s 发生暂态事件,暂态时间:%lld,暂态持续时间:%f,暂态幅值:%f,暂态类型:%d",LD_info->name,LD_info->mp_id, LD_info->qvvr[LD_info->qvvr_idx].QVVR_time, LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime, LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg, LD_info->qvvr[LD_info->qvvr_idx].QVVR_type); ret = transfer_json_qvvr_data(g_node_id, //这个参数没有使用 LD_info->line_id, //监测点序号 (double)LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg, (double)LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime/s_or_ms, //上传转换为ms LD_info->qvvr[i].QVVR_time + utc_or_beijing, //上传北京时间 end_tm + utc_or_beijing, //上传北京时间 LD_info->qvvr[LD_info->qvvr_idx].QVVR_type, //伏值、持续时间、开始时间、结束时间、暂态类型 "", "", //两个文件路径为空 LD_info->mp_id, LD_info->qvvr[LD_info->qvvr_idx].QVVR_Rptname, ied_usr->dev_type);//监测点号,文件和监测点暂态事件匹配上的暂态报告名,终端类型 if(!ret)//失败 { printf("\n~~~~~~~~~~~~~~~~~ QVVR_json_data send error: line_id=%d \n",LD_info->line_id); } break; } } if (find_paired == FALSE) { LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //全都没有匹配上直接释放这个点,下次事件可以直接在这个点上使用 printf("\nERROR:~~~~~~~~~~~~~ processQVVR qvvr returned to 0,but found no data to pair!, line_id=%d,QVVR_type=%d \n", LD_info->line_id, LD_info->qvvr[LD_info->qvvr_idx].QVVR_type); //mq日志 if(strcmp(cfg.UnitOfTimeUnit, "1") == 0){//持续时间上送的是秒1还是毫秒0 DIY_WARNLOG_CODE(LD_info->mp_id,2,LOG_CODE_TRANSIENT,"【WARN】监测点:%s - id:%s记录了一个暂态事件但是没有匹配到事件的发生时间,装置型号:%s 配置的暂态持续时间单位是秒",LD_info->name,LD_info->mp_id,ied_usr->dev_type); } else{ DIY_WARNLOG_CODE(LD_info->mp_id,2,LOG_CODE_TRANSIENT,"【WARN】监测点:%s - id:%s记录了一个暂态事件但是没有匹配到事件的发生时间,装置型号:%s 配置的暂态持续时间单位是毫秒",LD_info->name,LD_info->mp_id,ied_usr->dev_type); } } printf("\n~~~~~~~~~~~~~~~~~ processQVVR_end: line_id=%d \n",LD_info->line_id); } // 函数功能:根据触发时间戳(trig_tm)查找匹配的 QVVR 数据。 // 输入参数: // - LD_info:指向 LD_info_t 类型结构体的指针,包含多个 QVVR 数据。 // - trig_tm:触发时间戳,用于与 QVVR 数据中的时间进行匹配。 // 输出参数: // - 返回匹配的 QVVR 数据的指针。如果没有找到匹配的 QVVR 数据,则返回 NULL。 // 返回值: // - 如果找到符合条件的 QVVR 数据,返回指向该数据的指针。 // - 如果没有找到符合条件的 QVVR 数据,返回 NULL。 QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info, long long trig_tm) { long long diff; // 用于计算时间戳差异 int i; // 循环计数器 // 遍历 LD_info 中的 QVVR 数据数组 for (i = 0; i < QVVR_NUM; i++) { // 计算当前 QVVR 数据的时间戳与触发时间戳之间的差异 diff = abs(LD_info->qvvr[i].QVVR_time - trig_tm); //调试用 printf("QVVRTIME:%lld >>>>> COMTRADE trig_tm:%lld >>>>> diff:%lld\n",LD_info->qvvr[i].QVVR_time,trig_tm,diff); // 如果该 QVVR 数据的状态是 "已配对"(QVVR_DATA_PAIRED)并且时间差小于等于 1(单位:毫秒) if ((LD_info->qvvr[i].used_status == QVVR_DATA_PAIRED) && (diff <= 1)) { // 如果匹配,返回该 QVVR 数据的指针 printf(">>>>> pair QVVR success>>>>>> \n"); return &(LD_info->qvvr[i]); } } printf(">>>>> pair QVVR fail>>>>>> \n"); // 如果没有找到匹配的 QVVR 数据,返回 NULL return NULL; } #if 0 QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info,long long trig_tm) { long long diff; int i; for (i=0;iqvvr[i].QVVR_time-trig_tm); if ( (LD_info->qvvr[i].used_status==QVVR_DATA_PAIRED) && (diff<=1) ) { return &(LD_info->qvvr[i]); } } return NULL; } #endif ////////////////////录波文件处理///////////////////////////// void processRDRE_start(LD_info_t* LD_info) { LD_info->RDRE_FltNum = -1; printf("\n~~~~~~RDRE~~~~~~ processRDRE_start: line_id=%d \n",LD_info->line_id); } void processRDRE_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v) { if ( strstr(FULL_FCDA_Name,"FltNum$stVal") ) LD_info->RDRE_FltNum = (int)(v+0.4); printf("\n~~~~~~RDRE~~~~~~ processRDRE_data: line_id=%d ,mms_str=%s,v=%f \n",LD_info->line_id,FULL_FCDA_Name,v); } void processRDRE_end(LD_info_t* LD_info) { if (LD_info->RDRE_FltNum<=0) return; prepare_call_cn_wavelist(LD_info,LD_info->RDRE_FltNum); printf("\n~~~~~~RDRE~~~~~~ processRDRE_end: line_id=%d \n",LD_info->line_id); } //////////////////////////////////////////////////////////////////////////