Files
microser/mms/rdb_ext_utils.c

750 lines
24 KiB
C
Raw Normal View History

2025-01-16 16:17:01 +08:00
/**
* @file: $RCSfile: rdb_ext_utils.c,v $
2025-05-09 16:53:07 +08:00
* @brief: $ rdb usr_ext扩充的结构的一些工具函数
2025-01-16 16:17:01 +08:00
*
* @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 <string.h>
#include "rdb_client.h"
#include "xmltools.h"
#include "db_interface.h"
2025-03-04 17:29:04 +08:00
#include "../cfg_parse/custom_printf.h"//lnk20250225
2025-05-30 15:40:20 +08:00
#include "../log4cplus/log4.h"//lnk添加log4
2025-01-16 16:17:01 +08:00
//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;
2025-05-09 16:53:07 +08:00
////////////////////////str 辅助函数//////////////////////////
2025-01-16 16:17:01 +08:00
char* str_trim_both(char* temp,const char* pattern)
{ // pattern such as " \t" or " \t\'"
unsigned int i,j;
for(i=0;i<strlen(temp);i++) {
if ( strchr(pattern,temp[i]) == NULL )
break;
}
temp +=i;
for(j=(strlen(temp)-1);j>=0;j--) {
if ( strchr(pattern,temp[j]) )
temp[j] = 0;
else
break;
}
return(temp);
}
2025-05-09 16:53:07 +08:00
////////////////////////rdb 61850扩充结构 辅助函数//////////////////////////
2025-01-16 16:17:01 +08:00
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 ; cpuno<ied->cpucount; 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 ; cpuno<ied->cpucount; 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 ; cpuno<ied->cpucount; 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_no<LD_info->rptcount; 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;
}
////////////////////////////////////////
2025-05-09 16:53:07 +08:00
//WW 2023-08-29 由于rcb_info和dev_type绑定不是和监测点绑定这里修改规则保留报告名称匹配
2025-01-16 16:17:01 +08:00
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 ; cpuno<ied->cpucount; cpuno++) {
LD_info = &(ied_usr->LD_info[cpuno]);
for(rpt_no=0 ; rpt_no<LD_info->rptcount; rpt_no++) {
rptinfo = LD_info->rptinfo[rpt_no];
printf("%d rptinfo %s,rcbinfo %s ", rpt_no, rptinfo->rptID, rcb_info->RptID);
2025-05-09 16:53:07 +08:00
if (strcmp(rcb_info->RptID,rptinfo->rptID)==0)//WW 修改为匹配字符串
2025-01-16 16:17:01 +08:00
return rptinfo;
}
}
return NULL;
}
2025-05-09 16:53:07 +08:00
//WW 2023-08-29 注释
2025-01-16 16:17:01 +08:00
////////////////////////////////////////
////////////////////////////////////////
2025-05-09 16:53:07 +08:00
//WW 2023-08-29 注释
2025-01-16 16:17:01 +08:00
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 ; cpuno<ied->cpucount; cpuno++) {
LD_info = &(ied_usr->LD_info[cpuno]);
for(rpt_no=0 ; rpt_no<LD_info->rptcount; rpt_no++) {
rptinfo = LD_info->rptinfo[rpt_no];
if (rcb_info==rptinfo->m_rcb_info)
return rptinfo;
}
}
return NULL;
}
////////////////////////////////////////
2025-05-09 16:53:07 +08:00
//WW 2023-08-29 注释 end
2025-01-16 16:17:01 +08:00
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; iedno<g_node->n_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;
}
2025-05-09 16:53:07 +08:00
//lnk20250114新增通过终端id查找终端
2025-01-16 16:17:01 +08:00
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;
}
2025-05-09 16:53:07 +08:00
//lnk20250121找不使用的ied空间
2025-01-22 17:00:34 +08:00
ied_t* find_ied_unused()
2025-01-21 17:48:37 +08:00
{
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) {
2025-05-09 16:53:07 +08:00
return ied_find_unused;//找到第一个就返回
2025-01-21 17:48:37 +08:00
}
}
return NULL;
}
2025-01-16 16:17:01 +08:00
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 ; cpuno<ied->cpucount; 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; iedno<g_node->n_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; iedno<g_node->n_clients; iedno++) {
ied = g_node->clients[iedno];
ied_usr = (ied_usr_t*)ied->usr_ext;
for(cpuno=0 ; cpuno<ied->cpucount; cpuno++) {
LD_info = &(ied_usr->LD_info[cpuno]);
if (LD_info ) {
LD_info->real_data = 0;
LD_info->soe_data = 0;
}
}
}
}
2025-07-30 16:30:10 +08:00
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;
}
}
2025-01-16 16:17:01 +08:00
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_no<LD_info->rptcount; 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_no<LD_info->rptcount; rpt_no++) {
rptinfo = LD_info->rptinfo[rpt_no];
2025-05-09 16:53:07 +08:00
//if (rptinfo->report_PQ_type & REPORT_TYPE_REAL)//遍历所有报告判断报告类型
if (rptinfo->report_PQ_type)//上层已判断实时数据,不需要再判断
2025-01-16 16:17:01 +08:00
return rptinfo->count;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2025-05-09 16:53:07 +08:00
////////////////////电压波动处理/////////////////////////////
2025-01-16 16:17:01 +08:00
void processQVVR_start(LD_info_t* LD_info)
{
int i;
for (i=0;i<QVVR_NUM;i++) {
if (LD_info->qvvr[i].used_status==QVVR_DATA_NOT_USED) {
2025-05-09 16:53:07 +08:00
LD_info->qvvr_idx = i; //这个点没使用,使用这个点
2025-01-16 16:17:01 +08:00
break;
}
}
2025-05-09 16:53:07 +08:00
if (i>=QVVR_NUM) { //已经使用到了最后一个点
uint32_t timestamp = LD_info->qvvr[0].timestamp;//第一个点的时间
LD_info->qvvr_idx = 0;//从第一个点开始记录
2025-01-16 16:17:01 +08:00
echo_warn1("QVVR data memory is full,to replace the oldest,line_id=%d \n",LD_info->line_id);
for (i=1;i<QVVR_NUM;i++) {
2025-05-09 16:53:07 +08:00
if (LD_info->qvvr[i].timestamp<timestamp) {//找到时间最小的点,使用它的位置
2025-01-16 16:17:01 +08:00
LD_info->qvvr_idx = i;
timestamp = LD_info->qvvr[i].timestamp;
}
}
}
2025-05-09 16:53:07 +08:00
LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_RECEIVED;//这个点标记为收到暂态数据
LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 0; //类型未定
2025-09-04 16:26:00 +08:00
LD_info->qvvr[LD_info->qvvr_idx].timestamp = apr_time_sec(apr_time_now());//记录当前时间
2025-01-16 16:17:01 +08:00
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;
2025-05-20 16:31:12 +08:00
printf("\n~~~~~~~~~~~~~~~~~ processQVVR_time: line_id=%d ,Time=%lld \n",LD_info->line_id,Time);//这里是报告上送的时间
2025-01-16 16:17:01 +08:00
}
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") )
2025-03-10 21:26:17 +08:00
LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime = (float)v;
2025-01-16 16:17:01 +08:00
else if ( strstr(FULL_FCDA_Name,"VVa$mag$f") )
2025-03-10 21:26:17 +08:00
LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg = (float)v;
2025-01-16 16:17:01 +08:00
else {
2025-05-09 16:53:07 +08:00
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) ) //电压暂升
2025-03-10 21:26:17 +08:00
LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1210001;
2025-05-09 16:53:07 +08:00
else if ( strstr(FULL_FCDA_Name,"IntrStr$stVal") && (v>0.99) ) //电压中断
2025-03-10 21:26:17 +08:00
LD_info->qvvr[LD_info->qvvr_idx].QVVR_type = 1210004;
2025-01-16 16:17:01 +08:00
}
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)
{
2025-05-09 16:53:07 +08:00
//lnk20241227lnk添加暂态事件直接上报等录波事件上来后那边会再上报一次更新文件路径这里不更新文件路径
2025-01-16 16:17:01 +08:00
ied_t *ied = LD_info->ied;
ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied);
int ret;
////////////////////////////////////////////////////////////////////////////////////////////////////////////
int find_paired = FALSE;
int i;
2025-05-09 16:53:07 +08:00
if (LD_info->qvvr[LD_info->qvvr_idx].QVVR_start)//波动数据处理时FCDA包含VarStr$stValQVVR_start为1退出处理
2025-01-16 16:17:01 +08:00
return;
2025-05-20 16:31:12 +08:00
//获取时间类型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;
2025-05-21 10:45:44 +08:00
if(strcmp(cfg.UnitOfTimeUnit, "1") == 0){//持续时间上送的是秒1还是毫秒0
2025-05-20 16:31:12 +08:00
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);
2025-05-20 16:31:12 +08:00
}
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);
2025-05-20 16:31:12 +08:00
}
2025-05-21 10:45:44 +08:00
if(strcmp(cfg.ValueOfTimeUnit, "utc") == 0){//上送的是utc还是北京
2025-07-29 18:10:03 +08:00
utc_or_beijing = 0;//61850库已经转换过了八小时毫秒数28800000;
2025-05-20 16:31:12 +08:00
}
else{
utc_or_beijing = 0;
}
2025-05-09 16:53:07 +08:00
for (i=0;i<QVVR_NUM;i++) { //暂降/暂升/中断等进入处理,遍历所有波动位置
2025-09-04 16:26:00 +08:00
if (i==LD_info->qvvr_idx) //跳过监测点当前波动位置,不会和自己做匹配。第一次记录波形后第一次的第一个事件会让0号点为QVVR_DATA_RECEIVED
//第二次qvvr_idx=11号中为QVVR_DATA_RECEIVEDQVVR_start=0会和0点做匹配
2025-05-20 16:31:12 +08:00
{
printf("skip this index\n");
2025-01-16 16:17:01 +08:00
continue;
2025-05-20 16:31:12 +08:00
}
2025-05-09 16:53:07 +08:00
if (LD_info->qvvr[i].used_status != QVVR_DATA_RECEIVED)//跳过没有收到波动的位置
2025-05-20 16:31:12 +08:00
{
printf("qvvr %d is not received\n",i);
2025-01-16 16:17:01 +08:00
continue;
2025-03-11 21:07:17 +08:00
2025-05-20 16:31:12 +08:00
}
//添加时间判断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){
2025-05-21 10:45:44 +08:00
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));
2025-03-11 21:07:17 +08:00
continue;
2025-03-12 14:33:55 +08:00
}
2025-03-11 21:07:17 +08:00
2025-05-09 16:53:07 +08:00
//其他某位置的波动也没有定义类型/这个位置的波动类型和当前位置的波动类型一致,暂降事件一次会发三个报告,启动和上值和结束
2025-01-16 16:17:01 +08:00
if ( (LD_info->qvvr[i].QVVR_type==0)||(LD_info->qvvr[i].QVVR_type==LD_info->qvvr[LD_info->qvvr_idx].QVVR_type) ) {
2025-03-11 11:29:24 +08:00
2025-05-20 16:31:12 +08:00
//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;//结束时间是持续时间加最初的触发时间,毫秒
2025-03-11 21:07:17 +08:00
2025-05-30 15:40:20 +08:00
//调试用
2025-03-11 11:29:24 +08:00
printf("\n~~~~~~~now qvvr node type before record is %d~~~~~~~~~~ \n",LD_info->qvvr[LD_info->qvvr_idx].QVVR_type);
2025-03-11 21:07:17 +08:00
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);
2025-03-11 11:29:24 +08:00
2025-05-09 16:53:07 +08:00
LD_info->qvvr[i].used_status = QVVR_DATA_PAIRED; //匹配上了
2025-01-16 16:17:01 +08:00
LD_info->qvvr[i].QVVR_type = LD_info->qvvr[LD_info->qvvr_idx].QVVR_type;
2025-05-20 16:31:12 +08:00
LD_info->qvvr[i].QVVR_PerTime = LD_info->qvvr[LD_info->qvvr_idx].QVVR_PerTime;//存在内存的还是原始读出的数据
2025-05-09 16:53:07 +08:00
LD_info->qvvr[i].QVVR_Amg = LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg; //记录当前这个点的波动数据到找到的点位置上,确保记录的是最新的相同类型的事件
2025-01-16 16:17:01 +08:00
2025-05-09 16:53:07 +08:00
LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //当前这个点位置释放
2025-01-16 16:17:01 +08:00
find_paired = TRUE;
2025-03-10 21:26:17 +08:00
2025-05-30 15:40:20 +08:00
//调试用
2025-03-11 21:07:17 +08:00
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);
2025-05-09 16:53:07 +08:00
//匹配后再发qvvr起始时间要填暂态触发的时间就是第一次事件上送时只有时间没有值的那个时间
2025-05-30 15:40:20 +08:00
//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,
2025-09-04 16:26:00 +08:00
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);
2025-05-30 15:40:20 +08:00
2025-05-09 16:53:07 +08:00
ret = transfer_json_qvvr_data(g_node_id, //这个参数没有使用
LD_info->line_id, //监测点序号
2025-03-11 21:07:17 +08:00
(double)LD_info->qvvr[LD_info->qvvr_idx].QVVR_Amg,
2025-05-20 16:31:12 +08:00
(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, //上传北京时间
2025-05-09 16:53:07 +08:00
LD_info->qvvr[LD_info->qvvr_idx].QVVR_type, //伏值、持续时间、开始时间、结束时间、暂态类型
2025-05-20 16:31:12 +08:00
"",
"", //两个文件路径为空
LD_info->mp_id,
LD_info->qvvr[LD_info->qvvr_idx].QVVR_Rptname,
ied_usr->dev_type);//监测点号,文件和监测点暂态事件匹配上的暂态报告名,终端类型
2025-05-09 16:53:07 +08:00
if(!ret)//失败
2025-03-10 21:26:17 +08:00
{
printf("\n~~~~~~~~~~~~~~~~~ QVVR_json_data send error: line_id=%d \n",LD_info->line_id);
}
2025-01-16 16:17:01 +08:00
break;
}
}
if (find_paired == FALSE) {
2025-05-09 16:53:07 +08:00
LD_info->qvvr[LD_info->qvvr_idx].used_status = QVVR_DATA_NOT_USED; //全都没有匹配上直接释放这个点,下次事件可以直接在这个点上使用
2025-01-16 16:17:01 +08:00
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);
2025-09-04 16:26:00 +08:00
//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);
2025-09-04 16:26:00 +08:00
}
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);
2025-09-04 16:26:00 +08:00
}
2025-01-16 16:17:01 +08:00
}
printf("\n~~~~~~~~~~~~~~~~~ processQVVR_end: line_id=%d \n",LD_info->line_id);
}
2025-05-09 16:53:07 +08:00
// 函数功能根据触发时间戳trig_tm查找匹配的 QVVR 数据。
// 输入参数:
// - LD_info指向 LD_info_t 类型结构体的指针,包含多个 QVVR 数据。
// - trig_tm触发时间戳用于与 QVVR 数据中的时间进行匹配。
// 输出参数:
// - 返回匹配的 QVVR 数据的指针。如果没有找到匹配的 QVVR 数据,则返回 NULL。
// 返回值:
// - 如果找到符合条件的 QVVR 数据,返回指向该数据的指针。
// - 如果没有找到符合条件的 QVVR 数据,返回 NULL。
2025-01-16 16:17:01 +08:00
QVVR_t* find_qvvr_by_trig_tm(LD_info_t* LD_info, long long trig_tm)
{
2025-05-09 16:53:07 +08:00
long long diff; // 用于计算时间戳差异
int i; // 循环计数器
2025-01-16 16:17:01 +08:00
2025-05-09 16:53:07 +08:00
// 遍历 LD_info 中的 QVVR 数据数组
2025-01-16 16:17:01 +08:00
for (i = 0; i < QVVR_NUM; i++) {
2025-05-09 16:53:07 +08:00
// 计算当前 QVVR 数据的时间戳与触发时间戳之间的差异
2025-01-16 16:17:01 +08:00
diff = abs(LD_info->qvvr[i].QVVR_time - trig_tm);
2025-05-09 16:53:07 +08:00
//调试用
2025-03-10 21:26:17 +08:00
printf("QVVRTIME:%lld >>>>> COMTRADE trig_tm:%lld >>>>> diff:%lld\n",LD_info->qvvr[i].QVVR_time,trig_tm,diff);
2025-05-09 16:53:07 +08:00
// 如果该 QVVR 数据的状态是 "已配对"QVVR_DATA_PAIRED并且时间差小于等于 1单位毫秒
2025-01-16 16:17:01 +08:00
if ((LD_info->qvvr[i].used_status == QVVR_DATA_PAIRED) && (diff <= 1)) {
2025-05-09 16:53:07 +08:00
// 如果匹配,返回该 QVVR 数据的指针
2025-03-10 21:26:17 +08:00
printf(">>>>> pair QVVR success>>>>>> \n");
2025-01-16 16:17:01 +08:00
return &(LD_info->qvvr[i]);
}
}
2025-03-10 21:26:17 +08:00
printf(">>>>> pair QVVR fail>>>>>> \n");
2025-05-09 16:53:07 +08:00
// 如果没有找到匹配的 QVVR 数据,返回 NULL
2025-01-16 16:17:01 +08:00
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;i<QVVR_NUM;i++) {
diff = abs(LD_info->qvvr[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
2025-05-09 16:53:07 +08:00
////////////////////录波文件处理/////////////////////////////
2025-01-16 16:17:01 +08:00
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);
}
//////////////////////////////////////////////////////////////////////////