1904 lines
72 KiB
C
1904 lines
72 KiB
C
/**
|
||
* @file: $RCSfile: mms_process.c,v $
|
||
* @brief: $PROFIBUS 与SSRTDB交互
|
||
*
|
||
* @version: $Revision: 1.28 $
|
||
* @date: $Date: 2022/11/28 07:13:13 $
|
||
* @author: $Author: lizhongming $
|
||
* @state: $State: Exp $
|
||
*
|
||
* @latest: $Id: mms_process.c,v 1.28 2022/11/28 07:13:13 lizhongming Exp $
|
||
*/
|
||
#include <string.h>
|
||
#include "rdb_client.h"
|
||
#include <stdlib.h>
|
||
#include "db_interface.h"
|
||
#include "node.h"
|
||
#include "ied.h"
|
||
#include "../json/mms_json_inter.h"
|
||
#include "../cfg_parse/custom_printf.h"//lnk20250225
|
||
|
||
#include "../log4cplus/log4.h"//lnk添加log4
|
||
|
||
void clear_rpt_counter_by_trigger(trigger_t *trigger);
|
||
|
||
//lnk20241031
|
||
extern void SOEFileWeb(char* localpath,char* cloudpath,char* wavepath);
|
||
//lnk 2024-11-4 添加时间转换函数
|
||
char* convertMsToDateTimeString(int64_t msTime);
|
||
//lnk20250115
|
||
extern pthread_mutex_t mtx;
|
||
extern apr_pool_t* g_cfg_pool;
|
||
extern apr_pool_t* g_init_pool;
|
||
|
||
extern int g_DevFlag; //日志配置中读取的参数,暂无特定使用lnk20250121
|
||
|
||
extern int IED_COUNT;
|
||
|
||
//lnk20250115end
|
||
|
||
#ifdef DEBUG_SISCO
|
||
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
|
||
#endif
|
||
|
||
#ifdef _OS_UNIX_
|
||
#include <sys/vfs.h>
|
||
#endif
|
||
extern uint32_t g_dead_lock_counter;
|
||
extern uint32_t g_thread_blocked_times;
|
||
|
||
extern uint16_t g_client_id;
|
||
|
||
extern RPT_TYPEIDS g_rpt_typeids;
|
||
//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 char *g_sysfile_filedir;
|
||
extern char g_onlyIP[255]; //直连某个IP,仅仅为方便测试
|
||
//extern int g_sysfile_appid; //add by rzx
|
||
//extern apr_time_t g_file_valid_time;
|
||
extern uint32_t g_min_free_size;
|
||
/////////////////////////////////////////////////////////////////
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
extern uint32_t g_node_id;
|
||
|
||
extern int three_secs_enabled;
|
||
extern int auto_register_report_enabled;
|
||
extern int FRONT_MP_NUM;
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
extern int FILE_FLAG;
|
||
|
||
extern int recall_len;
|
||
extern int recall_sta;
|
||
extern int recall_daily;
|
||
extern char* UDS_UPLOAD_URL;
|
||
|
||
///////////////////////////////////////////////////////////////////
|
||
//lnk20250122start
|
||
apr_status_t init_rem_dib_table()
|
||
{
|
||
int pos = 0;
|
||
int iedno,chnl_no;
|
||
ied_t *ied;
|
||
struct in_addr ip;
|
||
chnl_usr_t *chnl_usr;
|
||
|
||
if(IED_COUNT < g_pt61850app->chnl_counts){
|
||
set_rem_dib_table_size( g_pt61850app->chnl_counts );//按照最大的终端数来申请
|
||
g_pt61850app->chnl_usr = apr_pcalloc( g_init_pool,g_pt61850app->chnl_counts*sizeof(chnl_usr_t*) );
|
||
printf( "set_rem_dib_table_size %d \n",g_pt61850app->chnl_counts );
|
||
}
|
||
else{
|
||
set_rem_dib_table_size( IED_COUNT );//按照最大的终端数来申请
|
||
g_pt61850app->chnl_usr = apr_pcalloc( g_init_pool,IED_COUNT*sizeof(chnl_usr_t*) );
|
||
printf( "set_rem_dib_table_size %d \n",IED_COUNT );
|
||
}
|
||
|
||
for(iedno=0 ; iedno<g_node->n_clients; iedno++) {
|
||
ied = g_node->clients[iedno];
|
||
for(chnl_no=0 ; chnl_no<ied->chncount; chnl_no++) {
|
||
chnl_usr = ied->channel[chnl_no].connect;
|
||
g_pt61850app->chnl_usr[pos] = chnl_usr;
|
||
ip.s_addr = htonl(ied->channel[chnl_no].addr);
|
||
strcpy(chnl_usr->ip_str,inet_ntoa(ip));
|
||
printf( " add_rem_dib_table %s:%d \n",chnl_usr->ip_str ,ied->channel[chnl_no].port );
|
||
add_rem_dib_table (pos++,chnl_usr->ip_str,ied->channel[chnl_no].port );
|
||
{
|
||
char comm_str[256];
|
||
memset(comm_str,0,256);
|
||
apr_snprintf(comm_str,sizeof(comm_str),"%16s:%d\t\tinited",chnl_usr->ip_str,ied->channel[chnl_no].port);
|
||
add_comm_log(comm_str);
|
||
}
|
||
}
|
||
}
|
||
return APR_SUCCESS;
|
||
}
|
||
//lnk20250122end
|
||
|
||
void CloseIECReports(chnl_usr_t *chnl_usr)
|
||
{
|
||
ied_t *ied;
|
||
ied_usr_t *ied_usr;
|
||
LD_info_t *LD_info;
|
||
rptinfo_t *rptinfo = NULL;
|
||
int cpuno,rpt_no;
|
||
ST_RET ret;
|
||
|
||
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++) {
|
||
char rpt_inst_name[65];
|
||
rptinfo = LD_info->rptinfo[rpt_no];
|
||
if ( ! rptinfo->rpt_registered )
|
||
continue;
|
||
if ( rptinfo->chnl_id != chnl_usr->chnl_id)
|
||
continue;
|
||
|
||
rptinfo->rpt_registered = FALSE;
|
||
//注销报告后,取消10分钟 再注册一次的限制,可立即注册
|
||
rptinfo->m_LastRegisterFailedTime = sGetMsTime() -10*60*1000;
|
||
rptinfo->m_rcb_info = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
void closeChannel(chnl_usr_t *chnl_usr)
|
||
{
|
||
char comm_str[256];
|
||
memset(comm_str,0,256);
|
||
apr_snprintf(comm_str,sizeof(comm_str),"%16s:%d\t\tdisconnected !!!",chnl_usr->ip_str,chnl_usr->chnl->port);
|
||
add_comm_log(comm_str);
|
||
FRONT_MP_NUM--;
|
||
echo_warn1("Close Channel IP: %s",chnl_usr->ip_str );
|
||
|
||
CloseIECReports(chnl_usr);
|
||
echo_warn1("-------Close Channel IP: %s success!!!!!!!!!", chnl_usr->ip_str);
|
||
|
||
if (chnl_usr->net_info) {
|
||
ALL_RCB_INFO *all_rcb_info;
|
||
RCB_INFO *rcb_info;
|
||
ST_RET ret;
|
||
if(chnl_usr->net_info->user_info)
|
||
{
|
||
all_rcb_info = (ALL_RCB_INFO *)chnl_usr->net_info->user_info;
|
||
while((rcb_info = (RCB_INFO *)list_get_first(&all_rcb_info->rcb_info_list)) != NULL)
|
||
rcb_info_destroy (rcb_info);
|
||
chk_free(all_rcb_info);
|
||
chnl_usr->net_info->user_info=NULL;
|
||
}
|
||
chnl_usr->net_info->rem_vmd = NULL;
|
||
echo_warn("---------start disconnectFromServer!\n");
|
||
ret = mms_disconnectFromServer(chnl_usr->net_info,&chnl_usr->m_reqCtrl);
|
||
echo_warn("---------end disconnectFromServer!\n");
|
||
|
||
if (ret != SD_SUCCESS){
|
||
echo_warn("---------disconnectFromServer success!\n");
|
||
|
||
echo_warn2( "CHANNEL %s,NetInfo= %x mms_disconnectFromServer failed ,Disconnect it roughly! \n",chnl_usr->ip_str,chnl_usr->net_info);
|
||
|
||
mvl_free_req_ctrl(chnl_usr->m_reqCtrl);
|
||
|
||
chnl_usr->net_info->user_ext = NULL;
|
||
chnl_usr->net_info = NULL;
|
||
|
||
|
||
chnl_usr->m_reqCtrl = NULL;
|
||
chnl_usr->net_info = NULL;
|
||
chnl_usr->m_state = CHANNEL_DISCONNECTED;
|
||
chnl_usr->m_ClosedMsTime = sGetMsTime();
|
||
|
||
chnl_usr->chnl->status = STATUS_BREAKOFF;
|
||
}
|
||
else{
|
||
chnl_usr->m_state = CHANNEL_DISCONNECTING;
|
||
chnl_usr->m_StartDisconnectingTime = sGetMsTime();
|
||
}
|
||
}else {
|
||
chnl_usr->m_state = CHANNEL_DISCONNECTED;
|
||
chnl_usr->m_ClosedMsTime = sGetMsTime();
|
||
|
||
chnl_usr->chnl->status = STATUS_BREAKOFF;
|
||
}
|
||
}
|
||
|
||
ST_VOID Callback_channel_disconnect_ind(MVL_NET_INFO * NetInfo, ST_INT discType)
|
||
{
|
||
chnl_usr_t *chnl_usr;
|
||
|
||
chnl_usr = (chnl_usr_t*)NetInfo->user_ext;
|
||
|
||
if ( chnl_usr ) {
|
||
if(chnl_usr->m_state == CHANNEL_CONNECTING)
|
||
{ //do nothing;
|
||
printf("Do nothing,m_state == CHANNEL_CONNECTING ,NetInfo = %x",NetInfo);
|
||
}else if ( chnl_usr->m_state == CHANNEL_CONNECTED )
|
||
{
|
||
closeChannel(chnl_usr);
|
||
}else if ( chnl_usr->m_state == CHANNEL_DISCONNECTING )
|
||
{ //do nothing;
|
||
printf("Do nothing,m_state == CHANNEL_DISCONNECTING ,NetInfo = %x",NetInfo);
|
||
}else if ( chnl_usr->m_state == CHANNEL_DISCONNECTED )
|
||
{ //do nothing;
|
||
printf("Do nothing,m_state == CHANNEL_DISCONNECTED ,NetInfo = %x",NetInfo);
|
||
}
|
||
|
||
|
||
chnl_usr->net_info = NULL;
|
||
NetInfo->user_ext = NULL;
|
||
|
||
}
|
||
printf(" Callback_channel_disconnect_ind ,NetInfo = %x",NetInfo);
|
||
|
||
//zw修改 2023 - 8 - 17 通讯中断回调函数 PG库记录当日中断次数
|
||
ied_usr_t* ied_usr = (ied_usr_t*)(chnl_usr->chnl[0].ied->usr_ext);
|
||
}
|
||
|
||
|
||
void IECReport_tryGI(chnl_usr_t *chnl_usr,rptinfo_t *rptinfo)
|
||
{
|
||
char varName[64] = "";
|
||
ST_BOOLEAN GI = TRUE; /* call GI */
|
||
|
||
if ( (sGetMsTime() -rptinfo->m_LastGITime) < g_pt61850app->giTime*1000 )
|
||
return;
|
||
rptinfo->m_LastGITime = sGetMsTime();
|
||
get_rpt_inst_name(rptinfo,varName);
|
||
strcat(varName, "$GI");
|
||
mms_named_var_write (chnl_usr->net_info, varName, DOM_SPEC, rptinfo->LD_info->LD_name,
|
||
g_rpt_typeids.mmsbool, (ST_CHAR *) &GI, g_pt61850app->mmsOpTimeout);
|
||
}
|
||
|
||
//增加处理根据稳态,或暂态功能等,决定 报告是否需要注册、取消注册或 不做任何处理
|
||
int judge_rpt_next_should_do(rptinfo_t *rptinfo)
|
||
{
|
||
int should_register_state = 1; //各功能默认注册
|
||
int is_real_report = (rptinfo->report_PQ_type & REPORT_TYPE_REAL);//报告控制中包含的类型
|
||
int is_soe_report = (rptinfo->report_PQ_type & REPORT_TYPE_SOE);
|
||
|
||
if (three_secs_enabled) {
|
||
should_register_state = 0; //3秒功能模块,默认不注册
|
||
if (is_real_report) {//映射中包含控制块且触发
|
||
should_register_state = rptinfo->LD_info->real_data;
|
||
}
|
||
if (is_soe_report) {
|
||
should_register_state = rptinfo->LD_info->soe_data;
|
||
}
|
||
}
|
||
|
||
if (should_register_state==rptinfo->rpt_registered)//已经触发/没有触发,没有变动
|
||
return SHOULD_DO_NOTHING;
|
||
else if (should_register_state)//有变动且要触发
|
||
return SHOULD_REGISTER;
|
||
else
|
||
return SHOULD_UNREGISTER;//有变动,不触发
|
||
}
|
||
|
||
void ChannelCheckIECReports(chnl_usr_t *chnl_usr)
|
||
{
|
||
ied_t *ied;
|
||
ied_usr_t *ied_usr;
|
||
LD_info_t *LD_info;
|
||
rptinfo_t *rptinfo = NULL;
|
||
channel_t *channel = NULL;
|
||
int cpuno,rpt_no;
|
||
char rpt_inst_name[65];
|
||
ST_RET ret;
|
||
|
||
ied = chnl_usr->chnl->ied;
|
||
ied_usr = GET_IEDEXT_ADDR(ied);
|
||
channel = chnl_usr->chnl;
|
||
|
||
for(cpuno=0 ; cpuno<ied->cpucount; cpuno++)
|
||
|
||
{
|
||
LD_info = &(ied_usr->LD_info[cpuno]); //遍历监测点
|
||
|
||
if (LD_info->cpuno==0)
|
||
continue;
|
||
|
||
for(rpt_no=0 ; rpt_no<LD_info->rptcount; rpt_no++) { //遍历报告(映射文件中读取的报告控制)
|
||
rptinfo = LD_info->rptinfo[rpt_no] ;
|
||
|
||
if (judge_rpt_next_should_do(rptinfo)==SHOULD_DO_NOTHING)//检查是否触发
|
||
continue;
|
||
|
||
if(rptinfo->m_curRptSuffix==-1)
|
||
rptinfo->m_curRptSuffix = g_pt61850app->rptSuffix[g_client_id][0] ;
|
||
|
||
get_rpt_inst_name(rptinfo,rpt_inst_name);//获取报告名
|
||
|
||
if ( ! rptinfo->rpt_registered ) {
|
||
if ( (sGetMsTime() -rptinfo->m_LastRegisterFailedTime) > 20*1000 ) {
|
||
//注册失败后间隔 20秒 再注册一次
|
||
RCB_INFO *rcb_info;
|
||
printf("start mms_register_iec_rpt................................\n");
|
||
|
||
if ( strstr(rptinfo->rptID,"LLN0$BR$brcbFlickerData") )
|
||
rptinfo->IntgPd = 600; //10分钟
|
||
|
||
/////////////////////////WW 2023-08-30 增加设备类型与报告绑定
|
||
rcb_info = mms_register_iec_rpt (chnl_usr->net_info, &g_rpt_typeids,
|
||
LD_info->LD_name,rpt_inst_name,g_pt61850app->mmsOpTimeout, rptinfo->IntgPd,rptinfo->TrgOpt,
|
||
(ST_UINT8*)rptinfo->m_EntryID ,(ST_UINT8*)rptinfo->OptFlds);
|
||
//WW end
|
||
///////////////////////////
|
||
if( !rcb_info )
|
||
{
|
||
if ( ++rptinfo->m_curRptSuffix > g_pt61850app->rptSuffix[g_client_id][1] )
|
||
rptinfo->m_curRptSuffix = g_pt61850app->rptSuffix[g_client_id][0] ;
|
||
|
||
rptinfo->m_LastRegisterFailedTime = sGetMsTime() ;
|
||
|
||
echo_err9("\n注册报告失败!Rregister iec_rpt failed !!! IED_ID=%d ,CPU=%d , domain: %s ,rpt_inst_name: %s ,ip: %s:%d,chnl_id: %d ,IntgPd=%d ,TrgOpt=0x%x \n",
|
||
APR_EGENERAL, LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl->port,
|
||
chnl_usr->chnl_id, rptinfo->IntgPd,rptinfo->TrgOpt );
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
double GIoffset;
|
||
rptinfo->rpt_registered = TRUE;
|
||
rptinfo->m_rcb_info = rcb_info;
|
||
rptinfo->chnl_id = chnl_usr->chnl_id;
|
||
chnl_usr->m_NegRespTimes = 0;
|
||
chnl_usr->m_LastPosRespTime = sGetMsTime();
|
||
|
||
echo_msg11("\nRegister iec_rpt succeed, IED_ID=%d ,CPU=%d ,domain: %s ,rpt_inst_name: %s ,ip: %s:%d,chnl_id: %d ,IntgPd=%d ,TrgOpt=0x%x ,OptFlds=0x%x%x \n",
|
||
LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl->port,chnl_usr->chnl_id,
|
||
rptinfo->IntgPd,rptinfo->TrgOpt,rptinfo->OptFlds[0],rptinfo->OptFlds[1] );
|
||
|
||
// add here to GI not the same time
|
||
GIoffset = 0.5 * g_pt61850app->giTime;
|
||
rptinfo->m_LastGITime = sGetMsTime() - GIoffset*1000;
|
||
}
|
||
printf("end mms_register_iec_rpt................................\n");
|
||
}
|
||
}
|
||
else { //rpt_registered ==TRUE
|
||
if ( (sGetMsTime() -rptinfo->m_LastUnRegisterFailedTime) > 20*1000 ) {
|
||
//取消注册失败后间隔 20秒 再取消注册一次
|
||
printf("start mms_unregister_iec_rpt................................\n");
|
||
|
||
ret = mms_unregister_iec_rpt (chnl_usr->net_info, &g_rpt_typeids,
|
||
LD_info->LD_name,rpt_inst_name,g_pt61850app->mmsOpTimeout);
|
||
|
||
if( ret == SD_FAILURE ) {
|
||
rptinfo->m_LastUnRegisterFailedTime = sGetMsTime() ;
|
||
echo_err6("\n取消注册报告失败!UnRregister iec_rpt failed !!! IED_ID=%d ,CPU=%d , domain: %s ,rpt_inst_name: %s ,ip: %s,chnl_id: %d \n",
|
||
APR_EGENERAL, LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl_id);
|
||
}
|
||
else {
|
||
rptinfo->rpt_registered = FALSE;
|
||
echo_msg7("\nUnRegister iec_rpt succeed, IED_ID=%d ,CPU=%d ,domain: %s ,rpt_inst_name: %s ,ip: %s:%d,chnl_id: %d \n",
|
||
LD_info->ied->id,LD_info->cpuno,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl->port,chnl_usr->chnl_id );
|
||
}
|
||
printf("end mms_unregister_iec_rpt................................\n");
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void ChannelCheckWaveFiles(chnl_usr_t *chnl_usr)
|
||
{
|
||
ied_t *ied;
|
||
ied_usr_t *ied_usr;
|
||
LD_info_t *LD_info;
|
||
int cpuno;
|
||
|
||
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->line_id<=0) {
|
||
continue;
|
||
}
|
||
call_cn_wavelist(LD_info); //try to call wave file
|
||
}
|
||
}
|
||
|
||
void ChannelCheckIECLogs(chnl_usr_t *chnl_usr)
|
||
{
|
||
ST_RET ret;
|
||
ied_t *ied;
|
||
ied_usr_t *ied_usr;
|
||
LD_info_t *LD_info;
|
||
loginfo_t *loginfo = NULL;
|
||
int cpuno;
|
||
|
||
double now;
|
||
static double last_check_recall_config_time = 0.0;
|
||
|
||
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->logcount<=0)
|
||
continue;
|
||
loginfo = LD_info->loginfo[0] ;
|
||
|
||
apr_sleep(apr_time_from_sec(1) / 10);
|
||
|
||
Check_Recall_Config(LD_info->mp_id);//尝试获取xml结构
|
||
|
||
if (LD_info->autorecallcount != 0 && LD_info->autorecallflag != 1) {
|
||
int i;
|
||
int failed_count = 0;
|
||
for (i = 0; i < LD_info->autorecallcount; i++) {
|
||
|
||
LD_info->autorecallflag = 1;
|
||
|
||
//当前不区分稳态和暂态lnk20241030,如果做区分修改:Check_Recall_Config从xml文件获取数据后,赋值给了LD_info
|
||
loginfo->need_steady = LD_info->autorecall[i]->need_steady; loginfo->need_voltage = LD_info->autorecall[i]->need_voltage;
|
||
|
||
loginfo->start_time = apr_time_from_sec(LD_info->autorecall[i]->start - 5);
|
||
loginfo->end_time = apr_time_from_sec(LD_info->autorecall[i]->end - 5);
|
||
|
||
if (loginfo->need_steady == 0 && loginfo->need_voltage == 0)
|
||
continue;
|
||
if (loginfo->end_time <= loginfo->start_time)
|
||
continue;
|
||
|
||
printf("start mms_jread................................\n");
|
||
|
||
echo_msg6("\n mms_jread IED_ID=%d ,CPU=%d ,domain: %s ,logName: %s ,ip: %s,chnl_id: %d \n",
|
||
LD_info->ied->id, LD_info->cpuno, LD_info->LD_name, loginfo->logName, chnl_usr->ip_str, chnl_usr->chnl_id);
|
||
|
||
ret = mms_jread(loginfo, chnl_usr->net_info, loginfo->LD_info->LD_name, loginfo->logName,
|
||
loginfo->start_time, loginfo->end_time, g_pt61850app->mmsOpTimeout, chnl_usr->ip_str);
|
||
if (ret != SD_SUCCESS) {
|
||
echo_warn6("\n mms_jread Failed! IED_ID=%d ,CPU=%d ,domain: %s ,logName: %s ,ip: %s,chnl_id: %d \n",
|
||
LD_info->ied->id, LD_info->cpuno, LD_info->LD_name, loginfo->logName, chnl_usr->ip_str, chnl_usr->chnl_id);
|
||
failed_count++;
|
||
}
|
||
|
||
del_mvl_type_ctrl();
|
||
|
||
loginfo->need_steady = 0;
|
||
loginfo->need_voltage = 0;
|
||
loginfo->start_time = loginfo->end_time;
|
||
|
||
g_dead_lock_counter = 0;
|
||
g_thread_blocked_times = 0; //防止补招时间过长导致进程退出
|
||
|
||
now = sGetMsTime();
|
||
last_check_recall_config_time = now;
|
||
printf("end ==============%.2f================\n", last_check_recall_config_time);
|
||
printf("end mms_jread................................\n");
|
||
}
|
||
|
||
if (failed_count==0) {//成功
|
||
Delete_recall_Xml(LD_info->mp_id);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
|
||
void process_3s_config(trigger_3s_xml_t *trigger_3s_xml)
|
||
{
|
||
int i,j;
|
||
trigger_t *trigger;
|
||
trigger_t *trigger_work;
|
||
int trigger_num;
|
||
ied_t *ied;
|
||
LD_info_t *LD_info;
|
||
|
||
int need_write_file;
|
||
int new_in_work_found;
|
||
|
||
printf("start process_3s_config\n");
|
||
|
||
need_write_file = FALSE;
|
||
trigger = trigger_3s_xml->new_triggers; //3s配置文件中的newtrigger数组,如果没有newtrigger这里就是0
|
||
trigger_num = trigger_3s_xml->new_trigger_num;
|
||
for (i=0; i<trigger_num; i++){
|
||
new_in_work_found = FALSE;
|
||
for (j=0; j<trigger_3s_xml->work_trigger_num; j++){
|
||
trigger_work = &trigger_3s_xml->work_triggers[j];
|
||
if (trigger_work->dev_idx==trigger[i].dev_idx && trigger_work->line_id==trigger[i].line_id ) {
|
||
|
||
if (trigger[i].real_data>=0)
|
||
trigger_work->real_data = trigger[i].real_data;//更新rtdata标志
|
||
if (trigger[i].soe_data>=0)
|
||
trigger_work->soe_data = trigger[i].soe_data; //更新soe标志
|
||
trigger_work->limit = trigger[i].limit;
|
||
|
||
clear_rpt_counter_by_trigger(trigger_work);//清理报告
|
||
new_in_work_found = TRUE;
|
||
}
|
||
}
|
||
if (!new_in_work_found) { //newtrigger为0,这是全新的触发,不是正在工作的触发
|
||
clear_rpt_counter_by_trigger(&trigger[i]);
|
||
if (trigger[i].real_data<0)
|
||
trigger[i].real_data = 0;
|
||
if (trigger[i].soe_data<0)
|
||
trigger[i].soe_data = 0;
|
||
trigger_3s_xml->work_triggers[trigger_3s_xml->work_trigger_num++] = trigger[i];
|
||
}
|
||
need_write_file = TRUE;//需要将新增的点写到文件中
|
||
}
|
||
|
||
trigger = trigger_3s_xml->delete_triggers; //如果没有deletetrigger这里就是0
|
||
trigger_num = trigger_3s_xml->delete_trigger_num;
|
||
for (i=0; i<trigger_num; i++){
|
||
for (j=0; j<trigger_3s_xml->work_trigger_num; j++){
|
||
trigger_work = &trigger_3s_xml->work_triggers[j];
|
||
if (trigger_work->dev_idx==trigger[i].dev_idx && trigger_work->line_id==trigger[i].line_id ) {
|
||
clear_rpt_counter_by_trigger(trigger_work);
|
||
trigger_work->dev_idx = INVALID_DEV_IDX;
|
||
}
|
||
}
|
||
need_write_file = TRUE;
|
||
}
|
||
|
||
trigger = trigger_3s_xml->modify_triggers; //如果没有modifytrigger这里就是0
|
||
trigger_num = trigger_3s_xml->modify_trigger_num;
|
||
for (i=0; i<trigger_num; i++){
|
||
for (j=0; j<trigger_3s_xml->work_trigger_num; j++){
|
||
trigger_work = &trigger_3s_xml->work_triggers[j];
|
||
if (trigger_work->dev_idx==trigger[i].dev_idx && trigger_work->line_id==trigger[i].line_id ) {
|
||
*trigger_work = trigger[i];
|
||
clear_rpt_counter_by_trigger(trigger_work);
|
||
}
|
||
}
|
||
need_write_file = TRUE;
|
||
}
|
||
|
||
clear_all_LD_real_soe_report_shoud_register(); //清空所有需要注册的报告,根据实时配置文件来。这里使LD_info->real_data = 0;LD_info->soe_data = 0;就不会触发报告
|
||
|
||
trigger = trigger_3s_xml->work_triggers; //文件的work块
|
||
trigger_num = trigger_3s_xml->work_trigger_num;
|
||
|
||
for (i=0; i<trigger_num; i++){ //遍历work块中所有触发点
|
||
int real_report_count = 0; //实时报告数量
|
||
|
||
if (trigger[i].dev_idx==INVALID_DEV_IDX){//跳过错误的终端号
|
||
printf("dev_idx incaild\n");
|
||
continue;
|
||
}
|
||
|
||
ied = find_ied_from_dev_idx(trigger[i].dev_idx); //通过文件中的dev号找到配置的设备,找不到说明不在这个进程里跳过(多进程的实现是否有必要?如果要实现就得每个进程一个操作目录)
|
||
if (!ied){
|
||
printf("can't find ied by dev_idx\n");
|
||
continue;
|
||
}
|
||
|
||
LD_info = find_LD_info_from_line_id(ied,trigger[i].line_id); //用文件中的检测点号找到配置的监测点
|
||
if (!LD_info){
|
||
printf("can't find line by line_idx\n");
|
||
continue;
|
||
}
|
||
|
||
real_report_count = get_real_report_count(LD_info); //获取监测点的实时报告数量LD_info->rptinfo[rpt_no]->count
|
||
|
||
//调试用
|
||
printf("terminal:%s - mp:%s real_report_count %d\n", ((ied_usr_t*)(ied->usr_ext))->terminal_id, LD_info->mp_id, real_report_count);
|
||
|
||
trigger[i].count = real_report_count; //记录此时这个监测点的实时报告数量
|
||
if (trigger[i].real_data && trigger[i].limit && (real_report_count>trigger[i].limit) ) {//监测点的实时报告数量大于当前文件中的限制,这个监测点的数据清零不再触发
|
||
trigger[i].real_data = 0;
|
||
trigger[i].limit = 0;
|
||
trigger[i].count = 0;
|
||
need_write_file = TRUE;
|
||
}
|
||
LD_info->real_data = trigger[i].real_data; //根据文件中的配置来设置,然后在报告触发中触发实时报告
|
||
LD_info->soe_data = trigger[i].soe_data;
|
||
LD_info->limit = trigger[i].limit;
|
||
LD_info->count = trigger[i].count;
|
||
if (LD_info->limit > 0) //限制数更新记录
|
||
need_write_file = TRUE;
|
||
if ( trigger[i].real_data==0 && trigger[i].soe_data==0 )//不触发条件记录
|
||
need_write_file = TRUE;
|
||
}
|
||
|
||
if (need_write_file)
|
||
create_3s_xml(trigger_3s_xml); //写入文件的work块
|
||
}
|
||
|
||
void del_process_recall_config(recall_xml_t* recall_xml)
|
||
{
|
||
int i,j;
|
||
recall_t *recall;
|
||
recall_t *recall_work;
|
||
int recall_num;
|
||
ied_t *ied;
|
||
LD_info_t *LD_info;
|
||
loginfo_t *loginfo = NULL;
|
||
int need_write_file;
|
||
|
||
need_write_file = FALSE;
|
||
recall = recall_xml->new_recalls;
|
||
recall_num = recall_xml->new_recall_num;
|
||
for (i=0; i<recall_num; i++){
|
||
recall_xml->work_recalls[recall_xml->work_recall_num++] = recall[i];
|
||
need_write_file = TRUE;
|
||
}
|
||
|
||
recall = recall_xml->work_recalls;
|
||
recall_num = recall_xml->work_recall_num;
|
||
for (i=0; i<recall_num; i++){
|
||
LD_info = find_LD_info_only_from_line_id(recall[i].line_id);
|
||
if (!LD_info)
|
||
continue;
|
||
if (LD_info->logcount<=0)
|
||
continue;
|
||
loginfo = LD_info->loginfo[0] ;
|
||
|
||
loginfo->need_steady = recall[i].need_steady;
|
||
loginfo->need_voltage = recall[i].need_voltage;
|
||
|
||
loginfo->start_time = recall[i].start_time;
|
||
loginfo->end_time = recall[i].end_time;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
void check_3s_config()
|
||
{
|
||
double now;
|
||
static double last_check_3s_config_time = 0.0;//初始化时间
|
||
trigger_3s_xml_t trigger_3s_xml; //3s触发文件
|
||
|
||
if (!three_secs_enabled) //cfg_3s_data进程才会开启
|
||
return;
|
||
now = sGetMsTime(); //当前时间
|
||
if ( fabs(now - last_check_3s_config_time) < 3*1000 ) //wait 3secs //当前进程任务执行时查看当前时间和上次执行时间间隔,小于3秒不执行,大于等于3秒往下执行
|
||
return;
|
||
|
||
printf("begin 3s config...\n");
|
||
|
||
last_check_3s_config_time = now; //记录本次运行时间
|
||
while (APR_SUCCESS==parse_3s_xml(&trigger_3s_xml)){ //处理3秒文件
|
||
//处理实时触发加台账锁lnk20250114
|
||
//pthread_mutex_lock(&mtx); printf("3s hold lock !!!!!!!!!!!");
|
||
process_3s_config(&trigger_3s_xml); //根据文件处理数据
|
||
//pthread_mutex_unlock(&mtx); printf("3s free lock !!!!!!!!!!!");
|
||
}
|
||
}
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
//lnk20250114参照实时数据方法处理台账信息
|
||
int isValidModelId(const char* model_id) {
|
||
size_t i;
|
||
|
||
if (model_id == NULL)
|
||
{
|
||
printf("!!!model_id null!!!\n");
|
||
return 0;
|
||
} // NULL 无效
|
||
|
||
size_t len = strlen(model_id);
|
||
if (len < 4) {
|
||
printf("!!!model_id length < 4!!!\n");
|
||
return 0; // 长度 < 4 无效
|
||
}
|
||
|
||
// 检查是否全是空格
|
||
for (i = 0; i < len; i++) {
|
||
if (!isspace((unsigned char)model_id[i])) {
|
||
return 1; // 只要包含非空格字符,就是合法的
|
||
}
|
||
}
|
||
printf("!!!model_id only space!!!\n");
|
||
return 0; // 仅包含空格,无效
|
||
}
|
||
|
||
void process_ledger_update(trigger_update_xml_t *ledger_update_xml)
|
||
{
|
||
int i,j;
|
||
terminal *update;
|
||
terminal *update_work;
|
||
int update_num;
|
||
ied_t *ied;
|
||
LD_info_t *LD_info;
|
||
int new_in_work_found;
|
||
|
||
ied_usr_t* ied_usr;
|
||
int chnl_no;
|
||
chnl_usr_t *chnl_usr = NULL;
|
||
|
||
printf("!!!start update ledger!!!\n");
|
||
|
||
update = ledger_update_xml->new_updates; //处理新增台账部分
|
||
update_num = ledger_update_xml->new_update_num;
|
||
printf("add ledger num:%d\n",update_num);
|
||
for (i=0; i<update_num; i++){ //查看所有需要新增的台账
|
||
new_in_work_found = FALSE;
|
||
if(update[i].terminal_id != NULL){
|
||
printf("add ledger of %s\n",update[i].terminal_id);
|
||
ied = find_ied_from_terminal_id(update[i].terminal_id); //通过文件中的终端号找到配置的设备
|
||
if (ied){
|
||
printf("find ied by terminal_id, terminal already exsist\n");
|
||
new_in_work_found = TRUE; //当前运行的台账中找到已有台账,变为更新
|
||
|
||
// 将当前终端从 new_updates 数组中移到 modify_updates 数组
|
||
if (ledger_update_xml->modify_update_num < MAX_UPDATEA_NUM) {
|
||
// 添加到 modify_updates 数组
|
||
ledger_update_xml->modify_updates[ledger_update_xml->modify_update_num] = update[i];
|
||
ledger_update_xml->modify_update_num++; // 更新 modify 数组的计数器
|
||
|
||
// 删除该终端(从 new_updates 数组中移除)
|
||
for (j = i; j < ledger_update_xml->new_update_num - 1; j++) {
|
||
ledger_update_xml->new_updates[j] = ledger_update_xml->new_updates[j + 1]; // 向前移动元素
|
||
}
|
||
|
||
ledger_update_xml->new_update_num--; // 更新 new_update_num,减少一个元素
|
||
continue;
|
||
} else {
|
||
fprintf(stderr, "Exceeded MAX_UPDATEA_NUM limit for modify_updates!\n");
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!new_in_work_found) { //这是全新的台账,在台账数组中没有包含这个设备
|
||
|
||
int terminal_index;
|
||
int ied_take = 0; //当前台账数组里有不使用的ied空间?0没有,1有
|
||
//进行台账添加和初始化操作
|
||
//1-申请新的内存空间//////////////////////////////
|
||
//新的台账数量 (n_clients) 和原有的台账数量 (原数量为 g_node->n_clients)
|
||
int new_client_count = g_node->n_clients + 1; // 增加一个新的台账
|
||
|
||
//判断新增进程后是否超过原有的台账数组,如果超过了就从不使能的ied空间中找可用空间,如果还是没有那就提示不能荷载更多终端
|
||
if(new_client_count > IED_COUNT){ //不更新台账数量
|
||
ied_t *ied_unused = NULL;
|
||
ied_usr_t* ied_usr_unused = NULL;
|
||
ied_unused = find_ied_unused();//遍历g_node找到第一个不使用的ied,这个ied之前初始化时分配过空间,直接占用
|
||
if(ied_unused != NULL){
|
||
ied_usr_unused = (ied_usr_t*)ied_unused->usr_ext;
|
||
ied = ied_unused; //新增的ied指向已有的未使用的ied空间
|
||
terminal_index = ied_usr_unused->dev_idx; //记录这个ied的编号,即g_node的下标
|
||
|
||
//打印提示
|
||
printf("!!!!!!!!ied index:%d ,origin terminal_id:%s has been taken!!!!!!!!!!\n",ied_usr_unused->dev_idx,ied_usr_unused->terminal_id);
|
||
|
||
//终端初始化,不需要再申请空间
|
||
ied_usr = (ied_usr_t*)ied->usr_ext;
|
||
ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;
|
||
|
||
ied_usr->dev_flag = ENABLE;//终端有效
|
||
|
||
ied->chncount = 1; //通信端口数
|
||
//不再分配通道空间
|
||
ied->channel[0].ied = ied; //通道的所属设备
|
||
ied->channel[0].status = STATUS_BREAKOFF;//初始化为通信中断
|
||
ied->cpucount = 0; //监测点数初始为0,读取监测点台账时写入
|
||
|
||
ied_take = 1;//ied之前存在
|
||
|
||
}
|
||
else{ //在已有的全部台账中都没找到不使用的ied,说明这个进程可挂的台账满了,不再处理
|
||
printf("!!!!!!!!!!ledger array is full!!!!!!\n");
|
||
|
||
//添加mq响应台账添加失败:台账挂满
|
||
//update[i].guid
|
||
char msg[256];
|
||
sprintf(msg, "终端 id: %s 台账更新失败, 这个进程的台账空间已满,达到了配置台账数量的最大值", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
|
||
return;
|
||
}
|
||
|
||
}//新台账数量小于等于设定的台账数量
|
||
else{
|
||
|
||
//调试用
|
||
printf("!!!!!!!!!!gnodeindex:%d!!!!!!\n",new_client_count - 1);
|
||
|
||
// 新增的台账在已有的台账数组中记录
|
||
g_node->clients[new_client_count - 1] = (ied_t*)apr_pcalloc(g_cfg_pool, sizeof(ied_t));
|
||
|
||
// 更新台账数量
|
||
g_node->n_clients = new_client_count; // 更新台账数量
|
||
//1-申请新的内存空间//////////////////////////////
|
||
|
||
//2-处理终端台账///////////////////////////////////
|
||
ied = g_node->clients[new_client_count - 1];//终端台账指针定向到ied数组当前位置的后一位
|
||
|
||
terminal_index = new_client_count;//新的台账终端
|
||
|
||
ied_usr = (ied_usr_t*)apr_pcalloc(g_init_pool, sizeof(ied_usr_t));
|
||
ied->usr_ext = ied_usr;//内存挂到ied上
|
||
if (ied_usr == NULL){
|
||
char msg[256];
|
||
snprintf(msg, sizeof(msg), "终端 id: %s 台账更新失败,没有找到台账的终端空间", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
return ;
|
||
}
|
||
|
||
|
||
ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;//从FeProject/子功能目录/etc/pt61850netd_pqfe.xml中读取的总查询时间
|
||
|
||
ied_usr->LD_info = (LD_info_t*)apr_pcalloc(g_init_pool, MAX_CPUNO * sizeof(LD_info_t));//内存挂到ied上
|
||
if (ied_usr->LD_info == NULL){
|
||
char msg[256];
|
||
snprintf(msg, sizeof(msg), "终端 id: %s 台账更新失败,没有找到台账的监测点空间", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
return ;
|
||
}
|
||
|
||
|
||
ied_usr->dev_flag = ENABLE;//终端有效
|
||
|
||
ied->chncount = 1; //通信端口数,一个终端一般只有一个
|
||
ied->channel = (channel_t*)apr_pcalloc(g_cfg_pool, sizeof(channel_t) * ied->chncount);//内存挂到ied上
|
||
ied->channel[0].ied = ied; //通道的所属设备
|
||
ied->channel[0].status = STATUS_BREAKOFF;//初始化为通信中断
|
||
ied->cpucount = 0; //监测点数初始为0,读取监测点台账时写入
|
||
//2-处理终端台账///////////////////////////////////
|
||
}
|
||
|
||
//3-写入台账内容//////////////////////////////
|
||
int ret = update_one_terminal_ledger(update,i,ied,terminal_index,ied_take);
|
||
if(ret){
|
||
printf("ledger can not be update!!!!!quit process!!!!!\n");
|
||
char msg[256];
|
||
snprintf(msg, sizeof(msg), "终端 id: %s 台账更新失败,无法写入台账", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
}
|
||
//3-写入台账内容///////////////////////////////////
|
||
|
||
//4-配置映射文件//////////////////////////////
|
||
char model[64];
|
||
// 获取模型ID,检查是否返回 NULL
|
||
parse_model_cfg_web_one(ied,&model);//存储在/FeProject/dat/
|
||
|
||
if (isValidModelId(model)) { //lnk20250313防止拿不到映射文件
|
||
// 安全拷贝字符串到 model 数组
|
||
strncpy(model, model, sizeof(model) - 1);
|
||
model[sizeof(model) - 1] = '\0'; // 确保以 null 结尾
|
||
printf("ledger Model ID: %s\n", model);
|
||
} else {
|
||
printf("ledger No model ID found.quit\n");
|
||
char msg[256];
|
||
snprintf(msg, sizeof(msg), "终端 id: %s 台账更新失败,没有找到装置型号", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
return ;
|
||
}
|
||
char full_path[128];
|
||
snprintf(full_path, sizeof(full_path), "/FeProject/dat/%s.xml", model); // 拼接路径
|
||
|
||
// 打印模型路径
|
||
printf("ledger icd config file full path: %s\n", full_path);
|
||
|
||
//映射文件解析
|
||
Set_xml_nodeinfo_one(ied_usr->dev_type);
|
||
//4-配置映射文件///////////////////////////////////
|
||
|
||
//5-报告块初始化//////////////////////////////
|
||
parse_rpt_log_ini_one(ied);
|
||
//5-报告块初始化///////////////////////////////////
|
||
|
||
//调试
|
||
printf("ledger id: %s\n", ((ied_usr_t*)ied->channel[0].ied->usr_ext)->terminal_id);
|
||
|
||
//6-init_rem_dib_table//////////////////////////////
|
||
init_rem_dib_table_one(ied);
|
||
//6-init_rem_dib_table///////////////////////////////////
|
||
|
||
//7启动终端日志
|
||
init_loggers_bydevid(((ied_usr_t*)ied->channel[0].ied->usr_ext)->terminal_id);
|
||
|
||
//8响应添加成功
|
||
//update[i].guid
|
||
char msg[256];
|
||
snprintf(msg, sizeof(msg), "终端 id: %s 台账添加成功", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////modify
|
||
update = ledger_update_xml->modify_updates; //处理修改台账部分
|
||
update_num = ledger_update_xml->modify_update_num;
|
||
printf("modify ledger num:%d\n",update_num);
|
||
for (i=0; i<update_num; i++){ //查看所有需要新增的台账
|
||
new_in_work_found = FALSE;
|
||
if(update[i].terminal_id != NULL){
|
||
printf("modify ledger of %s\n",update[i].terminal_id);
|
||
ied = find_ied_from_terminal_id(update[i].terminal_id); //通过文件中的终端号找到配置的设备
|
||
if (ied){
|
||
printf("find ied by terminal_id, terminal already exsist\n");
|
||
new_in_work_found = TRUE; //当前运行的台账中找到已有台账,更新它
|
||
|
||
//关闭这个终端的所有连接//////////////////////////////////////////////////////////////////////
|
||
for(chnl_no=0 ; chnl_no<ied->chncount; chnl_no++) {
|
||
chnl_usr = (chnl_usr_t*)ied->channel[chnl_no].connect;
|
||
if (chnl_usr->m_state!=CHANNEL_CONNECTED){//跳过未连接的通道
|
||
continue;
|
||
}
|
||
closeChannel(chnl_usr);//关闭更新台账后,任务会自动连接
|
||
}
|
||
|
||
//更新数据/////////////////////////////////////////////////////////////////////////////////
|
||
//3-写入台账内容//////////////////////////////
|
||
ied_usr = ied->usr_ext;
|
||
|
||
//清空logger
|
||
remove_loggers_by_terminal_id(update[i].terminal_id);
|
||
|
||
//写入前先清空已有数据
|
||
clearIedUsr(ied_usr);//不会清空dev_idx
|
||
|
||
//ied_usr->last_call_wavelist_time = sGetMsTime() + g_pt61850app->giTime * 1000;//从FeProject/子功能目录/etc/pt61850netd_pqfe.xml中读取的总查询时间
|
||
|
||
ied_usr->dev_flag = ENABLE;//终端有效
|
||
|
||
int ret = update_one_terminal_ledger(update,i,ied,ied_usr->dev_idx,1);//1:更新已有的ied
|
||
if(ret){
|
||
printf("ledger can not be update!!!!!quit process!!!!!\n");
|
||
|
||
char msg[256];
|
||
snprintf(msg, sizeof(msg), "终端 id: %s 台账更新失败,台账无法写入", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
return ;
|
||
}
|
||
//3-写入台账内容////////////////////////////////////////////
|
||
|
||
//4-配置映射文件///////////////////////////////////////////
|
||
char model[64] = {0};
|
||
// 获取模型ID,检查是否返回 NULL
|
||
parse_model_cfg_web_one(ied,&model);//存储在/FeProject/dat/
|
||
|
||
if (isValidModelId(model)) {
|
||
// 安全拷贝字符串到 model 数组
|
||
strncpy(model, model, sizeof(model) - 1);
|
||
model[sizeof(model) - 1] = '\0'; // 确保以 null 结尾
|
||
printf("ledger Model ID: %s\n", model);
|
||
} else {
|
||
printf("ledger No model ID found.\n");
|
||
|
||
char msg[256];
|
||
snprintf(msg, sizeof(msg), "终端 id: %s 台账更新失败,没有找到装置型号", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
return ;
|
||
}
|
||
char full_path[128];
|
||
snprintf(full_path, sizeof(full_path), "/FeProject/dat/%s.xml", model); // 拼接路径
|
||
|
||
// 打印模型路径
|
||
printf("ledger icd config file full path: %s\n", full_path);
|
||
|
||
//映射文件解析
|
||
Set_xml_nodeinfo_one(ied_usr->dev_type);
|
||
//4-配置映射文件///////////////////////////////////
|
||
|
||
//5-报告块初始化//////////////////////////////
|
||
parse_rpt_log_ini_one(ied);
|
||
//5-报告块初始化///////////////////////////////////
|
||
|
||
//6-init_rem_dib_table//////////////////////////////
|
||
init_rem_dib_table_one(ied);
|
||
//6-init_rem_dib_table///////////////////////////////////
|
||
//更新数据//////////////////////////////////////////////////////////////////////
|
||
|
||
//7启动终端日志
|
||
init_loggers_bydevid(((ied_usr_t*)ied->channel[0].ied->usr_ext)->terminal_id);
|
||
|
||
//8响应添加成功
|
||
//update[i].guid
|
||
char msg[256];
|
||
snprintf(msg, sizeof(msg), "终端 id: %s 台账修改成功", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
}
|
||
}
|
||
|
||
if (!new_in_work_found){
|
||
printf("modify_updates can not find ied!!!!!!\n");
|
||
|
||
//添加mq响应台账添加失败:台账找不到
|
||
//update[i].guid
|
||
char msg[256];
|
||
sprintf(msg, "终端 id: %s 台账修改失败, 无法找到这个终端", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
}
|
||
}
|
||
///////////////////////////////////////////////////////////////////////////////delete
|
||
update = ledger_update_xml->delete_updates; //处理删除台账部分
|
||
update_num = ledger_update_xml->delete_update_num; //删除的数量
|
||
printf("delete ledger num:%d\n",update_num);
|
||
|
||
for (i=0; i<update_num; i++){ //查看所有需要删除的台账
|
||
new_in_work_found = FALSE; //找到现存台账的标志
|
||
if(update[i].terminal_id != NULL){ //处理非空台账
|
||
printf("delete ledger of %s\n",update[i].terminal_id);
|
||
|
||
ied = find_ied_from_terminal_id(update[i].terminal_id); //通过文件中的终端号找到配置的设备,没找到就不处理
|
||
if (ied){
|
||
printf("find ied by terminal_id, terminal already exsist\n");
|
||
new_in_work_found = TRUE; //当前运行的台账中找到已有台账,更新它
|
||
|
||
//关闭这个终端的所有连接//////////////////////////////////////////////////////////////////////
|
||
for(chnl_no=0 ; chnl_no<ied->chncount; chnl_no++) {
|
||
chnl_usr = (chnl_usr_t*)ied->channel[chnl_no].connect;
|
||
if (chnl_usr->m_state!=CHANNEL_CONNECTED){ //跳过没连接的通道,一般一个终端只有一个
|
||
continue;
|
||
}
|
||
closeChannel(chnl_usr);//关闭更新台账后,如果是删除则不会再连接,关闭连接时这个ied的报告会被清除,报告控制会被注销
|
||
}
|
||
|
||
//更新数据//////////////////////////////////////////////////////////////////////
|
||
//3-删除台账内容//////////////////////////////
|
||
|
||
//调试用
|
||
// 假设要删除 g_node->clients 中的某个 ied,index 为删除的索引
|
||
int index_to_remove = 0;
|
||
ied_t* ied_find = NULL;
|
||
int iedno;
|
||
ied_usr_t* ied_usr_find = NULL; //遍历的ied
|
||
ied_usr = (ied_usr_t*)ied->usr_ext;//要删除的ied
|
||
for (iedno = 0; iedno < g_node->n_clients; iedno++) {
|
||
ied_find = g_node->clients[iedno];
|
||
ied_usr_find = (ied_usr_t*)ied_find->usr_ext;
|
||
if (ied_usr_find && strcmp(ied_usr_find->terminal_id, ied_usr->terminal_id) == 0) {
|
||
index_to_remove = iedno;//找到要删除的ied在g_node中的位置
|
||
break; //找到退出
|
||
}
|
||
}
|
||
|
||
// 先清理要删除的 ied 的内容
|
||
ied_t* ied_to_remove = g_node->clients[index_to_remove];//指向g_node对应的内存区
|
||
|
||
if(ied_to_remove == ied){//通过终端id找到的ied应该也指向g_node对应的内存区
|
||
printf("this ied is ied_to_remove\n");
|
||
}
|
||
//调试用
|
||
|
||
//清空logger
|
||
remove_loggers_by_terminal_id(update[i].terminal_id);
|
||
|
||
//清空ied的内容
|
||
clearIed(ied_to_remove);
|
||
|
||
//3-删除台账内容///////////////////////////////////
|
||
|
||
//4-配置映射文件//////////////////////////////
|
||
//映射文件保留,如果再次添加这个ied,如果是相同的映射文件则可以直接加载
|
||
//4-配置映射文件///////////////////////////////////
|
||
|
||
//5-报告块//////////////////////////////
|
||
//关闭连接时这个ied的报告已清空。报告控制块保留,因为报告控制块是根据设备类型设置的,如果删除会影响其他同类型的ied。这个ied对应的控制块在清空内容时已清空
|
||
//5-报告块///////////////////////////////////
|
||
|
||
//6-init_rem_dib_table//////////////////////////////
|
||
//rem_dib_table的内容将会被保留,如果有新的台账使用这个位置,将会直接覆盖
|
||
//6-init_rem_dib_table///////////////////////////////////
|
||
//更新数据//////////////////////////////////////////////////////////////////////
|
||
|
||
//7响应添加成功
|
||
//update[i].guid
|
||
char msg[256];
|
||
snprintf(msg, sizeof(msg), "终端 id: %s 台账删除成功", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
}
|
||
}
|
||
|
||
if (!new_in_work_found) {
|
||
printf("modify_updates can not find ied!!!!!!\n");
|
||
|
||
//添加mq响应台账添加失败:台账找不到
|
||
//update[i].guid
|
||
|
||
char msg[256];
|
||
sprintf(msg, "终端 id: %s 台账删除失败, 无法找到这个终端", update[i].terminal_id);
|
||
send_reply_to_kafka_c(update[i].guid, "2", msg);
|
||
|
||
}
|
||
}
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
if (ledger_update_xml->modify_update_num || ledger_update_xml->new_update_num || ledger_update_xml->delete_update_num){
|
||
create_ledger_log(ledger_update_xml); //写入文件
|
||
}
|
||
|
||
}
|
||
//台账更新调试打印函数
|
||
// 检查字符串是否为空
|
||
// 检查字符串是否为空
|
||
int is_empty(const char* str) {
|
||
return (str == NULL || str[0] == '\0');
|
||
}
|
||
|
||
// 打印 monitor 结构体信息
|
||
void print_monitor(const monitor* mon) {
|
||
printf("Monitor ID: %s\n", is_empty(mon->monitor_id) ? "N/A" : mon->monitor_id);
|
||
printf("Terminal Code: %s\n", is_empty(mon->terminal_code) ? "N/A" : mon->terminal_code);
|
||
printf("Monitor Name: %s\n", is_empty(mon->monitor_name) ? "N/A" : mon->monitor_name);
|
||
printf("Logical Device Sequence: %s\n", is_empty(mon->logical_device_seq) ? "N/A" : mon->logical_device_seq);
|
||
printf("Voltage Level: %s\n", is_empty(mon->voltage_level) ? "N/A" : mon->voltage_level);
|
||
printf("Terminal Connect: %s\n", is_empty(mon->terminal_connect) ? "N/A" : mon->terminal_connect);
|
||
printf("Timestamp: %s\n", is_empty(mon->timestamp) ? "N/A" : mon->timestamp);
|
||
printf("Status: %s\n", is_empty(mon->status) ? "N/A" : mon->status);
|
||
}
|
||
|
||
// 打印 terminal 结构体信息
|
||
void print_terminal(const terminal* tmnl) {
|
||
printf("GUID: %s\n", is_empty(tmnl->guid) ? "N/A" : tmnl->guid);//lnk20250506
|
||
printf("Terminal ID: %s\n", is_empty(tmnl->terminal_id) ? "N/A" : tmnl->terminal_id);
|
||
printf("Terminal Code: %s\n", is_empty(tmnl->terminal_code) ? "N/A" : tmnl->terminal_code);
|
||
printf("Organization Name: %s\n", is_empty(tmnl->org_name) ? "N/A" : tmnl->org_name);
|
||
printf("Maintenance Name: %s\n", is_empty(tmnl->maint_name) ? "N/A" : tmnl->maint_name);
|
||
printf("Station Name: %s\n", is_empty(tmnl->station_name) ? "N/A" : tmnl->station_name);
|
||
printf("Factory Name: %s\n", is_empty(tmnl->tmnl_factory) ? "N/A" : tmnl->tmnl_factory);
|
||
printf("Terminal Status: %s\n", is_empty(tmnl->tmnl_status) ? "N/A" : tmnl->tmnl_status);
|
||
printf("Device Type: %s\n", is_empty(tmnl->dev_type) ? "N/A" : tmnl->dev_type);
|
||
printf("Device Key: %s\n", is_empty(tmnl->dev_key) ? "N/A" : tmnl->dev_key);
|
||
printf("Device Series: %s\n", is_empty(tmnl->dev_series) ? "N/A" : tmnl->dev_series);
|
||
printf("Address: %s\n", is_empty(tmnl->addr_str) ? "N/A" : tmnl->addr_str);
|
||
printf("Port: %s\n", is_empty(tmnl->port) ? "N/A" : tmnl->port);
|
||
printf("Timestamp: %s\n", is_empty(tmnl->timestamp) ? "N/A" : tmnl->timestamp);
|
||
|
||
// 打印监测点信息,如果监测点字段为空,则打印 N/A
|
||
int i;
|
||
for (i = 0; i < 10 && !is_empty(tmnl->line[i].monitor_id); ++i) {
|
||
printf(" Monitor %d:\n", i + 1);
|
||
print_monitor(&tmnl->line[i]);
|
||
}
|
||
}
|
||
|
||
// 打印 trigger_update_xml_t 结构体信息
|
||
void print_trigger_update_xml(const trigger_update_xml_t* trigger_update) {
|
||
printf("Work Updates Count: %d\n", trigger_update->work_update_num);
|
||
printf("New Updates Count: %d\n", trigger_update->new_update_num);
|
||
printf("Delete Updates Count: %d\n", trigger_update->delete_update_num);
|
||
printf("Modify Updates Count: %d\n", trigger_update->modify_update_num);
|
||
|
||
printf("\nWork Updates:\n");
|
||
int i;
|
||
for (i = 0; i < trigger_update->work_update_num; ++i) {
|
||
printf("Work Update %d:\n", i + 1);
|
||
print_terminal(&trigger_update->work_updates[i]);
|
||
}
|
||
|
||
printf("\nNew Updates:\n");
|
||
for (i = 0; i < trigger_update->new_update_num; ++i) {
|
||
printf("New Update %d:\n", i + 1);
|
||
print_terminal(&trigger_update->new_updates[i]);
|
||
}
|
||
|
||
printf("\nDelete Updates:\n");
|
||
for (i = 0; i < trigger_update->delete_update_num; ++i) {
|
||
printf("Delete Update %d:\n", i + 1);
|
||
print_terminal(&trigger_update->delete_updates[i]);
|
||
}
|
||
|
||
printf("\nModify Updates:\n");
|
||
for (i = 0; i < trigger_update->modify_update_num; ++i) {
|
||
printf("Modify Update %d:\n", i + 1);
|
||
print_terminal(&trigger_update->modify_updates[i]);
|
||
}
|
||
}
|
||
|
||
void check_ledger_update()//lnk20250113
|
||
{
|
||
double now;
|
||
static double last_check_3s_config_time = 0.0;//初始化时间
|
||
|
||
now = sGetMsTime(); //当前时间
|
||
if ( fabs(now - last_check_3s_config_time) < 3*1000 ) //wait 3secs //当前进程任务执行时查看当前时间和上次执行时间间隔,小于3秒不执行,大于等于3秒往下执行
|
||
return;
|
||
|
||
// 动态分配内存给 trigger_ledger_update_xml 结构体
|
||
trigger_update_xml_t* trigger_ledger_update_xml = (trigger_update_xml_t*)malloc(sizeof(trigger_update_xml_t));
|
||
if (trigger_ledger_update_xml == NULL) {
|
||
printf("Memory allocation failed!\n");
|
||
return; // 如果内存分配失败,返回
|
||
}
|
||
|
||
//每次都初始化防止重复
|
||
memset(trigger_ledger_update_xml, 0, sizeof(trigger_update_xml_t));
|
||
|
||
|
||
|
||
//printf("check ledger update...trigger_ledger_update_xml:%d\n",trigger_ledger_update_xml->modify_update_num);//减少不必要的打印
|
||
|
||
last_check_3s_config_time = now; //记录本次运行时间
|
||
|
||
//判断是否满足执行条件,一个文件就是一个终端,读取文件后删除文件
|
||
if (APR_SUCCESS==parse_ledger_update_xml(trigger_ledger_update_xml)){ //处理台账更新文件,如果有可以更新或者添加台账的
|
||
//调试用
|
||
print_trigger_update_xml(trigger_ledger_update_xml);
|
||
|
||
//处理台账更新加台账锁lnk20250114
|
||
//pthread_mutex_lock(&mtx); printf("ledgerupdate hold lock !!!!!!!!!!!");
|
||
process_ledger_update(trigger_ledger_update_xml); //台账更新
|
||
//pthread_mutex_unlock(&mtx); printf("ledgerupdate free lock !!!!!!!!!!!");
|
||
|
||
}
|
||
|
||
// 使用完后释放动态分配的内存
|
||
free(trigger_ledger_update_xml);
|
||
}
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
#ifdef _OS_UNIX_
|
||
uint32_t get_freedisk_MB(uint32_t* totalSizeMB)
|
||
{
|
||
struct statfs diskInfo;
|
||
unsigned long long totalBlocks = 0;
|
||
unsigned long long totalSize = 0;
|
||
size_t mbTotalsize = 0;
|
||
size_t freeDisk=0;
|
||
size_t mbFreeDisk = 0;
|
||
|
||
statfs("/home/pq", &diskInfo);
|
||
totalBlocks = diskInfo.f_bsize;
|
||
totalSize = totalBlocks * diskInfo.f_blocks;
|
||
mbTotalsize = totalSize >> 20;
|
||
freeDisk = diskInfo.f_bfree*totalBlocks;
|
||
mbFreeDisk = freeDisk >> 20;
|
||
printf("/home/pq total=%dMB, free=%dMB \n", mbTotalsize, mbFreeDisk);
|
||
if (totalSizeMB)
|
||
*totalSizeMB = mbTotalsize;
|
||
return mbFreeDisk;
|
||
}
|
||
#else
|
||
uint32_t get_freedisk_MB(uint32_t* totalSizeMB) {
|
||
if (totalSizeMB)
|
||
*totalSizeMB = 1000;
|
||
return 5;
|
||
}
|
||
#endif
|
||
|
||
void check_disk_quota()
|
||
{
|
||
double now;
|
||
static double last_check_time = -10000000.0;
|
||
uint32_t freeSizeMB,totalSizeMB;
|
||
|
||
if(g_node_id != STAT_DATA_BASE_NODE_ID)
|
||
return;
|
||
now = sGetMsTime();
|
||
if ( fabs(now - last_check_time) < 15*1000 ) //wait 15 secs
|
||
return;
|
||
|
||
last_check_time = now;
|
||
|
||
freeSizeMB = get_freedisk_MB(&totalSizeMB);
|
||
|
||
//printf("Current user disk free size: %dMB ,total size: %dMB \n",freeSizeMB,totalSizeMB);
|
||
if (freeSizeMB<g_min_free_size)
|
||
echo_warn2("Current user disk free size: %dMB < %dMB, please check!\n",freeSizeMB,g_min_free_size);
|
||
if ((freeSizeMB/(totalSizeMB/100+1) )<10)
|
||
echo_warn2("Current user disk free size percent < 10%%, free size: %dMB ,total size: %dMB ,please check!\n",
|
||
freeSizeMB,totalSizeMB);
|
||
}
|
||
|
||
void create_recall_xml()
|
||
{
|
||
//生成待补招xml文件
|
||
if (g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_HIS_DATA_BASE_NODE_ID || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID)) {
|
||
DeletcRecallXml();
|
||
CreateRecallXml();
|
||
}
|
||
}
|
||
|
||
void Delete_recall_Xml(char* id) {
|
||
if (g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_HIS_DATA_BASE_NODE_ID || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID)) {
|
||
delete_recall_xml(id);
|
||
|
||
}
|
||
}
|
||
|
||
void Check_Recall_Config(char *id) //检查补招配置文件Recall.xml
|
||
{
|
||
if (g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_HIS_DATA_BASE_NODE_ID || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID)) {
|
||
|
||
recall_xml_t recall_xml;
|
||
memset((char*)&recall_xml, 0, sizeof(recall_xml_t));
|
||
parse_recall_xml(&recall_xml,id); //解析补招文件
|
||
process_recall_config(&recall_xml); //解析的补招数据赋值到全局变量
|
||
}
|
||
}
|
||
|
||
void CheckAllConnectedChannel()
|
||
{
|
||
chnl_usr_t *chnl_usr;
|
||
static uint32_t chnl_sequence_no = 0;
|
||
|
||
|
||
//lnk20250514如果进程启动没有台账则不往下执行,等待台账更新
|
||
if(g_pt61850app->chnl_counts == 0)return;
|
||
//lnk20250514如果进程启动没有台账则不往下执行,等待台账更新
|
||
|
||
|
||
//一次访问一个终端
|
||
do {
|
||
chnl_usr = g_pt61850app->chnl_usr[chnl_sequence_no];
|
||
chnl_sequence_no = (chnl_sequence_no+1) % g_pt61850app->chnl_counts;
|
||
} while ( (g_onlyIP[0]!=0) && (strcmp(g_onlyIP,chnl_usr->ip_str)!=0) );
|
||
|
||
if(chnl_usr->m_state == CHANNEL_CONNECTED)
|
||
{
|
||
|
||
ChannelCheckIECReports(chnl_usr);//报告
|
||
if ( (g_node_id == SOE_COMTRADE_BASE_NODE_ID) || (g_node_id == HIS_DATA_BASE_NODE_ID) || (g_node_id == NEW_HIS_DATA_BASE_NODE_ID) || (g_node_id == RECALL_HIS_DATA_BASE_NODE_ID) || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID))
|
||
ChannelCheckWaveFiles(chnl_usr);//录波文件
|
||
if(g_node_id == HIS_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID || g_node_id == RECALL_HIS_DATA_BASE_NODE_ID || (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID))
|
||
ChannelCheckIECLogs(chnl_usr);//补招文件
|
||
if ( (sGetMsTime() - chnl_usr->m_LastPosRespTime) > 15*1000 ) //wait 15 secs,隔15秒获取一次响应,两次没响应后关闭
|
||
{
|
||
char** varnames ;
|
||
int varnum;
|
||
|
||
ST_RET ret = mms_mvla_getnam(chnl_usr->net_info, VMD_SPEC, NULL,MMS_CLASS_DOM,g_pt61850app->mmsOpTimeout,
|
||
&varnames,&varnum,g_pt61850app->tmp_pool);
|
||
|
||
chnl_usr->m_LastPosRespTime = sGetMsTime();
|
||
if (ret == SD_SUCCESS) {
|
||
|
||
chnl_usr->m_NegRespTimes = 0;
|
||
}else {
|
||
|
||
printf("%d--------------\n", chnl_usr->m_NegRespTimes);
|
||
chnl_usr->m_NegRespTimes++;
|
||
}
|
||
}
|
||
if ( chnl_usr->m_NegRespTimes >=2 ) {
|
||
|
||
closeChannel(chnl_usr);//???特殊情况是否需要 mms_release_connection
|
||
chnl_usr->m_NegRespTimes = 0;
|
||
chnl_usr->m_LastPosRespTime = sGetMsTime();
|
||
}
|
||
}
|
||
}
|
||
|
||
void CheckNextNotConnectedChannel()
|
||
{
|
||
static uint32_t chnl_total_no = 0;
|
||
chnl_usr_t *chnl_usr;
|
||
|
||
//lnk20250514如果进程启动没有台账则不往下执行,等待台账更新
|
||
if(g_pt61850app->chnl_counts == 0)return;
|
||
//lnk20250514如果进程启动没有台账则不往下执行,等待台账更新
|
||
|
||
do {
|
||
chnl_usr = g_pt61850app->chnl_usr[chnl_total_no];
|
||
chnl_total_no = (chnl_total_no+1) % g_pt61850app->chnl_counts;
|
||
} while ( (g_onlyIP[0]!=0) && (strcmp(g_onlyIP,chnl_usr->ip_str)!=0) );
|
||
|
||
//10-11-01 22:03 beijing
|
||
if( ( (chnl_total_no+1)==g_pt61850app->chnl_counts) || (g_onlyIP[0]!=0) ){
|
||
if(g_pt61850app->initNum<255)
|
||
g_pt61850app->initNum++;
|
||
}
|
||
|
||
if(chnl_usr->m_state == CHANNEL_CONNECTING)//正在连接
|
||
{
|
||
|
||
MVL_REQ_PEND* reqCtrl= chnl_usr->m_reqCtrl ;
|
||
|
||
if( reqCtrl->done == SD_TRUE)
|
||
{
|
||
|
||
if(reqCtrl->result == SD_SUCCESS)
|
||
{
|
||
|
||
ALL_RCB_INFO *all_rcb_info;
|
||
|
||
echo_warn4("\nCHANNEL_CONNECTED %s:%d ,NetInfo= %x chnl_usr= %x \n",
|
||
chnl_usr->ip_str,chnl_usr->chnl->port,chnl_usr->net_info,chnl_usr);
|
||
mvl_free_req_ctrl(chnl_usr->m_reqCtrl);
|
||
chnl_usr->m_reqCtrl = NULL;
|
||
|
||
chnl_usr->m_state = CHANNEL_CONNECTED;
|
||
chnl_usr->net_info->user_ext = chnl_usr;
|
||
|
||
all_rcb_info = (ALL_RCB_INFO *)chk_calloc(1, sizeof (ALL_RCB_INFO));
|
||
all_rcb_info->rpt_typeids = &g_rpt_typeids;
|
||
|
||
if (chnl_usr->net_info->user_info != NULL) {
|
||
echo_warn("chnl_usr->net_info->user_info is not NULL\n");
|
||
}
|
||
|
||
chnl_usr->net_info->user_info = all_rcb_info;
|
||
chnl_usr->chnl->ied->status = STATUS_NORMAL;
|
||
chnl_usr->chnl->status = STATUS_NORMAL;
|
||
|
||
{
|
||
char comm_str[256];
|
||
memset(comm_str,0,256);
|
||
apr_snprintf(comm_str,sizeof(comm_str),"%16s:%d\t\tconnected",chnl_usr->ip_str,chnl_usr->chnl->port);
|
||
add_comm_log(comm_str);
|
||
FRONT_MP_NUM++;
|
||
}
|
||
|
||
//lnk202411-1添加连接成功的记录
|
||
ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext;
|
||
apr_time_t t_now = apr_time_now();
|
||
printf("msTime:%ld",t_now);
|
||
connectlog_pgsql(ied_usr->terminal_id,convertMsToDateTimeString(t_now),1);//1成功
|
||
|
||
}
|
||
else
|
||
{// solaris 9 上 224秒
|
||
|
||
int secsSince = (int)(sGetMsTime() - chnl_usr->m_StartConnectingTime)/1000 ;
|
||
|
||
ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext;
|
||
|
||
printf( "reqCtrl->result == FAIL, Since StartConnecting %i sec ,channel IP %s:%d \n",secsSince,chnl_usr->ip_str,chnl_usr->chnl->port);
|
||
mvl_free_req_ctrl(chnl_usr->m_reqCtrl);
|
||
chnl_usr->m_reqCtrl = NULL;
|
||
chnl_usr->net_info->rem_vmd = NULL;
|
||
chnl_usr->m_state = CHANNEL_DISCONNECTED;
|
||
chnl_usr->m_ClosedMsTime = sGetMsTime();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
if ( (sGetMsTime() - chnl_usr->m_StartConnectingTime) > 300*1000 ) //300*1000 ) //wait 300 secs
|
||
{
|
||
ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext;
|
||
|
||
echo_warn2( "reqCtrl->done未完成,but time over 300 secs, close channel IP %s,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->net_info);
|
||
if (chnl_usr->net_info->req_pend_list) {
|
||
echo_warn("reqCtrl->done未完成,but time over 300 secs!!!!!!!!\n");
|
||
mvl_free_req_ctrl(chnl_usr->m_reqCtrl);
|
||
chnl_usr->m_reqCtrl = NULL;
|
||
}
|
||
mms_release_connection(chnl_usr->net_info);
|
||
|
||
chnl_usr->net_info->rem_vmd = NULL;
|
||
chnl_usr->m_state = CHANNEL_DISCONNECTED;
|
||
chnl_usr->m_ClosedMsTime = sGetMsTime();
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
else if(chnl_usr->m_state == CHANNEL_DISCONNECTED)
|
||
{
|
||
|
||
if ( (sGetMsTime() - chnl_usr->m_ClosedMsTime) > NEXT_CONNECT_TIME ) //wait 10 secs
|
||
{
|
||
|
||
ST_RET ret;
|
||
ST_CHAR serverARName[32];
|
||
ied_usr_t *ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext;
|
||
apr_snprintf(serverARName,sizeof(serverARName),"%s:%d",chnl_usr->ip_str,chnl_usr->chnl->port);
|
||
if (chnl_usr->chnl->ied->cpucount != NULL && chnl_usr->chnl->ied->cpucount > 0 && ied_usr->dev_flag == ENABLE) {//2023-09-26 czy 如果line count<0 不需要连接//lnk20250121如果终端无效则不连接
|
||
ret = mms_connectToServer(ied_usr->dev_key, ied_usr->dev_series, serverARName, &(chnl_usr->net_info), &(chnl_usr->m_reqCtrl));
|
||
|
||
if (ret == SD_SUCCESS)
|
||
{
|
||
|
||
echo_msg3("mms_connectToServer IP %s:%d ,NetInfo= %x \n", chnl_usr->ip_str, chnl_usr->chnl->port, chnl_usr->net_info);
|
||
chnl_usr->m_state = CHANNEL_CONNECTING;
|
||
chnl_usr->m_StartConnectingTime = sGetMsTime();
|
||
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
chnl_usr->m_ClosedMsTime = sGetMsTime();
|
||
|
||
echo_warn3("FAILED: mms_connectToServer IP %s:%d ,NetInfo= %x \n", chnl_usr->ip_str, chnl_usr->chnl->port, chnl_usr->net_info);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
else if(chnl_usr->m_state == CHANNEL_DISCONNECTING) //need check timeout?会不会永远停留在这里
|
||
{
|
||
|
||
MVL_REQ_PEND* reqCtrl= chnl_usr->m_reqCtrl ;
|
||
if( reqCtrl->done == SD_TRUE)
|
||
{
|
||
|
||
echo_warn3( "CHANNEL_DISCONNECTING done %s:%d,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->chnl->port,chnl_usr->net_info);
|
||
mvl_free_req_ctrl(chnl_usr->m_reqCtrl);
|
||
if(chnl_usr->net_info)
|
||
chnl_usr->net_info->user_ext = NULL;
|
||
|
||
chnl_usr->m_reqCtrl = NULL;
|
||
chnl_usr->net_info = NULL;
|
||
chnl_usr->m_state = CHANNEL_DISCONNECTED;
|
||
chnl_usr->m_ClosedMsTime = sGetMsTime();
|
||
//断联成功
|
||
ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext;
|
||
apr_time_t t_now = apr_time_now();
|
||
connectlog_pgsql(ied_usr->terminal_id,convertMsToDateTimeString(t_now),0);
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
echo_warn2( "CHANNEL_DISCONNECTING waiting ... %s,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->net_info);
|
||
|
||
if ( (sGetMsTime() - chnl_usr->m_StartDisconnectingTime) > 30*1000 ) // //wait 30 secs ?????
|
||
{
|
||
|
||
echo_warn2( "CHANNEL_DISCONNECTING reqCtrl->done未完成,but time over 180 secs, close channel IP %s,NetInfo= %x ",chnl_usr->ip_str,chnl_usr->net_info);
|
||
mvl_free_req_ctrl(chnl_usr->m_reqCtrl);
|
||
chnl_usr->net_info->user_ext = NULL;
|
||
|
||
mms_release_connection(chnl_usr->net_info);
|
||
chnl_usr->net_info->rem_vmd = NULL;
|
||
chnl_usr->m_reqCtrl = NULL;
|
||
chnl_usr->net_info = NULL;
|
||
chnl_usr->m_state = CHANNEL_DISCONNECTED;
|
||
chnl_usr->m_ClosedMsTime = sGetMsTime();
|
||
//超时断联成功
|
||
ied_usr_t* ied_usr = (ied_usr_t*)chnl_usr->chnl->ied->usr_ext;
|
||
apr_time_t t_now = apr_time_now();
|
||
connectlog_pgsql(ied_usr->terminal_id,convertMsToDateTimeString(t_now),0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//////////////////////*********相关控制操作**********////////////////////////////////////////////////
|
||
static ST_RET Read_Named_Var(LD_info_t *LD_info,chnl_usr_t *chnl_usr,char* VarName,ST_INT type_id, ST_VOID *dataDest, ST_INT timeOut)
|
||
{
|
||
ST_RET ret= SD_FAILURE;
|
||
ST_CHAR *domName = LD_info->LD_name;
|
||
int Need_Destroy_Typeid = FALSE;
|
||
assert(chnl_usr && LD_info);
|
||
if (type_id==-1) {
|
||
Need_Destroy_Typeid = TRUE;
|
||
type_id= mms_var_type_id_create (chnl_usr->net_info,DOM_SPEC, domName, VarName,timeOut);
|
||
if (type_id==-1) ret = SD_FAILURE; else ret = SD_SUCCESS;
|
||
if (ret == SD_FAILURE) return SD_FAILURE;
|
||
}
|
||
ret=mms_named_var_read (chnl_usr->net_info,VarName,DOM_SPEC, domName,type_id, dataDest, timeOut);
|
||
if (Need_Destroy_Typeid)
|
||
if (type_id!=-1) mvl_type_id_destroy(type_id);
|
||
return ret;
|
||
}
|
||
|
||
static ST_RET Write_Named_Var(LD_info_t *LD_info,chnl_usr_t *chnl_usr,char* VarName,ST_INT type_id, ST_VOID *dataDest, ST_INT timeOut)
|
||
{
|
||
ST_RET ret= SD_FAILURE;
|
||
ST_CHAR *domName = LD_info->LD_name;
|
||
int Need_Destroy_Typeid = FALSE;
|
||
assert(chnl_usr && LD_info);
|
||
if (type_id==-1) {
|
||
Need_Destroy_Typeid = TRUE;
|
||
type_id= mms_var_type_id_create (chnl_usr->net_info,DOM_SPEC, domName, VarName,timeOut);
|
||
if (type_id==-1) ret = SD_FAILURE; else ret = SD_SUCCESS;
|
||
if (ret == SD_FAILURE) return SD_FAILURE;
|
||
}
|
||
ret=mms_named_var_write(chnl_usr->net_info,VarName,DOM_SPEC, domName,type_id, dataDest, timeOut);
|
||
if (Need_Destroy_Typeid)
|
||
if (type_id!=-1) mvl_type_id_destroy(type_id);
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
<EnumType id="ctlModelsEnum">
|
||
<EnumVal ord="0">status-only</EnumVal>
|
||
<EnumVal ord="1">direct-with-normal-security</EnumVal>
|
||
<EnumVal ord="2">sbo-with-normal-security</EnumVal>
|
||
<EnumVal ord="3">direct-with-enhanced-security</EnumVal>
|
||
<EnumVal ord="4">sbo-with-enhanced-security</EnumVal>
|
||
</EnumType>
|
||
*/
|
||
|
||
|
||
#define TICKS_PER_MIN 60LL*1000LL*1000LL
|
||
|
||
|
||
int pt61850_write_cn_file(chnl_usr_t *chnl_usr, ied_t *ied, char *rem_filename, char *only_filename_ret)
|
||
{
|
||
int ret ;
|
||
|
||
char loc_filename[128], loc_file_fullname[256], rem_file_fullname[256],only_filename_str[256];
|
||
|
||
char *only_filename,*the_full_file;
|
||
|
||
memset(loc_filename,0,sizeof(loc_filename));
|
||
memset(only_filename_str,0,sizeof(only_filename_str) );
|
||
|
||
strcat(only_filename_str,rem_filename);
|
||
only_filename = only_filename_str;
|
||
the_full_file = only_filename_str;
|
||
while ( *the_full_file != 0 ) {
|
||
if (*the_full_file == '/')
|
||
only_filename=the_full_file+1;
|
||
the_full_file++;
|
||
}
|
||
|
||
memset(rem_file_fullname,0,sizeof(rem_file_fullname) );
|
||
if (strstr(rem_filename,"/")!= NULL) {
|
||
strcat(rem_file_fullname,rem_filename);
|
||
}
|
||
else {
|
||
strcat(rem_file_fullname,g_pt61850app->accPath);
|
||
strcat(rem_file_fullname,rem_filename);
|
||
}
|
||
|
||
memset(loc_file_fullname,0,sizeof(loc_file_fullname) );
|
||
apr_snprintf(loc_file_fullname,sizeof(loc_file_fullname),"../comtrade/%s",only_filename);
|
||
apr_snprintf(only_filename_ret,256,"%s",only_filename);
|
||
printf("\n >>>>>>>>>****** Get wave file : %s from %s\n",loc_file_fullname,rem_file_fullname);
|
||
|
||
ret = mms_getFile(chnl_usr->net_info,loc_file_fullname,rem_file_fullname,g_pt61850app->mmsOpTimeout);
|
||
if (ret==SD_SUCCESS) {
|
||
|
||
}
|
||
else {
|
||
echo_warn3(">>>>>**** Error!!! %s mms_getFile wave file : %s from %s\n",chnl_usr->ip_str ,loc_file_fullname,rem_file_fullname);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
apr_status_t prepare_call_cn_wavelist(LD_info_t *LD_info, int FltNum)
|
||
{
|
||
int i;
|
||
|
||
for (i=0;i<256;i++) {
|
||
if (LD_info->FltNum[i]<=0) {
|
||
LD_info->FltNum[i] = FltNum;
|
||
break;
|
||
}
|
||
}
|
||
return APR_SUCCESS;
|
||
}
|
||
|
||
apr_status_t call_cn_wavelist(LD_info_t *LD_info )
|
||
{
|
||
int ret ;
|
||
int chnl_no;
|
||
chnl_usr_t *chnl_usr = NULL;
|
||
char **filenames;
|
||
int filenum ;
|
||
int i;
|
||
char file_match_str[65];
|
||
char *ldstr;
|
||
ied_t *ied = LD_info->ied;
|
||
ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied);
|
||
int have_new_files = FALSE;
|
||
|
||
for (i=0;i<256;i++) {
|
||
if (LD_info->FltNum[i]<=0)
|
||
continue;
|
||
//LD名称规范四字节:PQMn, 或者PQLDn ,有5个字节, 但也只取4个字符进行匹配
|
||
ldstr = LD_info->LD_name+strlen(LD_info->LD_name)-4;
|
||
apr_snprintf(file_match_str,sizeof(file_match_str),"%s_%06d",ldstr,LD_info->FltNum[i]);
|
||
|
||
printf(">>>>>>>> IED [%d]: %s is calling cn wavefile, !!!!!!!! file_match_str=%s \n",ied->id,ied->name,file_match_str);
|
||
ret = SD_FAILURE;
|
||
filenum = 0;
|
||
assert(ied->chncount);
|
||
for(chnl_no=0 ; chnl_no<ied->chncount; chnl_no++) {
|
||
chnl_usr = (chnl_usr_t*)ied->channel[chnl_no].connect;
|
||
if (chnl_usr->m_state!=CHANNEL_CONNECTED)
|
||
continue;
|
||
ret = mms_mvla_fdir(chnl_usr->net_info,g_pt61850app->accPath,3*g_pt61850app->mmsOpTimeout,&filenames,&filenum,g_pt61850app->tmp_pool);
|
||
if (ret==SD_SUCCESS)
|
||
break;
|
||
}
|
||
if (ret==SD_SUCCESS) {
|
||
int cfg_idx,dat_idx;
|
||
char file_base_name[128];
|
||
char file_yyyymm[128];
|
||
char cfg_only_filename_ret[256];
|
||
char dat_only_filename_ret[256];
|
||
int ret2,ret3;
|
||
|
||
//WW 2023-11-01将录波段号由字符串匹配修改为int的fltnum匹配
|
||
ret2 = parse_file_names_by_fltnum(LD_info->FltNum[i], ldstr, filenames, filenum, &cfg_idx, &dat_idx, file_base_name, file_yyyymm);
|
||
//WW 2023-11-01 end
|
||
if (ret2 !=APR_SUCCESS)
|
||
return ret2;
|
||
|
||
//完成录波文件,记录在文件名dat/cfg_only_filename_ret中,两个后缀不一样的录波文件,要上传两次
|
||
ret2 = pt61850_write_cn_file(chnl_usr,ied,filenames[cfg_idx],cfg_only_filename_ret);
|
||
ret3 = pt61850_write_cn_file(chnl_usr,ied,filenames[dat_idx],dat_only_filename_ret);
|
||
have_new_files = TRUE;
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////上传文件
|
||
if (ret2==SD_SUCCESS && ret3==SD_SUCCESS ) { //两个文件都写好了
|
||
QVVR_t *qvvr; //暂态事件
|
||
long long start_tm,trig_tm,end_tm;
|
||
|
||
ret2 = extract_timestamp_from_cfg_file(filenames[cfg_idx],&start_tm,&trig_tm);//提取文件的开始时间和触发时间
|
||
printf(">>>>>>>> extract_timestamp_from_cfg_file end \n");
|
||
if (ret2 ==APR_SUCCESS) {
|
||
//to find the paired qvvr by the time of trig_tm
|
||
printf(">>>>>>>> extract_timestamp_from_cfg_file success \n");
|
||
qvvr = find_qvvr_by_trig_tm(LD_info,trig_tm); //根据文件的触发时间查找检测点记录的匹配上的暂态事件
|
||
if (qvvr) {
|
||
char* uuid_cfg = (char*)malloc(65 * sizeof(char));//上传文件后获取到的路径
|
||
char* uuid_dat = (char*)malloc(65 * sizeof(char));
|
||
char* filename_cfg = (char*)malloc(100 * sizeof(char));//上传文件后获取到的文件名
|
||
char* filename_dat = (char*)malloc(100 * sizeof(char));
|
||
|
||
//lnk202411-5 记录web返回的路径+文件名
|
||
char* wavepath_cfg = (char*)malloc(256 * sizeof(char));
|
||
char* wavepath_dat = (char*)malloc(256 * sizeof(char));
|
||
/*上传.cfg和.dat两个文件*/
|
||
char linux_cmd[256] = {0};
|
||
printf(">>>>>>>> qvvr ok end \n");
|
||
apr_snprintf(linux_cmd,sizeof(linux_cmd),"./sftp_upload %s %s/%04d",cfg_only_filename_ret,file_yyyymm,LD_info->line_id);//没有使用
|
||
|
||
char loc_file_fullname_cfg[256];//本地文件名
|
||
memset(loc_file_fullname_cfg, 0, sizeof(loc_file_fullname_cfg));
|
||
apr_snprintf(loc_file_fullname_cfg, sizeof(loc_file_fullname_cfg), "/home/pq/FeProject/comtrade/%s", cfg_only_filename_ret);
|
||
char oss_file_fullname_cfg[256];//远端文件名
|
||
memset(oss_file_fullname_cfg, 0, sizeof(oss_file_fullname_cfg));
|
||
apr_snprintf(oss_file_fullname_cfg, sizeof(oss_file_fullname_cfg), "comtrade/wave/%s/%s", LD_info->mp_id, cfg_only_filename_ret);
|
||
if (FILE_FLAG == 1) {
|
||
PutOSS(oss_file_fullname_cfg, loc_file_fullname_cfg);//使用buffer推送文件
|
||
}
|
||
else if (FILE_FLAG == 2) {
|
||
OBSFile(loc_file_fullname_cfg, oss_file_fullname_cfg, "putObject");//这里并没有上传文件流
|
||
}
|
||
else if(FILE_FLAG==3){
|
||
WebAPI_Uds_Upload(UDS_UPLOAD_URL, loc_file_fullname_cfg, uuid_cfg, filename_cfg);//通过form-data上传文件
|
||
}
|
||
//LNK20241031使用JSON编码文件上传-具体的远端路径可以用原本代码的硬编码或者在配置文件中获取
|
||
else if (FILE_FLAG == 4) {
|
||
char mq_file_fullname_cfg[256]; // 远端文件名
|
||
memset(mq_file_fullname_cfg, 0, sizeof(mq_file_fullname_cfg));
|
||
|
||
// 使用修改后的文件名传入 apr_snprintf
|
||
apr_snprintf(mq_file_fullname_cfg, sizeof(mq_file_fullname_cfg), "comtrade/%s/",
|
||
LD_info->ied->channel[0].addr_str);
|
||
|
||
SOEFileWeb(loc_file_fullname_cfg, mq_file_fullname_cfg, wavepath_cfg);
|
||
|
||
printf("\n>>>>>>!! %s %s...... \n", mq_file_fullname_cfg, loc_file_fullname_cfg);
|
||
}
|
||
|
||
if (FILE_FLAG == 4) {
|
||
|
||
}
|
||
else{
|
||
printf("\n>>>>>>!! %s %s...... \n", oss_file_fullname_cfg, loc_file_fullname_cfg);
|
||
}
|
||
|
||
apr_snprintf(linux_cmd,sizeof(linux_cmd),"./sftp_upload %s %s/%04d",dat_only_filename_ret,file_yyyymm,LD_info->line_id);//先通过sftp上传才发json过去
|
||
|
||
char loc_file_fullname_dat[256];
|
||
memset(loc_file_fullname_dat, 0, sizeof(loc_file_fullname_dat));
|
||
apr_snprintf(loc_file_fullname_dat, sizeof(loc_file_fullname_dat), "/home/pq/FeProject/comtrade/%s", dat_only_filename_ret);
|
||
char oss_file_fullname_dat[256];
|
||
memset(oss_file_fullname_dat, 0, sizeof(oss_file_fullname_dat));
|
||
apr_snprintf(oss_file_fullname_dat, sizeof(oss_file_fullname_dat), "comtrade/wave/%s/%s", LD_info->mp_id, dat_only_filename_ret);
|
||
if (FILE_FLAG == 1) {
|
||
PutOSS(oss_file_fullname_dat, loc_file_fullname_dat);//使用buffer推送文件
|
||
}
|
||
else if (FILE_FLAG == 2) {
|
||
OBSFile(loc_file_fullname_dat, oss_file_fullname_dat, "putObject");//这里并没有上传文件流
|
||
}
|
||
else if(FILE_FLAG==3){
|
||
WebAPI_Uds_Upload(UDS_UPLOAD_URL, loc_file_fullname_dat, uuid_dat, filename_dat);//通过form-data上传文件
|
||
}
|
||
//LNK20241031使用JSON编码文件上传-具体的远端路径可以用原本代码的硬编码或者在配置文件中获取
|
||
else if (FILE_FLAG == 4) {
|
||
char mq_file_fullname_dat[256]; // 远端文件名
|
||
memset(mq_file_fullname_dat, 0, sizeof(mq_file_fullname_dat));
|
||
|
||
// 使用修改后的文件名传入 apr_snprintf
|
||
apr_snprintf(mq_file_fullname_dat, sizeof(mq_file_fullname_dat), "comtrade/%s/",
|
||
LD_info->ied->channel[0].addr_str);
|
||
|
||
SOEFileWeb(loc_file_fullname_dat, mq_file_fullname_dat, wavepath_dat);
|
||
|
||
printf("\n>>>>>>!! %s %s...... \n", mq_file_fullname_dat, loc_file_fullname_dat);
|
||
}
|
||
|
||
if (FILE_FLAG == 4) {
|
||
|
||
}
|
||
else{
|
||
printf("\n>>>>>>!! %s %s...... \n", oss_file_fullname_dat, loc_file_fullname_dat);
|
||
}
|
||
|
||
/*上传.cfg和.dat两个文件*/
|
||
/*上传消息*/
|
||
//to send json of this qvvr and rdre
|
||
end_tm = (long long)(qvvr->QVVR_PerTime*1000) + trig_tm; //结束时间是持续时间加触发时间
|
||
if (FILE_FLAG == 3) {
|
||
size_t cfg_len = strlen(uuid_cfg) + strlen(filename_cfg) + 3; // 额外的3个字符用于"-"和结束符'\0'
|
||
char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // 动态分配足够的内存空间
|
||
size_t dat_len = strlen(uuid_dat) + strlen(filename_dat) + 3; // 额外的3个字符用于"-"和结束符'\0'
|
||
char* dat_result = (char*)malloc(dat_len * sizeof(char)); // 动态分配足够的内存空间
|
||
if (cfg_result != NULL && dat_result != NULL) {
|
||
snprintf(cfg_result, cfg_len, "%s-%s", uuid_cfg, filename_cfg); // 拼接字符串并确保不会溢出目标缓冲区
|
||
snprintf(dat_result, dat_len, "%s-%s", uuid_dat, filename_dat); // 拼接字符串并确保不会溢出目标缓冲区
|
||
ret3 = transfer_json_qvvr_data(g_node_id, LD_info->line_id, (double)qvvr->QVVR_Amg, (double)qvvr->QVVR_PerTime, start_tm, end_tm, qvvr->QVVR_type, cfg_result, dat_result, LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type);
|
||
}
|
||
free(cfg_result); // 使用完毕后释放动态分配的内存空间
|
||
free(dat_result); // 使用完毕后释放动态分配的内存空间
|
||
}
|
||
else if(FILE_FLAG==4)//lnk20241031发送暂态web消息
|
||
{
|
||
//内存分配部分不修改
|
||
size_t cfg_len = strlen(wavepath_cfg) + 1;
|
||
char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // 动态分配足够的内存空间
|
||
size_t dat_len = strlen(wavepath_dat) + 1;
|
||
char* dat_result = (char*)malloc(dat_len * sizeof(char)); // 动态分配足够的内存空间
|
||
|
||
if (cfg_result != NULL && dat_result != NULL) {
|
||
snprintf(cfg_result, cfg_len, wavepath_cfg); // 拼接字符串并确保不会溢出目标缓冲区
|
||
snprintf(dat_result, dat_len, wavepath_dat); // 拼接字符串并确保不会溢出目标缓冲区
|
||
ret3 = transfer_json_qvvr_data(g_node_id, //这个参数没有使用
|
||
LD_info->line_id, //监测点序号
|
||
(double)qvvr->QVVR_Amg, (double)qvvr->QVVR_PerTime,
|
||
qvvr->QVVR_time, //这里不使用文件中的开始时间start_tm,因为会影响写库,使用QVVR的时间QVVR_time//lnk20250311
|
||
end_tm, qvvr->QVVR_type, //伏值、持续时间、开始时间、结束时间、暂态类型
|
||
cfg_result, dat_result, //两个文件路径
|
||
LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type);//监测点号,文件和监测点暂态事件匹配上的暂态报告名,终端类型
|
||
}
|
||
free(cfg_result); // 使用完毕后释放动态分配的内存空间
|
||
free(dat_result); // 使用完毕后释放动态分配的内存空间
|
||
}
|
||
else if (FILE_FLAG == 1 || FILE_FLAG == 2)
|
||
{
|
||
size_t cfg_len = strlen(oss_file_fullname_cfg) + strlen(cfg_only_filename_ret) + 3; // 额外的3个字符用于"-"和结束符'\0'
|
||
char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // 动态分配足够的内存空间
|
||
size_t dat_len = strlen(oss_file_fullname_dat) + strlen(dat_only_filename_ret) + 3; // 额外的3个字符用于"-"和结束符'\0'
|
||
char* dat_result = (char*)malloc(dat_len * sizeof(char)); // 动态分配足够的内存空间
|
||
if (cfg_result != NULL && dat_result != NULL) {
|
||
snprintf(cfg_result, cfg_len, "%s-%s", oss_file_fullname_cfg, cfg_only_filename_ret); // 拼接字符串并确保不会溢出目标缓冲区
|
||
snprintf(dat_result, dat_len, "%s-%s", oss_file_fullname_dat, dat_only_filename_ret); // 拼接字符串并确保不会溢出目标缓冲区
|
||
ret3 = transfer_json_qvvr_data(g_node_id, LD_info->line_id, (double)qvvr->QVVR_Amg, (double)qvvr->QVVR_PerTime, start_tm, end_tm, qvvr->QVVR_type, cfg_result, dat_result, LD_info->mp_id, qvvr->QVVR_Rptname, ied_usr->dev_type);
|
||
}
|
||
free(cfg_result); // 使用完毕后释放动态分配的内存空间
|
||
free(dat_result); // 使用完毕后释放动态分配的内存空间
|
||
}
|
||
/*上传消息*/
|
||
qvvr->used_status = QVVR_DATA_NOT_USED;//上传信息后这个qvvr的状态置为未使用
|
||
free(uuid_cfg);
|
||
free(uuid_dat);
|
||
free(filename_cfg);
|
||
free(filename_dat);
|
||
|
||
//lnk 202411-5
|
||
free(wavepath_cfg);
|
||
free(wavepath_dat);
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
else {
|
||
if (ied && chnl_usr)
|
||
echo_warn2("mms_mvla_fdir Failed: IED [%d] %s \n", ied->id , chnl_usr->ip_str) ;
|
||
return APR_EAGAIN;
|
||
}
|
||
LD_info->FltNum[i]= -1;
|
||
}
|
||
|
||
if (have_new_files)
|
||
clear_old_comtrade_files();
|
||
|
||
return APR_SUCCESS;
|
||
}
|
||
|
||
//lnk 2024-11-4 添加时间转换函数
|
||
char* convertMsToDateTimeString(int64_t usTime) {
|
||
// 确保时间戳是有效的
|
||
if (usTime < 0) {
|
||
return "Invalid timestamp";
|
||
}
|
||
|
||
// 将 `apr_time_t` 微秒(us)转换为 `time_t` 秒(s)
|
||
time_t seconds = usTime / 1000000;
|
||
|
||
// 用 `struct tm` 变量存储时间
|
||
struct tm timeInfo;
|
||
// **使用 `localtime_r()` 考虑系统时区**
|
||
localtime_r(&seconds, &timeInfo);
|
||
|
||
// 静态分配的字符数组存储转换后的字符串
|
||
static char buffer[30];
|
||
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &timeInfo);
|
||
|
||
return buffer;
|
||
}
|
||
|