添加单点补招pqdif文件的逻辑
This commit is contained in:
@@ -103,6 +103,7 @@ static void format_time_ms(long long ms, char* buf, size_t buf_len){
|
||||
}
|
||||
|
||||
static apr_status_t ChannelCheckPQDIFFiles(chnl_usr_t *chnl_usr);
|
||||
static apr_status_t ChannelRecallPQDIFFiles(chnl_usr_t *chnl_usr, LD_info_t *LD_info, long long start_sec, long long end_sec);
|
||||
//lnk20250122start
|
||||
apr_status_t init_rem_dib_table()
|
||||
{
|
||||
@@ -580,21 +581,28 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr)
|
||||
LD_info_t *LD_info;
|
||||
loginfo_t *loginfo = NULL;
|
||||
int cpuno;
|
||||
int is_pqdif_process;
|
||||
|
||||
double now;
|
||||
static double last_check_recall_config_time = 0.0;
|
||||
|
||||
ied = chnl_usr->chnl->ied;
|
||||
ied_usr = GET_IEDEXT_ADDR(ied);
|
||||
is_pqdif_process = (g_node_id == PQDIF_DATA_BASE_NODE_ID);
|
||||
|
||||
for(cpuno=0 ; cpuno<ied->cpucount; cpuno++) {
|
||||
LD_info = &(ied_usr->LD_info[cpuno]);
|
||||
|
||||
//添加保护,防止台账中测点号不连续导致的崩溃
|
||||
if (LD_info->cpuno == 0 ||
|
||||
LD_info->LD_name == NULL ||
|
||||
LD_info->logcount <= 0 ||
|
||||
LD_info->loginfo == NULL)
|
||||
LD_info->LD_name == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_pqdif_process &&
|
||||
(LD_info->logcount <= 0 ||
|
||||
LD_info->loginfo == NULL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -620,11 +628,13 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr)
|
||||
continue;
|
||||
}*/
|
||||
|
||||
loginfo = LD_info->loginfo[0] ;
|
||||
if (!is_pqdif_process) {
|
||||
loginfo = LD_info->loginfo[0] ;
|
||||
|
||||
//添加保护,防止台账中测点号不连续导致的崩溃
|
||||
if (loginfo == NULL || loginfo->LD_info == NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
apr_sleep(apr_time_from_sec(1) / 10);
|
||||
|
||||
@@ -636,14 +646,17 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr)
|
||||
int failed_count = 0;
|
||||
|
||||
/////////////////////////////////////////////////////根据配置文件控制下发补招时间为北京时间还是utc时间
|
||||
long long utc_or_beijing = 0;
|
||||
if (!is_pqdif_process) {
|
||||
printf("~~~~~~~this dev type is %s~~~~~~~",ied_usr->dev_type);
|
||||
XmlConfigC cfg1;
|
||||
memset(&cfg1,0,sizeof(cfg1));
|
||||
if (get_xml_config_by_dev_type(ied_usr->dev_type, &cfg1)) {
|
||||
printf("ValueOfTimeUnit = %s\n", cfg1.ValueOfTimeUnit);
|
||||
} else {
|
||||
printf("读取失败,未找到 dev_type\n");
|
||||
}
|
||||
long long utc_or_beijing;
|
||||
utc_or_beijing = 0;
|
||||
|
||||
if(strcmp(cfg1.ValueOfTimeUnit, "utc") == 0){//装置时间是utc还是北京
|
||||
utc_or_beijing = 28800;//秒
|
||||
@@ -654,6 +667,11 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr)
|
||||
DIY_WARNLOG_CODE(LD_info->mp_id,2,LOG_CODE_RECALL,"【WARN】监测点:%s - id:%s开始补招数据,注意!下发补招时间为beijing时间,监测点对应装置型号:%s", LD_info->name,LD_info->mp_id,ied_usr->dev_type);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
DIY_WARNLOG_CODE(LD_info->mp_id,2,LOG_CODE_RECALL,"[PQDIF][RECALL] monitor:%s - id:%s start recall PQDIF files, dev_type:%s", LD_info->name,LD_info->mp_id,ied_usr->dev_type);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//记录本次补招的时间范围
|
||||
long long min_start_sec = LLONG_MAX;
|
||||
@@ -674,6 +692,9 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr)
|
||||
LD_info->autorecallflag = 1;//正在补招
|
||||
|
||||
//当前不区分稳态和暂态lnk20241030,如果做区分修改:Check_Recall_Config从xml文件获取数据后,赋值给了LD_info
|
||||
if (is_pqdif_process)
|
||||
continue;
|
||||
|
||||
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);//保证时间开头
|
||||
@@ -726,6 +747,24 @@ void ChannelCheckIECLogs(chnl_usr_t *chnl_usr)
|
||||
|
||||
//不管是否成功,这个补招文件必须删除,可能出现一直失败,循环读取文件和循环补招导致程序崩溃202050724lnk
|
||||
//if (failed_count==0) {//成功
|
||||
if (is_pqdif_process) {
|
||||
if (min_start_sec == LLONG_MAX || max_end_sec <= min_start_sec) {
|
||||
failed_count++;
|
||||
printf("[PQDIF][RECALL] invalid recall range mp_id=%s min=%lld max=%lld\n",
|
||||
LD_info->mp_id, min_start_sec, max_end_sec);
|
||||
}
|
||||
else {
|
||||
ret = ChannelRecallPQDIFFiles(chnl_usr, LD_info, min_start_sec, max_end_sec);
|
||||
if (ret != APR_SUCCESS)
|
||||
failed_count++;
|
||||
}
|
||||
|
||||
g_dead_lock_counter = 0;
|
||||
g_thread_blocked_times = 0;
|
||||
now = sGetMsTime();
|
||||
last_check_recall_config_time = now;
|
||||
}
|
||||
|
||||
Delete_recall_Xml(LD_info->mp_id);
|
||||
|
||||
// ===== [新增] 组装上送的补招开始/结束时间字符串(本地时区,直接“秒转字符串”)=====
|
||||
@@ -1652,7 +1691,8 @@ void CheckAllConnectedChannel()
|
||||
|
||||
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))
|
||||
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)
|
||||
|| g_node_id == PQDIF_DATA_BASE_NODE_ID)
|
||||
ChannelCheckIECLogs(chnl_usr);//补招文件
|
||||
|
||||
if ( (sGetMsTime() - chnl_usr->m_LastPosRespTime) > 15*1000 ) //wait 15 secs,隔15秒获取一次响应,两次没响应后关闭
|
||||
@@ -2063,42 +2103,60 @@ static void pqdif_make_time_match(int cpu_no, time_t tm_value, char* out, size_t
|
||||
tm_local.tm_hour);
|
||||
}
|
||||
|
||||
static int pqdif_match_recent_interval(const char* filename, int cpu_no)
|
||||
static int pqdif_use_interval_end_time(const char* dev_type)
|
||||
{
|
||||
return (dev_type != NULL && strcmp(dev_type, "PS_NET_PQDIF") == 0);
|
||||
}
|
||||
|
||||
static time_t pqdif_align_interval_start(long long sec)
|
||||
{
|
||||
time_t now_time;
|
||||
time_t hour_floor;
|
||||
time_t interval_end;
|
||||
time_t interval_start;
|
||||
struct tm tm_now;
|
||||
char start_match[64];
|
||||
char end_match[64];
|
||||
struct tm tm_local;
|
||||
int hour_mod;
|
||||
|
||||
memset(&tm_local, 0, sizeof(tm_local));
|
||||
hour_floor = (time_t)sec;
|
||||
localtime_r(&hour_floor, &tm_local);
|
||||
tm_local.tm_min = 0;
|
||||
tm_local.tm_sec = 0;
|
||||
hour_floor = mktime(&tm_local);
|
||||
|
||||
hour_mod = tm_local.tm_hour % PQDIF_AUTO_INTERVAL_HOURS;
|
||||
return hour_floor - hour_mod * 3600;
|
||||
}
|
||||
|
||||
static int pqdif_match_interval(const char* filename, int cpu_no, time_t interval_start, const char* dev_type)
|
||||
{
|
||||
time_t name_time;
|
||||
char time_match[64];
|
||||
|
||||
if (!pqdif_has_pqd_suffix(filename))
|
||||
return FALSE;
|
||||
|
||||
if (cpu_no <= 0)
|
||||
return FALSE;
|
||||
|
||||
now_time = time(NULL);
|
||||
localtime_r(&now_time, &tm_now);
|
||||
tm_now.tm_min = 0;
|
||||
tm_now.tm_sec = 0;
|
||||
hour_floor = mktime(&tm_now);
|
||||
|
||||
/* 最近一个完整周期:
|
||||
* 例如当前 11:xx、周期 2 小时,则完整周期是 08:00~10:00。
|
||||
* 普通设备按周期开始时间命名,PS_NET_PQDIF 振兴设备按周期结束时间命名。
|
||||
* 这里同时匹配开始和结束时间,避免需要额外区分厂家。
|
||||
/* C# 原逻辑按设备类型决定文件名时间:
|
||||
* - 普通设备用周期开始时间;
|
||||
* - PS_NET_PQDIF 用周期结束时间。
|
||||
* 这里保持同样规则,避免把普通设备下一周期的开始文件误认为本周期结束文件。
|
||||
*/
|
||||
hour_mod = tm_now.tm_hour % PQDIF_AUTO_INTERVAL_HOURS;
|
||||
interval_end = hour_floor - hour_mod * 3600;
|
||||
interval_start = interval_end - PQDIF_AUTO_INTERVAL_HOURS * 3600;
|
||||
name_time = interval_start;
|
||||
if (pqdif_use_interval_end_time(dev_type))
|
||||
name_time += PQDIF_AUTO_INTERVAL_HOURS * 3600;
|
||||
|
||||
pqdif_make_time_match(cpu_no, interval_start, start_match, sizeof(start_match));
|
||||
pqdif_make_time_match(cpu_no, interval_end, end_match, sizeof(end_match));
|
||||
pqdif_make_time_match(cpu_no, name_time, time_match, sizeof(time_match));
|
||||
return strstr(filename, time_match) != NULL;
|
||||
}
|
||||
|
||||
return (strstr(filename, start_match) != NULL || strstr(filename, end_match) != NULL);
|
||||
static int pqdif_match_recent_interval(const char* filename, int cpu_no, const char* dev_type)
|
||||
{
|
||||
time_t now_time;
|
||||
time_t interval_start;
|
||||
|
||||
now_time = time(NULL);
|
||||
interval_start = pqdif_align_interval_start((long long)now_time) - PQDIF_AUTO_INTERVAL_HOURS * 3600;
|
||||
return pqdif_match_interval(filename, cpu_no, interval_start, dev_type);
|
||||
}
|
||||
|
||||
static int pqdif_ensure_local_dir()
|
||||
@@ -2199,6 +2257,141 @@ static int pqdif_get_file_from_device(chnl_usr_t *chnl_usr, const char *rem_file
|
||||
return SD_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t ChannelRecallPQDIFFiles(chnl_usr_t *chnl_usr, LD_info_t *LD_info, long long start_sec, long long end_sec)
|
||||
{
|
||||
ied_t *ied;
|
||||
ied_usr_t *ied_usr;
|
||||
char **filenames = NULL;
|
||||
int filenum = 0;
|
||||
int ret;
|
||||
int file_idx;
|
||||
int fetched = 0;
|
||||
int existed = 0;
|
||||
int missing = 0;
|
||||
int failed = 0;
|
||||
time_t interval_start;
|
||||
time_t interval_step;
|
||||
|
||||
if (chnl_usr == NULL || chnl_usr->chnl == NULL || chnl_usr->chnl->ied == NULL ||
|
||||
chnl_usr->chnl->ied->usr_ext == NULL || chnl_usr->net_info == NULL ||
|
||||
LD_info == NULL) {
|
||||
printf("[PQDIF][RECALL] invalid context, skip\n");
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
if (LD_info->cpuno == 0 || LD_info->LD_name == NULL || LD_info->mp_id[0] == '\0') {
|
||||
printf("[PQDIF][RECALL] invalid LD_info, skip\n");
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
if (end_sec <= start_sec) {
|
||||
printf("[PQDIF][RECALL] invalid time range mp_id=%s start=%lld end=%lld\n",
|
||||
LD_info->mp_id, start_sec, end_sec);
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
ied = chnl_usr->chnl->ied;
|
||||
ied_usr = (ied_usr_t*)ied->usr_ext;
|
||||
|
||||
if (pqdif_ensure_local_dir() != SD_SUCCESS) {
|
||||
echo_warn1("[PQDIF][RECALL] create local dir failed: %s\n", PQDIF_LOCAL_DIR);
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
/* 单点补招与 C# 手动/补招逻辑保持一致:
|
||||
* 1. 先读取装置 /PQDIF/ 目录;
|
||||
* 2. 按 PQDIF_AUTO_INTERVAL_HOURS 将补招时间范围切成多个文件周期;
|
||||
* 3. 普通设备用周期开始时间匹配文件名,PS_NET_PQDIF 用周期结束时间匹配文件名;
|
||||
* 4. 每个周期只取一份匹配文件,下载接口直接调用 mms_getFile。
|
||||
*/
|
||||
ret = mms_mvla_fdir(chnl_usr->net_info,(ST_CHAR*)PQDIF_REMOTE_DIR,
|
||||
3*g_pt61850app->mmsOpTimeout,&filenames,&filenum,g_pt61850app->tmp_pool);
|
||||
if (ret != SD_SUCCESS) {
|
||||
echo_warn2("[PQDIF][RECALL] mms_mvla_fdir failed, IED=%d IP=%s\n", ied->id, chnl_usr->ip_str);
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
if (filenames == NULL || filenum <= 0) {
|
||||
printf("[PQDIF][RECALL] no file in remote dir %s, mp_id=%s IP=%s\n",
|
||||
PQDIF_REMOTE_DIR, LD_info->mp_id, chnl_usr->ip_str);
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
interval_step = PQDIF_AUTO_INTERVAL_HOURS * 3600;
|
||||
interval_start = pqdif_align_interval_start(start_sec);
|
||||
|
||||
printf("[PQDIF][RECALL] begin mp_id=%s cpuno=%d range=%lld~%lld interval_start=%lld files=%d dev_type=%s\n",
|
||||
LD_info->mp_id, LD_info->cpuno, start_sec, end_sec, (long long)interval_start,
|
||||
filenum, ied_usr->dev_type);
|
||||
|
||||
while ((long long)interval_start < end_sec) {
|
||||
int found_this_interval = FALSE;
|
||||
|
||||
for (file_idx = 0; file_idx < filenum; file_idx++) {
|
||||
const char *base_name;
|
||||
char remote_filename[256];
|
||||
char only_filename_ret[256];
|
||||
int ret_get;
|
||||
|
||||
if (filenames[file_idx] == NULL)
|
||||
continue;
|
||||
|
||||
base_name = pqdif_basename(filenames[file_idx]);
|
||||
if (base_name[0] == '\0')
|
||||
continue;
|
||||
|
||||
if (!pqdif_match_interval(base_name, LD_info->cpuno, interval_start, ied_usr->dev_type))
|
||||
continue;
|
||||
|
||||
found_this_interval = TRUE;
|
||||
if (pqdif_local_file_exists(base_name)) {
|
||||
existed++;
|
||||
printf("[PQDIF][RECALL] local file exists, skip mp_id=%s interval=%lld file=%s\n",
|
||||
LD_info->mp_id, (long long)interval_start, base_name);
|
||||
break;
|
||||
}
|
||||
|
||||
memset(remote_filename,0,sizeof(remote_filename));
|
||||
memset(only_filename_ret,0,sizeof(only_filename_ret));
|
||||
pqdif_build_remote_filename(filenames[file_idx], remote_filename, sizeof(remote_filename));
|
||||
if (remote_filename[0] == '\0') {
|
||||
failed++;
|
||||
break;
|
||||
}
|
||||
|
||||
ret_get = pqdif_get_file_from_device(chnl_usr, remote_filename, only_filename_ret, sizeof(only_filename_ret));
|
||||
if (ret_get == SD_SUCCESS) {
|
||||
fetched++;
|
||||
chnl_usr->m_LastPosRespTime = sGetMsTime();
|
||||
printf("[PQDIF][RECALL] fetch success mp_id=%s interval=%lld remote=%s local=%s/%s\n",
|
||||
LD_info->mp_id, (long long)interval_start, remote_filename, PQDIF_LOCAL_DIR, only_filename_ret);
|
||||
}
|
||||
else {
|
||||
failed++;
|
||||
echo_warn3("[PQDIF][RECALL] fetch failed mp_id=%s remote=%s IP=%s\n",
|
||||
LD_info->mp_id, remote_filename, chnl_usr->ip_str);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found_this_interval) {
|
||||
missing++;
|
||||
printf("[PQDIF][RECALL] no matched file mp_id=%s interval=%lld dev_type=%s\n",
|
||||
LD_info->mp_id, (long long)interval_start, ied_usr->dev_type);
|
||||
}
|
||||
|
||||
interval_start += interval_step;
|
||||
}
|
||||
|
||||
printf("[PQDIF][RECALL] finish mp_id=%s fetched=%d existed=%d missing=%d failed=%d\n",
|
||||
LD_info->mp_id, fetched, existed, missing, failed);
|
||||
|
||||
if (missing > 0 || failed > 0)
|
||||
return APR_EGENERAL;
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int pt61850_write_cn_file(chnl_usr_t *chnl_usr, ied_t *ied, char *rem_filename, char *only_filename_ret)
|
||||
{
|
||||
@@ -2338,7 +2531,7 @@ static apr_status_t ChannelCheckPQDIFFiles(chnl_usr_t *chnl_usr)
|
||||
* 这里保持同样的匹配方式,不依赖厂家前缀,也兼容普通设备用
|
||||
* 周期开始时间命名、振兴类设备用周期结束时间命名的差异。
|
||||
*/
|
||||
if (!pqdif_match_recent_interval(base_name, LD_info->cpuno))
|
||||
if (!pqdif_match_recent_interval(base_name, LD_info->cpuno, ied_usr->dev_type))
|
||||
continue;
|
||||
|
||||
matched++;
|
||||
|
||||
Reference in New Issue
Block a user