/** * @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 #include "rdb_client.h" //#include "../misc/utf8_to_gb.h" //#include "../misc/gb_to_utf8.h" #include #include "db_interface.h" #include "node.h" #include "ied.h" #include "../json/mms_json_inter.h" 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(int 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 #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 #if 0 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; 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 ); for(iedno=0 ; iednon_clients; iedno++) { ied = g_node->clients[iedno]; for(chnl_no=0 ; chnl_nochncount; 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; } #endif 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 ; iednon_clients; iedno++) { ied = g_node->clients[iedno]; for(chnl_no=0 ; chnl_nochncount; 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 ; cpunocpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); for(rpt_no=0 ; rpt_norptcount; 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; /*get_rpt_inst_name(rptinfo,rpt_inst_name); 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) { echo_warn3("unregister iec_rpt failed !!! domain: %s ,rpt_inst_name: %s ,chnl_id: %d \n", LD_info->LD_name,rpt_inst_name,chnl_usr->chnl_id); } else { printf("unregister iec_rpt succeed, domain: %s ,rpt_inst_name: %s ,chnl_id: %d \n", LD_info->LD_name,rpt_inst_name,chnl_usr->chnl_id); } */ rptinfo->rpt_registered = FALSE; //注销报告后,取消10分钟 再注册一次的限制,可立即注册 rptinfo->m_LastRegisterFailedTime = sGetMsTime() -10*60*1000; rptinfo->m_rcb_info = NULL; } } } void prcess_ied_comm_2_json(ied_t *ied,int status) { ied_usr_t *ied_usr = NULL; LD_info_t *LD_info = NULL; int cpuno ; apr_time_t tm = apr_time_now()/1000; if (!three_secs_enabled) return; ied_usr = (ied_usr_t*)ied->usr_ext; for(cpuno=0 ; cpunocpucount; cpuno++) { LD_info = &(ied_usr->LD_info[cpuno]); if (LD_info ) { //prcess_monitor_comm_2_json(LD_info->line_id,status,tm); } } } 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 ); //prcess_ied_comm_2_json(chnl_usr->chnl->ied,STATUS_BREAKOFF); //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_BREAKOFF, chnl_usr->chnl_id); //write_status_to_db(0,chnl_usr->chnl->addr); 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"); //cout<ip_str,chnl_usr->net_info); //mms_release_connection(chnl_usr->net_info); ??????? mvl_free_req_ctrl(chnl_usr->m_reqCtrl); chnl_usr->net_info->user_ext = NULL; chnl_usr->net_info = NULL; //cout<<"CHANNEL Close roughly, NetInfo_Channel_Map.entries()= "<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(); //cout<<"m_ClosedMsTime "<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; //cout<<"NetInfo_Channel_Map.entries()= "<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); } //cout <<"NetInfo_Channel_Map[NetInfo] " << pCh <net_info = NULL; NetInfo->user_ext = NULL; } printf(" Callback_channel_disconnect_ind ,NetInfo = %x",NetInfo); /* cout<<"after: NetInfo_Channel_Map.entries()= "<chnl[0].ied->usr_ext); //printf("%s", ied_usr->terminal_code); //connectlog_pgsql(ied_usr->terminal_code); //apr_time_t tm = apr_time_now();// //printf("time: %llu", tm); //apr_time_exp_t pTm; //apr_time_exp_gmt(&pTm, tm); //printf("time: %u %u %u", pTm.tm_year, pTm.tm_mon, pTm.tm_mday); } 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; printf("check error %s !!!!!!!!!!!!!!cpucount:%d\n",((ied_usr_t*)chnl_usr->chnl->ied->usr_ext)->terminal_id,(int)ied->cpucount); //printf("1 chnl_usr->ip_str = %s \n",chnl_usr->ip_str); for(cpuno=0 ; cpunocpucount; cpuno++) //for(cpuno = ied->cpucount - 1; cpuno >= 0; cpuno--) { LD_info = &(ied_usr->LD_info[cpuno]); //遍历监测点 if (LD_info->cpuno==0) continue; //printf("2 chnl_usr->ip_str = %s \n",chnl_usr->ip_str); for(rpt_no=0 ; rpt_norptcount; rpt_no++) { //遍历报告(映射文件中读取的报告控制) rptinfo = LD_info->rptinfo[rpt_no] ; /*if ( strstr(rptinfo->rptID,"LLN0$RP$urcbRealData") ) continue;*/ if (judge_rpt_next_should_do(rptinfo)==SHOULD_DO_NOTHING)//检查是否触发 continue; //printf("3 chnl_usr->ip_str = %s \n",chnl_usr->ip_str); 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); //rcb_info = mms_register_iec_rpt_by_devtype(chnl_usr->net_info, &g_rpt_typeids, // LD_info->LD_name, rpt_inst_name, g_pt61850app->mmsOpTimeout, ied_usr->dev_type, chnl_usr->ip_str, channel->port, // 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 ); //不再记录暂降日志lnk20241104 /*if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) { //暂降事件记录触发报告记录 SoeRptSql(LD_info->terminal_code,1, rptinfo->rptID); }*/ //zw修改 2023 - 8 - 18 新增触发报告失败记录 //printf("start %s \n", Rpt_errorlog_json()); //insert into "MEAS_PQ_COMM_ERROR_TR"("TERMINAL_ID","COMM_DATE","FILE_NAME") values('8afaa9a15707483a0157262f8e78077d',date'2023-08-18','FILENAME111') //char ERROR_DES[256] = "", ERROR_PARAM[256] = ""; //char** varnames; //int varnum,j; ////double beforeCallDomainMsTime = sGetMsTime() ; //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); //for (j = 0; j < varnum; ++j) { // //printf("LD %d name: %s \n", j, varnames[j]); // strcat(ERROR_PARAM, varnames[j]); // strcat(ERROR_PARAM, " "); //} //ret = mms_mvla_getnam(chnl_usr->net_info, DOM_SPEC, varnames[1], MMS_CLASS_VARLIST, 3, // &varnames, &varnum, g_pt61850app->tmp_pool); //for (j = 0; j < varnum; ++j) { // //printf("LD %d name: [%s] \n", j, varnames[j]); // strcat(ERROR_PARAM, varnames[j]); // strcat(ERROR_PARAM, " "); //} //strcat(ERROR_DES, ied_usr->org_name); //strcat(ERROR_DES, ","); //strcat(ERROR_DES, ied_usr->station_name); //strcat(ERROR_DES, ","); //strcat(ERROR_DES, ied_usr->dev_type); //strcat(ERROR_DES, ","); //strcat(ERROR_DES, chnl_usr->ip_str); //strcat(ERROR_DES, ","); //strcat(ERROR_DES, rpt_inst_name); //errorlog_json(LD_info->terminal_code, chnl_usr->ip_str, chnl_usr->chnl->port, g_node_id, "报告触发失败", ERROR_DES, ERROR_PARAM); } else { //不再记录暂降日志lnk20241104 /*if (g_node_id == SOE_COMTRADE_BASE_NODE_ID) { //暂降事件记录触发报告失败记录 SoeRptSql(LD_info->terminal_code, 0, rptinfo->rptID); }*/ double GIoffset; rptinfo->rpt_registered = TRUE; //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 去除 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"); } //double nowMsTime = sGetMsTime() ; //int ScanRateMs = 3*rptinfo->IntgPd*1000; //if (rptinfo->chnl_id==chnl_usr->chnl_id) { // //IECReport_tryGI(chnl_usr,rptinfo); // if ( (ScanRateMs) && BSTR_BIT_GET( &(rptinfo->TrgOpt), TRGOPS_BITNUM_INTEGRITY ) ) // IntgPd的时间 不等于0, 并且有效 // if ( (nowMsTime - rptinfo->m_LastDataTime) > ScanRateMs ) // { // echo_err4("大于三倍IntgPd的时间未收到数据,通道重连, domain: %s ,rpt_inst_name: %s ,ip: %s,chnl_id: %d \n", // APR_EGENERAL,LD_info->LD_name,rpt_inst_name,chnl_usr->ip_str,chnl_usr->chnl_id); // closeChannel(chnl_usr); // return; // } //} } //else { //rpt_registered ==TRUE } } } 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 ; cpunocpucount; 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 ; cpunocpucount; 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结构 //add_comm_log(LD_info->mp_id); 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; //loginfo->need_steady = 1; loginfo->need_voltage = 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); //printf("bef mms_jread............. %11d %11d \n", LD_info->autorecall[i]->start, LD_info->autorecall[i]->end); if (loginfo->need_steady == 0 && loginfo->need_voltage == 0) continue; if (loginfo->end_time <= loginfo->start_time) continue; /*if ( (sGetMsTime() -loginfo->last_checktime) < 180*1000 ) continue;*/ //loginfo->last_checktime = sGetMsTime(); printf("start mms_jread................................\n"); //now = sGetMsTime(); //last_check_recall_config_time = now; //printf("start ==============%.2f================\n", last_check_recall_config_time); 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); //set_log_LineID(LD_info->line_id); //set_line_info(LOG_IDX,LD_info->line_id,LD_info->SubV_Index,LD_info->Dev_Index,LD_info->Sub_Index,LD_info->GD_Index); //long long start = LD_info->autorecall[i]->start; //long long end = start; //for (;end < LD_info->autorecall[i]->end;) //{ // if (end < LD_info->autorecall[i]->end - 180) // { // start = end; // end = end + 180; // loginfo->start_time = apr_time_from_sec(start - 5); // loginfo->end_time = apr_time_from_sec(end - 5); // } // else { // start = end; // end = LD_info->autorecall[i]->end; // loginfo->start_time = apr_time_from_sec(start - 5); // loginfo->end_time = apr_time_from_sec(end - 5); // } //} //printf(" mms_jread..... start time: %d end time: %d\n", start, end); 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); } } /*apr_time_from_sec(&loginfo->start_time, 1694275200); apr_time_from_sec(&loginfo->end_time, 1694361600);*/ } } 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 rpt_no; // rptinfo_t *rptinfo; 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; iwork_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]; 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; iwork_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; iwork_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; irptinfo[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; iwork_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; ilogcount<=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; } //remove_recall_xml(); } 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); process_3s_config(&trigger_3s_xml); //根据文件处理数据 pthread_mutex_unlock(&mtx); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //lnk20250114参照实时数据方法处理台账信息 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; imodify_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"); 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) return APR_ENOMEM; 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) return APR_ENOMEM; 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"); return 0; } //3-写入台账内容/////////////////////////////////// //4-配置映射文件////////////////////////////// char model[64] = {0}; // 获取模型ID,检查是否返回 NULL char* model_id = parse_model_cfg_web_one(ied);//存储在/FeProject/dat/ if (model_id != NULL) { // 安全拷贝字符串到 model 数组 strncpy(model, model_id, 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 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/////////////////////////////////// } } //////////////////////////////////////////////////////////////////////////////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; ichncount; 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; //写入前先清空已有数据 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"); return 0; } //3-写入台账内容//////////////////////////////////////////// //4-配置映射文件/////////////////////////////////////////// char model[64] = {0}; // 获取模型ID,检查是否返回 NULL char* model_id = parse_model_cfg_web_one(ied);//存储在/FeProject/dat/ if (model_id != NULL) { // 安全拷贝字符串到 model 数组 strncpy(model, model_id, 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 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/////////////////////////////////// //更新数据////////////////////////////////////////////////////////////////////// } } if (!new_in_work_found){ printf("modify_updates can not find ied!!!!!!\n"); } } ///////////////////////////////////////////////////////////////////////////////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; ichncount; 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"); } //调试用 //清空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/////////////////////////////////// //更新数据////////////////////////////////////////////////////////////////////// } } if (!new_in_work_found) { printf("modify_updates can not find ied!!!!!!\n"); } } ////////////////////////////////////////////////////////////////////////////// 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("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); process_ledger_update(trigger_ledger_update_xml); //台账更新 pthread_mutex_unlock(&mtx); } // 使用完后释放动态分配的内存 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 30) { recall_start = 30; } if (recall_lenth > 10) { recall_lenth = 10; } if (recall_start < recall_lenth) //起始天数小于补招长度 以起止天数到当天为长度 { recall_lenth = recall_start; } if (recall_count < recall_lenth) { recall_pgsql(recall_start - recall_count);//补招数据 //char* day = getoneday(recall_start - recall_count);//获取前n天 yyyy-mm-dd //printf("==============%s================\n", day); //deletechar(day); recall_count++; } else { recall_flag = 3; } } if (localTime.tm_hour != recall_dailytime && recall_flag == 3) { recall_flag = 1; recall_count = 0; } } void recall_pgsql(int num) { char* day = getoneday(num);//获取前n天 yyyy-mm-dd int i = 0; while (i < g_pt61850app->chnl_counts) { chnl_usr_t* chnl_usr; ied_t* ied; ied_usr_t* ied_usr; LD_info_t* LD_info; int cpuno = 0; chnl_usr = g_pt61850app->chnl_usr[i]; ied = chnl_usr->chnl->ied; ied_usr = GET_IEDEXT_ADDR(ied); if (chnl_usr->m_state == CHANNEL_CONNECTED) { while (cpuno < ied->cpucount) { LD_info = &(ied_usr->LD_info[cpuno]); if (LD_info->logcount <= 0) continue; printf("/home/pq mpid=%s\n", LD_info->mp_id); //替换成web接口2024-10-21 lnk //int ReDecide = OTL_Select_DecideRecall(day, LD_info->mp_id); //int ReDecide = OTL_Select_DecideRecall_web(day, LD_info->mp_id);//不使用lnk20241206 //if (ReDecide == 1) {//不使用lnk20241206 //替换成web接口2024-10-21 lnk //OTL_Select_recall(day, LD_info->mp_id); //OTL_Select_recall_web(day, LD_info->mp_id);//不使用lnk20241206 //}//不使用lnk20241206 g_dead_lock_counter = 0; g_thread_blocked_times = 0; cpuno++; } } i++; } deletechar(day); } 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); //process_recall_config(&recall_xml); //remove_recall_xml(); } } 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); //解析的补招数据赋值到全局变量 //process_recall_config(&recall_xml); //remove_recall_xml(); } /*recall_xml_t recall_xml; memset((char*)&recall_xml, 0, sizeof(recall_xml_t)); int ret = parse_recall_xml(&recall_xml); if (0 == ret) process_recall_config(&recall_xml);*/ } void CheckAllConnectedChannel() { chnl_usr_t *chnl_usr; static uint32_t chnl_sequence_no = 0; //10-11-02 20:18 beijing, only one ied by visited every loop 一次访问一个终端 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) ); //for (i=0; ichnl_counts; i++) { //chnl_usr = g_pt61850app->chnl_usr[i] ; //printf("CheckAllConnectedChannel chnl_usr->ip_str = %s \n",chnl_usr->ip_str); if(chnl_usr->m_state == CHANNEL_CONNECTED) { /*if(chnl_usr->chnl->ied->id==virtual_ied){ chnl_usr->m_state = CHANNEL_CONNECTED; return; }*/ 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 { char** varnames ; int varnum; //double beforeCallDomainMsTime = sGetMsTime() ; 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); //for ( j = 0; j < varnum; ++j) //printf("LD %d name: %s \n",j,varnames[j]); //ret = mms_mvla_getnam(chnl_usr->net_info, DOM_SPEC, varnames[1],MMS_CLASS_VARLIST,3, // &varnames,&varnum,g_pt61850app->tmp_pool); ////ret = mms_mvla_getnam(chnl_usr->net_info, DOM_SPEC, varnames[1], MMS_CLASS_VAR, 3, //// &varnames, &varnum, g_pt61850app->tmp_pool); //for ( j = 0; j < varnum; ++j) // printf("LD %d name: [%s] \n",j,varnames[j]); //double comdiff = sGetMsTime() - beforeCallDomainMsTime; //cout<<"cost secs to check com "<net_info, 15 ); chnl_usr->m_LastPosRespTime = sGetMsTime(); if (ret == SD_SUCCESS) { //chnl_usr->m_LastPosRespTime = sGetMsTime(); chnl_usr->m_NegRespTimes = 0; }else { // cout<<" "<GetIP()<<" 读 domain name 失败 "<m_NegRespTimes); chnl_usr->m_NegRespTimes++; } } if ( chnl_usr->m_NegRespTimes >=2 ) { //printf("==============chnl_usr->m_NegRespTimes================\n"); 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; // element_t *elem_a; // element_t *elem_b; 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) ); printf("check error chnl_total_no !!!!!!!!!!!!!! %d\n",chnl_total_no); //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->chnl->ied->chncount == 2){ //elem_a = RDB_GetElement(SUBSTATION, chnl_usr->chnl->ied->id,64264, 5); //elem_b = RDB_GetElement(SUBSTATION, chnl_usr->chnl->ied->id,64264, 6); //if(elem_a&&elem_b){ // if((((M_DP_NA_1_t*)elem_a->value.data)->diq.parts.DPI == 0x01)&&(((M_DP_NA_1_t*)elem_b->value.data)->diq.parts.DPI == 0x01)){ // iecs_set_ied_invalid(chnl_usr->chnl->ied); // } //} } else{ //elem_a = RDB_GetElement(SUBSTATION, chnl_usr->chnl->ied->id,64264, 5); //if(elem_a){ // if(((M_DP_NA_1_t*)elem_a->value.data)->diq.parts.DPI == 0x01){ // iecs_set_ied_invalid(chnl_usr->chnl->ied); // } //} } printf("check error94 !!!!!!!!!!!!!!\n"); printf("check error %s !!!!!!!!!!!!!!\n",((ied_usr_t*)chnl_usr->chnl->ied->usr_ext)->terminal_id); if(chnl_usr->m_state == CHANNEL_CONNECTING)//正在连接 { printf("check error93 !!!!!!!!!!!!!!\n"); MVL_REQ_PEND* reqCtrl= chnl_usr->m_reqCtrl ; printf("check error60 !!!!!!!!!!!!!!\n"); if( reqCtrl->done == SD_TRUE) { printf("check error92 !!!!!!!!!!!!!!\n"); if(reqCtrl->result == SD_SUCCESS) { printf("check error91 !!!!!!!!!!!!!!\n"); ALL_RCB_INFO *all_rcb_info; // cout<GetIP()<<" CHANNEL_CONNECTED netInfo "<net_info<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; //assert(chnl_usr->net_info->user_info == NULL); 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; //prcess_ied_comm_2_json(chnl_usr->chnl->ied,STATUS_NORMAL); //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_NORMAL, chnl_usr->chnl_id); { 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; connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),1);//1成功 } else {// solaris 9 上 224秒 printf("check error90 !!!!!!!!!!!!!!\n"); int secsSince = (int)(sGetMsTime() - chnl_usr->m_StartConnectingTime)/1000 ; //cout<<"reqCtrl->result == FAIL, Since StartConnecting "<GetIP()<<" !!! "<chnl->ied->usr_ext; if (g_node_id == STAT_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID) { //lnk202411-4 //connectlog_pgsql(ied_usr->terminal_code);//连接请求失败 printf("check error89 !!!!!!!!!!!!!!\n"); connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),0);//0失败 printf("check error88 !!!!!!!!!!!!!!\n"); } printf( "reqCtrl->result == FAIL, Since StartConnecting %i 秒 ,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 {// printf("check error61 !!!!!!!!!!!!!!\n"); 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; if (g_node_id == STAT_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID) { //connectlog_pgsql(ied_usr->terminal_code);//reqCtrl->done未完成,重连超时5分钟 //lnk202411-4 connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),0);//0失败 } //cout<GetIP()<<" reqCtrl->done == SD_false but time over 300 secs, close channel !!!"<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); //mvl_free_req_ctrl(chnl_usr->m_reqCtrl); //??? chnl_usr->net_info->rem_vmd = NULL; chnl_usr->m_state = CHANNEL_DISCONNECTED; chnl_usr->m_ClosedMsTime = sGetMsTime(); //if(chnl_usr->chnl->ied->id==virtual_ied){ // chnl_usr->m_state = CHANNEL_CONNECTED; // chnl_usr->chnl->ied->status = STATUS_NORMAL; // chnl_usr->chnl->status = STATUS_NORMAL; // //Special_CPU_Set(chnl_usr->chnl->ied, STATUS_NORMAL); // //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_NORMAL,0); //} } } } //if(pChannel->m_state == CHANNEL_CONNECTING) else if(chnl_usr->m_state == CHANNEL_DISCONNECTED) { //调试用 printf("check error99 !!!!!!!!!!!!!!\n"); if ( (sGetMsTime() - chnl_usr->m_ClosedMsTime) > NEXT_CONNECT_TIME ) //wait 10 secs { //调试用 printf("check error98 !!!!!!!!!!!!!!\n"); 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)); printf("check error73 !!!!!!!!!!!!!!\n"); if (ret == SD_SUCCESS) { printf("check error74 !!!!!!!!!!!!!!\n"); //if(chnl_usr->chnl->ied->id==virtual_ied){ // chnl_usr->m_state = CHANNEL_CONNECTED; // chnl_usr->chnl->ied->status = STATUS_NORMAL; // chnl_usr->chnl->status = STATUS_NORMAL; // //Special_CPU_Set(chnl_usr->chnl->ied, STATUS_NORMAL); // //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_NORMAL,0); // return; //} //echo_warn3("!!!!!!!!!!!!!!!!!!!!!!!!! %s:%d %x \n", chnl_usr->ip_str, chnl_usr->chnl->port, chnl_usr->net_info); 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(); //RDB_SetIedChnlStatus(chnl_usr->chnl->ied, STATUS_NOINIT, chnl_usr->chnl_id); //write_status_to_db(0,chnl_usr->chnl->addr); //lnk202411-1添加重新连接,并没有连接成功,没有正在连接的记录 //connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),1);//1成功 } else { //调试用 printf("check error97 !!!!!!!!!!!!!!\n"); chnl_usr->m_ClosedMsTime = sGetMsTime(); if (g_node_id == STAT_DATA_BASE_NODE_ID || g_node_id == NEW_HIS_DATA_BASE_NODE_ID) { //lnk202411-4 //connectlog_pgsql(ied_usr->terminal_code);//重连失败 //调试用 printf("check error96 !!!!!!!!!!!!!!\n"); connectlog_pgsql(ied_usr->terminal_code,convertMsToDateTimeString((int)sGetMsTime()),0);//0失败 printf("check error95 !!!!!!!!!!!!!!\n"); } echo_warn3("FAILED: mms_connectToServer IP %s:%d ,NetInfo= %x \n", chnl_usr->ip_str, chnl_usr->chnl->port, chnl_usr->net_info); } } } }//if(pChannel->m_state == CHANNEL_DISCONNECTED) else if(chnl_usr->m_state == CHANNEL_DISCONNECTING) //need check timeout?会不会永远停留在这里??? { printf("check error92 !!!!!!!!!!!!!!\n"); MVL_REQ_PEND* reqCtrl= chnl_usr->m_reqCtrl ; if( reqCtrl->done == SD_TRUE) { printf("check error72 !!!!!!!!!!!!!!\n"); //cout<GetIP()<<" CHANNEL_DISCONNECTING done"<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; //NetInfo_Channel_Map.remove(chnl_usr->net_info); //cout<<"CHANNEL_DISCONNECTING done NetInfo_Channel_Map.entries()= "<m_reqCtrl = NULL; chnl_usr->net_info = NULL; chnl_usr->m_state = CHANNEL_DISCONNECTED; chnl_usr->m_ClosedMsTime = sGetMsTime(); } else {// printf("check error70 !!!!!!!!!!!!!!\n"); // cout<GetIP()<<" CHANNEL_DISCONNECTING waiting ..."<ip_str,chnl_usr->net_info); if ( (sGetMsTime() - chnl_usr->m_StartDisconnectingTime) > 30*1000 ) // //wait 30 secs ????? { printf("check error71 !!!!!!!!!!!!!!\n"); //cout<GetIP()<<"CHANNEL_DISCONNECTING reqCtrl->done == SD_false but time over 180 secs, close channel !!!"<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; //NetInfo_Channel_Map.remove(chnl_usr->net_info); 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(); } } }//if(pChannel->m_state == CHANNEL_DISCONNECTING) ////////////////// printf("check error77 !!!!!!!!!!!!!!\n"); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////*********相关控制操作**********//////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// 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; } /* status-only direct-with-normal-security sbo-with-normal-security direct-with-enhanced-security sbo-with-enhanced-security */ #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 ; // ticks_t ticks; char loc_filename[128], loc_file_fullname[256], rem_file_fullname[256],only_filename_str[256]; // int result ;//= FILE_NAME_UNIQUE; // uint8_t cpuNo =0; char *only_filename,*the_full_file; // ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); 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_nochncount; 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); //ret2 = parse_file_names(file_match_str,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; //char ftp_filename[256]; //doCommService(); //memset(ftp_filename,0,256); 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 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(168 * sizeof(char)); char* wavepath_dat = (char*)malloc(168 * 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);//没有使用 //printf("\n>>>>>> %s ...... \n",linux_cmd); //system(linux_cmd); 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) { SOEFileWeb(loc_file_fullname_cfg, oss_file_fullname_cfg, wavepath_cfg); } 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过去 //printf("\n>>>>>> %s ...... \n",linux_cmd); //system(linux_cmd); 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) { SOEFileWeb(loc_file_fullname_dat, oss_file_fullname_dat, wavepath_dat); } 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, qvvr->QVVR_Amg, 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); char* cfg_result = (char*)malloc(cfg_len * sizeof(char)); // 动态分配足够的内存空间 size_t dat_len = strlen(wavepath_dat); 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, //监测点序号 qvvr->QVVR_Amg, 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 == 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, qvvr->QVVR_Amg, 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; 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(int msTime) { // 将毫秒时间戳转换为秒时间戳 time_t seconds = msTime / 1000; // 获取本地时间 struct tm* timeInfo = localtime(&seconds); // 静态分配的字符数组存储转换后的字符串 static char buffer[20]; strftime(buffer, sizeof(buffer), "%y-%m-%d %H:%M:%S", timeInfo); return buffer; }