/*
 * @Author: zchuo zhengchen.huo@lnxall.com
 * @Date: 2024-12-05 11:17:42
 * @LastEditors: ybzhou yibo.zhou@lnxall.com
 * @LastEditTime: 2026-03-28 15:06:39
 * @FilePath: /proto_forward/src/ems/micro_dev_model.c
 * @Description: 微网设备模型的所有方法以及微网一些非业务相关的轮子存于此
 * 
 * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. 
 */
#include "define.h"
#include "log_module.h"
#include "log_upper_data.h"
#include "microgridtopology.h"
#include "collector-api.h"
#include "deviceLayer.h" 
#include "emsctrlProc.h"
#include "discover.h"
#include "./jsonct.h"
#include "deviceLayer.h"
#include "mqtt_emms2.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <sys/param.h>
#include <sys/syslog.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "../business_log/business_log.h"

#define TEST_CASE 0

/*本文件内附函数分类目录:
1.算法
2.其他
3.功能测验
4.回调函数
5.遍历接口
6.对上统一设备控制接口
7.状态机相关
8.设备注册
*/

pthread_rwlock_t dev_log_rwlock;    // 微网设备模型数据读写锁
pthread_mutex_t variable_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t variable_cond = PTHREAD_COND_INITIALIZER;
struct UD_log *micro_log;

microgrid_exception_t g_microgrid_exception = {0};

/**
 * @brief 设置PCS异常上下文信息，记录异常发生前的正常状态及异常码
 * @param normal_state 异常发生前的正常状态
 * @param action 异常处理动作
 * @param type 异常类型
 * @param flag 异常方向标志
 */
void microgrid_set_exception_ctx(RELEVANCE_STATE normal_state, int action, int type, int flag)
{
    g_microgrid_exception.last_normal_state = normal_state;
    g_microgrid_exception.exception_action = action;
    switch (type)
    {
    case EXCEPT_TYPE_RESOLVE:
        g_microgrid_exception.exception_code = PCS_ERR_RESOLVE_FAILED;
        break;
    case EXCEPT_TYPE_ONOFF:
        g_microgrid_exception.exception_code = flag ? PCS_ERR_ON_FAILED : PCS_ERR_OFF_FAILED;
        break;
    case EXCEPT_TYPE_CONNECT:
        g_microgrid_exception.exception_code = flag ? PCS_ERR_CONNECT_FAILED : PCS_ERR_DISCONN_FAILED;
        break;
    case EXCEPT_TYPE_ICB_ONOFF:
        g_microgrid_exception.exception_code = flag ? ICB_ERR_ON_FAILED : ICB_ERR_OFF_FAILED;
        break;
    default:
        g_microgrid_exception.exception_code = PCS_ERR_RESOLVE_FAILED;
        break;
    }
}

const char state_string_enum_info[7][100] = 
{
    "待机",
    "市电并网",
    "离网",
    "柴发并网",
    "初始",
    "异常状态",
    "默认状态"
};


int state_machine_Init();
int microgrid_ac_init_check();
int mppt_power_reset(cabinet_inside_t *cab);
int mppt_power_check_power(cabinet_inside_t *cab);
int traverse_dev_cfg_callback(cabinet_inside_t *cab);
int traverse_cab_scale_flush_callback(cabinet_inside_t *cab);
int decision_data_flush();
int traverse_pcs_callback_set_connect(struct _pcs_t *pcs, const char *tag, void* val);
// 尽量少用全局变量 缓冲区数据生命周期与控制器进程共生死 不再设计释放情况 如若被恶意变动 本程序无法负责
bool TOU_userdef_mode();

extern const char * fast_stop_system_state_tab[];
extern const char * fast_stop_system_state_tab_not[];
// 各项参数
dev_info_all_t dev_info_all;
microgrid_ctrl_t microgrid_ctrl;
microgrid_cfg_t microgrid_cfg = {.en_dg_meter = 0};
microgrid_data_t microgrid_data;
microgrid_abnormal_t microgrid_abnormal;

// "LC"使能主从一体，主柜上叫LC，然后从机1...
// static const char *cabinet_des[] = {"LC", "LC1", "LC2", "LC3", "LC4", "LC5", "LC6", "LC7", "LC8", "LC9", "LC10", "LC11", "LC12", "LC13", "LC14", "LC15"};

dev_info_all_t *get_dev_info_all_var(void)
{
    return &dev_info_all;
}
microgrid_ctrl_t *get_microgrid_ctrl_var(void)
{
    return &microgrid_ctrl;
}
microgrid_cfg_t *get_microgrid_cfg_var(void)
{
    return &microgrid_cfg;
}
microgrid_data_t *get_microgrid_data_var(void)
{
    return &microgrid_data;
}

microgrid_abnormal_t *get_microgrid_abnormal_var(void)
{
    return &microgrid_abnormal;
}

void SocrearlyWarning(void){
    if(microgrid_data.SOC_average < microgrid_ctrl.SocAlarmThreshold){
        dev_set_dev_tag_int(DEV_NO_EMS, SOC_ALARM_CTRL, 1);
    }else
        dev_set_dev_tag_int(DEV_NO_EMS, SOC_ALARM_CTRL, 0); 
}

int collector_read_one_int_data_del_log(const char *nod, int *resp_val) // 从cache读数据
{
    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    tag_value tag_val = {0};
    memset(&tag_val, 0, sizeof(tag_value));
    int ret = read_data_form_tag_by_name(var->device_layer_ptr, (char *)nod, TYPE_TAG_INT, &tag_val);
    if (ret == 0)
    {
        *resp_val = tag_val.value.to_int;
    }
    else
    {
    }
    return ret;
}

int collector_read_one_float_data_del_log(const char *nod, double *resp_val) // 从cache读数据
{
    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    tag_value tag_val = {0};
    memset(&tag_val, 0, sizeof(tag_value));
    int ret = read_data_form_tag_by_name(var->device_layer_ptr, (char *)nod, TYPE_TAG_FLOAT, &tag_val);
    *resp_val = tag_val.value.to_float;
    return ret;
}

/* 返回值:  */
/**
 * @description: 汇聚所有同名(no)设备的数据 value存储数据 返回值提示value数据类型
 * @param {char} *dev: 设备sn
 * @param {char} *tag: tagname
 * @param {void} *value: 足量空间 存储 double/int类型的数据值
 * @return {int}  1:double类型 0:int类型 -1:查找失败
 */
int value_Concentration(const char *dev, const char *tag, void *value)
{
    int value_int = 0, value_int_all = 0;
    double value_double = 0, value_double_all = 0;
    int type_flag_int = 0, type_flag_double = 0;
    char nod[TAG_NAME_LEN] = {0};

    proto_forward_t *var = get_pcs_ctrl_var()->device_layer_ptr;

    //memset(nod,0,NODE_SIZE);
    
    for (int i = 0; i < 20; i++) 
    {
        if(0 == i)
        {
            snprintf(nod,TAG_NAME_LEN,"%s.%s",dev, tag);
        }
        else 
        {
            snprintf(nod,TAG_NAME_LEN,"%s%d.%s",dev, i, tag);
        }

        tag_t *tag_finded = NULL;
        // if((name == NULL||(tag_val == NULL)||(var == NULL))) return -3;
        if (hash_intptr_findptr(var->tag_map_hash, nod, strlen(nod), (void **)&tag_finded) < 0)
        {
            break;
        }

        if(0 == collector_read_one_int_data_del_log(nod, &value_int))
        {
            value_int_all += value_int;
            type_flag_int = 1;
        }
        else if(0 == collector_read_one_float_data_del_log(nod, &value_double)){
            value_double_all += value_double;
            type_flag_double = 1;
        }
        else {
            // 没找到 结束循环
            break;
        }
    }

    if(type_flag_double)
    {
        double *value_tmp = value;
        *value_tmp = value_double_all + (double)value_int_all;
        return 1;
    }
    else if(type_flag_int)
    {
        int *value_tmp = value;
        *value_tmp = (int)value_double_all + value_int_all;
        return 0;
    }


    return -1;
}

int get_all_bms_power(cabinet_inside_t *cab, void *value)
{
    for (int i = 0; i < cab->bms.num; i++) 
    {
        struct bms_data_t *data = &cab->bms.bms_param[i].info.bms_data;
        *(double *)value += data->Cur * data->Vol;
    }

    return 0;
}

/*屏控需要监控的数据点位*/
char *screen_control_data_name[] = {
    PCU_P, "CHANGE", "PCU_P"        //充电桩待定
};

/**
 * @description: 屏控主页数据刷新线程
 * @param {void} *arg
 * @return {*}
 */
void *flush_screen_control_data(void *arg)
{
    int cnt =  sizeof(screen_control_data_name) / sizeof(screen_control_data_name[0]);
    int ret = 0;
    char buf[20] = "";
    double value_double = 0, value_int = 0;
    while(1)
    {        
        sleep(1);
        for (int i = 0; i < cnt; i+=3 ) {
            value_double = 0, value_int = 0;
            ret = value_Concentration(screen_control_data_name[i + 1], screen_control_data_name[i + 2], (void*)buf);
            if(1 == ret)
            {
                value_double = *(double *)buf;
                dev_set_dev_tag_float(DEV_NO_EMS, screen_control_data_name[i], value_double);
            }
            else if(0 == ret)
            {
                value_int = *(int *)buf;
                dev_set_dev_tag_int(DEV_NO_EMS, screen_control_data_name[i], value_int);
            }
            else {
                ems_syslog(LOG_INFO, "error no find the tag");
            }    

        }
        
        dev_set_dev_tag_float(DEV_NO_EMS, BMS_SOC, microgrid_data.SOC_average);
        dev_set_dev_tag_float(DEV_NO_EMS, GRID_P, microgrid_data.grid_power);
        dev_set_dev_tag_float(DEV_NO_EMS, GRID_Q, microgrid_data.grid_repower);

        dev_set_dev_tag_float(DEV_NO_EMS, PCS_P, microgrid_data.pcs_power);
        dev_set_dev_tag_float(DEV_NO_EMS, PCS_Q, microgrid_data.pcs_repower);

        if(microgrid_cfg.mode_microgrid == 1)
        {
            dev_set_dev_tag_float(DEV_NO_EMS, MPPT_P, microgrid_data.mppt_power);
        }
        else if(microgrid_cfg.mode_microgrid == 2)
        {
            dev_set_dev_tag_float(DEV_NO_EMS, PV_P, microgrid_data.pv_power);
            dev_set_dev_tag_float(DEV_NO_EMS, PV_Q, microgrid_data.pv_repower);
        }
        


        value_double = 0, value_int = 0;

        ret = value_Concentration("BMS", "RackCurrent", (void*)buf);    // BMS特殊处理
        if(1 == ret)
        {
            value_double = *(double *)buf;
        }
        else if(0 == ret)
        {
            value_double = *(int *)buf;
        }
        else {
            
        }
        double bms_power = 0;
        traverse_cab_dev_func_arg(get_all_bms_power, &bms_power);
        dev_set_dev_tag_float(DEV_NO_EMS, BMS_P, bms_power / 1000);
    }
    return NULL;
}

void *microgrid_ac_init_check_loop(void *arg)
{
    while(1)
    {  
        usleep(400 * 1000);
        int micro_check = dev_get_dev_tag_int(DEV_NO_EMS, MICRO_CHECK);
        
        if (micro_check == 1)
        {
            microgrid_ac_init_check();
            dev_set_dev_tag_int(DEV_NO_EMS, MICRO_CHECK, 0);
            usleep(1000 * 1000);
        }
    }
}

typedef int (*dev_to_type_callback)(device_t *dev, ...);

int get_dev_num(device_t *dev, int *num)
{
    num++;
    return 0;
}

int get_dev_list(device_t *dev, device_t **dev_list)
{
    return 0;
}

int get_dev_no(device_t *dev, char **buf, int *size)
{
    buf[*size] = dev->no;
    if(10 == *size)
    {
        return -1;
    }
    size++;

    return 0;
}


/**
 * @description: 刷新ems_plan当前策略
 * @return {*}
 */
int get_now_plan_power()
{
    static char str_all[NUM_TOU_SEG_MAX][5][12];
    static int en = 1;
    if(en)      // 性能优化 由于该函数位于 Relevant_data_refresh 需优化性能
    {
        en = 0;
        for (int i = 0; i < get_tou_max_num(); i++) {
            snprintf(str_all[i][0],10,"S%dStHour",i + 1);
            snprintf(str_all[i][1],10,"S%dStMin",i + 1);
            snprintf(str_all[i][2],10,"S%dEnHour",i + 1);
            snprintf(str_all[i][3],10,"S%dEnMin",i + 1);
            snprintf(str_all[i][4],10,"S%dPower", i + 1);
            }
    }

    time_t rawtime; 
    time(&rawtime); 
    struct tm target_time = {};  
    localtime_r(&rawtime, &target_time);
    struct tm *timeinfo = &target_time;
    int current_hour = timeinfo->tm_hour; 
    int current_min = timeinfo->tm_min;
    int tmp_Sthour = 0, tmp_Stmin = 0, tmp_Enhour = 0, tmp_Enmin = 0;
    for (int i = 0; i < get_tou_max_num(); i++) {
        tmp_Sthour = dev_get_dev_tag_int(DEV_NO_EMS,str_all[i][0]);
        tmp_Stmin = dev_get_dev_tag_int(DEV_NO_EMS,str_all[i][1]);
        tmp_Enhour = dev_get_dev_tag_int(DEV_NO_EMS,str_all[i][2]);
        tmp_Enmin = dev_get_dev_tag_int(DEV_NO_EMS,str_all[i][3]);

        if(((current_hour == tmp_Sthour && current_min >= tmp_Stmin) || (current_hour > tmp_Sthour ))\
              && ((current_hour == tmp_Enhour && current_min <= tmp_Enmin) || (current_hour < tmp_Enhour)))
        {
            return dev_get_dev_tag_int(DEV_NO_EMS,str_all[i][4]);
        

        }
    
    }

    return 0;
}



/**
 * @description: 针对每一个 "柜" 模型设置PCS功率 后续可优化增加PCS比重设置
                 因针对每个柜的环境不同 下发时间 支持独立设定
 * @param {char} *dev: PCS 设备no
 * @param {double} power_exp: PCS期望设置功率   上次下发功率与本次下发功率相同 将不予调用下发接口直接退出函数(有另外机制支持同功率情况依旧能下发功率)
 * @param {int} adjust_time: 期望设置时间间隔 未超过这段时间将不设置功率直接跳出
 * @param {int} overtime: 超时设置时间间隔  超过这段时间从未设置功率 将根据上次设置功率 再次下发一次
 * @return {*} 0:成功 1:阻止下发 2:上次与本次下发一致]] 
 */
static int set_power_mppt_dev(const char *dev, double power_exp, double last_power, time_t last_time, int adjust_time, int overtime)
{

    time_t now_time = time(NULL );
    
    /*机制说明: 上一次功率下发与此次相同的话 函数跳出 即使不同 未超过轮询时间adjust_time 也不下发
    若 数值一直相同 但 超时 overtime 
    */

    
    if(((now_time - last_time) < adjust_time) || ((last_power == power_exp) && ((now_time - last_time) < overtime)))
    {
        if(last_power == power_exp)
        {
            return 2;
        }
        return 1;
    }

    last_power = power_exp; 
    last_time = time(NULL);

    /**///ems_syslog(LOG_ERR,"连续log标志:微网设置PCS功率%lf", power_exp);
    UD_log_sprintf(micro_log, "\n设备<%s>下发功率:%lf\n", dev, power_exp);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0009, dev, "[直流耦合]: 设备<%s>下发功率:%lf", dev, power_exp);
    pe_set_power(dev, power_exp);     // 功率下发走适配器不用点位映射
    // set_lc_power(power_exp);

    /**////**///ems_syslog(LOG_ERR,"PCS写入值 = %.4lf", (double)power_int / 100);

    return 0;
}

static int set_power_pcs_dev(const char *dev, double power_exp, double last_power, time_t last_time, int adjust_time, int overtime)
{

    time_t now_time = time(NULL );
    
    /*机制说明: 上一次功率下发与此次相同的话 函数跳出 即使不同 未超过轮询时间adjust_time 也不下发
    若 数值一直相同 但 超时 overtime 
    */

    
    if(((now_time - last_time) < adjust_time) || ((last_power == power_exp) && ((now_time - last_time) < overtime)))
    {
        if(last_power == power_exp)
        {
            return 2;
        }
        return 1;
    }

    last_power = power_exp; 
    last_time = time(NULL);

    /**///ems_syslog(LOG_ERR,"连续log标志:微网设置PCS功率%lf", power_exp);
    UD_log_sprintf(micro_log, "\n设备<%s>下发功率:%lf\n", dev, power_exp);

    if (microgrid_ctrl.EnPhaseCtrl == 0){
        pe_set_power(dev, power_exp);     // 功率下发走适配器不用点位映射
        // set_lc_power(power_exp);
    }
    else{
        double phase_power[PHASE_MAX];   // PCS相功率设置

        if (power_exp > 0){ 
            ems_syslog(LOG_NOTICE, "放电，三相均衡，exp_aphase %lf, exp_bphase %lf, exp_cphase %lf", microgrid_ctrl.pcs_exp_phasepower[PHASE_A], microgrid_ctrl.pcs_exp_phasepower[PHASE_B], microgrid_ctrl.pcs_exp_phasepower[PHASE_C]);
            double total_phase_power = microgrid_ctrl.pcs_exp_phasepower[PHASE_A] + microgrid_ctrl.pcs_exp_phasepower[PHASE_B] + microgrid_ctrl.pcs_exp_phasepower[PHASE_C];
            if (total_phase_power == 0){
                for (int i = 0; i < PHASE_MAX; i++){
                    phase_power[i] = 0;
                }
            }
            else{
                for (int i = 0; i < PHASE_MAX; i++){
                    phase_power[i] = power_exp * microgrid_ctrl.pcs_exp_phasepower[i] / total_phase_power;
                }        
            }
        }
        else{ // <0 充电 / =0静置，不考虑三相均衡，直接取均值
            ems_syslog(LOG_NOTICE, "<0 充电 / =0静置，不考虑三相均衡，直接取均值");
            for (int i = 0; i < PHASE_MAX; i++){
                phase_power[i] = power_exp / PHASE_MAX;
            }                 
        }
        ems_syslog(LOG_NOTICE, "PCS %s, aphase %lf, bphase %lf, cphase %lf", dev, phase_power[PHASE_A], phase_power[PHASE_B], phase_power[PHASE_C]);
        pe_set_value(dev, "set_power_A", phase_power[PHASE_A]);
        pe_set_value(dev, "set_power_B", phase_power[PHASE_B]);
        pe_set_value(dev, "set_power_C", phase_power[PHASE_C]);
    }

    /**////**///ems_syslog(LOG_ERR,"PCS写入值 = %.4lf", (double)power_int / 100);

    return 0;
}

static void set_mppt_onoff_by_power(struct _mppt_t *mppt, int bms_charge_enabled)
{
    time_t now = time(NULL);
    // 2 分钟内不重复操作，防止频繁切换
    if (now - mppt->info.mppt_ctrl.last_onoff_time < 120) {
        return;
    }
    mppt->info.mppt_ctrl.last_onoff_time = now;

    /*MPPT 功率设置非0且可充，且上次状态关机，则开机；否则上次状态开机，则关机*/
    if(mppt->info.mppt_ctrl.power_set != 0.0 && bms_charge_enabled == 1)
    {
        if (pe_get_onoff(mppt->no) == 0)
        {
            pe_set_onoff(mppt->no, 1);
        }
    }
    else
    {
        if (pe_get_onoff(mppt->no) == 1)
        {
            pe_set_onoff(mppt->no, 0);
        }
    }
}

static micro_error_code_msg_t code_tab[] =
{
	{_SUCCESS, "successful"},
	{BMS_ERR, "bms template cfg error"},
	{PCS_ERR, "pcs template cfg error"},
	{MPPT_ERR, "mppt template cfg error"},
	{METER_PCS_ERR, "meter_pcs template cfg error"},
	{METER_MPPT_ERR, "meter_mppt template cfg error"},
	{PV_ERR, "pv template cfg error"},
	{METER_PV_ERR, "meter_pv template cfg error"},
	{METER_GRID_ERR, "meter_grid template cfg error"},
    {METER_LOAD_ERR, "meter_load template cfg error"},
    {METER_DG_ERR, "meter_dg template cfg error"},
};

static void check_template_cfg_result(dev_serial_t code)
{
    char *err_msg = NULL;
    int i;
    for (i = 0; i < sizeof(code_tab) / sizeof(code_tab[0]); i++)
    {
        if ((int)code_tab[i].code == code)
        {
            err_msg = code_tab[i].msg;
            break;
        }
    }
    ems_syslog(LOG_ERR,"ERR: %s ", err_msg);
}



int get_all_soc_average(cabinet_inside_t *cab)
{
    microgrid_data.SOC_average += cab->cab_data.SOC_average;
    return 0;
}

 /**
  * @description: BMS 设备数据刷新 (单个柜子)
  * @param {cabinet_inside_t} cab
  * @param {_bms_t} *dev
  * @return {*} 0:正常 1:报错
  */
 int bms_flush_data(cabinet_inside_t *cab)
 {
    struct _bms_t *dev;
    char *no;
    double SOC_ceiling = 0;                     // 该柜的SOC最大值
    double SOC_average = 0;                     // 该柜的SOC平均值
    double SOC_floor = 100;                     // 该柜的SOC最小值
    double SOC_all = 0;

    double BMS_discharge_power = 0;
    double BMS_charge_power = 0;

    double cab_charge_power = 0;
    double cab_discharge_power = 0;


    double get_vol = 0, get_chargecur = 0, get_dischacur = 0;
    cab->cab_data.rackVmin = microgrid_ctrl.volmax;    // 置位以便比较
    cab->cab_data.rackVmax = microgrid_ctrl.volmin;
    cab->cab_ctrl.bms_charge_enabled = 1;
    cab->cab_ctrl.bms_discharge_enabled = 1;
    int bms_charge_num = 0;
    int bms_discharge_num = 0;
    int ret = 0;
	
    for(int i = 0; i < cab->bms.num; i++)
    {
		no = cab->bms.bms_param[i].no;
        dev = &cab->bms.bms_param[i];

        dev->info.bms_data.charging_power_max = cab->cab_ctrl.charge_max_cfg / cab->bms.num;  // 先定义每个BMS最大充放电功率均分
        dev->info.bms_data.discharging_power_max = cab->cab_ctrl.discharge_max_cfg / cab->bms.num;  

		
        ret = dev_get_function_double(no, "SOC", &dev->info.bms_data.SOC);
        SOC_all += dev->info.bms_data.SOC;

        if(SOC_ceiling < dev->info.bms_data.SOC)
        {
            SOC_ceiling = dev->info.bms_data.SOC;
        }
        
        if(SOC_floor > dev->info.bms_data.SOC)
        {
            SOC_floor = dev->info.bms_data.SOC;
        }

		dev->info.bms_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);

        ret |= dev_get_function_double(no, "get_vol", &get_vol);
        dev->info.bms_data.Vol = get_vol;

        ret |= dev_get_function_double(no, "get_cur", &dev->info.bms_data.Cur);
        ret |= dev_get_function_double(no, "get_chargecur", &get_chargecur);
        ret |= dev_get_function_double(no, "get_dischacur", &get_dischacur);

        if(ret)
        {
            ret = 0;
            ret |= dev_get_function_double(no, "get_Chargepower", &BMS_charge_power);
            ret |= dev_get_function_double(no, "get_disChapower", &BMS_discharge_power);
            if(ret)
            {
                BMS_charge_power = 0;
                BMS_discharge_power = 0;
            }
        }
        else 
        {
            BMS_charge_power = get_chargecur * get_vol / 1000;      // BMS 充电放电功率均为正
            BMS_discharge_power = get_dischacur * get_vol / 1000;
        }
        
        ret |= dev_get_function_double(no, "rackmaxv", &dev->info.bms_data.rackVmax);
        ret |= dev_get_function_double(no, "rackminv", &dev->info.bms_data.rackVmin);

                
        cab->cab_data.rackVmax = dev->info.bms_data.rackVmax > cab->cab_data.rackVmax ? dev->info.bms_data.rackVmax : cab->cab_data.rackVmax;
        cab->cab_data.rackVmin = dev->info.bms_data.rackVmin < cab->cab_data.rackVmin ? dev->info.bms_data.rackVmin : cab->cab_data.rackVmin;

        
        BMS_charge_power = -fabs(BMS_charge_power);
        BMS_discharge_power = fabs(BMS_discharge_power);

        if (BMS_charge_power < 0) {
            bms_charge_num++;
        }
        if (BMS_discharge_power > 0) {
            bms_discharge_num++;
        }

        dev->info.bms_data.charging_power_max = BMS_charge_power < dev->info.bms_data.charging_power_max ? dev->info.bms_data.charging_power_max : BMS_charge_power;
        dev->info.bms_data.discharging_power_max = BMS_discharge_power > dev->info.bms_data.discharging_power_max ? dev->info.bms_data.discharging_power_max : BMS_discharge_power;
        
        cab_charge_power += dev->info.bms_data.charging_power_max;
        cab_discharge_power += dev->info.bms_data.discharging_power_max;

    }

    if (bms_charge_num == 0)
    {
        cab->cab_ctrl.bms_charge_enabled = 0;
    }

    if (bms_discharge_num == 0)
    {
        cab->cab_ctrl.bms_discharge_enabled = 0;
    }

    SOC_average = SOC_all / cab->bms.num;
    cab->cab_data.SOC_average = SOC_average;
    cab->cab_data.SOC_ceiling = SOC_ceiling;
    cab->cab_data.SOC_floor = SOC_floor;
    
    // cab->cab_data.single_cell_alarm = 0;

    
    if ((microgrid_ctrl.EN_CELL_VOLT != 0))
    {
        int cur_vol_max = cab->cab_data.rackVmax;
        int cur_vol_min = cab->cab_data.rackVmin;
        int volmax = microgrid_ctrl.volmax;
        int volmaxerr = microgrid_ctrl.volmaxerr;
        int volmin = microgrid_ctrl.volmin;
        int volminerr = microgrid_ctrl.volminerr;
    
        if(0 == cab->cab_data.singleVmaxtime)
        {
            cab->cab_data.singleVmaxtime = time(NULL);
            cab->cab_data.singleVmintime = time(NULL);
        }

        if (cur_vol_max >= volmax && ((time(NULL) - cab->cab_data.singleVmaxtime) > microgrid_ctrl.singleV_sleep))
        {
            // dev_set_dev_tag_int(DEV_NO_EMS, SINGLE_CELL_VOL_THRESHOLD_ALARM, 1);
            cab->cab_data.single_cell_alarm |= 1;
            cab_charge_power = 0;
            cab->cab_ctrl.bms_charge_enabled = 0;
        }
        else if (cur_vol_max < (volmax - volmaxerr))
        {
            if ((cur_vol_min > (volmin + volminerr)))
            {
                // dev_set_dev_tag_int(DEV_NO_EMS, SINGLE_CELL_VOL_THRESHOLD_ALARM, 0);
                cab->cab_data.single_cell_alarm = 0;
            }
            cab->cab_data.singleVmaxtime = time(NULL);
        }
        else if (cur_vol_max < (volmax))
        {
            cab->cab_data.singleVmaxtime = time(NULL);
        }
  
        if (cur_vol_min <= volmin && ((time(NULL) - cab->cab_data.singleVmintime) > microgrid_ctrl.singleV_sleep))
        {
            // dev_set_dev_tag_int(DEV_NO_EMS, SINGLE_CELL_VOL_THRESHOLD_ALARM, 1);
            cab->cab_data.single_cell_alarm |= 1;
            cab_discharge_power = 0;
            cab->cab_ctrl.bms_discharge_enabled = 0;

        }
        else if (cur_vol_min > (volmin + volminerr))
        {
            if ((cur_vol_max < (volmax - volmaxerr)))
            {
                // dev_set_dev_tag_int(DEV_NO_EMS, SINGLE_CELL_VOL_THRESHOLD_ALARM, 0);
                cab->cab_data.single_cell_alarm = 0;
            }
            cab->cab_data.singleVmintime = time(NULL);
        }
        else if (cur_vol_min > (volmin))
        {
            cab->cab_data.singleVmintime = time(NULL);
        }
    }
    else
    {
        // dev_set_dev_tag_int(DEV_NO_EMS, SINGLE_CELL_VOL_THRESHOLD_ALARM, 0);
        cab->cab_data.single_cell_alarm = 0;
    }

    microgrid_ctrl.Single_Cell_Vol_Threshold_Alarm |= cab->cab_data.single_cell_alarm;


    cab->cab_ctrl.pcs_charge_max_actual = cab_charge_power;
    cab->cab_ctrl.pcs_discharge_max_actual = cab_discharge_power;

    cab->cab_ctrl.pcs_charge_max_actual = cab->cab_ctrl.pcs_charge_max_actual < cab->cab_ctrl.pcs_charge_max_set ? cab->cab_ctrl.pcs_charge_max_set : cab->cab_ctrl.pcs_charge_max_actual;  // 相对系统最大充电二者取最小
    cab->cab_ctrl.pcs_discharge_max_actual = cab->cab_ctrl.pcs_discharge_max_actual > cab->cab_ctrl.pcs_discharge_max_set ? cab->cab_ctrl.pcs_discharge_max_set : cab->cab_ctrl.pcs_discharge_max_actual;// 相对系统最大放电二者取最小
    
    if (microgrid_ctrl.choose_func == STRATAGY_TYPE_TOU) //tou下分时段限制电池充放电功率
    {
        int power_tmp = microgrid_ctrl.current_tou_info?microgrid_ctrl.current_tou_info->Power:0;
        if (power_tmp<0)
        {
            power_tmp = 0;
            ems_syslog(LOG_WARNING, "TOU power must >= 0 current value is %d ,will use 0!", microgrid_ctrl.current_tou_info->Power);

        }
        
        cab->cab_ctrl.pcs_charge_max_actual = cab->cab_ctrl.pcs_charge_max_actual < -power_tmp ? -power_tmp : cab->cab_ctrl.pcs_charge_max_actual;  
        cab->cab_ctrl.pcs_discharge_max_actual = cab->cab_ctrl.pcs_discharge_max_actual > power_tmp ? power_tmp : cab->cab_ctrl.pcs_discharge_max_actual;
    }
    
    if(ret)
    {
        return BMS_ERR;
    }
    return 0;
 }                                                                                                      

 /**
  * @description: PCS 设备数据刷新 (单个柜子)
  * @param {cabinet_inside_t} cab
  * @return {*} 0:正常 1:报错
  */
 int pcs_flush_data(cabinet_inside_t *cab)
 {
    struct _pcs_t *dev;
    char *no;
    double power = 0, repower = 0;
    double PhasePower[PHASE_MAX] = {0};
    int all_pcs_off_line = 1;
    int all_pcs_statu_err = 1;
    for(int i = 0; i < cab->pcs.num; i++)
    {
        int ret = 0;
        no = cab->pcs.pcs_param[i].no;
        dev = &(cab->pcs.pcs_param[i]);

		dev->info.pcs_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);

        // ret = dev_get_function_double(no, "get_power", );
        ret |= pe_get_power(no, &dev->info.pcs_data.out_power);
        ret |= pe_get_repower(no, &dev->info.pcs_data.out_repower);
        // ret = dev_get_function_double(no, "get_repower", &dev->info.pcs_data.out_repower);
        if(microgrid_ctrl.EnPhaseCtrl != 0)
        {
            ret |= dev_get_function_double(no, "get_power_A", &dev->info.pcs_data.AphaseActivePower);
            ret |= dev_get_function_double(no, "get_power_B", &dev->info.pcs_data.BphaseActivePower);
            ret |= dev_get_function_double(no, "get_power_C", &dev->info.pcs_data.CphaseActivePower);
        }
        //TODO: 最好是用适配器获取功率确保接口稳定
        if(ret)
        {
            dev->info.pcs_data.out_power = 0;
        }

        dev->info.pcs_data.statu = pe_get_onoff(no);

        if (dev->info.pcs_data.on_line)
        {
            all_pcs_off_line = 0;
        }

        if(dev->info.pcs_data.statu < 0)
        {
            ret |= dev->info.pcs_data.statu;
        }
        else
        {
            all_pcs_statu_err = 0;
        }
        
        dev->info.pcs_data.PF_network = pe_get_connect(no);
        
        if(dev->info.pcs_data.PF_network < 0)
        {
            ret |= dev->info.pcs_data.PF_network;
            cab->cab_ctrl.bms_charge_enabled = 0;
            cab->cab_ctrl.bms_discharge_enabled = 0;
            return PCS_ERR;
        }

        power += dev->info.pcs_data.out_power;
        repower += dev->info.pcs_data.out_repower;

    }

    for(int i = 0; i < PHASE_MAX; i++){
        cab->cab_data.PhasePower[i] = PhasePower[i];
    }
    if (all_pcs_off_line || all_pcs_statu_err)
    {
        cab->cab_ctrl.bms_charge_enabled = 0;
        cab->cab_ctrl.bms_discharge_enabled = 0;
    }
    cab->cab_data.pcs_output_power = power;
    cab->cab_data.pcs_output_repower = repower;
    cab->cab_ctrl.pcs_discharge_max_actual = microgrid_ctrl.dischargeMaxPower * cab->cab_cfg.scale;
    cab->cab_ctrl.pcs_charge_max_actual = microgrid_ctrl.chargeMaxPower * cab->cab_cfg.scale;
    cab->cab_ctrl.pcs_discharge_max_set = cab->cab_ctrl.pcs_discharge_max_actual;
    cab->cab_ctrl.pcs_charge_max_set = cab->cab_ctrl.pcs_charge_max_actual;
    microgrid_ctrl.pcs_exp_power_actual += cab->cab_ctrl.pcs_exp_power;

    return 0;
 }

 int get_all_en_power(cabinet_inside_t *cab)
 {
    // if(cab->cab_data.en)
    {
        microgrid_ctrl.discharge_max_set += cab->cab_ctrl.pcs_discharge_max_actual;
        microgrid_ctrl.charge_max_set += cab->cab_ctrl.pcs_charge_max_actual;
    }
    return 0;
 }


 /**
  * @description: meter_pcs 设备数据刷新 (单个柜子)
  * @param {cabinet_inside_t} cab
  * @return {*} 0:正常 1:报错
  */
 int meter_pcs_flush_data(cabinet_inside_t *cab)
 {
    struct _meter_pcs_t *dev;
    char *no;

    int ret = 0;
    for(int i = 0; i < cab->meter_pcs.num; i++)
    {
        no = cab->meter_pcs.meter_pcs_param[i].no;
        dev = &(cab->meter_pcs.meter_pcs_param[i]);
        
		dev->info.meter_pcs_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);

        ret |= dev_get_function_double(no, "get_power", &dev->info.meter_pcs_data.power);
        ret |= dev_get_function_double(no, "get_A_busvol", &dev->info.meter_pcs_data.AphaseVoltage);
        ret |= dev_get_function_double(no, "get_B_busvol", &dev->info.meter_pcs_data.BphaseVoltage);
        ret |= dev_get_function_double(no, "get_C_busvol", &dev->info.meter_pcs_data.CphaseVoltage);  
        if(microgrid_ctrl.EnPhaseCtrl != 0)
        {
            ret |= dev_get_function_double(no, "get_power_A", &dev->info.meter_pcs_data.AphaseActivePower);
            ret |= dev_get_function_double(no, "get_power_B", &dev->info.meter_pcs_data.BphaseActivePower);
            ret |= dev_get_function_double(no, "get_power_C", &dev->info.meter_pcs_data.CphaseActivePower);
        }
    }

    if(ret)
    {
        return METER_PCS_ERR;
    }    
    return _SUCCESS;
 }

int get_phase_power_dc(cabinet_inside_t *cab)
{
    if(cab->meter_pcs.num)
    {
        microgrid_data.PhasePower[PHASE_A] += cab->meter_pcs.meter_pcs_param[0].info.meter_pcs_data.AphaseActivePower;
        microgrid_data.PhasePower[PHASE_B] += cab->meter_pcs.meter_pcs_param[0].info.meter_pcs_data.BphaseActivePower;
        microgrid_data.PhasePower[PHASE_C] += cab->meter_pcs.meter_pcs_param[0].info.meter_pcs_data.CphaseActivePower;
    }
    else if(cab->pcs.num)
    {
        microgrid_data.PhasePower[PHASE_A] += cab->pcs.pcs_param[0].info.pcs_data.AphaseActivePower;
        microgrid_data.PhasePower[PHASE_B] += cab->pcs.pcs_param[0].info.pcs_data.BphaseActivePower;
        microgrid_data.PhasePower[PHASE_C] += cab->pcs.pcs_param[0].info.pcs_data.CphaseActivePower;
    }

    return 0;
}

int get_phase_power_ac(cabinet_inside_t *cab)
{
    microgrid_data.PhasePower[PHASE_A] += cab->cab_data.PhasePowerA;
    microgrid_data.PhasePower[PHASE_B] += cab->cab_data.PhasePowerB;
    microgrid_data.PhasePower[PHASE_C] += cab->cab_data.PhasePowerC;
    return 0;
}

int lc_flush_data(cabinet_inside_t *cab)
{
    cab->cab_data.on_line  = dev_get_dev_tag_int(cab->no, STATE_ONLINE);
    cab->cab_data.onoff   = dev_get_dev_tag_int(cab->no, ON_OFF_STATUS);
    cab->cab_data.connect = dev_get_dev_tag_int(cab->no, CONNECT_STATUS);
    cab->cab_data.pcs_output_power   = dev_get_dev_tag_float(cab->no, ACTIVE_POWER);
    cab->cab_data.pcs_output_repower = 0;//dev_get_dev_tag_float(cab->no, GET_REACTPOWER);
    cab->cab_data.SOC_average        = dev_get_dev_tag_float(cab->no, CURRENT_SOC); //平均SOC，当前认为单柜单BMS
    cab->cab_data.en                 = dev_get_dev_tag_int(cab->no, SYSTEM_STATUS);
    cab->cab_data.prohibited_char    = dev_get_dev_tag_int(cab->no, PROHIBITE_CHARGE);
    cab->cab_data.prohibited_dischar = dev_get_dev_tag_int(cab->no, PROHIBITE_DISCHARGE);

    cab->cab_data.PhasePowerA = dev_get_dev_tag_int(cab->no, PHASE_A_POWER);
    cab->cab_data.PhasePowerB = dev_get_dev_tag_int(cab->no, PHASE_B_POWER);
    cab->cab_data.PhasePowerC = dev_get_dev_tag_int(cab->no, PHASE_C_POWER);
    
    cab->cab_ctrl.pcs_charge_max_actual    = -fabs(dev_get_dev_tag_float(cab->no, MAX_CHARGE_POWER));
    cab->cab_ctrl.pcs_discharge_max_actual = dev_get_dev_tag_float(cab->no, MAX_DISCHA_POWER);

    cab->cab_cfg.capacity = dev_get_dev_tag_int(cab->no, LC_CAPACITY);
    microgrid_ctrl.pcs_exp_power_actual += cab->cab_ctrl.pcs_exp_power;
    if (cab->cab_cfg.capacity == 0) cab->cab_cfg.capacity = 100;
	return _SUCCESS;
}

static int flush_cabinet_online(void) {
    int on_line = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {   
        cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
        ems_syslog(LOG_NOTICE, "LC[%d] no: %s: on_line: %d", i, cabinets->no, cabinets->cab_data.on_line);
        if (cabinets->cab_data.on_line == 1) {
            on_line = 1;
            break;
        }    
    }
    if (dev_info_all.cabinet_info.num == 0 || on_line == 0) return 0;
    return 1;
}

static int flush_cabinet_onoff(int onoff) { // 关注： 0:关机 1:开机
    int on_line = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {   
        cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
        ems_syslog(LOG_NOTICE, "LC[%d] no: %s: on_line: %d statu: %d", i, cabinets->no, cabinets->cab_data.on_line, cabinets->cab_data.connect);
        if (cabinets->cab_data.on_line == 1) {on_line = 1;}
        if (onoff){
            if (cabinets->cab_data.en == 0 && cabinets->cab_data.onoff == 1) {  //一个为开就是开
                return 1; // 未知状态
            }  
        }
        else{
            if (cabinets->cab_data.en == 0 && cabinets->cab_data.onoff == 1) {
                return 0; 
            }  
        }      
    }
    if (dev_info_all.cabinet_info.num == 0 || on_line == 0) return 0;
    return 1;
}

static int flush_cabinet_grid_offgrid(int grid_offgrid) { // 关注： 0:离网 1:并网
    int on_line = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {   
        cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
        ems_syslog(LOG_NOTICE, "LC[%d] no: %s: on_line: %d connect: %d", i, cabinets->no, cabinets->cab_data.on_line, cabinets->cab_data.connect);
        if (cabinets->cab_data.on_line == 1) {on_line = 1;}
        if (grid_offgrid){
            if (cabinets->cab_data.en == 0 && cabinets->cab_data.connect == 0) {
                return 0; // 未知状态
            }  
        }
        else{
            if (cabinets->cab_data.en == 0 && cabinets->cab_data.connect == 1) {
                return 0; 
            }  
        }      
    }
    if (dev_info_all.cabinet_info.num == 0 || on_line == 0) return 0;
    return 1;
}

static int flush_pv_onoff(int onoff) { // 关注： 0:关机 1:开机
    int on_line = 0;
    for(int i = 0; i < dev_info_all.pv.num; i++)
    {   
        struct _pv_t *_pv = &dev_info_all.pv.pv_param[i];
        ems_syslog(LOG_NOTICE, "_pv[%d] no: %s: on_line: %d statu: %d", i, _pv->no, _pv->info.pv_data.on_line, _pv->info.pv_data.statu);
        if (_pv->info.pv_data.on_line == 1) {on_line = 1;}
        if (onoff){
            if (_pv->info.pv_data.on_line == 1 && _pv->info.pv_data.statu == 1) {   //一个为开就是开
                return 1; // 未知状态
            }  
        }
        else{
            if (_pv->info.pv_data.on_line == 1 && _pv->info.pv_data.statu == 1) {
                return 0; 
            }  
        }      
    }
    if (dev_info_all.pv.num == 0 || on_line == 0) return 0;
    return 1;
}


int dev_get_function_double_print(const char* dev_id, const char* function,double* value)
{

    if  (dev_get_function_double(dev_id, function,value) == -1)
    {
        ems_syslog(LOG_CRIT, "[微网] 点位异常:获取%s失败",dev_id);
    }
    else if (dev_get_function_double(dev_id, function,value) == -2)
    {
        ems_syslog(LOG_CRIT, "[微网] 点位异常:%s获取%s失败",dev_id,function);
    }
    else
    {
        ems_syslog(LOG_CRIT, "[微网] 点位正常:%s获取%s成功",dev_id,function);
    }
    return 0;
}
int dev_get_function_int_print(const char* dev_id, const char* function,int* value)
{
 
    if  (dev_get_function_int(dev_id, function,value) == -1)
    {
        ems_syslog(LOG_CRIT, "[微网] 点位异常:获取%s失败",dev_id);
    }
    else if (dev_get_function_int(dev_id, function,value) == -2)
    {
        ems_syslog(LOG_CRIT, "[微网] 点位异常:%s获取%s失败",dev_id,function);
    }
    else
    {
        ems_syslog(LOG_CRIT, "[微网] 点位正常:%s获取%s成功",dev_id,function);
    }
    return 0;

}
 /**
  * @description: 对微网初步检查，主要涉及到配置文件问题，仅用于提示错误信息
  * @param {cabinet_inside_t} cab
  * @return {*} 0:正常 1:报错
  */
 int microgrid_ac_init_check()
 {
    //1，检查微网模式
    {
        ems_syslog(LOG_CRIT, "[微网] ----------------------------------------------------------");
        if (microgrid_cfg.mode_microgrid == MODE_MICROGRID_DC){
            if (cabinet_info.ctrl_mode == EMS_MODE_DD)
            {
                ems_syslog(LOG_CRIT, "[微网] 模式正常:直流对等模式");
                BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 模式正常:直流对等模式");
            }else{
                ems_syslog(LOG_CRIT, "[微网] 模式异常:直流侧请切换为对等模式");
                BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 模式异常:直流侧请切换为对等模式");
            }
        }
        else if (microgrid_cfg.mode_microgrid == MODE_MICROGRID_AC){
            if (cabinet_info.ctrl_mode == EMS_MODE_ZC)
            {
                ems_syslog(LOG_CRIT, "[微网] 模式正常:交流主从模式");
                BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 模式正常:交流主从模式");
            }else{
                ems_syslog(LOG_CRIT, "[微网] 模式异常:交流侧请切换为主从模式");
                BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 模式异常:交流侧请切换为主从模式");
            }
        }
    }
    
    //2，检查从机状态
    {
        int on_line = 1;
        for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
        {   
            cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
            ems_syslog(LOG_NOTICE, "LC[%d] no: %s: on_line: %d", i, cabinets->no, cabinets->cab_data.on_line);
            if (cabinets->cab_data.on_line == 1) {
                
            }else{
                ems_syslog(LOG_CRIT, "[微网] LC异常:LC[%d]离线 no: %s",i, cabinets->no);
                on_line = 0;
            }
        }
        if (dev_info_all.cabinet_info.num != 0 && on_line != 0)
        {
            ems_syslog(LOG_CRIT, "[微网] LC正常:LC均在线");
        }
    }

    //3，检查系统状态/状态字
    {
        int SysStatus = dev_get_dev_tag_int(DEV_NO_EMS, SYSTEM_STATUS);
        int SysStatusWord = dev_get_dev_tag_int(DEV_NO_EMS, SYSTEM_STATUS_W);
        if (SysStatus == 0 && SysStatusWord == 0)
        {
            ems_syslog(LOG_CRIT, "[微网] 系统正常");
        }
        else
        {
            int fast_stop_system_state_tab_size = 15;  //fast_stop_system_state_tab大小一般是固定值的
            int fast_stop_system_state_tab_not_size = 2; //固定2
            int total_size = fast_stop_system_state_tab_size + fast_stop_system_state_tab_not_size;

            ems_syslog(LOG_CRIT, "[微网] 系统异常 异常信息:");
            int found = 0;
            for (int i = 0; i < total_size; i++)
            {
                if (i < fast_stop_system_state_tab_size)
                {
                    if ((SysStatusWord & (1ULL << i)) != 0)
                    {
                        found = 1;
                        ems_syslog(LOG_CRIT, "[微网] fast_stop_system_state_tab[%d]: %s\n", i, fast_stop_system_state_tab[i]);
                    }
                }
                else
                {
                    int idx = i - fast_stop_system_state_tab_size;
                    if ((SysStatusWord & (1ULL << i)) != 0)
                    {
                        found = 1;
                    ems_syslog(LOG_CRIT, "[微网] fast_stop_system_state_tab_not[%d]: %s (离线)\n", idx, fast_stop_system_state_tab_not[idx]);
                    }
                }
            }
            if (!found)
            {
                //...
            }
        }
    }

    //4,检查适配器
    {
        //1,检查关口表
        char *no;
        double temp_act_power = 0;  //临时存储不使用
        double temp_rea_power = 0;
        double temp_appr_power = 0;
        double temp_factor = 0;
        double temp_AphaseVoltage = 0;
        double temp_BphaseVoltage = 0;
        double temp_CphaseVoltage = 0;

        for(int i = 0; i < dev_info_all.meter_grid.num; i++)
        {
            struct _meter_grid_t *grid = &dev_info_all.meter_grid.meter_grid_param[i];
            no = grid->no;

            dev_get_function_double_print(grid->no, "get_power", &temp_act_power);
            dev_get_function_double_print(grid->no, "get_repower", &temp_rea_power);
            dev_get_function_double_print(grid->no, "get_apprpower", &temp_appr_power);
            dev_get_function_double_print(grid->no, "get_factor", &temp_factor);
            dev_get_function_double_print(grid->no, "get_A_busvol", &temp_AphaseVoltage);
            dev_get_function_double_print(grid->no, "get_B_busvol", &temp_BphaseVoltage);
            dev_get_function_double_print(grid->no, "get_C_busvol", &temp_CphaseVoltage);

        }

        //2,检查光伏
        double temp_power = 0;
        double temp_repower = 0;
        int temp_mode = 0;
        int temp_statu = 0;
        // double temp_AphaseVoltage = 0;
        // double temp_BphaseVoltage = 0;
        // double temp_CphaseVoltage = 0;
        for(int i = 0; i < dev_info_all.pv.num; i++)
        {
            struct _pv_t *pv = &dev_info_all.pv.pv_param[i];
            no = pv->no;

            dev_get_function_double_print(pv->no, "get_power", &temp_power);
            dev_get_function_double_print(pv->no, "get_repower", &temp_repower);
            dev_get_function_int_print(pv->no, "get_mode", &temp_mode);
            dev_get_function_int_print(pv->no, "get_onoff", &temp_statu);
            dev_get_function_double_print(pv->no, "get_A_busvol", &temp_AphaseVoltage);
            dev_get_function_double_print(pv->no, "get_B_busvol", &temp_BphaseVoltage);
            dev_get_function_double_print(pv->no, "get_C_busvol", &temp_CphaseVoltage);
        }

        //3，检查BMS
        double temp_SOC = 0;
        double temp_get_vol = 0;
        double temp_Cur = 0;
        double temp_get_chargecur = 0;
        double temp_get_dischacur = 0;
        
        for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
        {   
            cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
            for(int i = 0; i < cabinets->bms.num; i++)
            {
                no = cabinets->bms.bms_param[i].no;

                dev_get_function_double_print(no, "SOC", &temp_SOC);
                dev_get_function_double_print(no, "get_vol", &temp_get_vol);
                dev_get_function_double_print(no, "get_cur", &temp_Cur);
                dev_get_function_double_print(no, "get_chargecur", &temp_get_chargecur);
                dev_get_function_double_print(no, "get_dischacur", &temp_get_dischacur);
            }
        }

        //4，检查PCS
        double temp_get_power = 0;
        double temp_get_repower = 0;
        for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
        {   
            cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];

            for(int i = 0; i < cabinets->pcs.num; i++)
            {
                no = cabinets->pcs.pcs_param[i].no;

                if (pe_get_power(no, &temp_get_power) < 0)
                {
                    ems_syslog(LOG_CRIT, "[微网] 点位异常:%s获取%s失败",no,"get_power");
                }
                if (pe_get_repower(no, &temp_get_repower) < 0)
                {
                    ems_syslog(LOG_CRIT, "[微网] 点位异常:%s获取%s失败",no,"get_repower");
                }
                if (pe_get_onoff(no) < 0)
                {
                    ems_syslog(LOG_CRIT, "[微网] 点位异常:%s获取%s失败",no,"get_onoff");
                }
                if (pe_get_connect(no) < 0)
                {
                    ems_syslog(LOG_CRIT, "[微网] 点位异常:%s获取%s失败",no,"get_connect");
                }

            }
        }

        //5,...
        ems_syslog(LOG_CRIT, "[微网] ");
    }
    return 0;
 }




 /**
  * @description: mppt 设备数据刷新 (单个柜子)
  * @param {cabinet_inside_t} cab
  * @return {*} 0:正常 1:报错
  */
 int mppt_flush_data(cabinet_inside_t *cab)
 {
    struct _mppt_t *dev;
    char *no;
    double power = 0;
    cab->cab_ctrl.mppt_power_max = microgrid_ctrl.pvMax * cab->cab_cfg.scale;      //TODO: 修正功率分配逻辑 光伏功率分配可能需要独立
    for(int i = 0; i < cab->mppt.num; i++)
    {
        no = cab->mppt.mppt_param[i].no;
        dev = &(cab->mppt.mppt_param[i]);
        
		dev->info.mppt_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);
        

        if(pe_get_power(no, &dev->info.mppt_data.power))
        {
            /**///ems_syslog(LOG_ERR,"获取功率失败");
            double vol = 0, cur = 0;
            if((dev_get_function_double(no, "get_vol", &vol)) || dev_get_function_double(no, "get_cur", &cur))
            {
                return MPPT_ERR;
            }
            dev->info.mppt_data.power = fabs(vol) * fabs(cur) / 1000;
            
            if(dev->info.mppt_data.on_line)
            {
                microgrid_data.mppt_BusVol = MAX(0, vol);
                microgrid_data.mppt_BusCur += cur;
                microgrid_data.mppt_BusPow += dev->info.mppt_data.power;
                microgrid_data.mppt_OnOff |= dev->info.mppt_data.statu;
            }
            /**///ems_syslog(LOG_ERR,"dev->info.mppt_data.power = %lf", dev->info.mppt_data.power);

        }
        dev_get_function_int(no, "get_onoff", &dev->info.mppt_data.statu); //光伏mppt开关机状态读取
        // dev_get_function_int(no, "get_mode", &dev->info.mppt_data.mode);
        power += dev->info.mppt_data.power;
    }
    cab->cab_data.mppt_out_power = power;
    return _SUCCESS;
 }
 
/**
 * @description: meter_mppt 设备数据刷新 (单个柜子)
 * @param {cabinet_inside_t} cab
 * @return {*} 0:正常 1:报错
 */
int meter_mppt_flush_data(cabinet_inside_t *cab)
{
    struct _meter_mppt_t *dev;
    char *no;
    int ret = 0;
    for(int i = 0; i < cab->meter_mppt.num; i++)
    {
        no = cab->meter_mppt.meter_mppt_param[i].no;
        dev = &(cab->meter_mppt.meter_mppt_param[i]);

        dev->info.meter_mppt_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);

        ret |= pe_get_power(no, &dev->info.meter_mppt_data.power);
        ret |= dev_get_function_double(no, "get_vol", &dev->info.meter_mppt_data.Vol);
        ret |= dev_get_function_double(no, "get_cur", &dev->info.meter_mppt_data.Cur);
    }
    if(ret)
    {
        return METER_MPPT_ERR;
    } 
    return _SUCCESS;
}

 
/**
 * @description: meter_pv 设备数据刷新
 * @param {cabinet_inside_t} cab
 * @return {*} 0:正常 1:报错
 */
int pv_flush_data(void)
{
	char *no;
    int ret = 0;
    for(int i = 0; i < dev_info_all.pv.num; i++)
    {
        struct _pv_t *pv = &dev_info_all.pv.pv_param[i];
		no = pv->no;
		pv->info.pv_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);

        ret |= dev_get_function_double(pv->no, "get_power", &pv->info.pv_data.power);
        ret |= dev_get_function_double(pv->no, "get_repower", &pv->info.pv_data.repower);
        ret |= dev_get_function_int(pv->no, "get_mode", &pv->info.pv_data.mode);
        ret |= dev_get_function_int(pv->no, "get_onoff", &pv->info.pv_data.statu);
        ret |= dev_get_function_double(pv->no, "get_A_busvol", &pv->info.pv_data.AphaseVoltage);
        ret |= dev_get_function_double(pv->no, "get_B_busvol", &pv->info.pv_data.BphaseVoltage);
        ret |= dev_get_function_double(pv->no, "get_C_busvol", &pv->info.pv_data.CphaseVoltage);

        ret |= dev_get_function_double(pv->no, "get_A_buscur", &pv->info.pv_data.A_Cur);
        ret |= dev_get_function_double(pv->no, "get_B_buscur", &pv->info.pv_data.B_Cur);
        ret |= dev_get_function_double(pv->no, "get_C_buscur", &pv->info.pv_data.C_Cur);

        if(pv->info.pv_data.on_line)
        {
            microgrid_data.Aphase_V_PV = MAX(0, pv->info.pv_data.AphaseVoltage);
            microgrid_data.Bphase_V_PV = MAX(0, pv->info.pv_data.BphaseVoltage);
            microgrid_data.Cphase_V_PV = MAX(0, pv->info.pv_data.CphaseVoltage);
            microgrid_data.Aphase_C_PV += pv->info.pv_data.A_Cur;
            microgrid_data.Bphase_C_PV += pv->info.pv_data.B_Cur;
            microgrid_data.Cphase_C_PV += pv->info.pv_data.C_Cur;
        }
    }
    
    if(ret)
    {
        return PV_ERR;
    } 
    return _SUCCESS;
}

/**
 * @description: meter_pv 设备数据刷新
 * @param {cabinet_inside_t} cab
 * @return {*} 0:正常 1:报错
 */
int meter_pv_flush_data(void)
{
    char *no;
    int ret = 0;
    for(int i = 0; i < dev_info_all.meter_pv.num; i++)
    {
        struct _meter_pv_t *meter_pv = &dev_info_all.meter_pv.meter_pv_param[i];
        no = meter_pv->no;
        meter_pv->info.meter_pv_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);

        ret |= dev_get_function_double(meter_pv->no, "get_power", &meter_pv->info.meter_pv_data.power);
        ret |= dev_get_function_double(meter_pv->no, "get_repower", &meter_pv->info.meter_pv_data.repower);
        ret |= dev_get_function_double(meter_pv->no, "get_A_busvol", &meter_pv->info.meter_pv_data.AphaseVoltage);
        ret |= dev_get_function_double(meter_pv->no, "get_B_busvol", &meter_pv->info.meter_pv_data.BphaseVoltage);
        ret |= dev_get_function_double(meter_pv->no, "get_C_busvol", &meter_pv->info.meter_pv_data.CphaseVoltage);
    }
    if(ret)
    {
        return METER_PV_ERR;
    } 
    return _SUCCESS;
}

/**
 * @description: meter_grid 设备数据刷新
 * @param {cabinet_inside_t} cab
 * @return {*} 0:正常 1:报错 -1:没有关口表
 */
int meter_grid_flush_data(void)
{
    char *no;
    int ret = 0;
    for(int i = 0; i < dev_info_all.meter_grid.num; i++)
    {
        struct _meter_grid_t *grid = &dev_info_all.meter_grid.meter_grid_param[i];
        no = grid->no;
        grid->info.meter_grid_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);

        ret |= dev_get_function_double(grid->no, "get_power", &grid->info.meter_grid_data.act_power);
        ret |= dev_get_function_double(grid->no, "get_repower", &grid->info.meter_grid_data.rea_power);
        ret |= dev_get_function_double(grid->no, "get_apprpower", &grid->info.meter_grid_data.appr_power);
        ret |= dev_get_function_double(grid->no, "get_factor", &grid->info.meter_grid_data.factor);
        ret |= dev_get_function_double(grid->no, "get_A_busvol", &grid->info.meter_grid_data.AphaseVoltage);
        ret |= dev_get_function_double(grid->no, "get_B_busvol", &grid->info.meter_grid_data.BphaseVoltage);
        ret |= dev_get_function_double(grid->no, "get_C_busvol", &grid->info.meter_grid_data.CphaseVoltage);
        if(microgrid_ctrl.EnPhaseCtrl != 0)
        {
            ret |= dev_get_function_double(grid->no, "get_power_A", &grid->info.meter_grid_data.AphaseActivePower);
            ret |= dev_get_function_double(grid->no, "get_power_B", &grid->info.meter_grid_data.BphaseActivePower);
            ret |= dev_get_function_double(grid->no, "get_power_C", &grid->info.meter_grid_data.CphaseActivePower);
            //暂未用到
            // ret |= dev_get_function_double(grid->no, "get_A_busapppower", &grid->info.meter_grid_data.AphaseApparentPower);
            // ret |= dev_get_function_double(grid->no, "get_B_busapppower", &grid->info.meter_grid_data.BphaseApparentPower);
            // ret |= dev_get_function_double(grid->no, "get_C_busapppower", &grid->info.meter_grid_data.CphaseApparentPower);
        }
    }
    if(ret)
    {
        return METER_GRID_ERR;
    } 
    return _SUCCESS;
}


 /**
  * @description: meter_grid_lv 设备数据刷新
  * @param {cabinet_inside_t} cab
  * @return {*} 0:正常 1:报错 -1:没有关口表
  */
int meter_grid_lv_flush_data(void)
{
	char *no;
    int ret = 0;
    for(int i = 0; i < dev_info_all.meter_grid_lv.num; i++)
    {
        struct _meter_grid_t *grid = &dev_info_all.meter_grid_lv.meter_grid_param[i];
		no = grid->no;
		grid->info.meter_grid_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);

        ret |= dev_get_function_double(grid->no, "get_power", &grid->info.meter_grid_data.act_power);
        ret |= dev_get_function_double(grid->no, "get_repower", &grid->info.meter_grid_data.rea_power);
        ret |= dev_get_function_double(grid->no, "get_apprpower", &grid->info.meter_grid_data.appr_power);
        ret |= dev_get_function_double(grid->no, "get_factor", &grid->info.meter_grid_data.factor);
        ret |= dev_get_function_double(grid->no, "get_A_busvol", &grid->info.meter_grid_data.AphaseVoltage);
        ret |= dev_get_function_double(grid->no, "get_B_busvol", &grid->info.meter_grid_data.BphaseVoltage);
        ret |= dev_get_function_double(grid->no, "get_C_busvol", &grid->info.meter_grid_data.CphaseVoltage);
    }
    if(dev_info_all.meter_grid_lv.num > 0)
        microgrid_data.grid_lv_appower = dev_info_all.meter_grid_lv.meter_grid_param[0].info.meter_grid_data.appr_power;    // 暂时取第0表数据

    if(ret)
    {
        return METER_GRID_ERR;
    } 
    return _SUCCESS;
}
 /**
  * @description: meter_load 设备数据刷新
  * @param {cabinet_inside_t} cab
  * @return {*} 0:正常 1:报错 -1:没有负载表
  */
int meter_load_flush_data(void)
{
	char *no;
    for(int i = 0; i < dev_info_all.meter_load.num; i++)
    {
        struct _meter_load_t *load = &dev_info_all.meter_load.meter_load_param[i];
		no = load->no;
		load->info.meter_load_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);
        if( dev_get_function_double(load->no, "get_power", &load->info.meter_load_data.power))
        {
            return METER_LOAD_ERR;
        }
    }
    return _SUCCESS;
}

 /**
  * @description: meter_dg 设备数据刷新
  * @param {cabinet_inside_t} cab
  * @return {*} 0:正常 1:报错 -1:没有关口表
  */
int meter_dg_flush_data(void)
{
    if(0 == microgrid_cfg.en_dg_meter)
    {
        return 0;
    }
	char *no;
    struct _meter_dg_t *grid = &dev_info_all.meter_dg.meter_dg_param[0];
    no = grid->no;
    grid->info.meter_dg_data.on_line = dev_get_dev_tag_int(no, STATE_ONLINE);
    if(
        ( dev_get_function_double(grid->no, "get_power", &grid->info.meter_dg_data.act_power)) ||\
        ( dev_get_function_double(grid->no, "get_repower", &grid->info.meter_dg_data.rea_power)) ||\
        ( dev_get_function_double(grid->no, "get_A_busvol", &grid->info.meter_dg_data.AphaseVoltage)) ||\
        ( dev_get_function_double(grid->no, "get_B_busvol", &grid->info.meter_dg_data.BphaseVoltage)) ||\
        ( dev_get_function_double(grid->no, "get_C_busvol", &grid->info.meter_dg_data.CphaseVoltage)))
    {
        return METER_DG_ERR;
    }
    return _SUCCESS;
}

/**
 * @description: PCS输出功率汇总
 * @return {*} 总功率
 */
double get_all_pcs_outpower()
{
    double power_all = 0;
    for (int i = 0; i < dev_info_all.cabinet_info.num; i++) 
    {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];

        for (int j = 0; j < cab->pcs.num; j++) 
        {
            struct _pcs_t *pcs = &cab->pcs.pcs_param[j];
            power_all += pcs->info.pcs_data.out_power;
        
        }
    
    }
    return power_all;
}


/**
 * @description: PV总功率汇聚
 * @return {*} 汇总的功率
 */
double get_all_pv_power(void)
{
    double power_all = 0;
    for (int i = 0; i < dev_info_all.pv.num; i++) 
    {
        struct _pv_t *pv = &dev_info_all.pv.pv_param[i];

        if (pv->info.pv_data.on_line)
            power_all += pv->info.pv_data.power;
    
    }
    return power_all;
}

/**
 * @description: PV总无功功率汇聚
 * @return {*} 汇总的功率
 */
double get_all_pv_repower(void)
{
    double power_all = 0;
    for (int i = 0; i < dev_info_all.pv.num; i++) 
    {
        struct _pv_t *pv = &dev_info_all.pv.pv_param[i];

        if (pv->info.pv_data.on_line)
            power_all += pv->info.pv_data.repower;
    
    }
    return power_all;
}

/**
 * @description: METER PV总功率汇聚
 * @return {*} 汇总的功率
 */
double get_all_meter_pv_power(void)
{
    double power_all = 0;
    for (int i = 0; i < dev_info_all.meter_pv.num; i++) 
    {
        struct _meter_pv_t *_meter_pv = &dev_info_all.meter_pv.meter_pv_param[i];

        if (_meter_pv->info.meter_pv_data.on_line)
            power_all += _meter_pv->info.meter_pv_data.power;
    
    }
    return power_all;
}

/**
 * @description: METER PV总无功功率汇聚
 * @return {*} 汇总的功率
 */
double get_all_meter_pv_repower(void)
{
    double power_all = 0;
    for (int i = 0; i < dev_info_all.meter_pv.num; i++) 
    {
        struct _meter_pv_t *_meter_pv = &dev_info_all.meter_pv.meter_pv_param[i];
        
        if (_meter_pv->info.meter_pv_data.on_line)
            power_all += _meter_pv->info.meter_pv_data.repower;
    
    }
    return power_all;
}

/**
 * @description: mppt总功率汇总
 * @return {*}
 */
double get_all_mppt_power()
{
    double power_all = 0;
    for (int i = 0; i < dev_info_all.cabinet_info.num; i++) 
    {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];

        for (int j = 0; j < cab->mppt.num; j++) 
        {
            struct _mppt_t *mppt = &cab->mppt.mppt_param[j];
            power_all += mppt->info.mppt_data.power;
        }
    
    }
    return power_all;
}

double get_soc_average()
{
    microgrid_data.SOC_average = 0;
    traverse_cab_dev_func(get_all_soc_average);
    microgrid_data.SOC_average = microgrid_data.SOC_average / dev_info_all.cabinet_info.num;
    
    return microgrid_data.SOC_average;
}







void print_microgrid_cfg(const microgrid_cfg_t cfg);
// 打印 microgrid_ctrl_t 结构体
void print_microgrid_ctrl(const microgrid_ctrl_t ctrl);
int test_cab_info_ptf(cabinet_inside_t *cab);



/*========================================<算法>=======================================================*/



// 归中算法 将SOC回归至目标数值 假设归中目标为90 放电低过 90-阈值范围 或者 充电超过90 + 阈值范围后 停止归中算法使能
// 归中算法仅在PCS对外放电时生效 PCS对BMS充电期 由SOC充电上限控制
// 归中使能停止后，令光伏当前最大输出=PCS需要
// 归中算法原理:
// 在设置光伏=PCS输出之前 加上归中算法得到的增衰值
// 低SOC归中,充电: 光伏(输出)=PCS(对交流测输出)/-PCS(对直流侧充) + BMS(增衰值)

/**
 * @description: 归中算法 该函数会依据当前SOC 权重参数后得出当前BMS期望功率 BMS归中需求功率(相对直流母线) BNS充电:BMS_power > 0  BMS放电:BMS_power < 0
                 <<在当前版本中 该函数调用于针对单个柜子系统的BMS调控>>
 * @param {double} soc
 * @param {double} soc_min:SOC最小门限
 * @param {double} soc_max:SOC最大门限 
 * @param {double} SOCReturnDiff:上限归中范围
 * @param {double} discharging_power_max: 该柜的BMS最大输出功率之和
 * @param {double} charging_power_max: 最大充电功率(柜内BMS之和)
 * @param {double} flag
 * @return {*}
 */
double homingAlgorithmSOC(double soc, double soc_min, double soc_max, double SOCReturnDiff, double discharging_power_max, double charging_power_max,int *RTM_EN)
{  
    double BMS_power = 0;
    
    if(SOCReturnDiff <= 0)
    {
        SOCReturnDiff = 5;
    }
    // 归中值上下限约束设置 最大不可超过 SOCmax 最小不可低于SOCmin
    double RTM_min_SOC = soc_max - SOCReturnDiff;
    double RTM_max_SOC = soc_max + SOCReturnDiff;
    
    if(microgrid_ctrl.en_DOD)
    {

        RTM_min_SOC = RTM_min_SOC > 100 ? 100 : RTM_min_SOC;
        RTM_min_SOC = RTM_min_SOC < 0 ? 0 : RTM_min_SOC;

        
        RTM_max_SOC = RTM_max_SOC > 100 ? 100 : RTM_max_SOC;
        RTM_max_SOC = RTM_max_SOC < 0 ? 0 : RTM_max_SOC;
    }


    if(RTM_min_SOC > RTM_max_SOC)
    {
        // 输入错误参数将重置为默认参数
        /**///ems_syslog(LOG_ERR,"ERR: RTM_min_SOC > RTM_max_SOC ");
        RTM_min_SOC = 10;
        RTM_max_SOC = 90;
    }
        

   /**////**///ems_syslog(LOG_ERR,"连续log标志:RTM_min_SOC = %lf", RTM_min_SOC);
   /**////**///ems_syslog(LOG_ERR,"连续log标志:RTM_max_SOC = %lf", RTM_max_SOC);

    // 判断此刻SOC是否在归中阈值内 若不在则开启归中算法直到SOC在归中值时
    if (*RTM_EN == 0)
    {
        if (soc <= RTM_min_SOC)
            *RTM_EN= 1;
        else if (soc >= RTM_max_SOC)
            *RTM_EN= 2;
       /**////**///ems_syslog(LOG_ERR,"连续log标志:RTM_EN = %d", microgrid_cfg.RTM_EN);

    }
    if (*RTM_EN)
    {
        // 如果SOC超归中线 停止归中功率获取
        if (*RTM_EN== 1 && (soc >= soc_max))
        {
            *RTM_EN= 0;
       /**////**///ems_syslog(LOG_ERR,"连续log标志:SOC超归中线");

            goto END;
        }
        else if (*RTM_EN== 2 &&  (soc <= soc_max))
        {
            *RTM_EN= 0;
       /**////**///ems_syslog(LOG_ERR,"连续log标志:SOC超归中线");
            goto END;
        }
            
        // SOC大于归中设定值 削减光伏输出 让BMS承担额外输出 否则增大光伏最大输出 对BMS充电
        if (soc > soc_max)
        {
            // BMS_power = -(Micro_data_buf->BMS_data.discharging_power_max - (flag == 0 ? 0 : (out_power_get > 0 ? out_power_get : 0)));
            // 直流侧光伏可能功率过大覆盖PCS放电与储能的充电,届时 PCS防逆流导致PCS功率收放过快 BMS有可能无法吸收来着PCS降功率的冲击导致保护
            BMS_power = discharging_power_max;
            BMS_power < 0 ? BMS_power = 0 : BMS_power;
       /**////**///ems_syslog(LOG_ERR,"连续log标志:BMS放电");

        }
        else if (soc <= soc_max)
        {
            // BMS_power = Micro_data_buf->BMS_data.charging_power_max -  (flag == 0 ? 0 : (out_power_get > 0 ? out_power_get : 0));
            BMS_power = charging_power_max;
       /**////**///ems_syslog(LOG_ERR,"连续log标志:BMS充电");
            BMS_power > 0 ? BMS_power = 0 : BMS_power;
        }
    }
END:
       /**////**///ems_syslog(LOG_ERR,"连续log标志:return BMS_power = %lf", BMS_power);

    return BMS_power;
}

/**
 * @description: BMS最大充放电功率限制 控制单个柜子的充、放电最大门限逻辑。
 * @param {double} SOC: 当前SOC
 * @param {double} SOC_min: SOC最小下限
 * @param {double} SOC_max: SOC最大上限
 * @param {double} SOC_return_min: SOC下限回差
 * @param {double} SOC_return_max: SOC上限回差
 * @param {enum ENERGY_DIRECTION} flag: 充放电状态(1:仅放电 2:仅充电)
 * @return {*}
 */
int BMS_protect_to_ctrl_PCS(cabinet_inside_t *cab)
{
    // 放电或者过充后 将PCS最大输出功率按比例衰减 根据SOC实际状态来设置衰减值
    // 例如 SOC = 10 进行50的衰减
    // 这样SOC达到 下限时 PCS的功率将被限制为0
    /**////**///ems_syslog(LOG_ERR,"\n==============>\n信息保护参数\n");
    double SOC = cab->cab_data.SOC_average;
    double out_power_discharge = cab->cab_ctrl.pcs_discharge_max_actual;
    double out_power_charge = cab->cab_ctrl.pcs_charge_max_actual;
    double SOC_min = microgrid_ctrl.SOC_min;
    double SOC_max = microgrid_ctrl.SOC_max;

    SOC_max = SOC_max > 100 ? 100 : SOC_max;
    SOC_min = SOC_min < 0 ? 0 : SOC_min;
    double return_soc_max = SOC_max + microgrid_ctrl.SOCmaxReturnDiff;
    double return_soc_min= SOC_min + microgrid_ctrl.SOCminReturnDiff;
    
    if(microgrid_ctrl.en_DOD)
    {
        return_soc_max = return_soc_max > 100 ? 100 : return_soc_max;
        return_soc_min = return_soc_min < 0 ? 0 : return_soc_min;
    }
    else 
    {
        cab->cab_ctrl.pcs_discharge_max_set = fabs(out_power_discharge);
        cab->cab_ctrl.pcs_charge_max_set = -fabs(out_power_charge);
        if (cab->cab_ctrl.pcs_discharge_max_set < 1.0) // 禁放
        {
            cab->cab_ctrl.bms_discharge_enabled = 0;
        }

        if (cab->cab_ctrl.pcs_charge_max_set > -1.0) // 禁充
        {
            cab->cab_ctrl.bms_charge_enabled = 0;
        }
        return 0;
    }

    if(SOC <= SOC_min)
    {
        cab->cab_ctrl.pcs_discharge_max_set = 0;     // 禁放
        cab->cab_ctrl.pcs_charge_max_set = -fabs(out_power_charge); 
    }
    else if(SOC >= return_soc_max)
    {
        cab->cab_ctrl.pcs_discharge_max_set = fabs(out_power_discharge);
        cab->cab_ctrl.pcs_charge_max_set = 0;  // 禁充
    }
    else if(SOC <= return_soc_min && SOC > SOC_min)
    {
        cab->cab_ctrl.pcs_discharge_max_set = fabs(out_power_discharge) * ((SOC - SOC_min)/ microgrid_ctrl.SOCminReturnDiff); 
        cab->cab_ctrl.pcs_charge_max_set = -fabs(out_power_charge); 
    }
    else 
    {
        cab->cab_ctrl.pcs_discharge_max_set = fabs(out_power_discharge); 
        cab->cab_ctrl.pcs_charge_max_set = -fabs(out_power_charge); 
    }

    if (cab->cab_ctrl.pcs_discharge_max_set < 1.0) // 禁放
    {
        cab->cab_ctrl.bms_discharge_enabled = 0;
    }

    if (cab->cab_ctrl.pcs_charge_max_set > -1.0) // 禁充
    {
        cab->cab_ctrl.bms_charge_enabled = 0;
    }
    UD_log_sprintf(micro_log, "\n<最大放电限制:%lf>\n<最大充电限制:%lf>",\
        cab->cab_ctrl.pcs_discharge_max_set, cab->cab_ctrl.pcs_charge_max_set); 
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0008, NULL, "[直流耦合]: <最大放电限制:%lf> <最大充电限制:%lf>",\
        cab->cab_ctrl.pcs_discharge_max_set, cab->cab_ctrl.pcs_charge_max_set);

    return 0;
}



 /*
 防逆流算法:
 特性: 
 1.对采样周期不敏感 只对逆流和数据变化敏感
 2.采样窗口为 10 次关口表数值变化
 3.算法收敛 不易因自身引发震荡
 4.稳定PCS输出并适应任意波动范围的负载系统
 */
#define WINDOW_SIZE 10  // 窗口越大 PCS调整就越惰性 PCS波动越小 但相对响应就缓慢 窗口大小暂不方便放出作为参数 因为是一数组做数据循环 动态调整的话处理机制上需要另作优化

/**
 * @description: 防逆流算法 通过关口表与PCS实际输出功率 得到PCS期望防逆流功率
 * @param {double} grid_power:关口表功率 anti_reflux: 防逆流余量
 * @param {double} anti_reflux: flag = 1:防逆流余量
 * @param {double} filter:为了进一步减少PCS的频繁控制 负载的连续的几次最低功率将在 filter(kw) 范围内滤波
 * @param {double} pcs_max_output:  PCS最大输出功率
 * @param {double} pcs_min_output:  PCS最小输出功率
 * @param {double} pcs_output: PCS 实际输出功率
 * @param {int} flag: 1:清空整个算法窗口 以及其他残留参数 0:防逆流运行 //后续需加入系统重启功率连续逻辑 思路:先捕捉一段窗口值后再启用防逆流 
 * @return {double} 返回PCS期望功率
 */

// 逆流状态判断


int set_antiReflux_log_en(struct UD_log *self)
{
    return ud_log_Level & 0x001 ? TRUE : FALSE;
}

double antiReflux(double grid_power, double anti_reflux, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, int flag)
{

    // 检查是否逆流,异步计时

    static int cnt = 0, delay_cnt = 0, anti_reflux_EN = 0, anti_reflux_cnt = 0;
    static struct UD_log * log_antiReflux = NULL;
    
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_reflux_EN 防逆流功率调整记录器
    // anti_reflux_cnt 防逆流执行后 记录多个点位 用于解决防逆流后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_power = 0, pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, min = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    double arr_min = 0;
    // 记录最小值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
    if(NULL != log_antiReflux)
    {
        UD_log_sprintf(log_antiReflux, 
            "grid_power = %lf, anti_reflux = %lf, filter = %lf, pcs_max_output = %lf, pcs_min_output = %lf, pcs_output = %lf, flag = %d\n", 
            grid_power, anti_reflux, filter, pcs_max_output, pcs_min_output, pcs_output, flag);
        
    }
    else 
    {
        log_antiReflux = UD_log_creat("antiReflux.log", set_antiReflux_log_en);
    }


    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        pcs_power = 0;
        min = 0;
        cnt = 0;
        anti_reflux_EN = 0;
        anti_reflux_cnt = 0;
    }
    ems_syslog(LOG_DEBUG, "function:<%s>: Grid Power: %.2f "
       "Anti Reflux: %.2f"
       "Filter: %.2f"
       "PCS Max Output: %.2f"
       "PCS Min Output: %.2f"
       "PCS Output: %.2f"
       "Flag: %d",
       __FUNCTION__,
       grid_power,          // double 用 %f 格式
       anti_reflux,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       flag);
    BUSINESS_LOG(LOG_NOTICE, AL_ID_0008, NULL, "[算法]: 防逆流算法 Grid Power: %.2f Anti Reflux: %.2f Filter: %.2f PCS Max Output: %.2f PCS Min Output: %.2f PCS Output: %.2f Flag: %d", grid_power, anti_reflux, filter, pcs_max_output, pcs_min_output, pcs_output, flag);
    pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_min用于计算窗口期内关口表有几次功率低于min
    // cnt_max 则用于计算 有多少次 窗口功率是大于 min + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if(grid_power != arr[cnt] || time(NULL) - time_new > 10 || (grid_power < anti_reflux && grid_power >= 0 && anti_reflux_EN)) //
    {
        if((time(NULL) - time_new) > 10)
        {
            en_over_time = 1;
            /**///ems_syslog(LOG_ERR,""); // 对内部功率校准
            /**///ems_syslog(LOG_ERR,"连续log标志:超时刷新");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "antiReflux, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_min = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "antiReflux, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power < 0 || anti_reflux_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "antiReflux, adverse current data coverage, grid_power = %lf", grid_power);
            }
            
            if(arr_min > arr[i])
            {
                arr_min = arr[i]; // 拿到最小值
            }

            if(((arr[i]<(min))) || (arr[i] < anti_reflux && arr[i] > 0 )) // 记录不在滤波范围内的次数 且功率小于逆流阈值
            {
                cnt_min++;
            }
            else if(arr[i] > min)  
            {
                cnt_max++;
            }
            else {
                cnt_range++;
            }
        }
        //ems_syslog(LOG_ERR, "antiReflux,  最小值: %lf", arr_min);

        if(anti_reflux_EN)
        {
            anti_reflux_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power > 0 || pcs_output_last == pcs_output)) // 调回 /刷新6个点位后再进行新的平衡点计算 
        {
            //ems_syslog(LOG_ERR, "antiReflux, 刷新6个点位后再进行新的平衡点计算~~, anti_reflux_cnt:%d", anti_reflux_cnt);
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] < 0)    // 如果说当前就是逆流状态 触发防逆流机制 
        {
            /**///ems_syslog(LOG_ERR,"防逆流触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:防逆流触发");
            time_new = time(NULL);
            pcs_power = arr_min - anti_reflux + pcs_output;
            min = arr_min;
            anti_reflux_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<%s>: 逆流触发 time_new = %ld", __FUNCTION__, time_new);
            //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:arr_min = %lf, pcs_output = %lf", arr_min, pcs_output);
        }
        else if(cnt_min >= 3 || cnt_max == WINDOW_SIZE || (cnt_max == WINDOW_SIZE && arr_min > anti_reflux) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power + filter)) && (pcs_output > (pcs_power - filter)) && (grid_power >= anti_reflux) && (pcs_power < anti_reflux))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power;
            }

            pcs_power = arr_min - anti_reflux + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "antiReflux, ~~连续log标志:arr_min  = %lf  pcs_output = %lf", arr_min, pcs_output);

            min = arr_min ; // 刷新底限
            if(min < anti_reflux)
                anti_reflux_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<%s>: 功率调整", __FUNCTION__);
            /**////ems_syslog(LOG_ERR,"刷新底限:%lf", min);
        }

        if(time(NULL) - time_new > 10){
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;
            ems_syslog(LOG_DEBUG,"function:<%s>: 超时重置", __FUNCTION__);

        }

        pcs_output_last = pcs_output;
    }

END:
UD_log_sprintf(log_antiReflux, "\n期望功率:%lf", pcs_power);
BUSINESS_LOG(LOG_NOTICE, AL_ID_0008, NULL, "[算法]: 防逆流算法 期望功率:%lf", pcs_power);

    if (pcs_power > 0)
        pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    if(pcs_power < 0)
        pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
UD_log_sprintf(log_antiReflux, "\n限制后功率:%lf", pcs_power);
BUSINESS_LOG(LOG_NOTICE, AL_ID_0008, NULL, "[算法]: 防逆流算法 限制后功率:%lf", pcs_power);
    fwrite_flush_UD_log(log_antiReflux);
    
    ems_syslog(LOG_DEBUG, "function:<%s>: return power = %lf", __FUNCTION__, pcs_power);
    //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power;
}

double xl_antiReflux(double grid_power, double Pmlmax, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, double _Pmlmax, int flag)
{
    static int cnt = 0, delay_cnt = 0, anti_exceed_EN = 0, anti_reflux_cnt = 0;
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_exceed_EN 超需量功率调整记录器
    // anti_reflux_cnt 超需量执行后 记录多个点位 用于解决超需量后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_power = 0, pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, max = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    double arr_max = 0;
    // 记录最大值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>: Grid Power: %.2f "
       "Pmlmax: %.2f "
       "Filter: %.2f "
       "PCS Max Output: %.2f "
       "PCS Min Output: %.2f "
       "PCS Output: %.2f "
       "_Pmlmax: %.2f "
       "Flag: %d ",
       grid_power,          // double 用 %f 格式
       Pmlmax,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       _Pmlmax,
       flag);
    BUSINESS_LOG(LOG_NOTICE, AL_ID_0008, NULL, "[算法]: 变压器保护算法 Grid Power: %.2f Pmlmax: %.2f Filter: %.2f PCS Max Output: %.2f PCS Min Output: %.2f PCS Output: %.2f _Pmlmax: %.2f Flag: %d", grid_power, Pmlmax, filter, pcs_max_output, pcs_min_output, pcs_output, _Pmlmax, flag);
    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        pcs_power = 0;
        max = 0;
        cnt = 0;
        anti_exceed_EN = 0;
        anti_reflux_cnt = 0;
    }

    pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_max用于计算窗口期内关口表有几次功率高于max
    // cnt_min 则用于计算 有多少次 窗口功率是小于 max + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if(grid_power != arr[cnt] || time(NULL) - time_new > 10 || (grid_power < Pmlmax && (grid_power >= _Pmlmax)  && anti_exceed_EN)) //
    {
        if (time(NULL) - time_new > 10)
        {
            en_over_time = 1;
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "algorithm, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_max = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "algorithm, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power > Pmlmax || anti_exceed_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "algorithm, over capacity data coverage, grid_power = %lf", grid_power);
            }

            if(arr_max < arr[i])
            {
                arr_max = arr[i]; // 拿到最大值
            }

            if(arr[i] > max || (arr[i] < Pmlmax && arr[i] >_Pmlmax)) // 记录不在滤波范围内的次数 且功率大于需量阈值_Pmlmax
            {
                cnt_max++;
            }
            else if(arr[i] < max)  
            {
                cnt_min++;
            }
            else {
                cnt_range++;
            }

        }
        //ems_syslog(LOG_ERR, "algorithm, 最大值: %lf", arr_max);

        if(anti_exceed_EN)
        {
            anti_exceed_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power < Pmlmax || pcs_output_last == pcs_output))
        {
            //ems_syslog(LOG_ERR, "algorithm, 刷新6个点位后再进行新的平衡点计算~~");
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] > Pmlmax)    // 如果说当前就是超需量状态 触发超需量机制 
        {
            /**////**///ems_syslog(LOG_ERR,"超需量触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:超需量触发");
            time_new = time(NULL);
            pcs_power = arr_max - _Pmlmax + pcs_output;
            max = arr_max;
            anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 过需量触发 time_new = %ld", time_new);
        }
        else if(cnt_max >= 3 || cnt_min == WINDOW_SIZE || (cnt_min == WINDOW_SIZE && arr_max < _Pmlmax) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power + filter)) && (pcs_output > (pcs_power - filter)) && (grid_power <= _Pmlmax))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power;
            }

            pcs_power = arr_max - _Pmlmax + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "algorithm, ~~连续log标志:arr_max  = %lf  pcs_output = %lf", arr_max, pcs_output);

            max = arr_max ; // 刷新底限
            if(max > _Pmlmax)
                anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 功率调整");

           /**///ems_syslog(LOG_ERR,"刷新底限:%lf", max);

        }

        if(time(NULL) - time_new > 10) {
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;           
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 超时重置");
        }

        pcs_output_last = pcs_output;  
    }

END:
    if (pcs_power > 0)
        pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    if(pcs_power < 0)
        pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);

    //ems_syslog(LOG_ERR, "algorithm, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power;
}


double xl_LV_antiReflux(double grid_power, double Pmlmax, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, double _Pmlmax, int flag)
{
    static int cnt = 0, delay_cnt = 0, anti_exceed_EN = 0, anti_reflux_cnt = 0;
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_exceed_EN 超需量功率调整记录器
    // anti_reflux_cnt 超需量执行后 记录多个点位 用于解决超需量后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_power = 0, pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, max = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    double arr_max = 0;
    // 记录最大值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>: Grid Power: %.2f "
       "Pmlmax: %.2f "
       "Filter: %.2f "
       "PCS Max Output: %.2f "
       "PCS Min Output: %.2f "
       "PCS Output: %.2f "
       "_Pmlmax: %.2f "
       "Flag: %d ",
       grid_power,          // double 用 %f 格式
       Pmlmax,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       _Pmlmax,
       flag);
    BUSINESS_LOG(LOG_NOTICE, AL_ID_0008, NULL, "[算法]: 低压侧变压器保护算法 Grid Power: %.2f Pmlmax: %.2f Filter: %.2f PCS Max Output: %.2f PCS Min Output: %.2f PCS Output: %.2f _Pmlmax: %.2f Flag: %d", grid_power, Pmlmax, filter, pcs_max_output, pcs_min_output, pcs_output, _Pmlmax, flag);

    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        pcs_power = 0;
        max = 0;
        cnt = 0;
        anti_exceed_EN = 0;
        anti_reflux_cnt = 0;
    }

    pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_max用于计算窗口期内关口表有几次功率高于max
    // cnt_min 则用于计算 有多少次 窗口功率是小于 max + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if(grid_power != arr[cnt] || time(NULL) - time_new > 10 || (grid_power < Pmlmax && (grid_power >= _Pmlmax)  && anti_exceed_EN)) //
    {
        if (time(NULL) - time_new > 10)
        {
            en_over_time = 1;
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "algorithm, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_max = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "algorithm, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power > Pmlmax || anti_exceed_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "algorithm, over capacity data coverage, grid_power = %lf", grid_power);
            }

            if(arr_max < arr[i])
            {
                arr_max = arr[i]; // 拿到最大值
            }

            if(arr[i] > max || (arr[i] < Pmlmax && arr[i] >_Pmlmax)) // 记录不在滤波范围内的次数 且功率大于需量阈值_Pmlmax
            {
                cnt_max++;
            }
            else if(arr[i] < max)  
            {
                cnt_min++;
            }
            else {
                cnt_range++;
            }

        }
        //ems_syslog(LOG_ERR, "algorithm, 最大值: %lf", arr_max);

        if(anti_exceed_EN)
        {
            anti_exceed_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power < Pmlmax || pcs_output_last == pcs_output))
        {
            //ems_syslog(LOG_ERR, "algorithm, 刷新6个点位后再进行新的平衡点计算~~");
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] > Pmlmax)    // 如果说当前就是超需量状态 触发超需量机制 
        {
            /**////**///ems_syslog(LOG_ERR,"超需量触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:超需量触发");
            time_new = time(NULL);
            pcs_power = arr_max - _Pmlmax + pcs_output;
            max = arr_max;
            anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 过需量触发 time_new = %ld", time_new);
        }
        else if(cnt_max >= 3 || cnt_min == WINDOW_SIZE || (cnt_min == WINDOW_SIZE && arr_max < _Pmlmax) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power + filter)) && (pcs_output > (pcs_power - filter)) && (grid_power <= _Pmlmax))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power;
            }

            pcs_power = arr_max - _Pmlmax + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "algorithm, ~~连续log标志:arr_max  = %lf  pcs_output = %lf", arr_max, pcs_output);

            max = arr_max ; // 刷新底限
            if(max > _Pmlmax)
                anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 功率调整");

           /**///ems_syslog(LOG_ERR,"刷新底限:%lf", max);

        }

        if(time(NULL) - time_new > 10) {
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;           
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 超时重置");
        }

        pcs_output_last = pcs_output;  
    }

END:
    if (pcs_power > 0)
        pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    if(pcs_power < 0)
        pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);

    //ems_syslog(LOG_ERR, "algorithm, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power;
}

double xl_LV_antiReflux_Twin(double grid_check,double grid_power, double Pmlmax, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, double _Pmlmax, int flag)
{
    static double pcs_power_twin = 0;
    static int cnt = 0, delay_cnt = 0, anti_exceed_EN = 0, anti_reflux_cnt = 0;
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_exceed_EN 超需量功率调整记录器
    // anti_reflux_cnt 超需量执行后 记录多个点位 用于解决超需量后算法震荡问题
    /**///UD_log_sprintf(micro_log,"连续log标志:函数antiReflux刷新");
    static double  pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, max = 0, grid_check_last = 0;
    static struct UD_log * log_antiReflux = NULL;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    static double arr_max = 0;
    // 记录最大值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    if(NULL != log_antiReflux)
    {
        ems_syslog(LOG_DEBUG, 
            "grid_power = %lf, Pmlmax = %lf, filter = %lf, pcs_max_output = %lf, pcs_min_output = %lf, pcs_output = %lf, flag = %d, _Pmlmax = %lf ", 
            grid_power, Pmlmax, filter, pcs_max_output, pcs_min_output, pcs_output, flag, _Pmlmax);
        
    }
    else 
    {
        log_antiReflux = UD_log_creat("antiReflux.log", set_antiReflux_log_en);
    }
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>: Grid Power: %.2f "
       "Pmlmax: %.2f "
       "Filter: %.2f "
       "PCS Max Output: %.2f "
       "PCS Min Output: %.2f "
       "PCS Output: %.2f "
       "_Pmlmax: %.2f "
       "Flag: %d ",
       grid_power,          // double 用 %f 格式
       Pmlmax,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       _Pmlmax,
       flag);
    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        max = 0;
        cnt = 0;
        anti_exceed_EN = 0;
        anti_reflux_cnt = 0;
        time_new = time(NULL);
        return 0;
    }

    pcs_power_twin = (pcs_power_twin > pcs_max_output ? pcs_max_output : pcs_power_twin);
    pcs_power_twin = (pcs_power_twin < pcs_min_output ? pcs_min_output : pcs_power_twin);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_max用于计算窗口期内关口表有几次功率高于max
    // cnt_min 则用于计算 有多少次 窗口功率是小于 max + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if((grid_check_last != grid_check && grid_power != arr[cnt]) || time(NULL) - time_new > 10 || (grid_power < Pmlmax && (grid_power >= _Pmlmax)  && anti_exceed_EN)) //
    {
        if (time(NULL) - time_new > 10)
        {
            en_over_time = 1;
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //UD_log_sprintf(micro_log, "algorithm, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_max = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //UD_log_sprintf(micro_log, "algorithm, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power > Pmlmax || anti_exceed_EN)
            {
                arr[i] = grid_power;
                //UD_log_sprintf(micro_log, "algorithm, over capacity data coverage, grid_power = %lf", grid_power);
            }

            if(arr_max < arr[i])
            {
                arr_max = arr[i]; // 拿到最大值
            }

            if(arr[i] > max || (arr[i] < Pmlmax && arr[i] >_Pmlmax)) // 记录不在滤波范围内的次数 且功率大于需量阈值_Pmlmax
            {
                cnt_max++;
            }
            else if(arr[i] < max)  
            {
                cnt_min++;
            }
            else {
                cnt_range++;
            }

        }
        //UD_log_sprintf(micro_log, "algorithm, 最大值: %lf", arr_max);

        if(anti_exceed_EN)
        {
            anti_exceed_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power < Pmlmax || pcs_output_last == pcs_output))
        {
            //UD_log_sprintf(micro_log, "algorithm, 刷新6个点位后再进行新的平衡点计算~~");
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///UD_log_sprintf(micro_log,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///UD_log_sprintf(micro_log,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] > Pmlmax)    // 如果说当前就是超需量状态 触发超需量机制 
        {
            /**////**///UD_log_sprintf(micro_log,"超需量触发");
            /**///UD_log_sprintf(micro_log,"连续log标志:超需量触发");
            time_new = time(NULL);
            pcs_power_twin = arr_max - _Pmlmax + pcs_output;
            max = arr_max;
            anti_exceed_EN = 1;
            if (pcs_power_twin > 0)
                pcs_power_twin = (pcs_power_twin > pcs_max_output ? pcs_max_output : pcs_power_twin);
            if(pcs_power_twin < 0)
                pcs_power_twin = (pcs_power_twin < pcs_min_output ? pcs_min_output : pcs_power_twin);
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 过需量触发 time_new = %ld", time_new);
        }
        else if(cnt_max >= 3 || cnt_min == WINDOW_SIZE || (cnt_min == WINDOW_SIZE && arr_max < _Pmlmax) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///UD_log_sprintf(micro_log,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///UD_log_sprintf(micro_log,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power_twin + filter)) && (pcs_output > (pcs_power_twin - filter)) && (grid_power <= _Pmlmax))   // 对PCS功率滤波
            {
                /**///UD_log_sprintf(micro_log,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power_twin;
            }

            pcs_power_twin = arr_max - _Pmlmax + pcs_output;  // 40 - 5 + 40 = 
            //UD_log_sprintf(micro_log, "algorithm, ~~连续log标志:arr_max  = %lf  pcs_output = %lf", arr_max, pcs_output);

            max = arr_max ; // 刷新底限
            if(max > _Pmlmax)
                anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 功率调整");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }

            if (pcs_power_twin > 0)
                pcs_power_twin = (pcs_power_twin > pcs_max_output ? pcs_max_output : pcs_power_twin);
            if(pcs_power_twin < 0)
                pcs_power_twin = (pcs_power_twin < pcs_min_output ? pcs_min_output : pcs_power_twin);
            if(pcs_output > pcs_power_twin)
            {
                double val = pcs_output - pcs_power_twin;
                if(val > 1)
                {
                    int num = get_discover_dev_num();
                    num = num <= 0 ? 1 : num;
                    pcs_power_twin = (-val < ((arr_max - _Pmlmax)) / (double)num) ? (pcs_output + (arr_max - _Pmlmax) / (double)num) : pcs_power_twin;
                }
                
            }
            if(pcs_power_twin > 0)
            {
                pcs_power_twin = pcs_power_twin;
                if(pcs_output < pcs_power_twin)
                {
                    double val = pcs_power_twin - pcs_output;
                    if(val > fabs(Pmlmax - _Pmlmax))
                    {
                        int num = get_discover_dev_num();
                        num = num <= 0 ? 1 : num;
                        pcs_power_twin =  val / num;
                    }
                    
                }

            }
            grid_check_last = grid_check;
            if(pcs_power_twin < pcs_output_last)
            {
                // double tmp = fabs(pcs_power_twin) - fabs(pcs_output_last);
                // if(tmp > fabs(pcs_min_output * 0.2))
                // {
                //     pcs_power_twin = pcs_output_last - fabs(pcs_min_output) * 0.2;
                // }
            }
            if (pcs_power_twin > 0)
                pcs_power_twin = (pcs_power_twin > pcs_max_output ? pcs_max_output : pcs_power_twin);
            if(pcs_power_twin < 0)
                pcs_power_twin = (pcs_power_twin < pcs_min_output ? pcs_min_output : pcs_power_twin);


           /**///UD_log_sprintf(micro_log,"刷新底限:%lf", max);

        }

        if(time(NULL) - time_new > 10) {
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;           
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 超时重置");
        }

        pcs_output_last = pcs_output;  
    }
END:
    
    ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>:计算新的PCS输出功率 :%lf", pcs_power_twin);

    return pcs_power_twin;
}

double xl_antiReflux_Twin(double grid_check,double grid_power, double Pmlmax, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, double _Pmlmax, int flag)
{
    static double pcs_power_twin = 0;
    static int cnt = 0, delay_cnt = 0, anti_exceed_EN = 0, anti_reflux_cnt = 0;
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_exceed_EN 超需量功率调整记录器
    // anti_reflux_cnt 超需量执行后 记录多个点位 用于解决超需量后算法震荡问题
    /**///UD_log_sprintf(micro_log,"连续log标志:函数antiReflux刷新");
    static double  pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, max = 0, grid_check_last = 0;
    static struct UD_log * log_antiReflux = NULL;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    static double arr_max = 0;
    // 记录最大值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    if(NULL != log_antiReflux)
    {
        ems_syslog(LOG_DEBUG, 
            "grid_power = %lf, Pmlmax = %lf, filter = %lf, pcs_max_output = %lf, pcs_min_output = %lf, pcs_output = %lf, flag = %d, _Pmlmax = %lf ", 
            grid_power, Pmlmax, filter, pcs_max_output, pcs_min_output, pcs_output, flag, _Pmlmax);
        
    }
    else 
    {
        log_antiReflux = UD_log_creat("antiReflux.log", set_antiReflux_log_en);
    }
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>: Grid Power: %.2f "
       "Pmlmax: %.2f "
       "Filter: %.2f "
       "PCS Max Output: %.2f "
       "PCS Min Output: %.2f "
       "PCS Output: %.2f "
       "_Pmlmax: %.2f "
       "Flag: %d ",
       grid_power,          // double 用 %f 格式
       Pmlmax,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       _Pmlmax,
       flag);
    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        max = 0;
        cnt = 0;
        anti_exceed_EN = 0;
        anti_reflux_cnt = 0;
        time_new = time(NULL);
        return 0;
    }

    pcs_power_twin = (pcs_power_twin > pcs_max_output ? pcs_max_output : pcs_power_twin);
    pcs_power_twin = (pcs_power_twin < pcs_min_output ? pcs_min_output : pcs_power_twin);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_max用于计算窗口期内关口表有几次功率高于max
    // cnt_min 则用于计算 有多少次 窗口功率是小于 max + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if((grid_check_last != grid_check && grid_power != arr[cnt]) || time(NULL) - time_new > 10 || (grid_power < Pmlmax && (grid_power >= _Pmlmax)  && anti_exceed_EN)) //
    {
        if (time(NULL) - time_new > 10)
        {
            en_over_time = 1;
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //UD_log_sprintf(micro_log, "algorithm, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_max = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //UD_log_sprintf(micro_log, "algorithm, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power > Pmlmax || anti_exceed_EN)
            {
                arr[i] = grid_power;
                //UD_log_sprintf(micro_log, "algorithm, over capacity data coverage, grid_power = %lf", grid_power);
            }

            if(arr_max < arr[i])
            {
                arr_max = arr[i]; // 拿到最大值
            }

            if(arr[i] > max || (arr[i] < Pmlmax && arr[i] >_Pmlmax)) // 记录不在滤波范围内的次数 且功率大于需量阈值_Pmlmax
            {
                cnt_max++;
            }
            else if(arr[i] < max)  
            {
                cnt_min++;
            }
            else {
                cnt_range++;
            }

        }
        //UD_log_sprintf(micro_log, "algorithm, 最大值: %lf", arr_max);

        if(anti_exceed_EN)
        {
            anti_exceed_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power < Pmlmax || pcs_output_last == pcs_output))
        {
            //UD_log_sprintf(micro_log, "algorithm, 刷新6个点位后再进行新的平衡点计算~~");
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///UD_log_sprintf(micro_log,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///UD_log_sprintf(micro_log,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] > Pmlmax)    // 如果说当前就是超需量状态 触发超需量机制 
        {
            /**////**///UD_log_sprintf(micro_log,"超需量触发");
            /**///UD_log_sprintf(micro_log,"连续log标志:超需量触发");
            time_new = time(NULL);
            pcs_power_twin = arr_max - _Pmlmax + pcs_output;
            max = arr_max;
            anti_exceed_EN = 1;
            if (pcs_power_twin > 0)
                pcs_power_twin = (pcs_power_twin > pcs_max_output ? pcs_max_output : pcs_power_twin);
            if(pcs_power_twin < 0)
                pcs_power_twin = (pcs_power_twin < pcs_min_output ? pcs_min_output : pcs_power_twin);
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 过需量触发 time_new = %ld", time_new);
        }
        else if(cnt_max >= 3 || cnt_min == WINDOW_SIZE || (cnt_min == WINDOW_SIZE && arr_max < _Pmlmax) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///UD_log_sprintf(micro_log,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///UD_log_sprintf(micro_log,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power_twin + filter)) && (pcs_output > (pcs_power_twin - filter)) && (grid_power <= _Pmlmax))   // 对PCS功率滤波
            {
                /**///UD_log_sprintf(micro_log,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power_twin;
            }

            pcs_power_twin = arr_max - _Pmlmax + pcs_output;  // 40 - 5 + 40 = 
            //UD_log_sprintf(micro_log, "algorithm, ~~连续log标志:arr_max  = %lf  pcs_output = %lf", arr_max, pcs_output);

            max = arr_max ; // 刷新底限
            if(max > _Pmlmax)
                anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 功率调整");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }

            if (pcs_power_twin > 0)
                pcs_power_twin = (pcs_power_twin > pcs_max_output ? pcs_max_output : pcs_power_twin);
            if(pcs_power_twin < 0)
                pcs_power_twin = (pcs_power_twin < pcs_min_output ? pcs_min_output : pcs_power_twin);
            if(pcs_output > pcs_power_twin)
            {
                double val = pcs_output - pcs_power_twin;
                if(val > 1)
                {
                    int num = get_discover_dev_num();
                    num = num <= 0 ? 1 : num;
                    pcs_power_twin = (-val < ((arr_max - _Pmlmax)) / (double)num) ? (pcs_output + (arr_max - _Pmlmax) / (double)num) : pcs_power_twin;
                }
                
            }
            if(pcs_power_twin > 0)
            {
                pcs_power_twin = pcs_power_twin;
                if(pcs_output < pcs_power_twin)
                {
                    double val = pcs_power_twin - pcs_output;
                    if(val > fabs(Pmlmax - _Pmlmax))
                    {
                        int num = get_discover_dev_num();
                        num = num <= 0 ? 1 : num;
                        pcs_power_twin =  val / num;
                    }
                    
                }

            }
            grid_check_last = grid_check;
            if(pcs_power_twin < pcs_output_last)
            {
                // double tmp = fabs(pcs_power_twin) - fabs(pcs_output_last);
                // if(tmp > fabs(pcs_min_output * 0.2))
                // {
                //     pcs_power_twin = pcs_output_last - fabs(pcs_min_output) * 0.2;
                // }
            }
            if (pcs_power_twin > 0)
                pcs_power_twin = (pcs_power_twin > pcs_max_output ? pcs_max_output : pcs_power_twin);
            if(pcs_power_twin < 0)
                pcs_power_twin = (pcs_power_twin < pcs_min_output ? pcs_min_output : pcs_power_twin);


           /**///UD_log_sprintf(micro_log,"刷新底限:%lf", max);

        }

        if(time(NULL) - time_new > 10) {
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;           
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 超时重置");
        }

        pcs_output_last = pcs_output;  
    }
END:
    
    ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>:计算新的PCS输出功率 :%lf", pcs_power_twin);

    return pcs_power_twin;
}

static double pcs_power_traceLoad = 0;
double antiReflux_TraceLoad(double grid_check, double grid_power, double anti_reflux, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, int flag)
{

    // 检查是否逆流,异步计时

    static int cnt = 0, delay_cnt = 0, anti_reflux_EN = 0, anti_reflux_cnt = 0;
    static struct UD_log * log_antiReflux = NULL;
    
    
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_reflux_EN 防逆流功率调整记录器
    // anti_reflux_cnt 防逆流执行后 记录多个点位 用于解决防逆流后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_output_last = 0, arr[10] = {0}, min = 0, grid_check_last = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    static double arr_min = 0, pcs_power_tmp = 0;
    // 记录最小值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 


    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        min = 0;
        cnt = 0;
        anti_reflux_EN = 0;
        anti_reflux_cnt = 0;
        time_new = time(NULL);
        return 0;

    }
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: Grid Power: %.2f "
       "Anti Reflux: %.2f "
       "Filter: %.2f "
       "PCS Max Output: %.2f "
       "PCS Min Output: %.2f "
       "PCS Output: %.2f "
       "Flag: %d ",
       grid_power,          // double 用 %f 格式
       anti_reflux,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       flag);
    BUSINESS_LOG(LOG_NOTICE, AL_ID_0008, NULL, "[算法]: 负荷跟踪算法 Grid Power: %.2f Anti Reflux: %.2f Filter: %.2f PCS Max Output: %.2f PCS Min Output: %.2f PCS Output: %.2f Flag: %d", grid_power, anti_reflux, filter, pcs_max_output, pcs_min_output, pcs_output, flag);

    pcs_power_traceLoad = (pcs_power_traceLoad > pcs_max_output ? pcs_max_output : pcs_power_traceLoad);
    pcs_power_traceLoad = (pcs_power_traceLoad < pcs_min_output ? pcs_min_output : pcs_power_traceLoad);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_min用于计算窗口期内关口表有几次功率低于min
    // cnt_max 则用于计算 有多少次 窗口功率是大于 min + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if((grid_check_last != grid_check && grid_power != arr[cnt]) || (time(NULL) - time_new > 10) || (grid_power < anti_reflux && grid_power >= 0 && anti_reflux_EN)) //
    {
        if((time(NULL) - time_new) > 10)
        { 
            en_over_time = 1;
            /**///ems_syslog(LOG_ERR,""); // 对内部功率校准
            /**///ems_syslog(LOG_ERR,"连续log标志:超时刷新");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "antiReflux, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_min = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "antiReflux, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power < 0 || anti_reflux_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "antiReflux, adverse current data coverage, grid_power = %lf", grid_power);
            }
            
            if(arr_min > arr[i])
            {
                arr_min = arr[i]; // 拿到最小值
            }

            if(((arr[i]<(min))) || (arr[i] < anti_reflux && arr[i] > 0 )) // 记录不在滤波范围内的次数 且功率小于逆流阈值
            {
                cnt_min++;
            }
            else if(arr[i] > min)  
            {
                cnt_max++;
            }
            else {
                cnt_range++;
            }
        }
        //ems_syslog(LOG_ERR, "antiReflux,  最小值: %lf", arr_min);

        if(anti_reflux_EN)
        {
            anti_reflux_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power > 0 || pcs_output_last == pcs_output)) // 调回 /刷新6个点位后再进行新的平衡点计算 
        {
            //ems_syslog(LOG_ERR, "antiReflux, 刷新6个点位后再进行新的平衡点计算~~, anti_reflux_cnt:%d", anti_reflux_cnt);
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] < 0 || pcs_output < 0)    // 如果说当前就是逆流状态 触发防逆流机制 
        {
            /**///ems_syslog(LOG_ERR,"防逆流触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:防逆流触发");
            time_new = time(NULL);
            pcs_power_traceLoad = arr_min - anti_reflux + pcs_output;
            min = arr_min;
            anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 逆流触发 time_new = %ld", time_new);
            //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:arr_min = %lf, pcs_output = %lf", arr_min, pcs_output);
        }
        else if(cnt_min >= 3 || cnt_max == WINDOW_SIZE || (cnt_max == WINDOW_SIZE && arr_min > anti_reflux) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power_traceLoad + filter)) && (pcs_output > (pcs_power_traceLoad - filter)) && (grid_power >= anti_reflux) && (pcs_power_traceLoad < anti_reflux))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power_traceLoad;
            }

            pcs_power_traceLoad = arr_min - anti_reflux + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "antiReflux, ~~连续log标志:arr_min  = %lf  pcs_output = %lf", arr_min, pcs_output);

            min = arr_min ; // 刷新底限
            if(min < anti_reflux)
                anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 功率调整");
            /**////ems_syslog(LOG_ERR,"刷新底限:%lf", min);
        }

        if(time(NULL) - time_new > 10){
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 超时重置");

        }

        pcs_output_last = pcs_output;
    }
END:
    if (pcs_power_traceLoad > 0)
        pcs_power_traceLoad = (pcs_power_traceLoad > pcs_max_output ? pcs_max_output : pcs_power_traceLoad);
    if(pcs_power_traceLoad < 0)
        pcs_power_traceLoad = (pcs_power_traceLoad < pcs_min_output ? pcs_min_output : pcs_power_traceLoad);
    pcs_power_tmp = pcs_power_traceLoad;
    ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power = %lf", pcs_power_traceLoad);

    // 计算新的PCS输出功率
    if(pcs_output < pcs_power_traceLoad)
    {
        double val = pcs_power_traceLoad - pcs_output;
        if(val > 1)
        {
            int num = get_discover_dev_num();
            num = num <= 0 ? 1 : num;
            pcs_power_tmp = val > ((arr_min - anti_reflux) / num) ? (pcs_output + (arr_min - anti_reflux) / num) : pcs_power_traceLoad;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);

        }
        else {
            pcs_power_tmp = pcs_power_traceLoad;
        }
    }
    if(pcs_power_traceLoad < 0)
    {
        pcs_power_tmp = pcs_power_traceLoad;
        if(pcs_output > pcs_power_tmp)
        {
            double val = pcs_output - pcs_power_traceLoad;
            if(val > 1)
            {
                int num = get_discover_dev_num();
                num = num <= 0 ? 1 : num;
                pcs_power_tmp = pcs_output + (-val / num);
                ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);
            }
            
        }

    }
    grid_check_last = grid_check;
    if(pcs_power_tmp > pcs_output_last)
    {
        double tmp = fabs(pcs_power_tmp) - fabs(pcs_output_last);
        if(tmp > fabs(pcs_max_output * 0.2))
        {
            pcs_power_tmp = pcs_output_last + fabs(pcs_max_output) * 0.2;
        }
    }
UD_log_sprintf(log_antiReflux, "\n期望功率:%lf", pcs_power_tmp);
BUSINESS_LOG(LOG_NOTICE, AL_ID_0008, NULL, "[算法]: 负荷跟踪算法 期望功率:%lf", pcs_power_tmp);
    if (pcs_power_tmp > 0)
        pcs_power_tmp = (pcs_power_tmp > pcs_max_output ? pcs_max_output : pcs_power_tmp);
    if(pcs_power_tmp < 0)
        pcs_power_tmp = (pcs_power_tmp < pcs_min_output ? pcs_min_output : pcs_power_tmp);
UD_log_sprintf(log_antiReflux, "\n限制后功率:%lf", pcs_power_tmp);
BUSINESS_LOG(LOG_NOTICE, AL_ID_0008, NULL, "[算法]: 负荷跟踪算法 限制后功率:%lf", pcs_power_tmp);
    fwrite_flush_UD_log(log_antiReflux);
    
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: return power = %lf", pcs_power_tmp);
    //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power_tmp;
}

double xl_antiReflux_TraceLoad(double grid_check,double grid_power, double Pmlmax, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, double _Pmlmax, int flag)
{
    static int cnt = 0, delay_cnt = 0, anti_exceed_EN = 0, anti_reflux_cnt = 0;
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_exceed_EN 超需量功率调整记录器
    // anti_reflux_cnt 超需量执行后 记录多个点位 用于解决超需量后算法震荡问题
    /**///UD_log_sprintf(micro_log,"连续log标志:函数antiReflux刷新");
    static double  pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, max = 0, grid_check_last = 0;
    static struct UD_log * log_antiReflux = NULL;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    static double arr_max = 0;
    // 记录最大值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    if(NULL != log_antiReflux)
    {
        ems_syslog(LOG_DEBUG, 
            "grid_power = %lf, Pmlmax = %lf, filter = %lf, pcs_max_output = %lf, pcs_min_output = %lf, pcs_output = %lf, flag = %d, _Pmlmax = %lf ", 
            grid_power, Pmlmax, filter, pcs_max_output, pcs_min_output, pcs_output, flag, _Pmlmax);
        
    }
    else 
    {
        log_antiReflux = UD_log_creat("antiReflux.log", set_antiReflux_log_en);
    }
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>: Grid Power: %.2f "
       "Pmlmax: %.2f "
       "Filter: %.2f "
       "PCS Max Output: %.2f "
       "PCS Min Output: %.2f "
       "PCS Output: %.2f "
       "_Pmlmax: %.2f "
       "Flag: %d ",
       grid_power,          // double 用 %f 格式
       Pmlmax,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       _Pmlmax,
       flag);
    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        max = 0;
        cnt = 0;
        anti_exceed_EN = 0;
        anti_reflux_cnt = 0;
        time_new = time(NULL);
        return 0;
    }

    pcs_power_traceLoad = (pcs_power_traceLoad > pcs_max_output ? pcs_max_output : pcs_power_traceLoad);
    pcs_power_traceLoad = (pcs_power_traceLoad < pcs_min_output ? pcs_min_output : pcs_power_traceLoad);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_max用于计算窗口期内关口表有几次功率高于max
    // cnt_min 则用于计算 有多少次 窗口功率是小于 max + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if((grid_check_last != grid_check && grid_power != arr[cnt]) || time(NULL) - time_new > 10 || (grid_power < Pmlmax && (grid_power >= _Pmlmax)  && anti_exceed_EN)) //
    {
        if (time(NULL) - time_new > 10)
        {
            en_over_time = 1;
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //UD_log_sprintf(micro_log, "algorithm, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_max = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //UD_log_sprintf(micro_log, "algorithm, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power > Pmlmax || anti_exceed_EN)
            {
                arr[i] = grid_power;
                //UD_log_sprintf(micro_log, "algorithm, over capacity data coverage, grid_power = %lf", grid_power);
            }

            if(arr_max < arr[i])
            {
                arr_max = arr[i]; // 拿到最大值
            }

            if(arr[i] > max || (arr[i] < Pmlmax && arr[i] >_Pmlmax)) // 记录不在滤波范围内的次数 且功率大于需量阈值_Pmlmax
            {
                cnt_max++;
            }
            else if(arr[i] < max)  
            {
                cnt_min++;
            }
            else {
                cnt_range++;
            }

        }
        //UD_log_sprintf(micro_log, "algorithm, 最大值: %lf", arr_max);

        if(anti_exceed_EN)
        {
            anti_exceed_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power < Pmlmax || pcs_output_last == pcs_output))
        {
            //UD_log_sprintf(micro_log, "algorithm, 刷新6个点位后再进行新的平衡点计算~~");
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///UD_log_sprintf(micro_log,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///UD_log_sprintf(micro_log,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] > Pmlmax)    // 如果说当前就是超需量状态 触发超需量机制 
        {
            /**////**///UD_log_sprintf(micro_log,"超需量触发");
            /**///UD_log_sprintf(micro_log,"连续log标志:超需量触发");
            time_new = time(NULL);
            pcs_power_traceLoad = arr_max - _Pmlmax + pcs_output;
            max = arr_max;
            anti_exceed_EN = 1;
            if (pcs_power_traceLoad > 0)
                pcs_power_traceLoad = (pcs_power_traceLoad > pcs_max_output ? pcs_max_output : pcs_power_traceLoad);
            if(pcs_power_traceLoad < 0)
                pcs_power_traceLoad = (pcs_power_traceLoad < pcs_min_output ? pcs_min_output : pcs_power_traceLoad);
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 过需量触发 time_new = %ld", time_new);
        }
        else if(cnt_max >= 3 || cnt_min == WINDOW_SIZE || (cnt_min == WINDOW_SIZE && arr_max < _Pmlmax) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///UD_log_sprintf(micro_log,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///UD_log_sprintf(micro_log,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power_traceLoad + filter)) && (pcs_output > (pcs_power_traceLoad - filter)) && (grid_power <= _Pmlmax))   // 对PCS功率滤波
            {
                /**///UD_log_sprintf(micro_log,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power_traceLoad;
            }

            pcs_power_traceLoad = arr_max - _Pmlmax + pcs_output;  // 40 - 5 + 40 = 
            //UD_log_sprintf(micro_log, "algorithm, ~~连续log标志:arr_max  = %lf  pcs_output = %lf", arr_max, pcs_output);

            max = arr_max ; // 刷新底限
            if(max > _Pmlmax)
                anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 功率调整");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }

            if (pcs_power_traceLoad > 0)
                pcs_power_traceLoad = (pcs_power_traceLoad > pcs_max_output ? pcs_max_output : pcs_power_traceLoad);
            if(pcs_power_traceLoad < 0)
                pcs_power_traceLoad = (pcs_power_traceLoad < pcs_min_output ? pcs_min_output : pcs_power_traceLoad);
            if(pcs_output > pcs_power_traceLoad)
            {
                double val = pcs_output - pcs_power_traceLoad;
                if(val > 1)
                {
                    int num = get_discover_dev_num();
                    num = num <= 0 ? 1 : num;
                    pcs_power_traceLoad = (-val < ((arr_max - _Pmlmax)) / (double)num) ? (pcs_output + (arr_max - _Pmlmax) / (double)num) : pcs_power_traceLoad;
                }
                
            }
            if(pcs_power_traceLoad > 0)
            {
                pcs_power_traceLoad = pcs_power_traceLoad;
                if(pcs_output < pcs_power_traceLoad)
                {
                    double val = pcs_power_traceLoad - pcs_output;
                    if(val > 1)
                    {
                        int num = get_discover_dev_num();
                        num = num <= 0 ? 1 : num;
                        pcs_power_traceLoad =  val / num;
                    }
                    
                }

            }
            grid_check_last = grid_check;
            if(pcs_power_traceLoad < pcs_output_last)
            {
                // double tmp = fabs(pcs_power_traceLoad) - fabs(pcs_output_last);
                // if(tmp > fabs(pcs_min_output * 0.2))
                // {
                //     pcs_power_traceLoad = pcs_output_last - fabs(pcs_min_output) * 0.2;
                // }
            }
            if (pcs_power_traceLoad > 0)
                pcs_power_traceLoad = (pcs_power_traceLoad > pcs_max_output ? pcs_max_output : pcs_power_traceLoad);
            if(pcs_power_traceLoad < 0)
                pcs_power_traceLoad = (pcs_power_traceLoad < pcs_min_output ? pcs_min_output : pcs_power_traceLoad);


           /**///UD_log_sprintf(micro_log,"刷新底限:%lf", max);

        }

        if(time(NULL) - time_new > 10) {
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;           
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 超时重置");
        }

        pcs_output_last = pcs_output;  
    }
END:
    
    ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>:计算新的PCS输出功率 :%lf", pcs_power_traceLoad);

    return pcs_power_traceLoad;
}


double antiReflux_Reverse(double grid_check, double grid_power, double anti_reflux, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, int flag)
{

    // 检查是否逆流,异步计时
    static double pcs_power_reverse = 0;
    static int cnt = 0, delay_cnt = 0, anti_reflux_EN = 0, anti_reflux_cnt = 0;
    static struct UD_log * log_antiReflux = NULL;
    
    
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_reflux_EN 防逆流功率调整记录器
    // anti_reflux_cnt 防逆流执行后 记录多个点位 用于解决防逆流后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_output_last = 0, arr[10] = {0}, min = 0, grid_check_last = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    static double arr_min = 0, pcs_power_tmp = 0;
    // 记录最小值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 


    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        min = 0;
        cnt = 0;
        anti_reflux_EN = 0;
        anti_reflux_cnt = 0;
        time_new = time(NULL);
        return 0;

    }
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: Grid Power: %.2f "
       "Anti Reflux: %.2f "
       "Filter: %.2f "
       "PCS Max Output: %.2f "
       "PCS Min Output: %.2f "
       "PCS Output: %.2f "
       "Flag: %d ",
       grid_power,          // double 用 %f 格式
       anti_reflux,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       flag);
    pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
    pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_min用于计算窗口期内关口表有几次功率低于min
    // cnt_max 则用于计算 有多少次 窗口功率是大于 min + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if((grid_check_last != grid_check && grid_power != arr[cnt]) || (time(NULL) - time_new > 10) || (grid_power < anti_reflux && grid_power >= 0 && anti_reflux_EN)) //
    {
        if((time(NULL) - time_new) > 10)
        { 
            en_over_time = 1;
            /**///ems_syslog(LOG_ERR,""); // 对内部功率校准
            /**///ems_syslog(LOG_ERR,"连续log标志:超时刷新");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "antiReflux, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_min = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "antiReflux, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power < 0 || anti_reflux_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "antiReflux, adverse current data coverage, grid_power = %lf", grid_power);
            }
            
            if(arr_min > arr[i])
            {
                arr_min = arr[i]; // 拿到最小值
            }

            if(((arr[i]<(min))) || (arr[i] < anti_reflux && arr[i] > 0 )) // 记录不在滤波范围内的次数 且功率小于逆流阈值
            {
                cnt_min++;
            }
            else if(arr[i] > min)  
            {
                cnt_max++;
            }
            else {
                cnt_range++;
            }
        }
        //ems_syslog(LOG_ERR, "antiReflux,  最小值: %lf", arr_min);

        if(anti_reflux_EN)
        {
            anti_reflux_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power > 0 || pcs_output_last == pcs_output)) // 调回 /刷新6个点位后再进行新的平衡点计算 
        {
            //ems_syslog(LOG_ERR, "antiReflux, 刷新6个点位后再进行新的平衡点计算~~, anti_reflux_cnt:%d", anti_reflux_cnt);
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] < 0 || pcs_output < 0)    // 如果说当前就是逆流状态 触发防逆流机制 
        {
            /**///ems_syslog(LOG_ERR,"防逆流触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:防逆流触发");
            time_new = time(NULL);
            pcs_power_reverse = arr_min - anti_reflux + pcs_output;
            min = arr_min;
            anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 逆流触发 time_new = %ld", time_new);
            //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:arr_min = %lf, pcs_output = %lf", arr_min, pcs_output);
        }
        else if(cnt_min >= 3 || cnt_max == WINDOW_SIZE || (cnt_max == WINDOW_SIZE && arr_min > anti_reflux) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power_reverse + filter)) && (pcs_output > (pcs_power_reverse - filter)) && (grid_power >= anti_reflux) && (pcs_power_reverse < anti_reflux))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power_reverse;
            }

            pcs_power_reverse = arr_min - anti_reflux + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "antiReflux, ~~连续log标志:arr_min  = %lf  pcs_output = %lf", arr_min, pcs_output);

            min = arr_min ; // 刷新底限
            if(min < anti_reflux)
                anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 功率调整");
            /**////ems_syslog(LOG_ERR,"刷新底限:%lf", min);
        }

        if(time(NULL) - time_new > 10){
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 超时重置");

        }

        pcs_output_last = pcs_output;
    }
END:
    if (pcs_power_reverse > 0)
        pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
    if(pcs_power_reverse < 0)
        pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
    pcs_power_tmp = pcs_power_reverse;
    ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power = %lf", pcs_power_reverse);

    // 计算新的PCS输出功率
    if(pcs_output < pcs_power_reverse)
    {
        double val = pcs_power_reverse - pcs_output;
        if(val > 1)
        {
            int num = get_discover_dev_num();
            num = num <= 0 ? 1 : num;
            pcs_power_tmp = val > ((arr_min - anti_reflux) / num) ? (pcs_output + (arr_min - anti_reflux) / num) : pcs_power_reverse;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);

        }
        else {
            pcs_power_tmp = pcs_power_reverse;
        }
    }
    if(pcs_power_reverse < 0)
    {
        pcs_power_tmp = pcs_power_reverse;
        if(pcs_output > pcs_power_tmp)
        {
            double val = pcs_output - pcs_power_reverse;
            if(val > 1)
            {
                int num = get_discover_dev_num();
                num = num <= 0 ? 1 : num;
                pcs_power_tmp = pcs_output + (-val / num);
                ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);
            }
            
        }

    }
    grid_check_last = grid_check;
    if(pcs_power_tmp > pcs_output_last)
    {
        double tmp = fabs(pcs_power_tmp) - fabs(pcs_output_last);
        if(tmp > fabs(pcs_max_output * 0.2))
        {
            pcs_power_tmp = pcs_output_last + fabs(pcs_max_output) * 0.2;
        }
    }
UD_log_sprintf(log_antiReflux, "\n期望功率:%lf", pcs_power_tmp);

    if (pcs_power_tmp > 0)
        pcs_power_tmp = (pcs_power_tmp > pcs_max_output ? pcs_max_output : pcs_power_tmp);
    if(pcs_power_tmp < 0)
        pcs_power_tmp = (pcs_power_tmp < pcs_min_output ? pcs_min_output : pcs_power_tmp);
UD_log_sprintf(log_antiReflux, "\n限制后功率:%lf", pcs_power_tmp);
    fwrite_flush_UD_log(log_antiReflux);
    
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: return power = %lf", pcs_power_tmp);
    //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power_tmp;
}

double xl_antiReflux_Reverse(double grid_check,double grid_power, double Pmlmax, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, double _Pmlmax, int flag)
{
    static double pcs_power_reverse = 0;
    static int cnt = 0, delay_cnt = 0, anti_exceed_EN = 0, anti_reflux_cnt = 0;
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_exceed_EN 超需量功率调整记录器
    // anti_reflux_cnt 超需量执行后 记录多个点位 用于解决超需量后算法震荡问题
    /**///UD_log_sprintf(micro_log,"连续log标志:函数antiReflux刷新");
    static double  pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, max = 0, grid_check_last = 0;
    static struct UD_log * log_antiReflux = NULL;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    static double arr_max = 0;
    // 记录最大值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    if(NULL != log_antiReflux)
    {
        ems_syslog(LOG_DEBUG, 
            "grid_power = %lf, Pmlmax = %lf, filter = %lf, pcs_max_output = %lf, pcs_min_output = %lf, pcs_output = %lf, flag = %d, _Pmlmax = %lf ", 
            grid_power, Pmlmax, filter, pcs_max_output, pcs_min_output, pcs_output, flag, _Pmlmax);
        
    }
    else 
    {
        log_antiReflux = UD_log_creat("antiReflux.log", set_antiReflux_log_en);
    }
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>: Grid Power: %.2f "
       "Pmlmax: %.2f "
       "Filter: %.2f "
       "PCS Max Output: %.2f "
       "PCS Min Output: %.2f "
       "PCS Output: %.2f "
       "_Pmlmax: %.2f "
       "Flag: %d ",
       grid_power,          // double 用 %f 格式
       Pmlmax,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       _Pmlmax,
       flag);
    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        max = 0;
        cnt = 0;
        anti_exceed_EN = 0;
        anti_reflux_cnt = 0;
        time_new = time(NULL);
        return 0;
    }

    pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
    pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_max用于计算窗口期内关口表有几次功率高于max
    // cnt_min 则用于计算 有多少次 窗口功率是小于 max + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if((grid_check_last != grid_check && grid_power != arr[cnt]) || time(NULL) - time_new > 10 || (grid_power < Pmlmax && (grid_power >= _Pmlmax)  && anti_exceed_EN)) //
    {
        if (time(NULL) - time_new > 10)
        {
            en_over_time = 1;
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //UD_log_sprintf(micro_log, "algorithm, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_max = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //UD_log_sprintf(micro_log, "algorithm, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power > Pmlmax || anti_exceed_EN)
            {
                arr[i] = grid_power;
                //UD_log_sprintf(micro_log, "algorithm, over capacity data coverage, grid_power = %lf", grid_power);
            }

            if(arr_max < arr[i])
            {
                arr_max = arr[i]; // 拿到最大值
            }

            if(arr[i] > max || (arr[i] < Pmlmax && arr[i] >_Pmlmax)) // 记录不在滤波范围内的次数 且功率大于需量阈值_Pmlmax
            {
                cnt_max++;
            }
            else if(arr[i] < max)  
            {
                cnt_min++;
            }
            else {
                cnt_range++;
            }

        }
        //UD_log_sprintf(micro_log, "algorithm, 最大值: %lf", arr_max);

        if(anti_exceed_EN)
        {
            anti_exceed_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power < Pmlmax || pcs_output_last == pcs_output))
        {
            //UD_log_sprintf(micro_log, "algorithm, 刷新6个点位后再进行新的平衡点计算~~");
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///UD_log_sprintf(micro_log,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///UD_log_sprintf(micro_log,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] > Pmlmax)    // 如果说当前就是超需量状态 触发超需量机制 
        {
            /**////**///UD_log_sprintf(micro_log,"超需量触发");
            /**///UD_log_sprintf(micro_log,"连续log标志:超需量触发");
            time_new = time(NULL);
            pcs_power_reverse = arr_max - _Pmlmax + pcs_output;
            max = arr_max;
            anti_exceed_EN = 1;
            if (pcs_power_reverse > 0)
                pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
            if(pcs_power_reverse < 0)
                pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 过需量触发 time_new = %ld", time_new);
        }
        else if(cnt_max >= 3 || cnt_min == WINDOW_SIZE || (cnt_min == WINDOW_SIZE && arr_max < _Pmlmax) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///UD_log_sprintf(micro_log,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///UD_log_sprintf(micro_log,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power_reverse + filter)) && (pcs_output > (pcs_power_reverse - filter)) && (grid_power <= _Pmlmax))   // 对PCS功率滤波
            {
                /**///UD_log_sprintf(micro_log,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power_reverse;
            }

            pcs_power_reverse = arr_max - _Pmlmax + pcs_output;  // 40 - 5 + 40 = 
            //UD_log_sprintf(micro_log, "algorithm, ~~连续log标志:arr_max  = %lf  pcs_output = %lf", arr_max, pcs_output);

            max = arr_max ; // 刷新底限
            if(max > _Pmlmax)
                anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 功率调整");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }

            if (pcs_power_reverse > 0)
                pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
            if(pcs_power_reverse < 0)
                pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
            if(pcs_output > pcs_power_reverse)
            {
                double val = pcs_output - pcs_power_reverse;
                if(val > 1)
                {
                    int num = get_discover_dev_num();
                    num = num <= 0 ? 1 : num;
                    pcs_power_reverse = (-val < ((arr_max - _Pmlmax)) / (double)num) ? (pcs_output + (arr_max - _Pmlmax) / (double)num) : pcs_power_reverse;
                }
                
            }
            if(pcs_power_reverse > 0)
            {
                pcs_power_reverse = pcs_power_reverse;
                if(pcs_output < pcs_power_reverse)
                {
                    double val = pcs_power_reverse - pcs_output;
                    if(val > 1)
                    {
                        int num = get_discover_dev_num();
                        num = num <= 0 ? 1 : num;
                        pcs_power_reverse =  val / num;
                    }
                    
                }

            }
            grid_check_last = grid_check;
            if(pcs_power_reverse < pcs_output_last)
            {
                // double tmp = fabs(pcs_power_reverse) - fabs(pcs_output_last);
                // if(tmp > fabs(pcs_min_output * 0.2))
                // {
                //     pcs_power_reverse = pcs_output_last - fabs(pcs_min_output) * 0.2;
                // }
            }
            if (pcs_power_reverse > 0)
                pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
            if(pcs_power_reverse < 0)
                pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);


           /**///UD_log_sprintf(micro_log,"刷新底限:%lf", max);

        }

        if(time(NULL) - time_new > 10) {
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;           
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 超时重置");
        }

        pcs_output_last = pcs_output;  
    }
END:
    
    ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>:计算新的PCS输出功率 :%lf", pcs_power_reverse);

    return pcs_power_reverse;
}

/*========================================<其他>=======================================================*/

void microgrid_cfg_flush(pcs_ctrl_var_t *var)
{
    cabinet_info_t *cabinet_info_tmp = get_cabinet_info();      /*获取一些控件参数*/
    microgrid_cfg.var = var;

    // 配置参数录入，参数更改需重启控制器
    microgrid_cfg.RTM_EN = 0;
    microgrid_cfg.mode_microgrid = cabinet_info_tmp->mode_microgrid;
    microgrid_cfg.en_diesel_generator = cabinet_info_tmp->en_diesel_generator;
    microgrid_cfg.en_photovoltaic = cabinet_info_tmp->en_photovoltaic;
    microgrid_cfg.en_mains = cabinet_info_tmp->en_mains;
    microgrid_cfg.en_charging_pile = cabinet_info_tmp->en_charging_pile;
    microgrid_cfg.en_esc = cabinet_info_tmp->en_esc;
    microgrid_cfg.en_sts = cabinet_info_tmp->en_sts;
    microgrid_cfg.en_icb = cabinet_info_tmp->en_icb;
    microgrid_cfg.en_lcb = cabinet_info_tmp->en_lcb;
    microgrid_cfg.en_ats = cabinet_info_tmp->en_ats;



    // 控制参数录入，开机录入一次，后续在数据刷新函数里面循环刷新，可随时更改
    microgrid_ctrl.en_anti_reflux = g_usercfg_variant.EnProtectReverse;
    microgrid_ctrl.anti_reflux = dev_get_dev_tag_int(DEV_NO_EMS, EMS_PSET);    //  = Pset 防逆流余量
    microgrid_ctrl.pvMax = dev_get_dev_tag_int(DEV_NO_EMS, PV_MAX_POWER);         //  光伏输出最大功率,光伏系统功率上限
    microgrid_ctrl.dischargeMaxPower = abs(g_usercfg_variant.dischargeThreshold);
    microgrid_ctrl.chargeMaxPower =  -abs(g_usercfg_variant.chargeMaxPower);
    microgrid_ctrl.SOCmaxReturnDiff = dev_get_dev_tag_int(DEV_NO_EMS, EMS_SOCMAXERR); //  = SOCmaxReturnDiff;
    microgrid_ctrl.SOCmaxReturnDiff = microgrid_ctrl.SOCmaxReturnDiff <= 0 ? 0 : microgrid_ctrl.SOCmaxReturnDiff;
    microgrid_ctrl.SOCminReturnDiff = dev_get_dev_tag_int(DEV_NO_EMS, EMS_SOCMINERR); //  = SOCmaxReturnDiff;
    microgrid_ctrl.SOCminReturnDiff = microgrid_ctrl.SOCminReturnDiff <= 0 ? 0 : microgrid_ctrl.SOCmaxReturnDiff;
    microgrid_ctrl.en_DOD = dev_get_dev_tag_int(DEV_NO_EMS, EN_PROTECT_DOD);
    {   
        double dod_max = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMAX);
        double dod_min = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMIN);

        if(dod_max < dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_MAX))
        {
            dev_set_dev_tag_float(DEV_NO_EMS, SOC_NET_MAX, dod_max);
        }

        if(dod_min > dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_MIN))
        {
            dev_set_dev_tag_float(DEV_NO_EMS, SOC_NET_MIN, dod_min);
        }

        if(dod_max < dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MAX))
        {
            dev_set_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MAX, dod_max);
        }

        if(dod_min > dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MIN))
        {
            dev_set_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MIN, dod_min);
        }
    }
    if(microgrid_ctrl.en_DOD == 1)
    {
        microgrid_ctrl.SOC_max_combin = dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_MAX); // 
        microgrid_ctrl.SOC_min_combin = dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_MIN); //  
        microgrid_ctrl.SOC_max_netdead = dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MAX); // 
        microgrid_ctrl.SOC_min_netdead = dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MIN);
    }
    else{ // 若不开启DOD保护，SOC并离网上下限保护依然存在，只是边界值 0 100
        microgrid_ctrl.SOC_max_combin = 100;
        microgrid_ctrl.SOC_min_combin = 0;
        microgrid_ctrl.SOC_max_netdead = 100;
        microgrid_ctrl.SOC_min_netdead = 0;
        microgrid_ctrl.SOCmaxReturnDiff = 0;
        microgrid_ctrl.SOCminReturnDiff = 0;
    }    
    microgrid_ctrl.dg_rated_power = dev_get_dev_tag_float(DEV_NO_EMS, DG_RATED_POWER);
    microgrid_ctrl.dg_boot_soc = dev_get_dev_tag_float(DEV_NO_EMS, DG_BOOT_SOC);
    microgrid_ctrl.dg_off_soc = dev_get_dev_tag_float(DEV_NO_EMS, DG_OFF_SOC);

    microgrid_ctrl.EnProtectTransf = g_usercfg_variant.EnProtectTransf;
    microgrid_ctrl.Pmlmax = g_usercfg_variant.Pmlmax;
    microgrid_ctrl.K1 = g_usercfg_variant.K1;

    microgrid_ctrl.PmlmaxDiff = g_usercfg_variant.DemandMargin;
    microgrid_ctrl.DemandDiff = dev_get_dev_tag_int(DEV_NO_EMS, DYNAMIC_AUGMENT);
    microgrid_ctrl.DgDiff = g_usercfg_variant.DgDiff;
    microgrid_ctrl.SocAlarmThreshold = g_usercfg_variant.SocAlarmThreshold;
    microgrid_ctrl.en_ac_c2d = g_usercfg_variant.EnSwC2D;
    microgrid_ctrl.en_ac_d2c = g_usercfg_variant.EnSwD2C;
    microgrid_ctrl.action_timeout = g_usercfg_variant.action_timeout;
    microgrid_ctrl.en_bms_power_limit = dev_get_dev_tag_int(DEV_NO_EMS, BMS_POWER_LIMIT);
    microgrid_ctrl.pv_km = dev_get_dev_tag_int(DEV_NO_EMS, PV_KM);
    microgrid_ctrl.dead_night = dev_get_dev_tag_int(DEV_NO_EMS, DEAD_NIGHT);
    microgrid_ctrl.pv_mode = dev_get_dev_tag_int(DEV_NO_EMS, PV_MODE);
    microgrid_ctrl.pv_isctrl = dev_get_dev_tag_int(DEV_NO_EMS, PV_ISCTRL);
    microgrid_ctrl.auto_off = dev_get_dev_tag_int(DEV_NO_EMS, PCS_AUTO_TURN);
    microgrid_ctrl.EnPvPrectrl = dev_get_dev_tag_int(DEV_NO_EMS, EN_PV_PRECTRL);
    {
        microgrid_abnormal.DG_abnormal = dev_get_dev_tag_int(DEV_NO_EMS, DG_ABNORMAL);
        microgrid_abnormal.icb_abnormal = dev_get_dev_tag_int(DEV_NO_EMS, ICB_ABNORMAL);
        microgrid_abnormal.lcb_abnormal = dev_get_dev_tag_int(DEV_NO_EMS, LCB_ABNORMAL);
    }
}


int dev_cfg_scale_flush(cabinet_inside_t *cab)
{
    for (int i = 0; i < cab->mppt.num; i++) 
    {
        // struct _mppt_t * mppt = &cab->mppt.mppt_param[i];
        // mppt->info.mppt_cfg.scale = 1.0 / cab->mppt.num;
    }

    for (int i = 0; i < cab->pcs.num; i++) 
    {
        // struct _pcs_t * pcs = &cab->pcs.pcs_param[i];
        // pcs->info.pcs_cfg.scale = 1.0 / cab->pcs.num;
    }

    return 0;
}

int get_all_cab_out_power(cabinet_inside_t *cab, void *value)
{
    *(double *)value  += cab->cab_data.pcs_output_power;
    return 0;
}

int get_all_cab_out_repower(cabinet_inside_t *cab, void *value)
{
    *(double *)value  += cab->cab_data.pcs_output_repower;
    return 0;
}

int get_all_cab_out_phasepower(cabinet_inside_t *cab, void *value)
{
    double *p = (double *) value;
    for (int i = 0; i < PHASE_MAX; i++) {
        p[i] += cab->cab_data.PhasePower[i];
    }
    return 0;
}

int get_all_cab_soc_sum(cabinet_inside_t *cab, void *value)
{
    if (cab->cab_data.en == 0)
        *(double *)value  += cab->cab_data.SOC_average;
    return 0;
}

int get_all_cab_real_sum(cabinet_inside_t *cab, void *num)
{
    if (cab->cab_data.on_line == 1 && cab->cab_data.en == 0 && cab->pcs.num > 0)
        *(int *)num  += 1;
    return 0;
}

// 更新黑夜识别标记，自带防抖
static void update_dead_night_flag(float pv_power) {
    static time_t under_time = 0;
    static time_t over_time = 0;

    time_t now = time(NULL);
    int timeout = microgrid_ctrl.dead_night == 0 ? 180 : microgrid_ctrl.dead_night;

    if (pv_power < PV_POWER_THRESHOLD) {
        over_time = 0;
        if (under_time == 0) under_time = now;

        if ((now - under_time) >= timeout) {
            microgrid_data.night_flag = 1;
        }
    } 
    else {
        under_time = 0;
        if (over_time == 0) over_time = now;

        if ((now - over_time) >= timeout) {
            microgrid_data.night_flag = 0;
        }
    }
}

static void calculate_lc_data(void)
{
    double SOC_ceiling = 0;                     // SOC最大值
    double SOC_average = 0;                     // SOC平均值
    double SOC_floor = 100;                     // SOC最小值
    double _soc = 0, _pcs_power = 0, _pcs_repower = 0;
    int num = 0;

    int capacity = 0;
    //pv--------------------------------------------------------------------
    if (dev_info_all.meter_pv.num > 0){ // 若系统有光伏表，则优先使用光伏表功率
        microgrid_data.pv_power = get_all_meter_pv_power();
        microgrid_data.pv_repower = get_all_meter_pv_repower();
    }
    else{
        microgrid_data.pv_power = get_all_pv_power();
        microgrid_data.pv_repower = get_all_pv_repower();
    }
    if (microgrid_data.pv_power < 0) microgrid_data.pv_power = 0;
    update_dead_night_flag(microgrid_data.pv_power);

    microgrid_data.pv_on_statu = flush_pv_onoff(1);
    microgrid_data.pv_off_statu = flush_pv_onoff(0);

    //pcs--------------------------------------------------------------------
    microgrid_data.on_line = flush_cabinet_online();
    microgrid_data.on_statu = flush_cabinet_onoff(1);
    microgrid_data.off_statu = flush_cabinet_onoff(0);
    microgrid_data.grid_statu = flush_cabinet_grid_offgrid(1);
    microgrid_data.offgrid_statu = flush_cabinet_grid_offgrid(0);

    traverse_cab_dev_func_arg(get_all_cab_out_power, &_pcs_power);
    traverse_cab_dev_func_arg(get_all_cab_out_repower, &_pcs_repower);
    microgrid_data.pcs_power = _pcs_power; // 统计所有柜子PCS功率，由于储能表采集效率不高，暂不考虑使用储能表，PCS功率"负充正放"
    microgrid_data.pcs_repower = _pcs_repower;

    //bms--------------------------------------------------------------------
    traverse_cab_dev_func_arg(get_all_cab_soc_sum, &_soc);
    traverse_cab_dev_func_arg(get_all_cab_real_sum, &num); // 计算最大、最小、平均SOC时，应考虑LC是否在线、是否可用
    if (num != 0)
        SOC_average = (double)_soc / num;
    else
        SOC_average = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {   
        cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
        if (cabinets->cab_data.on_line == 1 && cabinets->cab_data.en == 0) {
            if(cabinets->cab_data.SOC_average > SOC_ceiling)
            {
                SOC_ceiling = cabinets->cab_data.SOC_average;
            }
            
            if(cabinets->cab_data.SOC_average < SOC_floor)
            {
                SOC_floor = cabinets->cab_data.SOC_average;
            }
        }
        capacity += cabinets->cab_cfg.capacity;  // 总容量 
    }
    microgrid_data.SOC_average = SOC_average;
    microgrid_data.SOC_ceiling = SOC_ceiling;
    microgrid_data.SOC_floor = SOC_floor;

    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)  // 实时更新各柜子装机比例
    {   
        cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
        cabinets->cab_cfg.scale = (double)cabinets->cab_cfg.capacity / capacity;  
        ems_syslog(LOG_INFO, "cabinet no: %s scale: %lf", cabinets->no, cabinets->cab_cfg.scale);
    }
    traverse_cab_dev_func(traverse_cab_scale_flush_callback);    
}

void ac_cab_scale_calculate(void)
{
    int capacity = 0;	

    cabinet_info_t *cab = get_cabinet_info(); 
	if(cab->ctrl_mode) // 0:对等模式,1:主从模式 初步计算一下各柜子比例
	{
        for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
        {   
            cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
            capacity += cabinets->cab_cfg.capacity;  // 总容量 
        }
        ems_syslog(LOG_INFO, "total capacity: %d", capacity);

        for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
        {   
            cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
            cabinets->cab_cfg.scale = (double)cabinets->cab_cfg.capacity / capacity;
            ems_syslog(LOG_INFO, "cabinet no: %s scale: %lf", cabinets->no, cabinets->cab_cfg.scale);  
        }
        traverse_cab_dev_func(traverse_cab_scale_flush_callback);   
    }
}

/**
 * @description: 设备静态参数设置
 * @return {*}
 */
void dev_cfg_flush()
{
    traverse_cab_dev_func(traverse_dev_cfg_callback);
    traverse_cab_dev_func(dev_cfg_scale_flush);
}


/*========================================<功能测验>=======================================================*/
void test_dev_info_ptf()
{
    ems_syslog(LOG_ERR,"关口表数据");

    ems_syslog(LOG_ERR,"act_power = %lf", dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.act_power);
    ems_syslog(LOG_ERR,"AphaseVoltage = %lf", dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.AphaseVoltage);
    ems_syslog(LOG_ERR,"BphaseVoltage = %lf", dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.BphaseVoltage);
    ems_syslog(LOG_ERR,"CphaseVoltage = %lf", dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.CphaseVoltage);
}


int test_pcs_set_power(cabinet_inside_t *cab, void *power)
{
    cab->cab_ctrl.pcs_exp_power = *(double *)power * cab->cab_cfg.scale;
    return 0;

}

int test_mppt_set_power(cabinet_inside_t *cab, void *power)
{
    cab->cab_ctrl.mppt_exp_power = *(double *)power;
    return 0;

}

int test_cab_info_ptf(cabinet_inside_t *cab)
{
    ems_syslog(LOG_ERR,"cab:%s:", cab->no);

    // cab_ctrl 结构体
    ems_syslog(LOG_ERR,"cab.ctrl.pcs_discharge_max_actual:%lf:", cab->cab_ctrl.pcs_discharge_max_actual);
    ems_syslog(LOG_ERR,"cab.ctrl.pcs_charge_max_actual:%lf:", cab->cab_ctrl.pcs_charge_max_actual);
    ems_syslog(LOG_ERR,"cab.ctrl.pcs_discharge_max_set:%lf:", cab->cab_ctrl.pcs_discharge_max_set);
    ems_syslog(LOG_ERR,"cab.ctrl.pcs_charge_max_set:%lf:", cab->cab_ctrl.pcs_charge_max_set);
    ems_syslog(LOG_ERR,"cab.ctrl.pcs_exp_power:%lf:", cab->cab_ctrl.pcs_exp_power);
    ems_syslog(LOG_ERR,"cab.ctrl.bms_exp_power:%lf:", cab->cab_ctrl.bms_exp_power);
    ems_syslog(LOG_ERR,"cab.ctrl.mppt_exp_power:%lf:", cab->cab_ctrl.mppt_exp_power);

    // cab_data 结构体
    ems_syslog(LOG_ERR,"cab.data.SOC_average:%lf:", cab->cab_data.SOC_average);
    ems_syslog(LOG_ERR,"cab.data.SOC_ceiling:%lf:", cab->cab_data.SOC_ceiling);
    ems_syslog(LOG_ERR,"cab.data.SOC_floor:%lf:", cab->cab_data.SOC_floor);
    ems_syslog(LOG_ERR,"cab.data.pcs_output_power:%lf:", cab->cab_data.pcs_output_power);
    ems_syslog(LOG_ERR,"cab.data.onoff:%d:", cab->cab_data.onoff);
    ems_syslog(LOG_ERR,"cab.data.connect:%d:", cab->cab_data.connect);
    ems_syslog(LOG_ERR,"cab.data.mppt_out_power:%lf:", cab->cab_data.mppt_out_power);
    ems_syslog(LOG_ERR,"cab.data.en:%d:", cab->cab_data.en);

    // cab_cfg 结构体
    ems_syslog(LOG_ERR,"cab.cfg.discharge_max_cfg:%lf:", cab->cab_ctrl.discharge_max_cfg);
    ems_syslog(LOG_ERR,"cab.cfg.charge_max_cfg:%lf:", cab->cab_ctrl.charge_max_cfg);
    ems_syslog(LOG_ERR,"cab.cfg.scale:%lf:", cab->cab_cfg.scale);
    ems_syslog(LOG_ERR,"cab.cfg.mppt_power_max:%lf:", cab->cab_ctrl.mppt_power_max);

    ems_syslog(LOG_ERR,"PCS:num = %d", cab->pcs.num);
    ems_syslog(LOG_ERR,"mppt:num = %d", cab->mppt.num);
    ems_syslog(LOG_ERR,"bms:num = %d", cab->bms.num);
    ems_syslog(LOG_ERR,"meter_mppt:num = %d", cab->meter_mppt.num);
    ems_syslog(LOG_ERR,"meter_pcs:num = %d", cab->meter_pcs.num);


    // PCS 打印
    for (int i = 0; i < cab->pcs.num; i++) {
        ems_syslog(LOG_ERR,"PCS.no:%s", cab->pcs.pcs_param[i].no);
        
        // PCS 配置
        ems_syslog(LOG_ERR,"PCS[%d].cfg.scale:%lf", i, cab->pcs.pcs_param[i].info.pcs_cfg.scale);
        
        // PCS 控制
        ems_syslog(LOG_ERR,"PCS[%d].ctrl.out_power_set:%lf", i, cab->pcs.pcs_param[i].info.pcs_ctrl.out_power_set);
        
        // PCS 数据
        ems_syslog(LOG_ERR,"PCS[%d].data.on_line:%d", i, cab->pcs.pcs_param[i].info.pcs_data.on_line);
        ems_syslog(LOG_ERR,"PCS[%d].data.out_power_get:%lf", i, cab->pcs.pcs_param[i].info.pcs_data.out_power);
        ems_syslog(LOG_ERR,"PCS[%d].data.statu:%d", i, cab->pcs.pcs_param[i].info.pcs_data.statu);
        ems_syslog(LOG_ERR,"PCS[%d].data.PF_network:%d", i, cab->pcs.pcs_param[i].info.pcs_data.PF_network);
    }

    // BMS 打印
    for (int i = 0; i < cab->bms.num; i++) {
        ems_syslog(LOG_ERR,"BMS.no:%s", cab->bms.bms_param[i].no);
        
        // BMS 配置
        ems_syslog(LOG_ERR,"BMS[%d].cfg.scale:%lf", i, cab->bms.bms_param[i].info.bms_cfg.scale);
        
        // BMS 数据
        ems_syslog(LOG_ERR,"BMS[%d].data.on_line:%d", i, cab->bms.bms_param[i].info.bms_data.on_line);
        ems_syslog(LOG_ERR,"BMS[%d].data.SOC:%lf", i, cab->bms.bms_param[i].info.bms_data.SOC);
        ems_syslog(LOG_ERR,"BMS[%d].data.charging_power_max:%lf", i, cab->bms.bms_param[i].info.bms_data.charging_power_max);
        ems_syslog(LOG_ERR,"BMS[%d].data.discharging_power_max:%lf", i, cab->bms.bms_param[i].info.bms_data.discharging_power_max);
        
        // BMS 额外属性
        ems_syslog(LOG_ERR,"BMS[%d].charging_power_max:%lf", i, cab->bms.bms_param[i].charging_power_max);
        ems_syslog(LOG_ERR,"BMS[%d].discharging_power_max:%lf", i, cab->bms.bms_param[i].discharging_power_max);
    }

    // MPPT 打印
    for (int i = 0; i < cab->mppt.num; i++) {
        ems_syslog(LOG_ERR,"MPPT.no:%s", cab->mppt.mppt_param[i].no);
        
        // MPPT 配置
        ems_syslog(LOG_ERR,"MPPT[%d].cfg.scale:%lf", i, cab->mppt.mppt_param[i].info.mppt_cfg.scale);
        
        // MPPT 控制
        ems_syslog(LOG_ERR,"MPPT[%d].ctrl.power_set:%lf", i, cab->mppt.mppt_param[i].info.mppt_ctrl.power_set);
        
        // MPPT 数据
        ems_syslog(LOG_ERR,"MPPT[%d].data.on_line:%d", i, cab->mppt.mppt_param[i].info.mppt_data.on_line);
        ems_syslog(LOG_ERR,"MPPT[%d].data.power:%lf", i, cab->mppt.mppt_param[i].info.mppt_data.power);
        ems_syslog(LOG_ERR,"MPPT[%d].data.statu:%d", i, cab->mppt.mppt_param[i].info.mppt_data.statu);
        ems_syslog(LOG_ERR,"MPPT[%d].data.mode:%d", i, cab->mppt.mppt_param[i].info.mppt_data.mode);
    }
    return 0;
}


#define PRINT_MEMBER(structure, member, format) \
    /**///ems_syslog(LOG_ERR,#structure "." #member " = " format, structure.member);

// 打印 microgrid_cfg_t 结构体
void print_microgrid_cfg(const microgrid_cfg_t cfg) {
    /**///ems_syslog(LOG_ERR,"================================================\n");
    PRINT_MEMBER(cfg, pvMax, "%f");
    // PRINT_MEMBER(cfg, SOC_RTM, "%f");
    PRINT_MEMBER(cfg, SOCmaxReturnDiff, "%f");
    PRINT_MEMBER(cfg, SOCminReturnDiff, "%f");
    PRINT_MEMBER(cfg, SOC_max_combin, "%f");
    PRINT_MEMBER(cfg, SOC_min_combin, "%f");
    PRINT_MEMBER(cfg, SOC_max_netdead, "%f");
    PRINT_MEMBER(cfg, SOC_min_netdead, "%f");
    PRINT_MEMBER(cfg, RTM_EN, "%d");
    PRINT_MEMBER(cfg, anti_reflux, "%f");
    PRINT_MEMBER(cfg, DemandErr, "%f");
    PRINT_MEMBER(cfg, Pmlmax, "%f");
    PRINT_MEMBER(cfg, dischargeMaxPower, "%f");
    PRINT_MEMBER(cfg, chargeMaxPower, "%f");
    PRINT_MEMBER(cfg, mode_microgrid, "%d");
    PRINT_MEMBER(cfg, en_diesel_generator, "%d");
    PRINT_MEMBER(cfg, en_photovoltaic, "%d");
    PRINT_MEMBER(cfg, en_mains, "%d");
    PRINT_MEMBER(cfg, en_charging_pile, "%d");
    PRINT_MEMBER(cfg, en_esc, "%d");
    PRINT_MEMBER(cfg, en_STS, "%d");
    PRINT_MEMBER(cfg, en_await_change, "%d");
}

// 打印 microgrid_ctrl_t 结构体
void print_microgrid_ctrl(const microgrid_ctrl_t ctrl) {
    /**///ems_syslog(LOG_ERR,"================================================\n");
    PRINT_MEMBER(ctrl, plan_statu, "%d");
    PRINT_MEMBER(ctrl, Grid_offgrid_statu, "%d");
    PRINT_MEMBER(ctrl, onoff_statu, "%d");
    PRINT_MEMBER(ctrl, discharge_max_set, "%f");
    PRINT_MEMBER(ctrl, charge_max_set, "%f");
    PRINT_MEMBER(ctrl, plan_set_power, "%f");
    PRINT_MEMBER(ctrl, choose_func, "%d");
    PRINT_MEMBER(ctrl, SOC_max, "%f");
    PRINT_MEMBER(ctrl, SOC_min, "%f");
    PRINT_MEMBER(ctrl, pcs_exp_power, "%f");
    PRINT_MEMBER(ctrl, bms_exp_power, "%f");
    PRINT_MEMBER(ctrl, pv_exp_power, "%f");
    PRINT_MEMBER(ctrl, mppt_exp_power, "%f");
}

/**
 * @description: 微网接口测试函数 可在此对接口进行调式或测验
 * @return {*}
 */
void test_func()
{
    time_t time_tmp = time(NULL);
    long i = 0;
    while((time(NULL) - time_tmp) < 10)
    {
        i++;
        Relevant_data_refresh();
    }
    ems_syslog(LOG_ERR,"\n\n\n\n微网测试\n\n\n\n\n\n\n");
    ems_syslog(LOG_ERR,"测试结果:%ld\n", i);


    return;

    for (int i = 0; i<5; i++) {
    
        Relevant_data_refresh();
        sleep(1);

    }

    ems_syslog(LOG_ERR,"\n\n\n\n微网测试流程启动\n\n\n\n\n\n\n");

    Relevant_data_refresh();

    ems_syslog(LOG_ERR,"\nmicrogrid_cfg 参数打印\n");
    print_microgrid_cfg(microgrid_cfg);

    ems_syslog(LOG_ERR,"\nmicrogrid_ctrl 参数打印\n");
    print_microgrid_ctrl(microgrid_ctrl);

    ems_syslog(LOG_ERR,"\n柜内设备 数据打印\n");
    traverse_cab_dev_func(test_cab_info_ptf);

    double pcs_power = 30;
    
    ems_syslog(LOG_ERR,"\n设置PCS总功率和mppt总功率 设置为30\n");
    traverse_cab_dev_func_arg(test_pcs_set_power, &pcs_power);
    traverse_cab_dev_func_arg(test_mppt_set_power, &pcs_power);
    MPPT_set_power(30, 1);
    PCS_set_power(30, 1);
    time_t temp =  time(NULL);
    ems_syslog(LOG_ERR,"开关机测试流程启动");
    ems_syslog(LOG_ERR,"设置关机");
    set_pcs_onoff(0);
    if(100 > time(NULL) - temp)
    {
        ems_syslog(LOG_ERR,"设置成功");
    }
    else
        ems_syslog(LOG_ERR,"设置失败");
    

    ems_syslog(LOG_ERR,"设置离网");
    temp =  time(NULL);

    set_pcs_connect(0);

    if(100 > time(NULL) - temp)
    {
        ems_syslog(LOG_ERR,"设置成功");
    }
    else
        ems_syslog(LOG_ERR,"设置失败");
    sleep(5);
    
    temp =  time(NULL);
    ems_syslog(LOG_ERR,"设置开机");
    set_pcs_onoff(1);
    if(100 > time(NULL) - temp)
    {
        ems_syslog(LOG_ERR,"设置成功");
    }
    else
        ems_syslog(LOG_ERR,"设置失败");
    sleep(5);
    temp =  time(NULL);
    ems_syslog(LOG_ERR,"设置开机");
    set_pcs_onoff(1);
    if(100 > time(NULL) - temp)
    {
        ems_syslog(LOG_ERR,"设置成功");
    }
    else
        ems_syslog(LOG_ERR,"设置失败");


    set_pcs_onoff(0);
    if(100 > time(NULL) - temp)
    {
        ems_syslog(LOG_ERR,"设置成功");
    }
    else
        ems_syslog(LOG_ERR,"设置失败");

    sleep(5);

    set_pcs_onoff(0);
    if(100 > time(NULL) - temp)
    {
        ems_syslog(LOG_ERR,"设置成功");
    }
    else
        ems_syslog(LOG_ERR,"设置失败");


    ems_syslog(LOG_ERR,"开关机测试结束:%ld", time(NULL));
    ems_syslog(LOG_ERR,"\n柜内设备 数据打印\n");
    traverse_cab_dev_func(test_cab_info_ptf);
    ems_syslog(LOG_ERR,"微网测试流程结束 杀死本次进程");
    exit(0);
}



/*========================================<回调函数>=======================================================*/

int set_pcs_ctrl_dischargepower(cabinet_inside_t *cab, void *arg)
{
    cab->cab_ctrl.pcs_discharge_max_set = *(double *)arg;
    return 0;
}

int set_pcs_ctrl_chargepower(cabinet_inside_t *cab, void *arg)
{
    cab->cab_ctrl.pcs_charge_max_set = *(double *)arg * cab->cab_cfg.scale;
    return 0;
}

/**
 * @description: 检查并网离网是否与目标值一致
 * @param {_pcs_t} *pcs
 * @param {char} *tag
 * @param {void*} value
 * @return {*}
 */
int check_all_pcs_connect_status(struct _pcs_t *pcs, const char *tag, void* value)
{
    if(pcs->info.pcs_data.PF_network != *(int *)value)
    {
        return -1;
    }

    return 0;
}

int traverse_cab_scale_flush_callback(cabinet_inside_t *cab)
{
    cab->cab_ctrl.charge_max_cfg = -fabs(microgrid_ctrl.chargeMaxPower * cab->cab_cfg.scale);
    cab->cab_ctrl.discharge_max_cfg = fabs(microgrid_ctrl.dischargeMaxPower * cab->cab_cfg.scale);

    return 0;
}

/**
 * @description: 处理柜子的cfg参数
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int traverse_dev_cfg_callback(cabinet_inside_t *cab)
{
    
    cab->cab_ctrl.charge_max_cfg = -fabs(microgrid_ctrl.chargeMaxPower * cab->cab_cfg.scale);
    cab->cab_ctrl.discharge_max_cfg = fabs(microgrid_ctrl.dischargeMaxPower * cab->cab_cfg.scale);


    cab->cab_cfg.mppt_power_max = microgrid_ctrl.pvMax / dev_info_all.cabinet_info.num;      //TODO: 修正功率分配逻辑 光伏功率分配可能需要独立

    return 0;
}

int set_all_pcs_exp_power(cabinet_inside_t *cab, void *flag)
{
    int ret = 0;

    cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.pcs_exp_power > cab->cab_ctrl.pcs_discharge_max_set ? cab->cab_ctrl.pcs_discharge_max_set : cab->cab_ctrl.pcs_exp_power;
    cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.pcs_exp_power < cab->cab_ctrl.pcs_charge_max_set ? cab->cab_ctrl.pcs_charge_max_set : cab->cab_ctrl.pcs_exp_power;   

    cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.pcs_exp_power > cab->cab_ctrl.pcs_discharge_max_actual ? cab->cab_ctrl.pcs_discharge_max_actual : cab->cab_ctrl.pcs_exp_power;
    cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.pcs_exp_power < cab->cab_ctrl.pcs_charge_max_actual ? cab->cab_ctrl.pcs_charge_max_actual : cab->cab_ctrl.pcs_exp_power;   


    for (int i = 0; i < cab->pcs.num; i++) {
        struct _pcs_t *pcs = &cab->pcs.pcs_param[i];
        ret = set_power_pcs_dev(
            pcs->no,
            pcs->info.pcs_cfg.scale / cab->cab_cfg.scale * cab->cab_ctrl.pcs_exp_power,
            pcs->info.pcs_ctrl.last_set_power, 
            pcs->info.pcs_ctrl.last_time,
            microgrid_ctrl.sleep_pcs, 
            *(int *)flag == 1 ? -1 : (microgrid_ctrl.sleep_pcs + 10));
        
        if(0 == ret)
        {
            pcs->info.pcs_ctrl.last_time = time(NULL);
            pcs->info.pcs_ctrl.last_set_power = pcs->info.pcs_cfg.scale / cab->cab_cfg.scale * cab->cab_ctrl.pcs_exp_power;
        }
    }

    return 0;
}


/**
 * @description: 对目标柜子运行归中算法 并统一出总BMS期望功率
 * @param {cabinet_inside_t} *cab: 目标柜
 * @param {void} *arg: 功率反馈指针
 * @return {*}
 */
int cabinet_homingAlgorithmSOC(cabinet_inside_t *cab, void *arg)
{
    double *value = (double *)arg;
    /**///ems_syslog(LOG_ERR,"连续log标志:SOC_average = %lf",cab->cab_data.SOC_average);
    /**///ems_syslog(LOG_ERR,"连续log标志:SOC_min = %lf",microgrid_ctrl.SOC_min);
    /**///ems_syslog(LOG_ERR,"连续log标志:SOC_max = %lf",microgrid_ctrl.SOC_max);
    /**///ems_syslog(LOG_ERR,"连续log标志:SOCmaxReturnDiff = %lf",microgrid_ctrl.SOCmaxReturnDiff);
    /**///ems_syslog(LOG_ERR,"连续log标志:pcs_discharge_max_actual = %lf",cab->cab_ctrl.pcs_discharge_max_actual);
    /**///ems_syslog(LOG_ERR,"连续log标志:pcs_charge_max_actual = %lf",cab->cab_ctrl.pcs_charge_max_actual);
  
    cab->cab_ctrl.bms_exp_power = homingAlgorithmSOC(
        cab->cab_data.SOC_average, \
        microgrid_ctrl.SOC_min, \
        microgrid_ctrl.SOC_max,\
        microgrid_ctrl.SOCmaxReturnDiff, \
        cab->cab_ctrl.pcs_discharge_max_actual, \
        cab->cab_ctrl.pcs_charge_max_actual,&cab->cab_ctrl.RTM_EN);

    *value += cab->cab_ctrl.bms_exp_power;
    UD_log_sprintf(micro_log, " \n<BMS 归中算法\n算法相关参数: SOC平均值:%lf SOC上限:%lf SOC下限:%lf SOC上限回差:%lf BMS最大可充功率:%lf BMS最大可放功率:%lf\n算法推导当前柜BMS总期望功率:%lf> RTN:%d\n", \
                                        cab->cab_data.SOC_average,\
                                        microgrid_ctrl.SOC_max, \
                                        microgrid_ctrl.SOC_min,\
                                        microgrid_ctrl.SOCmaxReturnDiff,\
                                        cab->cab_ctrl.pcs_discharge_max_actual,\
                                        cab->cab_ctrl.pcs_charge_max_actual,\
                                        cab->cab_ctrl.bms_exp_power,cab->cab_ctrl.RTM_EN);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0010, cab->no, "[直流耦合]: BMS 归中算法 算法相关参数: SOC平均值:%lf SOC上限:%lf SOC下限:%lf SOC上限回差:%lf BMS最大可充功率:%lf BMS最大可放功率:%lf 算法推导当前柜BMS总期望功率:%lf> RTN:%d", cab->cab_data.SOC_average, microgrid_ctrl.SOC_max, microgrid_ctrl.SOC_min, microgrid_ctrl.SOCmaxReturnDiff, cab->cab_ctrl.pcs_discharge_max_actual, cab->cab_ctrl.pcs_charge_max_actual, cab->cab_ctrl.bms_exp_power,cab->cab_ctrl.RTM_EN);
    return 0;

}

/**
 * @description: 多柜PCS期望功率设置
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int cabinet_pcs_exp_power_set(cabinet_inside_t *cab)
{
    
    cab->cab_ctrl.pcs_exp_power = microgrid_ctrl.pcs_exp_power * cab->cab_cfg.scale;   // 功率分发
/**////**///ems_syslog(LOG_ERR,"cab中PCS期望功率:%lf", cab->cab_ctrl.pcs_exp_power);
    UD_log_sprintf(micro_log, "\ncab[%s] 期望PCS功率: %lf", cab->no, cab->cab_ctrl.pcs_exp_power);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0011, cab->no, "[直流耦合]: cab[%s] 期望PCS功率: %lf", cab->no, cab->cab_ctrl.pcs_exp_power);

    return 0;
}

/**
 * @description: 由于SOC低阈值时最大放电功率会被削减 而此时更换策略有可能下一策略不对最大充放电变量刷新，故而调用此函数刷新
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int pcs_limit_reset(cabinet_inside_t *cab)
{
    cab->cab_ctrl.pcs_discharge_max_set = cab->cab_ctrl.pcs_discharge_max_actual;
    cab->cab_ctrl.pcs_charge_max_set =  -fabs(cab->cab_ctrl.pcs_charge_max_actual);
    return 0;
}

/**
 * @description: 光伏基础门限功率调度逻辑 mppt_exp_power = bms_exp_power + pcs_output_power;
                    MPPT的期望功率调度(仅用于直流侧目前功率调度逻辑 如有新的调度逻辑 可再开发回调逻辑来执行 确保不会冲突)
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int cabinet_mppt_exp_power_set(cabinet_inside_t *cab)
{
    if(cab->cab_ctrl.bms_charge_enabled)
        cab->cab_ctrl.mppt_exp_power = cab->cab_data.pcs_output_power - cab->cab_ctrl.bms_exp_power;
    else
        cab->cab_ctrl.mppt_exp_power = 0;
    
    /*柜内功率限幅*/
    cab->cab_ctrl.mppt_exp_power = cab->cab_ctrl.mppt_exp_power > cab->cab_ctrl.mppt_power_max ? cab->cab_ctrl.mppt_power_max : cab->cab_ctrl.mppt_exp_power;
    /**////**///ems_syslog(LOG_ERR,"cab中mppt期望功率:%lf", cab->cab_ctrl.mppt_exp_power);
    UD_log_sprintf(micro_log, "\ncab[%s] 柜总光伏期望: %lf", cab->no, cab->cab_ctrl.mppt_exp_power);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0011, cab->no, "[直流耦合]: cab[%s] 柜总光伏期望: %lf", cab->no, cab->cab_ctrl.mppt_exp_power);
    return 0;
}

/**
 * @description: MPPT期望功率写0
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int mppt_power_reset(cabinet_inside_t *cab)
{
    cab->cab_ctrl.mppt_exp_power = 0;
    return 0;
}

int pcs_power_reset(cabinet_inside_t *cab)
{
    cab->cab_ctrl.pcs_exp_power = 0;
    return 0;
}
/**
 * @description: mppt设置功率回调
 * @param {_mppt_t} *mppt: 设备对象
 * @param {char} *tag: 点位映射tag
 * @param {void* } value: 目标值
 * @return {*}
 */
int traverse_mppt_callback_power_set(cabinet_inside_t *cab, void *flag)
{
    int ret = 0;

    for (int i = 0; i < cab->mppt.num; i++) {
        struct _mppt_t *mppt = &cab->mppt.mppt_param[i];
        mppt->info.mppt_ctrl.power_set = mppt->info.mppt_ctrl.power_set < 0 ? 0 : mppt->info.mppt_ctrl.power_set;

        ret = set_power_mppt_dev(
            mppt->no,
            mppt->info.mppt_ctrl.power_set,
            mppt->info.mppt_ctrl.last_set_power, 
            mppt->info.mppt_ctrl.last_time,
            1, 
            *(int *)flag == 1 ? -1 : 10);
        
        if(0 == ret)
        {
            mppt->info.mppt_ctrl.last_time = time(NULL);
            mppt->info.mppt_ctrl.last_set_power = mppt->info.mppt_ctrl.power_set;
        }
        set_mppt_onoff_by_power(mppt, cab->cab_ctrl.bms_charge_enabled);
    }

    return 0;
}

/**
 * @description: 对所有mppt的double点位设值
 * @param {_pcs_t} *pcs
 * @return {*}
 */
/**
 * @description: 
 * @param {_mppt_t} *mppt
 * @param {char} *tag
 * @param {void* } value
 * @return {*}
 */
int traverse_mppt_callback_double_set(struct _mppt_t *mppt, const char *tag, void*  value)
{
    dev_set_function(mppt->no,  tag, *(double *)value);
    return 0;
}

/**
 * @description: 对所有mppt的int点位设值
 * @param {_mppt_t} *mppt
 * @param {char} *tag
 * @param {void*} value
 * @return {*}
 */
int traverse_mppt_callback_int_set(struct _mppt_t *mppt, const char *tag, void* value)
{
    dev_set_function(mppt->no, tag, *(int*)value);
    return 0;
}


/**
 * @description: 
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int mppt_power_distribution(cabinet_inside_t *cab)
{
    struct Photovoltaic_power_adjust inf = {0};
    int ret = 0;
    UD_log_sprintf(micro_log, "\ncab[%s] 柜内光伏期望");

    if(cab->cab_ctrl.mppt_power_max < cab->cab_ctrl.mppt_exp_power)  // 最大功率单柜限幅
        cab->cab_ctrl.mppt_exp_power = cab->cab_ctrl.mppt_power_max;
    if(0 > cab->cab_ctrl.mppt_exp_power)  // 负功率单柜限幅
        cab->cab_ctrl.mppt_exp_power = 0;
    
    ret = Photovoltaic_adjust_init(&inf, cab->cab_ctrl.mppt_exp_power, microgrid_ctrl.mppt_eq, microgrid_ctrl.mppt_eq_tl, microgrid_ctrl.mppt_eq_rt, cab->mppt.num);

    for(int i = 0; i < cab->mppt.num; i++)
    {
        struct _mppt_t *mppt = &cab->mppt.mppt_param[i];
        Photovoltaic_adjust_info_set_data(&inf, mppt->info.mppt_data.power, (double)1 / cab->mppt.num, i);  // 注册
    }
    if(cab->mppt.num)
    {
        Photovoltaic_regulation_algorithm(&inf);
    }
    for (int i = 0; i < cab->mppt.num; i++) {
        
        struct _mppt_t *mppt = &cab->mppt.mppt_param[i];

        mppt->info.mppt_ctrl.power_set = inf.info[i].power_set;

        if((cab->cab_ctrl.mppt_power_max / cab->mppt.num) < mppt->info.mppt_ctrl.power_set)
            mppt->info.mppt_ctrl.power_set = cab->cab_ctrl.mppt_power_max / cab->mppt.num;
        if(0 > mppt->info.mppt_ctrl.power_set) 
            mppt->info.mppt_ctrl.power_set = 0;
        UD_log_sprintf(micro_log, "\n  柜内光伏 %s 期望: %lf", mppt->no, mppt->info.mppt_ctrl.power_set);
        BUSINESS_LOG(LOG_NOTICE, DC_ID_0012, mppt->no, "[直流耦合]: 柜内光伏 %s 期望: %lf", mppt->no, mppt->info.mppt_ctrl.power_set); 
    }

    if(0 == ret)
    {
        free(inf.info);
    }
    return 0;
}

/**
 * @description: 
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int mppt_power_check_power(cabinet_inside_t *cab)
{
    Relevant_data_refresh();
    for (int i = 0; i < cab->mppt.num; i++) {
        if((int)cab->mppt.mppt_param[i].info.mppt_ctrl.power_set != (int)cab->mppt.mppt_param[i].info.mppt_data.power)
        {
            return 1;
        }
    }
    return 0;
}


/**
 * @description: 
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int pcs_power_check_power(cabinet_inside_t *cab)
{
    Relevant_data_refresh();
    for (int i = 0; i < cab->pcs.num; i++) {
        struct _pcs_t pcs = cab->pcs.pcs_param[i];
        if((int)pcs.info.pcs_ctrl.out_power_set != (int)pcs.info.pcs_data.out_power && pcs.info.pcs_data.statu)
        {
            return 1;
        }
    }
    return 0;
}


/**
 * @description: 针对单柜的离网模式下 MPPT 功率 = BMS功率 + PCS输出功率
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int off_grid_mppt_exp_power_func(cabinet_inside_t *cab)
{
    if(cab->cab_ctrl.bms_charge_enabled)
        cab->cab_ctrl.mppt_exp_power = cab->cab_ctrl.pcs_exp_power - cab->cab_ctrl.bms_exp_power;
    else
        cab->cab_ctrl.mppt_exp_power = 0;
    UD_log_sprintf(micro_log, "\n cab[%s] 柜总光伏期望: %lf", cab->no, cab->cab_ctrl.mppt_exp_power);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0013, cab->no, "[直流耦合]: cab[%s] 柜总光伏期望: %lf", cab->no, cab->cab_ctrl.mppt_exp_power);
    return 0;
}

/**
 * @description: pcs功率分配
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int set_pcs_power(cabinet_inside_t *cab)
{
    cab->cab_ctrl.pcs_exp_power = microgrid_ctrl.pcs_exp_power * cab->cab_cfg.scale;
    return 0;
}


/**
 * @description: 单柜BMS期望功率设置 为 0
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int set_bms_power_zero(cabinet_inside_t *cab)
{
    cab->cab_ctrl.bms_exp_power = 0;
    return 0;
}


/**
 * @description: 单个柜子预设其充电功率最大值
 * @param {cabinet_inside_t} *cab
 * @param {void} *arg
 * @return {*}
 */
int set_cab_charge_max(cabinet_inside_t *cab, void *arg)
{
    cab->cab_ctrl.pcs_charge_max_set = *(double *)arg;
    return 0;
}


int traverse_pcs_callback_set_onoff(struct _pcs_t *pcs, const char *tag, void* val);
/**
 * @description: 设置所有的PCS开关机 对单柜设备接口
 * @param {int} flag: 0:关机 1:开机
 * @return {*}
 */
int set_all_pcs_onoff_tag_pcs_auto(int flag) /*确定好PCS的开关机校验时间*/
{
    static time_t pcs_power_time = 0;

    if(microgrid_ctrl.pcs_auto_turn)
    {
        switch (microgrid_ctrl.pcs_auto_statu) 
        {
            case 0:
                if((int)microgrid_ctrl.pcs_exp_power_actual == 0)
                {
                    pcs_power_time = time(NULL);
                    microgrid_ctrl.pcs_auto_statu = 1;
                }
            break;

            case 1:
                if((int)microgrid_ctrl.pcs_exp_power_actual != 0)
                {
                    microgrid_ctrl.pcs_auto_statu = 0;
                }
                else 
                {
                    if(microgrid_ctrl.pcs_auto_turn_off_time < (time(NULL) - pcs_power_time))
                    {
                        microgrid_ctrl.pcs_auto_statu = 2;
                    }
                }
            break;

            case 2:
                flag = 0;   // 关PCS
                if((int)microgrid_ctrl.pcs_exp_power_actual != 0)
                {
                    microgrid_ctrl.pcs_auto_statu = 0;
                }

            break;
            
            default:
            break;
        }
    }
    int ret = 0;
    release_confirmation(
        traverse_pcs(traverse_pcs_callback_set_onoff, NULL, &flag), 
        traverse_pcs(traverse_pcs_callback_check_onoff, NULL, &flag), 
        30, 
        120, 
        ret);

    if(0 != ret)
    {
        UD_log_sprintf(micro_log, "\n<PCS 设置开关机失败  设置目标[%d]  0:关机 1:开机>\n", flag);
        BUSINESS_LOG(LOG_NOTICE, DC_ID_0014, "pcs_ctrl", "[直流耦合]: PCS 设置开关机失败  设置目标[%d]  0:关机 1:开机", flag);
    }
    else 
    {
        UD_log_sprintf(micro_log, "\n<PCS 设置开关机成功[%d]  0:关机 1:开机>\n", flag);
        BUSINESS_LOG(LOG_NOTICE, DC_ID_0014, "pcs_ctrl", "[直流耦合]: PCS 设置开关机成功[%d]  0:关机 1:开机", flag);
    }
        
    return ret;
}

int set_all_pcs_onoff_tag(int flag) /*确定好PCS的开关机校验时间*/
{

    int ret = 0;
    release_confirmation(
        traverse_pcs(traverse_pcs_callback_set_onoff, NULL, &flag), 
        traverse_pcs(traverse_pcs_callback_check_onoff, NULL, &flag), 
        30, 
        120, 
        ret);
        
    return ret;
}

int set_cab_onoff(cabinet_inside_t *cab)
{
    dev_set_dev_tag_int(cab->no, ON_OFF_STATE, microgrid_ctrl.onoff);
    return 0;
}

int get_cab_onoff(cabinet_inside_t *cab)
{
    Relevant_data_refresh();
    if(microgrid_ctrl.onoff != cab->cab_data.onoff)
    {
        return 1;
    }
    return 0;
}

/**
 * @description: 设置所有的PCS开关机 对lc接口
 * @param {int} flag: 0:关机 1:开机
 * @return {*} 0:成功
 */
int set_all_pcs_onoff_lc(int flag)
{
    microgrid_ctrl.onoff = flag;
    
    int ret = 0;
    release_confirmation(
        traverse_cab_dev_func(set_cab_onoff), 
        traverse_cab_dev_func(get_cab_onoff),
        30, 
        120, 
        ret);
    return 0;
}


/**
 * @description: 设置并离网 - 面对设置点位控制
 * @param {int} flag: 0:离网 1:并网
 * @return {*} 0:成功 1:失败
 */
int set_all_pcs_connect_tag(int flag)
{
    int ret = 0;
    /**///ems_syslog(LOG_ERR,"设置并离网%d", flag);

    release_confirmation(traverse_pcs(traverse_pcs_callback_set_connect, NULL, &flag), 
        traverse_pcs(traverse_pcs_callback_check_connect, NULL, &flag), 
        20, 
        120, 
        ret);
        
    return ret;
}


int set_cab_connect(cabinet_inside_t *cab)
{
    dev_set_dev_tag_int(cab->no, SET_CONNECT, microgrid_ctrl.Grid_offgrid);
    return 0;
}

int get_cab_connect(cabinet_inside_t *cab)
{
    Relevant_data_refresh();
    if(microgrid_ctrl.onoff != cab->cab_data.onoff)
    {
        return 1;
    }
    return 0;
}

/**
 * @description: 设置并离网 - 面对lc控制
 * @param {int} flag: 0:离网 1:并网
 * @return {*} 0:成功 1:失败
 */
int set_all_pcs_connect_lc(int flag)    /*TODO*/
{
    microgrid_ctrl.Grid_offgrid = flag;
    
    int ret = 0;
    release_confirmation(
        traverse_cab_dev_func(set_cab_connect), 
        traverse_cab_dev_func(get_cab_connect),
        30, 
        120, 
        ret);
        
    return ret;
}



/**
 * @description: 调用 dev_xxx_function 接口 校验状态 例如你设置一个值后 再要校验这个值设置是否成功 可采用此机制 且函数临时实现局限性可见
 * @param {int} value_set: 设置值
 * @param {int} value_check: 回读校验值
 * @param {char} *dev_name: 设备SN
 * @param {char} *tagname_set: 要设置值的tagname
 * @param {char} *tagname_get: 要读取的目标tagname
 * @param {int} sleep_time: loop设置的时间间隔
 * @param {int} overtime: 超时时间
 * @return {*}1:超时   0:正常 
 */
int set_value_check_value_int(int value_set, int value_check, const char *dev_name, const char *tagname_set, const char *tagname_get, int sleep_time, int overtime)
{
    time_t now = time(NULL);
    int value_get = 0;

    dev_get_function_int(dev_name,tagname_get, &value_get);     // 如果条件直接满足 便不下发数据
    if(value_get == value_check)
    {
        return 0;
    }
    
    do
    {
        dev_get_function_int(dev_name,tagname_set, &value_set);
        sleep(sleep_time);
        dev_get_function_int(dev_name,tagname_get, &value_get);

    }while ((value_get != value_check) && (time(NULL) - now < overtime));


    if(value_get != value_check)
    {
        return 1;
    }
    return 0;

}

// 调用 dev_xxx_function  return:   1:超时   0:正常 
int set_value_check_value_double(double value_set, double value_check, const char *dev_name, const char *tagname_set, const char *tagname_get, int sleep_time, int overtime)
{
    time_t now = time(NULL);
    double value_get = 0;
    do
    {
        dev_set_function(dev_name,tagname_set, value_set);
        sleep(1);
        dev_get_function_double(dev_name,tagname_get, &value_get );

    }while (0 == value_check && (time(NULL) - now < overtime));


    if(value_get != value_check)
    {
        return 1;
    }
    return 0;

}


/*========================================<遍历接口>=======================================================*/


/**
 * @description: PCS遍历回调函数-入参为double类型-设置值
 * @param {_pcs_t} *pcs
 * @return {*}
 */
int traverse_pcs_callback_double_set(struct _pcs_t *pcs, const char *tag, void*  value)
{
    dev_set_function(pcs->no,  tag, *(double *)value);
    return 0;
}

/**
 * @description: PCS遍历回调函数-入参为int类型-设置值
 * @param {_pcs_t} *pcs
 * @return {*}
 */
int traverse_pcs_callback_int_set(struct _pcs_t *pcs, const char *tag, void* value)
{
    dev_set_function(pcs->no, tag, *(int*)value);

    return 0;
}


/**
 * @description: 遍历柜子 不带入参
 * @param {cabinet_inside_t} *cab
 * @return {*}
 */
int traverse_cab_dev_func(int (*func)(cabinet_inside_t *cab))
{
    int ret = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {   
        cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
		ret = func(cabinets);
        if(ret)
        {
            check_template_cfg_result(ret);
            return 1;
        }
    }
    return 0;
}

/**
 * @description: 遍历柜子 带入参
 * @param {cabinet_inside_t} *cab
 * @param {void} *arg
 * @param {void} *arg
 * @return {*}
 */
int traverse_cab_dev_func_arg(int (*func)(cabinet_inside_t *cab, void *arg), void *arg)
{
    int ret = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {   
        cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
		ret = func(cabinets, arg);
        if(ret)
        {
            check_template_cfg_result(ret);
            return 1;
        }
    }
    return 0;
}


/*遍历所有 dev_type 的设备的 no 
*/
int traversing_dev_to_type(const char *dev_type, dev_to_type_callback func, int value)
{
    proto_forward_t *vars = get_pcs_ctrl_var()->device_layer_ptr;
    int ret = 0;
    for (size_t i = 0; i < vars->channels_size; i++)
    {
        for (size_t j = 0; j < vars->channels[i]->devs_size; j++)
        {
            device_t *dev = vars->channels[i]->devs[j];

            if (0 == strcmp(dev->dev_type, dev_type))
            {
                ret = func(dev, value);

                if (ret == -1)
                {
                    return -1;
                }
                if (ret == 1)
                {
                    break;
                }
            }
        }
    }

    return 0;
}

/**
 * @description: PCS遍历回调函数-入参为int类型-读取值-校验
 * @param {_pcs_t} *pcs
 * @return {*} 0:PCS 开关机校验成功 -1:开关机校验失败 这里直接返回-1 对应接口traverse_pcs 也就是说 只有所有PCS开机/关机成功 该traverse_pcs才会返回0否则认为本次校验失败
 */
int traverse_pcs_callback_set_onoff(struct _pcs_t *pcs, const char *tag, void* val)
{
    pe_set_onoff(pcs->no, *(int *)val);
    
    return 0;
}


/**
 * @description: PCS遍历回调函数-入参为int类型-读取值-校验
 * @param {_pcs_t} *pcs
 * @return {*} 0:PCS开关机校验成功 -1:开关机校验失败 这里直接返回-1 对应接口traverse_pcs 也就是说 只有所有PCS开机/关机成功 该traverse_pcs才会返回0否则认为本次校验失败
 */
int traverse_pcs_callback_check_onoff(struct _pcs_t *pcs, const char *tag, void* val)
{
    if(pe_get_onoff(pcs->no) == *(int *)val)
        return 0;
    return -1;
}

/**
 * @description: PCS遍历回调函数-入参为int类型-读取值-校验
 * @param {_pcs_t} *pcs
 * @return {*} 0:PCS 开关机校验成功 -1:开关机校验失败 这里直接返回-1 对应接口traverse_pcs 也就是说 只有所有PCS开机/关机成功 该traverse_pcs才会返回0否则认为本次校验失败
 */
int traverse_pcs_callback_set_connect(struct _pcs_t *pcs, const char *tag, void* val)
{
    if(pe_set_connect(pcs->no, *(int *)val))
        return 1;
    return 0;
}


/**
 * @description: PCS遍历回调函数-入参为int类型-读取值-校验
 * @param {_pcs_t} *pcs
 * @return {*} 0:PCS 开关机校验成功 -1:开关机校验失败 这里直接返回-1 对应接口traverse_pcs 也就是说 只有所有PCS开机/关机成功 该traverse_pcs才会返回0否则认为本次校验失败
 */
int traverse_pcs_callback_check_connect(struct _pcs_t *pcs, const char *tag, void* val)
{
    Relevant_data_refresh();
    if(pcs->info.pcs_data.PF_network != *(int*)val)  
    {
        /**///ems_syslog(LOG_ERR,"返回1");
        return -1;
    }
    /**///ems_syslog(LOG_ERR,"返回0");

    return 0;

}
int traverse_pcs_check_connect(struct _pcs_t *pcs, const char *tag, void* val)
{
    if(pcs->info.pcs_data.PF_network != *(int*)val)  
    {
        /**///ems_syslog(LOG_ERR,"返回1");
        return -1;
    }
    /**///ems_syslog(LOG_ERR,"返回0");

    return 0;

}

/**
 * @description: 遍历所有PCS设备接口-附带参数
 * @param {int (*func)(struct _pcs_t *pcs, const char *tag, void* value)} *func: 遍历所有PCS设备时的回调函数  回调函数return: 0:正常 1:下一个柜子 其他:终止循环
 * @param {char} *tag: 外部入参
 * @param {void} *value 外部入参
 * @return {*} 返回回调函数返回值
 */
int traverse_pcs(int (*func)(struct _pcs_t *pcs, const char *tag, void* value), const char *tag, void *value)
{
    int ret = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {   
        cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
        for (int j =0; j < cabinets->pcs.num; j++) 
        {
            struct _pcs_t *pcs = &cabinets->pcs.pcs_param[j];
            ret = func(pcs, tag, value);
            if(1 == ret)
            {
                break;
            }
            if(0 == ret)
            {
                continue;
            }
            return ret;
        }
    }
    
    return 0;
}

/**
 * @description: 遍历所有MPPT设备接口-附带参数
 * @param {int (*func)(struct _pcs_t *pcs, const char *tag, void* value)} *func: 遍历所有PCS设备时的回调函数  回调函数return: 0:正常 1:下一个柜子 其他:终止循环
 * @param {char} *tag: 外部入参
 * @param {void} *value 外部入参
 * @return {*} 返回回调函数返回值
 */
int traverse_mppt(int (*func)(struct _mppt_t *mppt, const char *tag, void* value), const char *tag, void *value)
{
    int ret = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {   
        cabinet_inside_t *cabinets = dev_info_all.cabinet_info.cabinet_inside[i];
        for (int j =0; j < cabinets->mppt.num; j++) 
        {
            struct _mppt_t *mppt = &cabinets->mppt.mppt_param[j];
            ret = func(mppt, tag, value);
            if(1 == ret)
            {
                break;
            }
            if(0 == ret)
            {
                continue;
            }
            return ret;
        }
    }
    
    return 0;
}


/*========================================<对上统一设备控制接口>=======================================================*/


int ph_set_onoff_callback(int onoff)
{
    int ret = 0;
    if(microgrid_cfg.mode_microgrid == 2)
    {
        for(int i = 0; i < dev_info_all.pv.num; i++)
        {   
            ret |= pe_set_onoff(dev_info_all.pv.pv_param[i].no, onoff);
        }
    }
    if(microgrid_cfg.mode_microgrid == 1)
    {
        for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
        {   
            for (int j = 0; j < dev_info_all.cabinet_info.cabinet_inside[i]->mppt.num; j++) {
                struct _mppt_t *mppt = &dev_info_all.cabinet_info.cabinet_inside[i]->mppt.mppt_param[j];
                ret |= pe_set_onoff(mppt->no, onoff);
            }
        }
    }
    return ret;
}

int ph_set_power_callback(double power)
{
    int ret = 0;
    if(microgrid_cfg.mode_microgrid == 2)
    {
        for(int i = 0; i < dev_info_all.pv.num; i++)
        {   
            ret |= pe_set_power(dev_info_all.pv.pv_param[i].no, power / dev_info_all.pv.num);
        }
    }
    if(microgrid_cfg.mode_microgrid == 1)
    {
        int num_mppt = 0;
        for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
        {
            num_mppt += dev_info_all.cabinet_info.cabinet_inside[i]->mppt.num;
        }
        for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
        {   
            for (int j = 0; j < dev_info_all.cabinet_info.cabinet_inside[i]->mppt.num; j++) {
                struct _mppt_t *mppt = &dev_info_all.cabinet_info.cabinet_inside[i]->mppt.mppt_param[j];
                pe_set_power(mppt->no, power / num_mppt);
            }
        }
    }

    return ret;
}


int Photovoltaic_adjust_info_set_data(struct Photovoltaic_power_adjust *info, double output_power, double k, int n)
{
    if (NULL == info || NULL == info->info || n > info->num)
        return -1;
    info->info[n].output_power = output_power;
    info->info[n].k = k;
    return 0;
}

int Photovoltaic_adjust_init(struct Photovoltaic_power_adjust *info, double exp_power, double step_value, double pulse_peak, double Balanced_step, int num)
{
    if(NULL == info)
    {
        ems_syslog(LOG_ERR, "info_data_err");
        return -1;
    }
    info->exp_power = exp_power;
    info->Step_value = step_value;
    info->Pulse_peak = pulse_peak;
    info->Balanced_step = Balanced_step;
    info->num = num;
    info->info = (struct Photovoltaic_info *)calloc(sizeof(struct Photovoltaic_info) , num);
    return 0;
}

/*
光伏动态功率分配算法调用
*/
int Photovoltaic_regulation_algorithm(struct Photovoltaic_power_adjust *arg)
{
    struct Photovoltaic_power_adjust *info = arg;
    int sle_0 = 0, sle_1 = 0;
    // double power_default = 0;
    double power_sle_1 = 0;
    double power_all = 0;
    if(NULL == info || NULL == info->info || 0 == info->num)
    {
        ems_syslog(LOG_ERR, "info_data_err");
        return -1;
    }

    for(int i = 0; i < info->num; i++)  // 识别盈缺
    {
        power_all += info->info[i].output_power;
        if(info->info[i].output_power < info->exp_power * info->info[i].k)
        {
            info->info[i].Sle = 0;
            sle_0++;
        }
        else
        {
            info->info[i].Sle = 1;
            power_sle_1 += info->info[i].output_power; 
            sle_1++;
        }
    }

    if((int)power_all < (int)info->exp_power)
    {
        double def = (info->exp_power - power_all) * (info->num > 0 ? (double)1 / info->num : 0); // 缺省功率
        double tmp = (def > info->Step_value ? info->Step_value : def);
        tmp = (tmp > (info->Pulse_peak / info->num)) ? (info->Pulse_peak / info->num ) : tmp;
        tmp = (tmp >  info->Step_value )? info->Step_value : tmp;
        

        // 期望值的三层限制: 1. 缺省功率均值; 2. 总跃进功率不超过脉冲峰值; 3. 单个设备最大跃进值不超过脉冲峰值
        for(int i = 0; i < info->num; i++)
        {
            info->info[i].power_set = info->info[i].output_power + tmp; // 均衡步进功率

            // if(info->info[i].output_power < (info->exp_power * info->info[i].k))
            // {
            //     info->info[i].power_set = info->info[i].output_power + tmp; // 均衡步进功率
            // }
            // else {
            //     info->info[i].power_set = info->info[i].output_power + tmp;
            // }
            
        }
    }
    else
    {
        for(int i = 0; i < info->num; i++)
        {
            double tmp_Balanced_step = 0;
            if(info->info[i].Sle == 0)
            {
                tmp_Balanced_step = info->Balanced_step > (info->Pulse_peak / sle_0) ? (info->Pulse_peak / sle_0) : info->Balanced_step;
                tmp_Balanced_step = tmp_Balanced_step > info->Step_value ? info->Step_value : tmp_Balanced_step;

                info->info[i].power_set = info->info[i].output_power + tmp_Balanced_step;
                info->info[i].power_set = info->info[i].power_set > info->exp_power ? info->exp_power : info->info[i].power_set;
            }
        }

        for(int i = 0; i < info->num; i++)
        {
            if(info->info[i].Sle == 1)
            {
                info->info[i].power_set = info->info[i].output_power - (power_all - info->exp_power) * (power_sle_1 ? info->info[i].output_power / power_sle_1 : 0);
            }
        }
    }
    return 0;

}

/*汇总当前EMS下所有PCS的实际输出功率*/
double get_all_pcs_out_power()
{
    double sum = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {
        for(int j = 0; j < dev_info_all.cabinet_info.cabinet_inside[i]->pcs.num; j++)
        {
            struct _pcs_t *pcs = &dev_info_all.cabinet_info.cabinet_inside[i]->pcs.pcs_param[j];
            sum += pcs->info.pcs_data.out_power;
        }
        
    }

    return sum;
}

/* 
基于光伏调度的PCS功率分配算法
*/
int get_mppt_power(cabinet_inside_t *cab, void *arg)
{
    if(cab->cab_ctrl.bms_exp_power <= 0)
    {
        *(double *)arg += cab->cab_data.mppt_out_power;
    }
    else
    {
        *(double *)arg += cab->cab_ctrl.bms_exp_power;  // 本条件下光伏设置为0
    }
    return 0;
}
int cab_pcs_dispower(double pcs_power)
{
    double mppt_all_power = 0;
    double mppt_all_power_actual = 0;
    double mppt_all_power_charge_cab = 0;   // 仅需充电柜子的光伏功率 
    double stewint_cab_mppt_power = 0;      // 静置柜的光伏功率
    double bms_charge_power = 0;      // 静置柜的光伏功率
    double bms_charge_power_actual = 0;      // 静置柜的光伏功率
    double cab_no_sw_pcs_discharge_max_set = 0;      // 非静置的柜子的可充放功率汇总
    double cab_discharge_pcs_discharge_max_set = 0;      // 非静置的柜子的可充放功率汇总
    double cab_charge_pcs_discharge_max_set = 0;      // 需要充电的柜子的可放功率汇总
    double cab_charge_pcs_charge_max_actual = 0;      // 需要充电的柜子的可充功率汇总
    double cab_charge_max = 0;          // 需充电柜的总最大可充功率-PCS可设置功率
    double cab_power_sw_exp_power = 0;
    double all_max_actual_dis_power = 0;

    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {
        cabinet_inside_t  *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        all_max_actual_dis_power += cab->cab_ctrl.pcs_discharge_max_set;

        if(cab->cab_ctrl.bms_exp_power > 0) // 如果是期望放电
        {
            cab_no_sw_pcs_discharge_max_set += cab->cab_ctrl.pcs_discharge_max_set;
            cab_discharge_pcs_discharge_max_set += cab->cab_ctrl.pcs_discharge_max_set;
            mppt_all_power += cab->cab_ctrl.bms_exp_power;  // 本条件下光伏设置为0
            bms_charge_power += fabs(cab->cab_ctrl.pcs_charge_max_actual) < fabs(cab->cab_ctrl.pcs_discharge_max_set) ? fabs(cab->cab_ctrl.pcs_charge_max_actual) : fabs(cab->cab_ctrl.pcs_discharge_max_set) ;    // 最大可充参与算法计算以闭合逻辑
        }
         else if(cab->cab_ctrl.bms_exp_power < 0) // 如果是期望充电
        {
            cab_no_sw_pcs_discharge_max_set += cab->cab_ctrl.pcs_discharge_max_set;
            cab_charge_pcs_discharge_max_set += cab->cab_ctrl.pcs_discharge_max_set;
            cab_charge_pcs_charge_max_actual += cab->cab_ctrl.pcs_charge_max_actual;
            mppt_all_power_charge_cab += cab->cab_data.mppt_out_power;

            mppt_all_power_actual += cab->cab_data.mppt_out_power;
            mppt_all_power += cab->cab_data.mppt_out_power;
            bms_charge_power += cab->cab_ctrl.bms_exp_power;    // 记录储能需求充电功率
            bms_charge_power_actual += cab->cab_ctrl.bms_exp_power;
            double tmp = -cab->cab_data.mppt_out_power - cab->cab_ctrl.bms_exp_power;
            
            cab_charge_max += tmp < 0 ? 0 : tmp;  // 转为正数 限幅 过压问题交给设备自己处理
        }
        else
        {
            mppt_all_power += cab->cab_data.mppt_out_power;
            mppt_all_power_actual += cab->cab_data.mppt_out_power;
            stewint_cab_mppt_power += cab->cab_data.mppt_out_power;
        }
    }

    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {
        cabinet_inside_t  *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        if(cab->cab_ctrl.bms_exp_power < 0) // 如果是期望充电
        {
            double tmp = cab_charge_pcs_discharge_max_set * (cab_charge_pcs_charge_max_actual == 0 ? 0 : cab->cab_ctrl.pcs_charge_max_actual / cab_charge_pcs_charge_max_actual);
            if((tmp + cab->cab_ctrl.pcs_discharge_max_set) < cab->cab_data.mppt_out_power)
            {
                
            }
        }
    }
    
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++) // 静置柜功率分配计算闭环处理
    {
        cabinet_inside_t  *cab = dev_info_all.cabinet_info.cabinet_inside[i];

        if(mppt_all_power_actual > pcs_power)      // 实际总光伏 > 负载
        {
            double tmp = (pcs_power - stewint_cab_mppt_power);
            

            if(tmp >= 0)
            {
                if(cab_charge_pcs_discharge_max_set > tmp)
                {
                    
                    if(cab->cab_ctrl.bms_exp_power < 0) // 如果是期望充电
                    {
                        cab->cab_ctrl.pcs_exp_power = tmp * (mppt_all_power_charge_cab == 0 ? (cab->cab_ctrl.pcs_discharge_max_set / cab_charge_pcs_discharge_max_set) : (cab->cab_data.mppt_out_power / mppt_all_power_charge_cab));
                    }
                    else if(cab->cab_ctrl.bms_exp_power > 0) // 如果是期望放电
                    {
                        cab->cab_ctrl.pcs_exp_power = 0;            
                    }
                }
                else 
                {
                    if(cab->cab_ctrl.bms_exp_power > 0) // 如果是期望放电
                    {
                        // 不足功率让充满电的柜子按照系统最大可充放进行比例分配
                        cab->cab_ctrl.pcs_exp_power = (tmp - cab_charge_pcs_discharge_max_set) * (cab_discharge_pcs_discharge_max_set == 0 ? 0 : (cab->cab_ctrl.pcs_discharge_max_set / cab_discharge_pcs_discharge_max_set));
                    }
                    else if(cab->cab_ctrl.bms_exp_power < 0) // 如果是期望充电
                    {
                        // 按照最大放电功率分配
                        cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.pcs_discharge_max_set;
                    }
                }
            }

            if(cab->cab_ctrl.bms_exp_power == 0)    // 优先消耗
            {
                cab->cab_ctrl.pcs_exp_power = pcs_power * (stewint_cab_mppt_power == 0 ? 0 : (cab->cab_data.mppt_out_power / stewint_cab_mppt_power));  // 限制最大输出不超过最大期望(闭环)
                cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.pcs_exp_power > cab->cab_data.mppt_out_power ? cab->cab_data.mppt_out_power : cab->cab_ctrl.pcs_exp_power;
            }

        }
        else 
        {
            double tmp = (pcs_power - mppt_all_power_actual) * (cab->cab_ctrl.pcs_discharge_max_set / MAX(all_max_actual_dis_power, 1));
            cab->cab_ctrl.pcs_exp_power = cab->cab_data.mppt_out_power + tmp;
        }
    }

    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)  // 只为总光伏>负载且静置光伏功率充裕的充电柜配比功率
    {
        cabinet_inside_t  *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        if(mppt_all_power_actual >= pcs_power)      // 实际总光伏 > 负载
        {
            if(stewint_cab_mppt_power <= pcs_power) // 静置柜光不充足
            {
            }
            else 
            {
                if(cab->cab_ctrl.bms_exp_power < 0) // 如果是期望充电
                {
                    double tmp = -cab->cab_data.mppt_out_power - cab->cab_ctrl.bms_exp_power;
                    
                    cab->cab_ctrl.pcs_exp_power = cab_power_sw_exp_power * (tmp / cab_charge_max);
                }
            }
        }

        UD_log_sprintf(micro_log, "\n cab[%d]期望功率: %f", i, cab->cab_ctrl.pcs_exp_power);
        BUSINESS_LOG(LOG_NOTICE, DC_ID_0015, cab->no, "[直流耦合]: cab[%d]期望功率: %f", i, cab->cab_ctrl.pcs_exp_power);
    }
    return 0;

}

int cab_pcs_chargpower(double dis_power, double charge_power)
{
    double exp_charge_power = 0, exp_charge_power_limit = 0;
    int num_charg_cab = 0;
    for (int i = 0; i < dev_info_all.cabinet_info.num; i++) { // 期望充电的柜子预设好其光伏期望功率(未限幅)
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        if(cab->cab_ctrl.bms_exp_power < 0) // 期望充
        {
            cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.bms_exp_power + cab->cab_data.mppt_out_power;
            exp_charge_power += (cab->cab_data.mppt_out_power + cab->cab_ctrl.bms_exp_power) < cab->cab_ctrl.pcs_charge_max_set ? cab->cab_ctrl.pcs_charge_max_set : (cab->cab_data.mppt_out_power + cab->cab_ctrl.bms_exp_power);
            num_charg_cab++; 
        }
    }

    exp_charge_power_limit = exp_charge_power < charge_power ? charge_power : exp_charge_power;

    for (int i = 0; i < dev_info_all.cabinet_info.num; i++)     // 期望充电的柜子预设好其期望充电功率
    {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        if(num_charg_cab && cab->cab_ctrl.bms_exp_power < 0) // 期望充
        {
            double tmp = exp_charge_power_limit * ( exp_charge_power == 0 ? 0 : (((cab->cab_data.mppt_out_power + cab->cab_ctrl.bms_exp_power) < cab->cab_ctrl.pcs_charge_max_set ? cab->cab_ctrl.pcs_charge_max_set : (cab->cab_data.mppt_out_power + cab->cab_ctrl.bms_exp_power)) / exp_charge_power));
            cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.pcs_exp_power < tmp ? tmp : cab->cab_ctrl.pcs_exp_power;    // 充进来 
            cab->cab_ctrl.mppt_exp_power = cab->cab_ctrl.mppt_exp_power > -cab->cab_ctrl.bms_exp_power ? -cab->cab_ctrl.bms_exp_power : cab->cab_ctrl.mppt_exp_power;
        }
        
        if(cab->cab_ctrl.bms_exp_power > 0) // 期望放
        {
            cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.mppt_exp_power > dis_power ? dis_power : cab->cab_ctrl.mppt_exp_power; // BMS 提供
        }
        
        if(cab->cab_ctrl.bms_exp_power == 0)
        {
            cab->cab_ctrl.pcs_exp_power = cab->cab_data.mppt_out_power > dis_power ? dis_power : cab->cab_data.mppt_out_power;     // 保持光伏提供
        }
        UD_log_sprintf(micro_log, "\ncab[%d]柜期望功率: %lf", i, cab->cab_ctrl.pcs_exp_power);
        BUSINESS_LOG(LOG_NOTICE, DC_ID_0016, cab->no, "[直流耦合]: cab[%d]期望功率: %f", i, cab->cab_ctrl.pcs_exp_power);
    }

    return 0;
}

int cab_pcs_stewing(double dis_power)
{
    double exp_charge_power = 0, charge_power = 0;
    int num_charg_cab = 0;
    int num_discharge_cab = 0;

    for (int i = 0; i < dev_info_all.cabinet_info.num; i++) {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        if(cab->cab_ctrl.bms_exp_power < 0) // 期望充
        {
            num_charg_cab++; 
        }
        else {
            charge_power += cab->cab_data.pcs_output_power; // 获取其他柜子输出的功率 若有会充入其他柜
            num_discharge_cab++;
        }
    }
    for (int i = 0; i < dev_info_all.cabinet_info.num; i++) { 
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        if(cab->cab_ctrl.bms_exp_power < 0) // 期望充
        {
            cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.pcs_exp_power <= charge_power / num_charg_cab ? cab->cab_ctrl.pcs_exp_power : charge_power / num_charg_cab;
            
            // 没充满的柜子记录需求功率 
            exp_charge_power += cab->cab_ctrl.bms_exp_power + cab->cab_data.mppt_out_power; 
        }
    }

    exp_charge_power = exp_charge_power < charge_power ? charge_power : exp_charge_power;

    for (int i = 0; i < dev_info_all.cabinet_info.num; i++)    
    {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        if(num_charg_cab && cab->cab_ctrl.bms_exp_power < 0) // 期望充
        {
            double tmp = exp_charge_power / num_charg_cab;
            cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.pcs_exp_power > tmp ? tmp : cab->cab_ctrl.pcs_exp_power;    // 充进来 
        }
        
        if(cab->cab_ctrl.bms_exp_power > 0) // 期望放
        {
            cab->cab_ctrl.pcs_exp_power = cab->cab_ctrl.mppt_exp_power; // BMS 提供光伏期望放出功率 优先消纳储能 直到SOC归中
        }
        
        if(cab->cab_ctrl.bms_exp_power == 0)
        {
            cab->cab_ctrl.pcs_exp_power = cab->cab_data.mppt_out_power;     // 保持光伏提供
        }
    }

    return 0;
}


int info_set_data_callback(cabinet_inside_t *cab, void *arg)
{
    if(NULL == arg)
    {
        return 0;
    }
    
    struct Photovoltaic_power_adjust *inf = (struct Photovoltaic_power_adjust *)arg;

    Photovoltaic_adjust_info_set_data(inf, cab->cab_data.pcs_output_power, (double)1 / dev_info_all.cabinet_info.num, inf->num);

    inf->num++;

    return 0;
}

int info_set_mppt_power_callback(cabinet_inside_t *cab, void *arg)
{
    if(NULL == arg)
    {
        return 0;
    }
    struct Photovoltaic_power_adjust *inf = (struct Photovoltaic_power_adjust *)arg;
    cab->cab_ctrl.mppt_exp_power = inf->info[inf->num].power_set - cab->cab_ctrl.bms_exp_power;
    if(cab->cab_ctrl.mppt_exp_power > (-cab->cab_ctrl.bms_exp_power + cab->cab_ctrl.pcs_exp_power))  // 考虑BMS 、PCS的功率需求限幅
        cab->cab_ctrl.mppt_exp_power = (-cab->cab_ctrl.bms_exp_power + cab->cab_ctrl.pcs_exp_power);
    inf->num++;

    // cab->cab_ctrl.mppt_exp_power -= cab->cab_ctrl.bms_exp_power;
    if(cab->cab_ctrl.bms_exp_power > 0)
    {
        cab->cab_ctrl.mppt_exp_power = 0;   // 先写死为0
    }
    
    else if(cab->cab_ctrl.bms_exp_power == 0)
    {
        if(cab->cab_ctrl.mppt_exp_power > (-cab->cab_ctrl.pcs_charge_max_actual))  // 考虑BMS 、PCS的功率需求限幅
            cab->cab_ctrl.mppt_exp_power = (-cab->cab_ctrl.pcs_charge_max_actual);
    }
    else {
        if(cab->cab_ctrl.mppt_exp_power > (-cab->cab_ctrl.bms_exp_power + cab->cab_ctrl.pcs_exp_power))  // 考虑BMS 、PCS的功率需求限幅
            cab->cab_ctrl.mppt_exp_power = (-cab->cab_ctrl.bms_exp_power + cab->cab_ctrl.pcs_exp_power);
    }
    UD_log_sprintf(micro_log, "\n cab[%s]光伏总需求: %lf", cab->no, cab->cab_ctrl.mppt_exp_power);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0017, cab->no, "[直流耦合]: cab[%s]光伏总需求: %lf", cab->no, cab->cab_ctrl.mppt_exp_power);
    return 0;
}


int cabinet_mppt_and_bms_power_set_dispower(cabinet_inside_t *cab)
{
    cab->cab_ctrl.mppt_exp_power -= cab->cab_ctrl.bms_exp_power;
    if(cab->cab_ctrl.bms_exp_power > 0)
    {
        cab->cab_ctrl.mppt_exp_power = 0;   // 先写死为0
    }
    
    else if(cab->cab_ctrl.bms_exp_power == 0)
    {
        if(cab->cab_ctrl.mppt_exp_power > (-cab->cab_ctrl.pcs_charge_max_actual))  // 考虑BMS 、PCS的功率需求限幅
            cab->cab_ctrl.mppt_exp_power = (-cab->cab_ctrl.pcs_charge_max_actual);
    }
    else {
        if(cab->cab_ctrl.mppt_exp_power > (-cab->cab_ctrl.bms_exp_power + cab->cab_ctrl.pcs_exp_power))  // 考虑BMS 、PCS的功率需求限幅
            cab->cab_ctrl.mppt_exp_power = (-cab->cab_ctrl.bms_exp_power + cab->cab_ctrl.pcs_exp_power);
    }

    return 0;
}

int cab_charge_info_set_data_callback(cabinet_inside_t *cab, void *arg)
{
    if(NULL == arg)
    {
        return 0;
    }

    struct Photovoltaic_power_adjust *inf = (struct Photovoltaic_power_adjust *)arg;

    if(cab->cab_ctrl.bms_exp_power < 0)    // 期望静置
    {
        Photovoltaic_adjust_info_set_data(inf, 0, (double)1 / dev_info_all.cabinet_info.num, inf->num);
    }

    if(cab->cab_ctrl.bms_exp_power == 0)    // 期望静置
    {
        Photovoltaic_adjust_info_set_data(inf, cab->cab_data.pcs_output_power, (double)1 / dev_info_all.cabinet_info.num, inf->num);
    }
    
    if(cab->cab_ctrl.bms_exp_power > 0)     // 期望放
    {
        Photovoltaic_adjust_info_set_data(inf, cab->cab_data.pcs_output_power, (double)1 / dev_info_all.cabinet_info.num, inf->num);
    }
    inf->num++;

    return 0;
}

int cab_charge_info_set_mppt_power_callback(cabinet_inside_t *cab, void *arg)
{
    if(NULL == arg)
    {
        return 0;
    }
    

    struct Photovoltaic_power_adjust *inf = (struct Photovoltaic_power_adjust *)arg;
    cab->cab_ctrl.mppt_exp_power = inf->info[inf->num].power_set;
    inf->num++;
    return 0;
}

/*目前仅支持放电*/
int Multi_cabinet_power_distribution(double exp_power)
{
    UD_log_sprintf(micro_log, "\n直流多柜光伏动态调度算法:放电调度算法");

    if(dev_info_all.cabinet_info.num <= 0)
    {
        ems_syslog(LOG_ERR, "Multi_cabinet_power_distribution: not find cab");
        return -1;
    }

    UD_log_sprintf(micro_log, "\nPCS期望放电:");

    
    double all_mppt_power = 0,all_bms_power = 0,pcs_power_tmp = 0;

    if (microgrid_ctrl.choose_func == STRATAGY_TYPE_TOU &&  microgrid_ctrl.current_tou_info &&microgrid_ctrl.current_tou_info->strategy == 0 && !microgrid_ctrl.en_anti_reflux)  //TOU的自发自用并且关闭防逆流时候有效
    {
        for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
        {
            cabinet_inside_t  *cab = dev_info_all.cabinet_info.cabinet_inside[i];
            if(cab->cab_ctrl.bms_exp_power < 0)
                all_mppt_power += cab->cab_data.mppt_out_power;
            all_bms_power+= cab->cab_ctrl.bms_exp_power > 0 ? 0 : cab->cab_ctrl.bms_exp_power;
            
        }
        
        pcs_power_tmp = all_mppt_power - all_bms_power; //光伏盈余
        pcs_power_tmp = pcs_power_tmp > 0 ? pcs_power_tmp : 0; //
        pcs_power_tmp = pcs_power_tmp > microgrid_ctrl.current_tou_info->SurplusToGrid ? microgrid_ctrl.current_tou_info->SurplusToGrid : 0;
    }
    cab_pcs_dispower(exp_power + pcs_power_tmp);

    struct Photovoltaic_power_adjust inf = {0};
    
    /*获取所有柜子的期望充电功率(BMS最大可充会限制PCS的最大充电功率,并对bms_exp_power限幅)-仅充电功率,放电功率不参与*/
    double cab_exp_power = 0, cab_mppt_outpower = 0;
    for(int i = 0; i < dev_info_all.cabinet_info.num; i++)
    {
        cabinet_inside_t  *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        cab_exp_power -= cab->cab_ctrl.bms_exp_power < 0 ? cab->cab_ctrl.bms_exp_power : 0;
        if(cab->cab_ctrl.bms_exp_power < 0)
            cab_mppt_outpower += cab->cab_data.mppt_out_power;
    }

    Photovoltaic_adjust_init(&inf, exp_power + cab_mppt_outpower, microgrid_ctrl.mppt_eq, microgrid_ctrl.mppt_eq_tl, microgrid_ctrl.mppt_eq_rt, dev_info_all.cabinet_info.num);
    
    inf.num = 0;    // 重新置数以便于回调访问
    traverse_cab_dev_func_arg(info_set_data_callback, &inf);
    Photovoltaic_regulation_algorithm(&inf);    // 算法调用

    inf.num = 0;    // 重新置数以便于回调访问

    UD_log_sprintf(micro_log, "\n柜光伏总需求:");
    traverse_cab_dev_func_arg(info_set_mppt_power_callback, &inf);

    if(inf.info)
    {
        free(inf.info);
    }

    return 0;

}
int Multi_cabinet_power_distribution_charge(double exp_power, double charge_max)
{
    UD_log_sprintf(micro_log, "\n直流多柜光伏动态调度算法:充电调度算法");

    if(dev_info_all.cabinet_info.num <= 0)
    {
        ems_syslog(LOG_ERR, "Multi_cabinet_power_distribution: not find cab");
        return -1;
    }

    double exp_charge_power = 0;
    int num_discharg_cab = 0;
    for (int i = 0; i < dev_info_all.cabinet_info.num; i++) { // 期望充电的柜子预设好其光伏期望功率(未限幅)
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        cab->cab_ctrl.mppt_exp_power = 0;   // 重置为0 以便后续计算
        if(cab->cab_ctrl.bms_exp_power < 0) // 期望充
        {
            exp_charge_power += cab->cab_ctrl.pcs_exp_power;
        }
        if(cab->cab_ctrl.bms_exp_power >= 0) // 期望充
        {
            num_discharg_cab++;
        }
    }


    struct Photovoltaic_power_adjust inf = {0};
    Photovoltaic_adjust_init(&inf, exp_power - exp_charge_power, microgrid_ctrl.mppt_eq, microgrid_ctrl.mppt_eq_tl, microgrid_ctrl.mppt_eq_rt, dev_info_all.cabinet_info.num);
    
    inf.num = 0;    // 重新置数以便于回调访问
    traverse_cab_dev_func_arg(cab_charge_info_set_data_callback, &inf);
    
    Photovoltaic_regulation_algorithm(&inf);    // 算法调用

    inf.num = 0;    // 重新置数以便于回调访问
    traverse_cab_dev_func_arg(cab_charge_info_set_mppt_power_callback, &inf);
    UD_log_sprintf(micro_log, "\nPCS期望功率:");
    cab_pcs_chargpower(exp_power, charge_max);
    traverse_cab_dev_func(cabinet_mppt_and_bms_power_set);
    
    if(inf.info)
    {
        free(inf.info);
    }

    

    return 0;

}
int Multi_cabinet_power_distribution_stewing(double exp_power)
{
    UD_log_sprintf(micro_log, "\n直流多柜光伏动态调度算法:静置调度算法");

    if(dev_info_all.cabinet_info.num <= 0)
    {
        ems_syslog(LOG_ERR, "Multi_cabinet_power_distribution: not find cab");
        return -1;
    }

    double exp_charge_power = 0;
    int num_discharg_cab = 0;
    for (int i = 0; i < dev_info_all.cabinet_info.num; i++) { // 期望充电的柜子预设好其光伏期望功率(未限幅)
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        cab->cab_ctrl.mppt_exp_power = 0;   // 重置为0 以便后续计算
        if(cab->cab_ctrl.bms_exp_power < 0) // 期望充
        {
            exp_charge_power += cab->cab_ctrl.pcs_exp_power;
        }
        if(cab->cab_ctrl.bms_exp_power >= 0) // 期望充
        {
            num_discharg_cab++;
        }
    }


    struct Photovoltaic_power_adjust inf = {0};
    Photovoltaic_adjust_init(&inf, (int)exp_power - (int)exp_charge_power, microgrid_ctrl.mppt_eq, microgrid_ctrl.mppt_eq_tl, microgrid_ctrl.mppt_eq_rt, dev_info_all.cabinet_info.num);
    
    inf.num = 0;    // 重新置数以便于回调访问
    traverse_cab_dev_func_arg(cab_charge_info_set_data_callback, &inf);
    
    Photovoltaic_regulation_algorithm(&inf);    // 算法调用

    inf.num = 0;    // 重新置数以便于回调访问
    traverse_cab_dev_func_arg(cab_charge_info_set_mppt_power_callback, &inf);
    UD_log_sprintf(micro_log, "\nPCS期望功率:");
    cab_pcs_chargpower(exp_power, 0);
    UD_log_sprintf(micro_log, "\n柜光伏总需求:");
    traverse_cab_dev_func(cabinet_mppt_and_bms_power_set);
    
    if(inf.info)
    {
        free(inf.info);
    }
    // cab_pcs_chargpower(exp_power, charge_max);

    

    return 0;

}
int cabinet_mppt_and_bms_power_set(cabinet_inside_t *cab)
{
    cab->cab_ctrl.mppt_exp_power -= cab->cab_ctrl.bms_exp_power;
    if(cab->cab_ctrl.bms_exp_power > 0)
    {
        cab->cab_ctrl.mppt_exp_power = 0;   // 先写死为0
    }
    
    else if(cab->cab_ctrl.bms_exp_power == 0)
    {
        if(cab->cab_ctrl.mppt_exp_power > (-cab->cab_ctrl.pcs_charge_max_actual))  // 考虑BMS 、PCS的功率需求限幅
            cab->cab_ctrl.mppt_exp_power = (-cab->cab_ctrl.pcs_charge_max_actual);
    }
    else {
        if(cab->cab_ctrl.mppt_exp_power > (-cab->cab_ctrl.bms_exp_power - cab->cab_ctrl.pcs_exp_power))  // 考虑BMS 、PCS的功率需求限幅
            cab->cab_ctrl.mppt_exp_power = (-cab->cab_ctrl.bms_exp_power - cab->cab_ctrl.pcs_exp_power);
    }
    UD_log_sprintf(micro_log, "\ncab[%s]柜期望功率: %lf", cab->no, cab->cab_ctrl.pcs_exp_power);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0018, cab->no, "[直流耦合]: cab[%s]柜期望功率: %lf", cab->no, cab->cab_ctrl.pcs_exp_power);

    return 0;
}

/**
 * @description: 获取柴发输出功率   目前柴发不见得能获取功率，需基于柴发表
 * @return {*}
 */
double GD_get_out_power()
{
    return microgrid_cfg.en_dg_meter ? dev_info_all.meter_dg.meter_dg_param[0].info.meter_dg_data.act_power : 0;
}

/**
 * @description: 一次性下发控制值
 * @param {int} set_value       
 * @param {int} check_time_s    检查时间间隔 单位:秒
 * @return {*}
 */
int dido_dg_ctrl_set(int set_value, int check_time_s) 
{

    struct dido_ctrl_t *dido_ctrl = &dev_info_all.dido.dido_param[0].info.dido_ctrl;

    dev_set_dev_tag_int(DEV_NO_EMS, DG_CTRL, dido_ctrl->DG_ctrl);
    dev_set_dev_tag_int(DEV_NO_EMS, LCB_CTRL, dido_ctrl->lcb_ctrl);
    dev_set_dev_tag_int(DEV_NO_EMS, ICB_CTRL, dido_ctrl->icb_ctrl);

    return 0;

}

/**
 * @description: 设置负载断路器(内置检查)
 * @param {int} set_value: 1:设置闭合  0:设置断开
 * @return {*}  0:成功  1:失败
 */
int dido_set_lcb(int set_value, int flag)
{
    struct dido_ctrl_t *dido_ctrl = &dev_info_all.dido.dido_param[0].info.dido_ctrl;
    struct dido_data_t *dido_data = &dev_info_all.dido.dido_param[0].info.dido_data;
    int ret = 0;
    collector_write_one_int_data(DEV_NO_EMS"."LCB_CTRL, set_value);
    dido_ctrl->lcb_ctrl = set_value;
    if(flag)
    {
        release_confirmation(
            collector_write_one_int_data(DEV_NO_EMS"."LCB_CTRL, set_value),
             (Relevant_data_refresh(), dido_data->lcb_sign == set_value),
              1, 10, ret);
    }
    return ret;
}

/**
 * @description: 设置并网断路器(内置检查)       注！若下发控制值与读取信号值一致 将不予下发
 * @param {int} set_value: 1:设置闭合  0:设置断开  
 * @param {int} flag: 0:单次下发不校验  1:校验
 * @return {*}  0:成功  1:失败
 */
int dido_set_icb(int set_value, int flag)
{
    struct dido_ctrl_t *dido_ctrl = &dev_info_all.dido.dido_param[0].info.dido_ctrl;
    struct dido_data_t *dido_data = &dev_info_all.dido.dido_param[0].info.dido_data;
    int ret = 0;
    if(microgrid_cfg.en_icb && dido_data->icb_sign != set_value)
    {
        dido_ctrl->icb_ctrl = set_value;
        collector_write_one_int_data(DEV_NO_EMS"."ICB_CTRL, set_value);
        if(flag)
        {
            release_confirmation(
                collector_write_one_int_data(DEV_NO_EMS"."ICB_CTRL, set_value), 
                (Relevant_data_refresh(), !(dido_data->icb_sign == set_value)), 
                1, 10, ret);
            if(ret)
            {
                UD_log_sprintf(micro_log, " \n<设置并离网断路器:[%d]失败 1:设置闭合 0:设置断开>\n", ret);
                BUSINESS_LOG(LOG_NOTICE, DC_ID_0019, "icb", "[直流耦合]: 设置并离网断路器:[%d]失败 1:设置闭合 0:设置断开", ret);
            }
            else 
            {
                UD_log_sprintf(micro_log, " \n<设置并离网断路器成功[%d] 1:设置闭合 0:设置断开>\n", ret);
                BUSINESS_LOG(LOG_NOTICE, DC_ID_0019, "icb", "[直流耦合]: 设置并离网断路器成功[%d] 1:设置闭合 0:设置断开", ret);
            }
            
        }
    }

    return ret;
}

/**
 * @description: 设置柴发启停(内置检查)
 * @param {int} set_value: 1:设置启动  0:设置停止
 * @param {int} flag: 1:校验阻塞确认  0:非校验无阻塞
 * @return {*}  0:成功  1:失败
 */
int set_dg_statu(int set_value, int flag)
{
    struct dido_ctrl_t *dido_ctrl = &dev_info_all.dido.dido_param[0].info.dido_ctrl;
    struct dido_data_t *dido_data = &dev_info_all.dido.dido_param[0].info.dido_data;
    dido_ctrl->DG_ctrl = set_value;
    int ret = 0;
    if(microgrid_cfg.en_diesel_generator)
    {
        if(set_value != dido_ctrl->DG_ctrl || set_value != dido_data->DG_sign)
        {
            collector_write_one_int_data(DEV_NO_EMS"."DG_CTRL, set_value);
            if(flag)
            {
                release_confirmation(collector_write_one_int_data(DEV_NO_EMS"."DG_CTRL, set_value), (Relevant_data_refresh(), dido_data->DG_sign == set_value), 10, 200, ret);
            }
        }

    }
    
    return ret;
}

/**
 * @description: 获取柴发开启状态
 * @return {*}      1:柴发接入  0:系统未接柴发
 */
int get_dg_statu()
{
    if(dev_info_all.dido.dido_param[0].info.dido_data.conn_sign == 1)
        return 1;
    return 0;
}

/**
 * @description: 将MPPT功率写0 常用于状态切换/异常处理
 * @return {*}  1:失败 0:成功 -1:光伏未使能
 */
int mppt_stop()
{
    int ret = 0;

    UD_log_sprintf(micro_log, "\n光伏停摆 目前只是写0功率, 不关机");

    if(microgrid_cfg.en_photovoltaic)    // 光伏使能
    {
        release_confirmation(
            traverse_cab_dev_func(mppt_power_reset),
            (0 == MPPT_set_power(0, 1) && traverse_cab_dev_func(mppt_power_check_power)),
            6,
            30,
            ret
        );
    }
    if(ret)
    {
        UD_log_sprintf(micro_log, "\n光伏功率下发接口无效");
    }
    return ret;
}

/**
 * @description: 将MPPT功率写0 常用于状态切换/异常处理
 * @return {*}  1:失败 0:成功 -1:光伏未使能
 */
int pcs_stop()
{
    int ret = 0;
    /**///ems_syslog(LOG_ERR,"mppt_stop");

    release_confirmation(
        traverse_cab_dev_func(pcs_power_reset),
        (0 == PCS_set_power(0, 1) && traverse_cab_dev_func(pcs_power_check_power)),
        1,
        10,
        ret
    );
    
    /**///ems_syslog(LOG_ERR,"mppt_stop 结束");

    return ret;
}

/**
 * @description: 
 * @param {double} power_exp: PCS期望设置功率 下发到柜期望功率
 * @return {*}
 */
int PCS_set_power_cab(double power_exp)
{
    power_exp = power_exp > microgrid_ctrl.dischargeMaxPower ? microgrid_ctrl.dischargeMaxPower : power_exp;
    power_exp = power_exp < microgrid_ctrl.chargeMaxPower ? microgrid_ctrl.chargeMaxPower : power_exp;
    
    traverse_cab_dev_func_arg(test_pcs_set_power, &power_exp);
    
    return 0;
    
}

/**
 * @description: 
 * @param {double} power_exp: PCS期望设置功率   上次下发功率与本次下发功率相同 将不予调用下发接口直接退出函数(有另外机制支持同功率情况依旧能下发功率)
 * @param {int} flag: 1:可靠下发 阻塞时间间隔将指令下发  0:不可靠下发, 不阻塞 会抛弃功率下发快速遍历
 * @return {*}
 */
int PCS_set_power(double power_exp, int flag)
{
    dev_set_dev_tag_float(DEV_NO_EMS, LOCAL_CTRL_POWER, power_exp);
    UD_log_sprintf(micro_log, "\n<PCS 期望功率 = %lf\n", power_exp);

    if(power_exp > microgrid_ctrl.dischargeMaxPower)
    {
        power_exp = microgrid_ctrl.dischargeMaxPower;
    }
    if(power_exp < microgrid_ctrl.chargeMaxPower)
    {
        power_exp = microgrid_ctrl.chargeMaxPower;
    }
    UD_log_sprintf(micro_log, "系统最大放电功率：%lf, 系统最大充电功率:%lf\nPCS 限制后功率 = %lf (负充正放)>\n", microgrid_ctrl.dischargeMaxPower, microgrid_ctrl.chargeMaxPower, power_exp);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0008, NULL, "[直流耦合]: 系统最大放电功率：%lf, 系统最大充电功率:%lf PCS 限制后功率 = %lf (负充正放)", microgrid_ctrl.dischargeMaxPower, microgrid_ctrl.chargeMaxPower, power_exp);

    microgrid_ctrl.pcs_exp_power = power_exp;

    traverse_cab_dev_func_arg(set_all_pcs_exp_power, &flag);
    return 0;
    
}

void Microgrid_soc_decision()
{
    int power = 0;
    int repower = 0;
    int socmax = 0;
    int socmin = 0;

    if(microgrid_ctrl.en_DOD == 1) {
        if (microgrid_ctrl.choose_func == STRATAGY_TYPE_TOU && microgrid_ctrl.current_tou_info) {
            microgrid_ctrl.SOC_max_combin = microgrid_ctrl.current_tou_info->SOCUpperLimit; // 
            microgrid_ctrl.SOC_min_combin = microgrid_ctrl.current_tou_info->SOCLowerLimit;//
        } else if (microgrid_ctrl.choose_func == STRATAGY_TYPE_PERIOD_CTRL) {
            (void)get_current_plan(&g_usercfg_variant, &power, &repower, &socmax, &socmin);
            microgrid_ctrl.SOC_max_combin = socmax;
            microgrid_ctrl.SOC_min_combin = socmin;
        }
        microgrid_ctrl.SOC_max_combin = MIN(dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_MAX), microgrid_ctrl.SOC_max_combin);
        microgrid_ctrl.SOC_min_combin = MAX(dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_MIN), microgrid_ctrl.SOC_min_combin);
        microgrid_ctrl.SOC_max_netdead = dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MAX); // 
        microgrid_ctrl.SOC_min_netdead = dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MIN);
    } else {
        microgrid_ctrl.SOC_max_combin = 100;
        microgrid_ctrl.SOC_min_combin = 0;
        microgrid_ctrl.SOC_max_netdead = 100;
        microgrid_ctrl.SOC_min_netdead = 0;
        microgrid_ctrl.SOCmaxReturnDiff = 0;
        microgrid_ctrl.SOCminReturnDiff = 0;
    }
}

/**
 * @description: 所有数据刷新的接口
 * @return {*} -1:数据获取错误-将影响到业务逻辑执行的错误(错误值会得到错误结果)   0:正常
 */
int Relevant_data_refresh()
{
    /**////**///ems_syslog(LOG_ERR,"\n\n 参数列表========================>");

    /*microgrid_ctrl 刷新 控制参数并不全在此处 会受其他逻辑调控*/
    {
        
        microgrid_ctrl.choose_func = g_usercfg_variant.StratagyType;    // 业务选择
        microgrid_ctrl.ControlMode = g_usercfg_variant.ControlMode;
        if (microgrid_ctrl.ControlMode == EMS_AUTO_MODE &&
            g_usercfg_variant.StratagyType == STRATAGY_TYPE_PERIOD_CTRL)
        {
            microgrid_ctrl.plan_set_power = update_plan_cfg(get_pcs_ctrl_var());
        }  
        microgrid_ctrl.current_tou_info = get_current_TOU_plan(&g_usercfg_variant);
        microgrid_ctrl.dg_rated_power = dev_get_dev_tag_float(DEV_NO_EMS, DG_RATED_POWER);
        microgrid_ctrl.dg_boot_soc = dev_get_dev_tag_float(DEV_NO_EMS, DG_BOOT_SOC);
        microgrid_ctrl.dg_off_soc = dev_get_dev_tag_float(DEV_NO_EMS, DG_OFF_SOC);
        microgrid_ctrl.MaxDemand = dev_get_dev_tag_int(DEV_NO_EMS, MAX_DEMAND);
        microgrid_ctrl.SurplusPower = dev_get_dev_tag_int(DEV_NO_EMS, SURPLUS_POWER);
        ems_syslog(LOG_DEBUG, "microgrid_ctrl.SurplusPower:%d", microgrid_ctrl.SurplusPower);
        microgrid_ctrl.en_anti_reflux = dev_get_dev_tag_int(DEV_NO_EMS, EN_PROTECT_REVERSE);
        microgrid_ctrl.EnTraceLoad = dev_get_dev_tag_int(DEV_NO_EMS, EN_TRACELOAD);
        microgrid_ctrl.EnProtectTransf = dev_get_dev_tag_int(DEV_NO_EMS, EN_PROTECT_TRANSF);
        microgrid_ctrl.Pmlmax = g_usercfg_variant.Pmlmax;
        microgrid_ctrl.K1 = g_usercfg_variant.K1;
        microgrid_ctrl.TraceLoad = 1.0 - (double )dev_get_dev_tag_int(DEV_NO_EMS, EMS_K2) / 100;
        if(microgrid_ctrl.TraceLoad <= 0 || microgrid_ctrl.TraceLoad > 1)
        {
            microgrid_ctrl.TraceLoad = 1;
        }

        microgrid_ctrl.anti_reflux = dev_get_dev_tag_int(DEV_NO_EMS, EMS_PSET);    //  = Pset 防逆流余量
        microgrid_ctrl.pvMax = dev_get_dev_tag_int(DEV_NO_EMS, PV_MAX_POWER);         //  光伏输出最大功率,光伏系统功率上限
        microgrid_ctrl.dischargeMaxPower = abs(dev_get_dev_tag_int("EMS", "dischargeMaxPower"));
        microgrid_ctrl.chargeMaxPower =  -abs(dev_get_dev_tag_int("EMS", "chargeMaxPower"));
        traverse_cab_dev_func(traverse_dev_cfg_callback); // 最大可充可放功率，同步到每个柜子
        microgrid_ctrl.SOCmaxReturnDiff = dev_get_dev_tag_int(DEV_NO_EMS, EMS_SOCMAXERR); //  = SOCmaxReturnDiff;
        microgrid_ctrl.SOCmaxReturnDiff = microgrid_ctrl.SOCmaxReturnDiff <= 0 ? 0 : microgrid_ctrl.SOCmaxReturnDiff;
        microgrid_ctrl.SOCminReturnDiff = dev_get_dev_tag_int(DEV_NO_EMS, EMS_SOCMINERR); //  = SOCmaxReturnDiff;
        microgrid_ctrl.SOCminReturnDiff = microgrid_ctrl.SOCminReturnDiff <= 0 ? 0 : microgrid_ctrl.SOCminReturnDiff;
        microgrid_ctrl.en_DOD = dev_get_dev_tag_int(DEV_NO_EMS, EN_PROTECT_DOD);
        microgrid_ctrl.mppt_eq_tl = dev_get_dev_tag_int(DEV_NO_EMS, MPPT_EQ_TL);
        microgrid_ctrl.mppt_eq = microgrid_ctrl.mppt_eq_tl;
        microgrid_ctrl.mppt_eq_rt = dev_get_dev_tag_int(DEV_NO_EMS, MPPT_EQ_RT);
        // SOC参数置为 确保在微网环境下的并、离网soc不会超过或低于DOD 告警soc
        {   
            double dod_max = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMAX);
            double dod_min = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMIN);
    
            if(dod_max < dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_MAX))
            {
                dev_set_dev_tag_float(DEV_NO_EMS, SOC_NET_MAX, dod_max);
            }
    
            if(dod_min > dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_MIN))
            {
                dev_set_dev_tag_float(DEV_NO_EMS, SOC_NET_MIN, dod_min);
            }
    
            if(dod_max < dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MAX))
            {
                dev_set_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MAX, dod_max);
            }
    
            if(dod_min > dev_get_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MIN))
            {
                dev_set_dev_tag_float(DEV_NO_EMS, SOC_NET_DEAD_MIN, dod_min);
            }
        }

        Microgrid_soc_decision(); // 计算微网soc上下限
        
        // microgrid_ctrl.DemandErr = g_usercfg_variant.Pmlmax; // TODO
        microgrid_ctrl.Pmlmax = dev_get_dev_tag_int(DEV_NO_EMS, EMS_PMLMAX);
        microgrid_ctrl.pcs_auto_turn = dev_get_dev_tag_int(DEV_NO_EMS, PCS_AUTO_TURN);
        microgrid_ctrl.pcs_auto_turn_off_time = dev_get_dev_tag_int(DEV_NO_EMS, PCS_AUTO_TURN_OFF_TIME);
        // microgrid_ctrl.SOC_RTM = microgrid_ctrl.SOC_max_combin;
        microgrid_ctrl.PmlmaxDiff = dev_get_dev_tag_float(DEV_NO_EMS, DEMAND_MARGIN);
        microgrid_ctrl.PmlmaxDiff = microgrid_ctrl.PmlmaxDiff == 0 ? 30 : microgrid_ctrl.PmlmaxDiff;
        microgrid_ctrl.DgDiff = dev_get_dev_tag_float(DEV_NO_EMS, EMS_DG_DIFF);
        microgrid_ctrl.SocAlarmThreshold = dev_get_dev_tag_int(DEV_NO_EMS, SOC_ALARM);
        microgrid_ctrl.en_ac_c2d = dev_get_dev_tag_int(DEV_NO_EMS, EN_SW_C2D);
        microgrid_ctrl.en_ac_d2c = dev_get_dev_tag_int(DEV_NO_EMS, EN_SW_D2C);
        microgrid_ctrl.action_timeout = dev_get_dev_tag_int(DEV_NO_EMS, ACTION_TIMEOUT);
        microgrid_ctrl.EnProtectTrasLV = dev_get_dev_tag_int(DEV_NO_EMS, ENPROTECTRASLV);
        microgrid_ctrl.PLVmlmax = dev_get_dev_tag_int(DEV_NO_EMS, PLVMLMAX);
        microgrid_ctrl.k4 = dev_get_dev_tag_int(DEV_NO_EMS, EMS_K4);
        microgrid_ctrl.DG_cap_pro = dev_get_dev_tag_int(DEV_NO_EMS, DG_CAP_PRO);
        microgrid_ctrl.en_bms_power_limit = dev_get_dev_tag_int(DEV_NO_EMS, BMS_POWER_LIMIT);
        microgrid_ctrl.pv_km = dev_get_dev_tag_int(DEV_NO_EMS, PV_KM);
        microgrid_ctrl.pv_mode = dev_get_dev_tag_int(DEV_NO_EMS, PV_MODE);
        microgrid_ctrl.pv_isctrl = dev_get_dev_tag_int(DEV_NO_EMS, PV_ISCTRL);
        microgrid_ctrl.dead_night = dev_get_dev_tag_int(DEV_NO_EMS, DEAD_NIGHT);
        microgrid_ctrl.DemandDiff = dev_get_dev_tag_int(DEV_NO_EMS, DYNAMIC_AUGMENT);
        microgrid_ctrl.sleep_pcs = dev_get_dev_tag_int(DEV_NO_EMS, EMS_ADJPRERIOD);
        microgrid_ctrl.auto_off = dev_get_dev_tag_int(DEV_NO_EMS, PCS_AUTO_TURN);
        microgrid_ctrl.EnPvPrectrl = dev_get_dev_tag_int(DEV_NO_EMS, EN_PV_PRECTRL);
        microgrid_ctrl.EnPhaseCtrl = dev_get_dev_tag_int(DEV_NO_EMS, ENABLE_SINGLE_PHASE_REVERSE);

        microgrid_ctrl.volmax = (int)(dev_get_dev_tag_float(DEV_NO_EMS, SINGLE_MAX_VOLTAGE)*1000);
        microgrid_ctrl.volmaxerr = (int)(dev_get_dev_tag_float(DEV_NO_EMS, SINGLE_MAX_VOLTAGE_ERR)*1000);
        microgrid_ctrl.volmin = (int)(dev_get_dev_tag_float(DEV_NO_EMS, SINGLE_MIN_VOLTAGE)*1000);
        microgrid_ctrl.volminerr = (int)(dev_get_dev_tag_float(DEV_NO_EMS, SINGLE_MIN_VOLTAGE_ERR)*1000);
        microgrid_ctrl.EN_CELL_VOLT = dev_get_dev_tag_int(DEV_NO_EMS, EN_CELL_VOLT_PROTECT);
        microgrid_ctrl.singleV_sleep = dev_get_dev_tag_int(DEV_NO_EMS, CELL_VOLT_PROTECT_TIME);

        if (microgrid_ctrl.choose_func == STRATAGY_TYPE_TOU && microgrid_ctrl.current_tou_info)
        {
            microgrid_ctrl.upper_limit = microgrid_ctrl.current_tou_info->DischargePower;
            microgrid_ctrl.lower_limit = microgrid_ctrl.current_tou_info->ChargePower;
            microgrid_ctrl.DemandStartHour = 0;//tou全时段可以充电 不想要充电用户可以分时段配置下限
            microgrid_ctrl.DemandStartMin = 0;
            
            microgrid_ctrl.DemandEndHour = 24;
            microgrid_ctrl.DemandEndMin = 0;
        }
        else
        {
            microgrid_ctrl.upper_limit = dev_get_dev_tag_int(DEV_NO_EMS, EMS_DISCHARGE_THRESHOLD);
            microgrid_ctrl.lower_limit = dev_get_dev_tag_int(DEV_NO_EMS, EMS_CHARGE_STARTPOWER);
            microgrid_ctrl.DemandStartHour = dev_get_dev_tag_int(DEV_NO_EMS, EMS_DEMAND_START_HOUR);
            microgrid_ctrl.DemandStartMin = dev_get_dev_tag_int(DEV_NO_EMS, EMS_DEMAND_START_MIN);
            
            microgrid_ctrl.DemandEndHour = dev_get_dev_tag_int(DEV_NO_EMS, EMS_DEMAND_END_HOUT);
            microgrid_ctrl.DemandEndMin = dev_get_dev_tag_int(DEV_NO_EMS, EMS_DEMAND_END_MIN);
        }
        


        {
            if(microgrid_ctrl.DemandEndHour <= microgrid_ctrl.DemandStartHour && microgrid_ctrl.DemandEndMin <= microgrid_ctrl.DemandStartMin)      // 防呆设计
            {
                if(microgrid_ctrl.DemandEndHour != microgrid_ctrl.DemandStartHour || microgrid_ctrl.DemandEndMin != microgrid_ctrl.DemandStartMin)
                {
                    dev_set_dev_tag_int(DEV_NO_EMS, EMS_DEMAND_END_HOUT, microgrid_ctrl.DemandStartHour);
                    dev_set_dev_tag_int(DEV_NO_EMS, EMS_DEMAND_END_MIN, microgrid_ctrl.DemandStartMin);
                }
                microgrid_ctrl.DemandEndHour = microgrid_ctrl.DemandStartHour;
                microgrid_ctrl.DemandEndMin = microgrid_ctrl.DemandStartMin;

            }

        }
    }

    microgrid_ctrl.Grid_offgrid = check_connect();
    
    if(1 == microgrid_ctrl.Grid_offgrid)
    {
        microgrid_ctrl.SOC_max = microgrid_ctrl.SOC_max_combin;
        microgrid_ctrl.SOC_min = microgrid_ctrl.SOC_min_combin;
    }
    else if(0 == microgrid_ctrl.Grid_offgrid){   
            microgrid_ctrl.SOC_max = microgrid_ctrl.SOC_max_netdead;
            microgrid_ctrl.SOC_min = microgrid_ctrl.SOC_min_netdead;
    }

    if(MODE_MICROGRID_DC == microgrid_cfg.mode_microgrid){
        microgrid_ctrl.discharge_max_set = 0;   // 先重置为0 再调接口函数将数据刷新 当然 也可用临时变量处理后再赋值 避免门限临时跌入0情况 
        microgrid_ctrl.charge_max_set = 0;
        traverse_cab_dev_func(get_all_en_power);
        /*禁充放保护使能后对系统最大充放电进行优化*/
        if(dev_get_dev_tag_int(DEV_NO_EMS, PROHIBITE_CHARGE))
        {
            microgrid_ctrl.charge_max_set = 0;
            microgrid_ctrl.pvMax = 0;

        }
        if(dev_get_dev_tag_int(DEV_NO_EMS, PROHIBITE_DISCHARGE))
        {
            microgrid_ctrl.discharge_max_set = 0;   
        }
    }
    microgrid_ctrl.pcs_exp_power_actual = 0;
    
    microgrid_data.PhasePower[PHASE_A] = 0;
    microgrid_data.PhasePower[PHASE_B] = 0;
    microgrid_data.PhasePower[PHASE_C] = 0;

    if(MODE_MICROGRID_DC == microgrid_cfg.mode_microgrid) { // 对等模式刷新柜内数据（直流侧耦合）
        microgrid_data.mppt_BusVol = 0;
        microgrid_data.mppt_BusCur = 0;
        microgrid_data.mppt_BusPow = 0;
        microgrid_data.mppt_OnOff = 0;

        microgrid_ctrl.Single_Cell_Vol_Threshold_Alarm = 0;
        traverse_cab_dev_func(pcs_flush_data);
        traverse_cab_dev_func(bms_flush_data);
        dev_set_dev_tag_int(DEV_NO_EMS, SINGLE_CELL_VOL_THRESHOLD_ALARM, microgrid_ctrl.Single_Cell_Vol_Threshold_Alarm);

        traverse_cab_dev_func(mppt_flush_data);

        traverse_cab_dev_func(meter_mppt_flush_data);
        traverse_cab_dev_func(meter_pcs_flush_data);
        traverse_cab_dev_func(get_phase_power_dc);
        pcs_ctrl_var_t *var = get_pcs_ctrl_var();
        if(var->enable_ems)
        {
            // if (var->enable_group_ctrl)
            {
                dev_set_dev_tag_int(DEV_NO_EMS, CONNECT_STATUS , microgrid_ctrl.Grid_offgrid);
                int flag = 1;
                if(traverse_pcs(traverse_pcs_check_connect, NULL, &flag) == 0)
                {
                    dev_set_dev_tag_int(DEV_NO_EMS, ON_OFF_STATUS, 1);
                }
                else
                {
                    dev_set_dev_tag_int(DEV_NO_EMS, ON_OFF_STATUS, 0);
                }
            }
        }

        dev_set_dev_tag_float(DEV_NO_EMS, BUS_V_MPPT, microgrid_data.mppt_BusVol);
        dev_set_dev_tag_float(DEV_NO_EMS, BUS_C_MPPT, microgrid_data.mppt_BusCur);
        dev_set_dev_tag_float(DEV_NO_EMS, BUS_P_MPPT, microgrid_data.mppt_BusPow);
        dev_set_dev_tag_int(DEV_NO_EMS, BUS_O_MPPT, microgrid_data.mppt_OnOff);

    }
    else if(MODE_MICROGRID_AC == microgrid_cfg.mode_microgrid){ // 主从模式刷新柜内数据（交流侧耦合）
        traverse_cab_dev_func(lc_flush_data);
        traverse_cab_dev_func(get_phase_power_ac);
    }
    
    // 柜外数据刷新
    if(MODE_MICROGRID_AC == microgrid_cfg.mode_microgrid)
    {
        microgrid_data.Aphase_V_PV = 0;
        microgrid_data.Bphase_V_PV = 0;
        microgrid_data.Cphase_V_PV = 0;
        microgrid_data.Aphase_C_PV = 0;
        microgrid_data.Bphase_C_PV = 0;
        microgrid_data.Cphase_C_PV = 0;
        meter_pv_flush_data();
        pv_flush_data();
        dev_set_dev_tag_float(DEV_NO_EMS, A_V_PV, microgrid_data.Aphase_V_PV);
        dev_set_dev_tag_float(DEV_NO_EMS, B_V_PV, microgrid_data.Bphase_V_PV);
        dev_set_dev_tag_float(DEV_NO_EMS, C_V_PV, microgrid_data.Cphase_V_PV);
        dev_set_dev_tag_float(DEV_NO_EMS, A_C_PV, microgrid_data.Aphase_C_PV);
        dev_set_dev_tag_float(DEV_NO_EMS, B_C_PV, microgrid_data.Bphase_C_PV);
        dev_set_dev_tag_float(DEV_NO_EMS, C_C_PV, microgrid_data.Cphase_C_PV);
    }
    if(meter_grid_flush_data()) // 关口表功率刷新有误 终止业务
    {
    }
    if(meter_grid_lv_flush_data()) // 关口表功率刷新有误 终止业务
    {
    }
    if(meter_load_flush_data()) // 负载表功率刷新有误 终止业务
    {
    }
    if(meter_dg_flush_data()) // 柴发表功率刷新有误 终止业务
    {
    }


    if (microgrid_ctrl.ControlMode == EMS_AUTO_MODE)
    {
        microgrid_ctrl.plan_set_power = update_plan_cfg(get_pcs_ctrl_var());
    }  
    /**///ems_syslog(LOG_ERR,"\n参数打印:microgrid_ctrl.plan_set_power = %lf\n", microgrid_ctrl.plan_set_power);
    microgrid_ctrl.plan_statu = microgrid_ctrl.plan_set_power > 0 ? DISCHARGE_DIRECTION : (microgrid_ctrl.plan_set_power < 0 ?  CHARGE_DIRECTION: ENERGY_DEFAULT);

    /*microgrid_data 刷新*/
    {
        if(MODE_MICROGRID_AC == microgrid_cfg.mode_microgrid)
        {
            calculate_lc_data();
        }
        else if(MODE_MICROGRID_DC == microgrid_cfg.mode_microgrid)
        {
            double temp_power = 0, temp_repower = 0;
            double PhasePower[PHASE_MAX] = {0};
            traverse_cab_dev_func_arg(get_all_cab_out_power, &temp_power);
            traverse_cab_dev_func_arg(get_all_cab_out_repower, &temp_repower);
            traverse_cab_dev_func_arg(get_all_cab_out_phasepower, PhasePower);
            microgrid_data.pcs_power = temp_power;
            microgrid_data.pcs_repower = temp_repower;
            for(int i = 0; i < PHASE_MAX; i++){
                microgrid_data.PhasePower[i] = PhasePower[i];
            }
            microgrid_data.mppt_power = get_all_mppt_power();
            get_soc_average();
        }
        else {
            // ; 
        }

        microgrid_data.grid_power = dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.act_power;
        microgrid_data.grid_repower = dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.rea_power;
        microgrid_data.grid_appower = dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.appr_power;
        microgrid_data.load_power = dev_info_all.meter_load.meter_load_param[0].info.meter_load_data.power;
        microgrid_data.dg_power = dev_info_all.meter_dg.meter_dg_param[0].info.meter_dg_data.act_power;
        microgrid_data.dg_repower = dev_info_all.meter_dg.meter_dg_param[0].info.meter_dg_data.rea_power;
        
        if (dev_info_all.meter_load.num <= 0) // 若系统没有负载表，则计算负载功率
        {
            if(MODE_MICROGRID_AC == microgrid_cfg.mode_microgrid){
                microgrid_data.load_power = microgrid_data.grid_power + microgrid_data.pcs_power + microgrid_data.pv_power + microgrid_data.dg_power;
            }else if(MODE_MICROGRID_DC == microgrid_cfg.mode_microgrid){
                microgrid_data.load_power = microgrid_data.grid_power + microgrid_data.pcs_power + microgrid_data.dg_power;
            }else {
                // ;
            }
        }
    }

    {
        struct dido_data_t *dido_data = &dev_info_all.dido.dido_param[0].info.dido_data;
        dido_data->conn_sign = dev_get_dev_tag_int(DEV_NO_EMS, CONN_SIGN);
        dido_data->ats_sign = dev_get_dev_tag_int(DEV_NO_EMS, ATS_SIGN);
        dido_data->lcb_sign = dev_get_dev_tag_int(DEV_NO_EMS, LCB_SIGN);
        dido_data->icb_sign = dev_get_dev_tag_int(DEV_NO_EMS, ICB_SIGN);
        dido_data->DG_sign = dev_get_dev_tag_int(DEV_NO_EMS, DG_SIGN);
    }
    
    // /**///ems_syslog(LOG_ERR,"\nmicrogrid_cfg 参数打印\n");
    // print_microgrid_cfg(microgrid_cfg);

    // /**///ems_syslog(LOG_ERR,"\nmicrogrid_ctrl 参数打印\n");
    // print_microgrid_ctrl(microgrid_ctrl);
    
    // /**///ems_syslog(LOG_ERR,"\n柜内设备 数据打印\n");
    // traverse_cab_dev_func(test_cab_info_ptf);
    // test_dev_info_ptf();
    {
        microgrid_abnormal.DG_abnormal = dev_get_dev_tag_int(DEV_NO_EMS, DG_ABNORMAL);
        microgrid_abnormal.icb_abnormal = dev_get_dev_tag_int(DEV_NO_EMS, ICB_ABNORMAL);
        microgrid_abnormal.lcb_abnormal = dev_get_dev_tag_int(DEV_NO_EMS, LCB_ABNORMAL);
    }
    decision_data_flush();
    dev_set_dev_tag_float(DEV_NO_EMS, GRID_ACT_POWER, microgrid_data.grid_power);
    dev_set_dev_tag_float(DEV_NO_EMS, LOAD_ACT_POWER, microgrid_data.grid_power + microgrid_data.pcs_power);

    if(microgrid_ctrl.ControlMode == EMS_AUTO_MODE)
    {
        dev_set_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER, microgrid_data.pcs_power);
        dev_set_dev_tag_float(DEV_NO_EMS, EXPECT_ACT_POWER, microgrid_data.pcs_power);
    }

    return 0;
}


/**
 * @description: 对PCS最大充放电功率规限来保护BMS   参数采取实际限制来处理 实际限制已完成实际设备、系统配置比较取值
 * @return {*}
 */
int cabinet_bms_protect()
{
    for (int i = 0; i < dev_info_all.cabinet_info.num; i++) {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        UD_log_sprintf(micro_log, "\ncab[%d]\n", i); 

        BMS_protect_to_ctrl_PCS(cab);
    }
    return 0;
}


/**
 * @description: 针对多柜模型执行归中算法 在本函数中设置好BMS期望功率并返回
 * @return {*}
 */
double cabinet_bms_centering()
{
    double power = 0;

    traverse_cab_dev_func_arg(cabinet_homingAlgorithmSOC, &power);
    return power;
}

/**
 * @description: 停掉所有能源控制设备的功率
 * @return {*}
 */
void stop_power_allocation()
{
    microgrid_ctrl.pcs_exp_power = 0;
    microgrid_ctrl.mppt_exp_power = 0;
    traverse_cab_dev_func(mppt_power_reset);
    traverse_cab_dev_func(cabinet_pcs_exp_power_set);      // 将0功率分配下去
    PCS_set_power(0, 0);  
    MPPT_set_power(0, 0);
}


/**
 * @description: 设置mppt功率接口 要留意的是 此处期望功率仅是全局功率期望 由于采取单柜模型
                 实际要下发的mppt功率来自于柜中mppt_exp_power功率 并通过scale进行分配
                 本函数调用不会阻塞，但有控制 功率下发 时间间隔与超时下发的机制，留意频繁调用
                 才能将功率正确发送，仅调用一次将大概率导致功率不会成功下发
 * @param {double} exp_power: 期望功率和柜有关 为适配上层结构 面向多柜管理 本期望功率并非真实下发功率进行配比
 * @param {int} flag: 1:可靠下发 0:快速遍历
 * @return {*}
 */
int MPPT_set_power(double exp_power, int flag)
{
    /**///ems_syslog(LOG_ERR,"设mppt功率%lf", exp_power);
    if(0 == microgrid_cfg.en_photovoltaic)
    {
        microgrid_ctrl.mppt_exp_power = 0;      // 总期望功率赋值
        UD_log_sprintf(micro_log, " \n<禁用光伏>\n");

        return 0;
    }
    UD_log_sprintf(micro_log, " \n<使能光伏\nMPPT期望功率:%lf\n", exp_power);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0008, NULL, "[直流耦合]: 使能光伏，MPPT期望功率:%lf", exp_power);

    if(exp_power > microgrid_ctrl.pvMax)
    {
        exp_power = microgrid_ctrl.pvMax;
    }
    if(exp_power < 0)
    {
        exp_power = 0;
    }
    UD_log_sprintf(micro_log, "光伏总最大功率%lf\nMPPT 限制后功率 = %lf>\n",microgrid_ctrl.pvMax, exp_power);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0008, NULL, "[直流耦合]: 光伏总最大功率%lf MPPT 限制后功率 = %lf", microgrid_ctrl.pvMax, exp_power);
    microgrid_ctrl.mppt_exp_power = exp_power;       // 总期望功率赋值

    traverse_cab_dev_func(mppt_power_distribution);     // 将每个单柜功率分配给每个mppt 其期望功率(cab->cab_ctrl.mppt_exp_power)另有逻辑设值
    traverse_cab_dev_func_arg(traverse_mppt_callback_power_set, &flag);

    /**///ems_syslog(LOG_ERR,"设置完毕");
    return 0;
}


/**
 * @description: 期望功率分发给子柜
 * @param {double} pcs_exp_power
 * @return {*}
 */
int set_pcs_exp_out_power(double pcs_exp_power)
{
    /*限幅*/
    microgrid_ctrl.pcs_exp_power = pcs_exp_power > microgrid_ctrl.dischargeMaxPower ? microgrid_ctrl.dischargeMaxPower : pcs_exp_power;
    microgrid_ctrl.pcs_exp_power = pcs_exp_power < microgrid_ctrl.chargeMaxPower ? microgrid_ctrl.chargeMaxPower : pcs_exp_power;

    /*设功率*/
    traverse_cab_dev_func(cabinet_pcs_exp_power_set);

    return 0;

}

/**
 * @description: 设置所有的PCS开关机
 * @param {int} flag 1:开机 0:关机
 * @return {*} 0:成功
 */
int set_pcs_onoff(int flag)
{
    int ret = 1;
    /**///ems_syslog(LOG_ERR,"设置开关机%d", flag);

    if(MODE_MICROGRID_DC == microgrid_cfg.mode_microgrid)
    {
        ret = set_all_pcs_onoff_tag(flag);
        if(0 != ret)
        {
            UD_log_sprintf(micro_log, "\n<PCS 设置开关机失败  设置目标[%d]  0:关机 1:开机>\n", flag);
            BUSINESS_LOG(LOG_NOTICE, DC_ID_0003, "PCS_log", "[直流耦合]: <PCS 设置开关机失败  设置目标[%d]  0:关机 1:开机> 将会进状态异常", flag);

        }
        else 
        {
            UD_log_sprintf(micro_log, "\n<PCS 设置开关机已[%d]  0:关机 1:开机>\n", flag);
            BUSINESS_LOG(LOG_NOTICE, DC_ID_0003, "PCS_log", "[直流耦合]: <PCS 设置开关机已[%d]  0:关机 1:开机>", flag);
        }
    }
    else if(MODE_MICROGRID_AC == microgrid_cfg.mode_microgrid) 
    {
        ret = set_all_pcs_onoff_lc(flag);
    }
    /**///ems_syslog(LOG_ERR,"设置开关机结束");

    return ret;
}


/**
 * @description: 设置所有PCS并离网
 * @param {int} flag 1:并网 0:离网
 * @return {*} 0:成功
 */
int set_pcs_connect(int flag)    /*TODO*/
{
    int ret = 1;
    microgrid_ctrl.Grid_offgrid = flag;
    if(MODE_MICROGRID_DC == microgrid_cfg.mode_microgrid)
    {
        ret = set_all_pcs_connect_tag(flag);
        if(0 != ret)
        {
            UD_log_sprintf(micro_log, "\n<PCS 设置并离网失败  设置目标[%d]  0:离网 1:并网>\n", flag);
            BUSINESS_LOG(LOG_NOTICE, DC_ID_0004, "PCS_log", "[直流耦合]: <PCS 设置并离网失败  设置目标[%d]  0:离网 1:并网>", flag);
        }
        else 
        {
            UD_log_sprintf(micro_log, "\n<PCS 设置并离网已[%d]  0:离网 1:并网>\n", flag);
            BUSINESS_LOG(LOG_NOTICE, DC_ID_0004, "PCS_log", "[直流耦合]: <PCS 设置并离网已[%d]  0:离网 1:并网>", flag);
        }
    }
    else if(MODE_MICROGRID_AC == microgrid_cfg.mode_microgrid) 
    {
        ret = set_all_pcs_connect_lc(flag);
    }

    return ret;
}


/**
 * @description: 检查系统并离网状态(数据源 关口表电压 DIDO(待加))
 * @return {*} 0:离网 1:并网
 */
int check_connect()
{
    if(microgrid_cfg.en_sts)
    {
        int i = microgrid_data.grid_statu;
        if(traverse_pcs(check_all_pcs_connect_status, NULL, &i)) // 当前并离网状态不一致 
        {
            i = 0;
            if(0 == traverse_pcs(check_all_pcs_connect_status, NULL, &i))       // 判是否离网
            {
                microgrid_data.grid_statu = 0;
                return microgrid_data.grid_statu;
            }

            i = 1;
            if(0 == traverse_pcs(check_all_pcs_connect_status, NULL, &i))       // 判是否并网
            {
                microgrid_data.grid_statu = 1;
                return microgrid_data.grid_statu;
            }
        }
    }
    else {
        microgrid_data.grid_statu = dev_info_all.dido.dido_param[0].info.dido_data.conn_sign;
    }

    return microgrid_data.grid_statu;
}


/**
 * @description: 检查PCS当前并离网状态
 * @return {*}  0:一致  -1:不一致
 */
int pcs_check_connect(int flag)
{
    return traverse_pcs(check_all_pcs_connect_status, NULL, &flag);
}



/*========================================<状态机相关>=======================================================*/

enum __decision_matrix
{
    NONE_DM = -1,
    FALES_DM = 0,
    TRUE_DM
};

// 状态机决策矩阵
/**
 * @description: 状态机决策矩阵用以初步提供状态机的目标工作状态，该矩阵设计是为将微网状态切换的各项判定机制抽象，从业务逻辑中尽量单独抽离，以便用以拓展。
                当前方案用以优化嵌套级过深的if else判定机制，将二维判定流程拍扁为一维，简化拓展难度。
                注:对该矩阵决策因子进行拓展将导致决策矩阵最大为指数级增长，最小为O1。是此方案劣势,配置困难度仍然存在。
                但相比if else，其优势是将逻辑抽象为配置表，静态描述。提供更多的操作性与代码可读性.
                要明确说明的是，决策因子是决断状态机的运作状态，是现有鸡、蛋的先来者，不涉及要进入目标状态的后置操作。比如并离网断路器，是在得到已决断的目标状态后再进行操作的设备。
                例如：并网模式下发现市电无电，视为切换离网。此时进入离网模式初始化，再操作断路器断开，若将断路器断开操作放置在前置判定段，将无从操作
 */
#define MATRIX_NUM 10
typedef struct {
    // 决策因子定义 1、0:有效值判定 -1:不做判定
    enum __decision_matrix en_sts;             // 使能 STS     0:失能 1:使能
    enum __decision_matrix grid_statu;         // PCS并网状态(全部)     0:离网 1:并网
    enum __decision_matrix en_ats;             // 使能 ATS     0:失能 1:使能
    enum __decision_matrix ats_sign;           // 信号 ATS     0:副电源 1:主电源
    enum __decision_matrix en_mains;           // 使能市电     0:失能 1:使能
    enum __decision_matrix en_dg;              // 使能柴发     0:失能 1:使能
    enum __decision_matrix en_icb;             // 使能 并离网断路器     0:失能 1:使能
    enum __decision_matrix DG_sign;            // 信号 柴发     0:关闭 1:启动
    enum __decision_matrix conn_sign;          // 信号 电压继电器 0:断开 1:闭合
    // enum __decision_matrix icb_sign;           // 信号 并离网继电器 0:断开 1:闭合    并离网信号不参与判定，因其数据为状态后置 判定无意义

    // 其他类型拓展 例如 float 可在使用

    enum _STATE_MICROGRID result;
} DecisionMatrixEntry;
DecisionMatrixEntry decision_data;

/**
 * @description: 数据刷新
 * @return {*}
 */
int decision_data_flush()
{
    struct _dido_t *dido = &dev_info_all.dido.dido_param[0];
    decision_data.en_sts = microgrid_cfg.en_sts;
    decision_data.grid_statu = microgrid_data.grid_statu;
    decision_data.en_ats = microgrid_cfg.en_ats;
    decision_data.ats_sign = dido->info.dido_data.ats_sign;
    decision_data.en_mains = microgrid_cfg.en_mains;
    decision_data.en_dg = microgrid_cfg.en_diesel_generator;
    decision_data.en_icb = microgrid_cfg.en_icb;
    decision_data.DG_sign = dido->info.dido_data.DG_sign;
    decision_data.conn_sign = dido->info.dido_data.conn_sign;

    return 0;
}
// 预定义状态决策表 判断优先级依次为从上至下 从左至右
static const DecisionMatrixEntry decision_table[] = {
    /*STS       grid_stat   en_ats      ats_sign    en_mains    en_dg       en_icb      DG_sign     conn_sign   result*/
    {NONE_DM,   NONE_DM,    FALES_DM,   NONE_DM,    TRUE_DM,    TRUE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    STATE_ABNORMAL},//未使能ATS但使能市电与柴发视为配置错误
    {NONE_DM,   NONE_DM,    FALES_DM,   NONE_DM,    TRUE_DM,    TRUE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    STATE_ABNORMAL},//未使能ATS但使能市电与柴发视为配置错误

    /*并网状态*/
    {TRUE_DM,   TRUE_DM,    TRUE_DM,    TRUE_DM,    TRUE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    STATE_CONNECT_GRID},
    {TRUE_DM,   TRUE_DM,    FALES_DM,   NONE_DM,    TRUE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    STATE_CONNECT_GRID},
    {FALES_DM,  NONE_DM,    TRUE_DM,    TRUE_DM,    TRUE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    TRUE_DM,    STATE_CONNECT_GRID},
    {FALES_DM,  NONE_DM,    FALES_DM,   NONE_DM,    TRUE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    TRUE_DM,    STATE_CONNECT_GRID},

    /*柴发并网状态*/
    {TRUE_DM,   TRUE_DM,    TRUE_DM,    FALES_DM,   NONE_DM,    TRUE_DM,    NONE_DM,    TRUE_DM,    NONE_DM,    STATE_CF_CONNECT_GRID},//STS下并网模式且柴发开机
    {TRUE_DM,   TRUE_DM,    FALES_DM,   NONE_DM,    NONE_DM,    TRUE_DM,    NONE_DM,    TRUE_DM,    NONE_DM,    STATE_CF_CONNECT_GRID},//STS下并网模式且柴发开机
    {FALES_DM,  NONE_DM,    TRUE_DM,    FALES_DM,   NONE_DM,    TRUE_DM,    NONE_DM,    TRUE_DM,    TRUE_DM,    STATE_CF_CONNECT_GRID},//非STS下并网模式且柴发开机
    {FALES_DM,  NONE_DM,    FALES_DM,   NONE_DM,    NONE_DM,    TRUE_DM,    NONE_DM,    TRUE_DM,    TRUE_DM,    STATE_CF_CONNECT_GRID},//非STS下并网模式且柴发开机

    /*不满足离网状态的待机状态优先判定 比离网判定优先判定*/
    {FALES_DM,  FALES_DM,   TRUE_DM,    FALES_DM,   FALES_DM,   TRUE_DM,    FALES_DM,   FALES_DM,   FALES_DM,   STATE_OFF_GRID},
    {FALES_DM,  NONE_DM,    NONE_DM,    NONE_DM,    TRUE_DM,    FALES_DM,   FALES_DM,   NONE_DM,    FALES_DM,   STATE_AWAIT},    //无断路器将无法保证离网运行是否安全
    {FALES_DM,  NONE_DM,    NONE_DM,    NONE_DM,    FALES_DM,   TRUE_DM,    FALES_DM,   NONE_DM,    FALES_DM,   STATE_AWAIT},   
    {FALES_DM,  NONE_DM,    NONE_DM,    NONE_DM,    TRUE_DM,    TRUE_DM,    FALES_DM,   NONE_DM,    FALES_DM,   STATE_AWAIT},   

    /*离网状态*/
    {TRUE_DM,   FALES_DM,   NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    STATE_OFF_GRID},        // 离网判定在前，优先判定进入离网状态 不会经过待机，离网状态的切换交给状态机的初始化处理
    {FALES_DM,  NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    FALES_DM,   STATE_OFF_GRID},

    /*待机状态:  待机有并网待机和离网待机 但离网待机的机制在于SOC低于一定阈值，并网待机大多基于用户配置实施 而SOC阈值判定目前不以嵌入到本矩阵，达成目标采取状态机判断函数对矩阵返回参数覆盖来操作。*/
    {TRUE_DM,   TRUE_DM,    NONE_DM,    NONE_DM,    FALES_DM,   NONE_DM,    NONE_DM,    NONE_DM,    NONE_DM,    STATE_AWAIT},//使能STS有市电但未使能市电判定优先级最好放柴发状态判定后面可省略部分判定条件交由其他状态先进行筛选
    {FALES_DM,  NONE_DM,    NONE_DM,    NONE_DM,    FALES_DM,   NONE_DM,    NONE_DM,    NONE_DM,    TRUE_DM,    STATE_AWAIT},//未能STS有市电但未使能市电    

};

int resolve_state_check(enum __decision_matrix date, enum __decision_matrix vol)
{
    if(vol == NONE_DM)
    {
        return 1;
    }
    if(date == vol)
        return 1;

    return 0;
}

/**
 * @description: 解析状态矩阵获取目标状态
 * @return {*}
 */
enum _STATE_MICROGRID resolve_state() {
    for (int i = 0; i < sizeof(decision_table) / sizeof(decision_table[0]); i++) 
    {
        if( resolve_state_check(decision_data.en_sts, decision_table[i].en_sts) &&
            resolve_state_check(decision_data.grid_statu, decision_table[i].grid_statu) &&
            resolve_state_check(decision_data.en_ats, decision_table[i].en_ats) &&
            resolve_state_check(decision_data.ats_sign, decision_table[i].ats_sign) &&
            resolve_state_check(decision_data.en_mains, decision_table[i].en_mains) &&
            resolve_state_check(decision_data.en_dg, decision_table[i].en_dg) &&
            resolve_state_check(decision_data.en_icb, decision_table[i].en_icb) &&
            resolve_state_check(decision_data.DG_sign, decision_table[i].DG_sign) &&
            resolve_state_check(decision_data.conn_sign, decision_table[i].conn_sign))
        {
        UD_log_sprintf(micro_log, "\ndecision_data.en_sts = %d,\
            decision_data.grid_statu = %d,decision_data.en_ats = %d,\
            decision_data.ats_sign = %d,decision_data.en_mains = %d,\
            decision_data.en_dg = %d,decision_data.en_icb = %d,\
            decision_data.DG_sign = %d,decision_data.conn_sign = %d,", \
            decision_data.en_sts, \
            decision_data.grid_statu, \
            decision_data.en_ats, \
            decision_data.ats_sign, \
            decision_data.en_mains, \
            decision_data.en_dg, \
            decision_data.en_icb, \
            decision_data.DG_sign, \
            decision_data.conn_sign);
        UD_log_sprintf(micro_log, "\n状态机判定机制，当前期望[%d]", i);
            return decision_table[i].result;
        }
        
    
    }
    
    UD_log_sprintf(micro_log, "\n没有的状态 说明配置异常嵌入异常处理!直接进异常!!!");
    return STATE_ABNORMAL;  // 没有的状态 说明配置异常嵌入异常处理开发自行补充
}


/* 创建状态机
*/
current_stat_t *creat_state_machine()
{
    current_stat_t *tmp = (current_stat_t *)calloc(1, sizeof(current_stat_t));
    if(NULL == tmp)
    {
        /**///ems_syslog(LOG_ERR,"Memory request failed:current_stat_t");
        return NULL;

    }
    tmp->state_action_size = STATE_MAX;

    return tmp;
}

/**
 * @description: 
 * @param {STATE_MACHINE_T} *state_machine
 * @param {RELEVANCE_STATE} next_state
 * @return {*}
 */
int state_switch(current_stat_t *state_machine, RELEVANCE_STATE next_state)
{
    if(state_machine->major_state == next_state)        // 状态相同 返回不切换
    {
        return 0;
    }

    state_machine->last_state = state_machine->major_state;
    state_machine->major_state = next_state;
    state_machine->state[state_machine->major_state].action_step_idx = 0;

    UD_log_sprintf(micro_log, "  由 [%d]状态 切入 [%d]状态 -> ", state_machine->last_state, state_machine->major_state);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0008, NULL, "[直流耦合]: 由 [%d]状态 切入 [%d]状态 ->", state_machine->last_state, state_machine->major_state);

    return 1;
}

/**
 * @description: 执行状态切换函数 得到状态并确认状态是否切换
 * @param {STATE_MACHINE_T} *state_machine:状态机
 * @return {-1:错误 0:不切换状态 1:切换状态}:
 */
int state_check_and_switch(current_stat_t *state_machine)
{
    if(NULL == state_machine)
    {
        /**///ems_syslog(LOG_ERR,"error:state_machine/state_action->state = NULL!!!");
        return -1;
    }
    UD_log_sprintf(micro_log, " \n状态切换校验[\n");
    RELEVANCE_STATE ret = state_machine->state[state_machine->major_state].handover_detect(state_machine->major_state);
    UD_log_sprintf(micro_log, " \n目标状态:[%d]  0:待机 1:市电并网 2:离网 3:柴发并网 4:初始 5:异常状态 6:默认状态\n]\n", ret);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0008, NULL, "[直流耦合]: 目标状态:[%d]  0:待机 1:市电并网 2:离网 3:柴发并网 4:初始 5:异常状态 6:默认状态", ret);
    if (STATE_ABNORMAL == ret)
    {
        ems_syslog(LOG_ERR, "exception_code 0x%x, exception_action %d, last_normal_state %d",
            g_microgrid_exception.exception_code, g_microgrid_exception.exception_action, g_microgrid_exception.last_normal_state);
    }
    return state_switch(state_machine, ret); // 切换
}


/* 
指定状态的内容注册
RELEVANCE_STATE (*handover_detect)(RELEVANCE_STATE state_self);             // 

RELEVANCE_STATE (*behaviour_func)(RELEVANCE_STATE state_self);              // 当前状态行为 

RELEVANCE_STATE (*init)(RELEVANCE_STATE last_state, RELEVANCE_STATE state); // 进入本状态初始化 

RELEVANCE_STATE state;                                                      // 自身状态    初始化产生
*/
int state_switch_registration(current_stat_t *state_machine, RELEVANCE_STATE state, RELEVANCE_STATE (*init)(RELEVANCE_STATE last_state, RELEVANCE_STATE state), RELEVANCE_STATE (*handover_detect)(RELEVANCE_STATE state_self),  int (*behaviour_func)(RELEVANCE_STATE state_self))
{
    if(NULL == state_machine)
    {
        /**///ems_syslog(LOG_ERR,"The argument is NULL:state_machine=%p, state_machine->state=%p!!", state_machine, state_machine->state);
        return -1;
    }
    state_machine->state[state].handover_detect = handover_detect;
    state_machine->state[state].behaviour_func = behaviour_func;
    state_machine->state[state].init = init;
    state_machine->state[state].state_self = state;

    return 0;
}

int state_init(current_stat_t *state_machine)
{
    RELEVANCE_STATE ret = 0;
    
    if(state_machine->state[state_machine->major_state].init)
        ret = state_machine->state[state_machine->major_state].init(state_machine->last_state, state_machine->major_state);
    else
    {
        /**///ems_syslog(LOG_ERR,"Err state_init: state:%d init unregistered",state_machine->major_state);
        return -1;
    }
    UD_log_sprintf(micro_log, "\n<[%d] 状态初始化>\n", state_machine->major_state);
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0002, state_string_enum_info[state_machine->major_state], "[直流耦合]: <[%d] 状态初始化>", state_machine->major_state);
    if (STATE_ABNORMAL == ret)
    {
        ems_syslog(LOG_ERR, "exception_code 0x%x, exception_action %d, last_normal_state %d",
            g_microgrid_exception.exception_code, g_microgrid_exception.exception_action, g_microgrid_exception.last_normal_state);
    }
    return state_switch(state_machine, ret);

}


static void states_exit(current_stat_t *state_machine)
{
    if(NULL == state_machine->states_exit)
    {
        return;
    }
    state_switch(state_machine, state_machine->states_exit(state_machine->last_state, state_machine->major_state));
}

bool TOU_userdef_mode()
{
    if (microgrid_ctrl.choose_func == STRATAGY_TYPE_TOU && microgrid_ctrl.current_tou_info && microgrid_ctrl.current_tou_info->strategy == 4) //TOU的自定义模式则只执行自定逻辑 不切换不控制
    {
        UD_log_sprintf(micro_log, "TOU自定义模式\n");
        BUSINESS_LOG(BLOG_NOTICE, MICRO_LOG_STATE_INFO,"TOU自定义模式", "TOU自定义模式\n");
        return true;
    }
    return false;
}

void execute_TOU_userdef()
{ 
    if (microgrid_ctrl.current_tou_info)
    {
        for (size_t i = 0; i < microgrid_ctrl.current_tou_info->userdefNum; i++)
        {
            if (microgrid_ctrl.current_tou_info->userdef[i].tag != NULL)
            {
                int result = 0;
                collector_read_one_int_data(microgrid_ctrl.current_tou_info->userdef[i].tag ,&result);
                if(result!=microgrid_ctrl.current_tou_info->userdef[i].value)
                    collector_write_one_int_data(microgrid_ctrl.current_tou_info->userdef[i].tag,microgrid_ctrl.current_tou_info->userdef[i].value);
            }
        }   
    }
}

/**
 * @description: 状态机主线程 校验状态并执行状态函数
 * @param {void} *args 状态机指针
 * @return {*}
 */
void *state_machine_pthread(void *args)
{
    int ret = 0;
    int once = 0;
    current_stat_t *state_machine = (current_stat_t *)args;
    RELEVANCE_STATE ret_state;
    int toutimes = 0;
START:
    

    if(NULL == state_machine)
    {
        ems_syslog(LOG_ERR,"state_machine is NULL !!!");
        goto END;
    }

    ret_state = state_init(state_machine);
    if(-1 == ret_state)
    {
        goto END;
    }
    else if(1 == ret_state)
    {
        states_exit(state_machine);
        fwrite_flush_UD_log(micro_log);
        goto START;
    }
    pthread_rwlock_wrlock(&dev_log_rwlock);


    while (1)
    {
        pthread_rwlock_unlock(&dev_log_rwlock);
        usleep(400 * 1000);
        pthread_rwlock_wrlock(&dev_log_rwlock);
        Relevant_data_refresh();
        
        if(g_usercfg_variant.ControlMode == 0)
        {
            if(once < 1)    // 小于N则执行N次
            {
                once++;
            }
            else {
                /*TODO*/
                once = 0;

            }
            UD_log_sprintf(micro_log, "手动模式\n");
            BUSINESS_LOG(LOG_NOTICE, DC_ID_0002, state_string_enum_info[state_machine->major_state], "[直流耦合]: 手动模式");
            fwrite_flush_UD_log(micro_log);
            sleep(1);
            continue;
        }
        if(g_usercfg_variant.ControlMode == 2)
        {
            if(once < 1)
            {
                once++;
            }
            else {
                /*TODO*/
                once = 0;

            }
            UD_log_sprintf(micro_log, "远程模式\n");
            BUSINESS_LOG(LOG_NOTICE, DC_ID_0002, state_string_enum_info[state_machine->major_state], "[直流耦合]: 远程模式");
            fwrite_flush_UD_log(micro_log);
            sleep(1);
            continue;
        }
        if (TOU_userdef_mode())
        {
            execute_TOU_userdef();
            sleep(1);
            if (toutimes == 0)
            {
                toutimes++;
                pcs_stop();
                mppt_stop();
            }
            
            continue;
        }
        else
        {
            toutimes = 0;
        }
        
        if(dev_get_dev_tag_float(DEV_NO_EMS, SYSTEM_STATUS))
        {
            if(once < 1)
            {
                once++;
            }
            else {
                /*TODO*/
                once = 0;
            }
            pcs_stop();
            mppt_stop();
            UD_log_sprintf(micro_log, "系统异常字段\n");
            BUSINESS_LOG(LOG_NOTICE, DC_ID_0002, state_string_enum_info[state_machine->major_state], "[直流耦合]: 系统异常字段");
            fwrite_flush_UD_log(micro_log);
            sleep(3);
            continue;
        }
        once = 0;
        
        /**///ems_syslog(LOG_ERR,"当前状态:%d!!!",state_machine->major_state );
        dev_set_dev_tag_int(DEV_NO_EMS, STATE_MACHINE, state_machine->major_state);
        ret = state_check_and_switch(state_machine);
        if(1 == ret)
        {
            states_exit(state_machine);
            fwrite_flush_UD_log(micro_log);
            goto START;
        }

        if(-1 == ret)
        {
            break;
        }

        if(state_machine->state[state_machine->major_state].behaviour_func)
        {
            UD_log_sprintf(micro_log, "状态行为[\n");
            state_machine->state[state_machine->major_state].behaviour_func(state_machine->major_state);
            UD_log_sprintf(micro_log, "]\n");

        }
        else
            ems_syslog(LOG_ERR,"Err:state:%d : behaviour_func unregistered", state_machine->major_state);
        SocrearlyWarning();
        fwrite_flush_UD_log(micro_log);
    }
END:
pthread_rwlock_unlock(&dev_log_rwlock);
    UD_log_sprintf(micro_log, "\n\n");

    fwrite_flush_UD_log(micro_log);
    while (1)
    {
        sleep(1);
        ems_syslog(LOG_ERR,"Err:The state machine thread terminates!!");
    }
    
    return NULL;
    

}


/*========================================<设备注册>=======================================================*/
#if 0
static lc_serial_t get_cabinet_by_string(char *typeString)
{
    for (lc_serial_t i = LC ; i < _MAX_LC ; i++)
    {
        if(strcmp(typeString, cabinet_des[i]) == 0)
	        return i;
    }
    proto_syslog(LOG_WARNING, "ERROR");
    return ERROR_LC;
}
#endif
// static void _free_memory(void *ptr) {
//     if (ptr != NULL) {
//         free(ptr);
//         ptr = NULL;
//     }
// }

static void microgrid_scale_init(void)  // 注意：光伏直流侧耦合只有单柜(对等柜)
{
	int i = 0, j = 0;
	float cab_scale = 0;
	float df_pcs_scale = 0, df_pv_scale = 0, df_mppt_scale = 0;

	dev_info_all_t *_dev_info_all = get_dev_info_all_var();
    // enum MODE_MICROGRID mode = get_cabinet_info()->mode_microgrid;
    int pcs_num = 0, pv_num = _dev_info_all->pv.num, mppt_num = 0;
	for (i = 0 ; i < _dev_info_all->cabinet_info.num; i++){
        cabinet_inside_t *_cabinet_inside  = _dev_info_all->cabinet_info.cabinet_inside[i];
        pcs_num += _cabinet_inside->pcs.num; // 总PCS个数
        mppt_num += _cabinet_inside->mppt.num;
	}
    microgrid_ctrl.mpptnum = mppt_num;
	if (pcs_num != 0) df_pcs_scale = 1.0f/pcs_num;

    if (mppt_num != 0) df_mppt_scale = 1.0f/mppt_num;

    if (pv_num != 0) df_pv_scale = 1.0f/pv_num;

	ems_syslog(LOG_ERR,"toatal pcs_num:%d df_pcs_scale:%f, pv_num:%d df_pv_scale:%f df_mppt_scale:%f", pcs_num, df_pcs_scale, pv_num, df_pv_scale, df_mppt_scale);
	
    for (i = 0 ; i < _dev_info_all->cabinet_info.num; i++)
    {
        cab_scale = 0;
        cabinet_inside_t *_cabinet_inside  = _dev_info_all->cabinet_info.cabinet_inside[i];//
        _cabinet_inside->cab_data.singleVmaxtime = time(NULL);
        _cabinet_inside->cab_data.singleVmintime = time(NULL);

        /**///ems_syslog(LOG_ERR,"dc, cabinet[%d] cabinet:%s, pcs_num %d", i, _cabinet_inside->no, _cabinet_inside->pcs.num);
        for (j = 0 ; j < _cabinet_inside->pcs.num; j++){
            struct _pcs_t *_pcs = &_cabinet_inside->pcs.pcs_param[j];//
            
            device_t *dev = (device_t *)_pcs->ptr;
            _pcs->info.pcs_cfg.scale = find_float_in_user_def(dev, "scale", df_pcs_scale);
            cab_scale += _pcs->info.pcs_cfg.scale;
        }

        /**///ems_syslog(LOG_ERR,"dc, cabinet[%d] cabinet:%s, mppt_num %d", i, _cabinet_inside->no, _cabinet_inside->mppt.num);
        for (j = 0 ; j < _cabinet_inside->mppt.num; j++){
            struct _mppt_t *_mppt = &_cabinet_inside->mppt.mppt_param[j];
            
            _mppt->info.mppt_cfg.scale = 1.0f/_cabinet_inside->mppt.num;
        }
        
        _cabinet_inside->cab_cfg.scale = cab_scale; //>>柜scale
    }

    for (j = 0 ; j < _dev_info_all->pv.num; j++){
        struct _pv_t *_pv = &_dev_info_all->pv.pv_param[j];
        device_t *dev = (device_t *)_pv->ptr;
        _pv->info.pv_cfg.scale = find_float_in_user_def(dev, "scale", df_pv_scale);
    }
}

static void microgrid_print_device_info(void)
{
	int i = 0, j = 0;

	dev_info_all_t *_dev_info_all = get_dev_info_all_var();
    enum MODE_MICROGRID mode = get_cabinet_info()->mode_microgrid;

	for (i = 0 ; i < _dev_info_all->meter_grid.num; i++)
	{
		 ems_syslog(LOG_ERR,"~~ meter_grid[%d] no:%s", i, _dev_info_all->meter_grid.meter_grid_param[i].no);
	}
	for (i = 0 ; i < _dev_info_all->meter_load.num; i++)
	{
		 ems_syslog(LOG_ERR,"~~ meter_load[%d] no:%s", i, _dev_info_all->meter_load.meter_load_param[i].no);
	}

    if (mode == MODE_MICROGRID_DC){
		 ems_syslog(LOG_ERR,"%s", "dc...");
		for (i = 0 ; i < _dev_info_all->cabinet_info.num; i++)//
		{
		    cabinet_inside_t *_cabinet_inside  = _dev_info_all->cabinet_info.cabinet_inside[i];
		    for (j = 0 ; j < _cabinet_inside->meter_mppt.num; j++){
				ems_syslog(LOG_ERR,"dc cabinet[%d] cabinet:%s, meter_pv[%d] no:%s", i, _cabinet_inside->no, j, _cabinet_inside->meter_mppt.meter_mppt_param[j].no);
		    }
		    for (j = 0 ; j < _cabinet_inside->mppt.num; j++){
				ems_syslog(LOG_ERR,"dc cabinet[%d] cabinet:%s, mppt[%d] no:%s scale:%f", i, _cabinet_inside->no, j, _cabinet_inside->mppt.mppt_param[j].no, _cabinet_inside->mppt.mppt_param[j].info.mppt_cfg.scale);
		    }
		}
    }
	else if (mode == MODE_MICROGRID_AC){  //>>交流侧耦合
        ems_syslog(LOG_ERR,"%s", "ac...");
		for (i = 0 ; i < _dev_info_all->meter_pv.num; i++)
		{
			ems_syslog(LOG_ERR,"ac meter_pv[%d] no:%s", i, _dev_info_all->meter_pv.meter_pv_param[i].no);
		}
		for (i = 0 ; i < _dev_info_all->pv.num; i++)
		{
			ems_syslog(LOG_ERR,"ac pv[%d] no:%s scale:%f", i, _dev_info_all->pv.pv_param[i].no,  _dev_info_all->pv.pv_param[i].info.pv_cfg.scale);
		}
	}
	
	for (i = 0 ; i < _dev_info_all->cabinet_info.num; i++)//
	{
	    cabinet_inside_t *_cabinet_inside  = _dev_info_all->cabinet_info.cabinet_inside[i];
	    for (j = 0 ; j < _cabinet_inside->meter_pcs.num; j++){
			ems_syslog(LOG_ERR,"~~ cabinet[%d] cabinet:%s, meter_pcs[%d] no:%s", i, _cabinet_inside->no, j, _cabinet_inside->meter_pcs.meter_pcs_param[j].no);
	    }
	    for (j = 0 ; j < _cabinet_inside->pcs.num; j++){
			ems_syslog(LOG_ERR,"~~ cabinet[%d] cabinet:%s, pcs[%d] no:%s scale:%f", i, _cabinet_inside->no, j, _cabinet_inside->pcs.pcs_param[j].no, _cabinet_inside->pcs.pcs_param[j].info.pcs_cfg.scale);
	    }
	    for (j = 0 ; j < _cabinet_inside->bms.num; j++){
			ems_syslog(LOG_ERR,"~~ cabinet[%d] cabinet:%s, bms[%d] no:%s", i, _cabinet_inside->no, j, _cabinet_inside->bms.bms_param[j].no);
	    }
		ems_syslog(LOG_ERR,"cabinet[%d] cabinet:%s, scale:%f", i, _cabinet_inside->no, _cabinet_inside->cab_cfg.scale);
	}	
}

/*获取柜子数量确定注册的范围*/
int dev_group_cfg_get_cab_num(const char *json_string) {
    // 解析JSON字符串
    char *cfg_json_str = read_file_data(json_string);
    cJSON *root = cJSON_Parse(cfg_json_str);
    if(cfg_json_str)
        free(cfg_json_str);
    if (root == NULL) {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL) {
            ems_syslog(LOG_ERR, "Error before: %s\n", error_ptr);
        }
        return 0;
    }
    
    // 确保根节点是数组
    if (!cJSON_IsArray(root)) {
        ems_syslog(LOG_ERR, "Root is not an array\n");
        cJSON_Delete(root);
        return 0;
    }
    
    // 遍历数组中的每个组
    cJSON *group_item = NULL;
    int i = 0;
    cJSON_ArrayForEach(group_item, root) 
    {
        if(i > CABINET_NUM_MAX)
        {
            continue;
        }
        i++;
    }
    cJSON_Delete(root);
    return i;
}

/*柜内设备注册*/
void cab_dev_regist(const char *json_string) 
{
    // 解析JSON字符串
    char *cfg_json_str = read_file_data(json_string);
    cJSON *root = cJSON_Parse(cfg_json_str);
    if(cfg_json_str)
        free(cfg_json_str);
    if (root == NULL) {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL) {
            ems_syslog(LOG_ERR, "Error before: %s\n", error_ptr);
        }
        return;
    }
    
    // 确保根节点是数组
    if (!cJSON_IsArray(root)) {
        ems_syslog(LOG_ERR, "Root is not an array\n");
        BUSINESS_LOG(LOG_NOTICE, INIT_ID_0001, "ini",  "[微网初始化]: 设备分组配置文件格式错误!!!");
        cJSON_Delete(root);
        return;
    }
    proto_forward_t *dev_var = get_proto_forward_var();
    
    // 遍历数组中的每个组
    cJSON *group_item = NULL;
    int group_num = 0;
    cJSON_ArrayForEach(group_item, root) 
    {
        // cJSON *group_name = cJSON_GetObjectItemCaseSensitive(group_item, "group");
        
        if(group_num > CABINET_NUM_MAX)
        {
            BUSINESS_LOG(LOG_NOTICE, INIT_ID_0001, "ini",  "[微网初始化]: 注册设备数量超限!!!");
            continue;
        }
        // 获取设备数组
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[group_num++];
        
        cJSON *devices = cJSON_GetObjectItemCaseSensitive(group_item, "devices");
        cab->no = calloc( DEV_NO_LEN, 1);
        if (cJSON_IsArray(devices)) {
            // 遍历设备数组
            cJSON *device_item = NULL;
            cJSON_ArrayForEach(device_item, devices) {
                // 获取设备属性
                cJSON *no = cJSON_GetObjectItemCaseSensitive(device_item, "no");
                cJSON *mp = NULL;
                if(get_cabinet_info()->mode_microgrid == MODE_MICROGRID_AC)
                {
                    mp = cJSON_GetObjectItemCaseSensitive(device_item, "mp");
                    if(cab->no && mp)
                    {
                        sprintf(cab->no, "%s", mp->valuestring);
                        BUSINESS_LOG(LOG_NOTICE, INIT_ID_0001, "ini",  "[微网初始化]: 注册柜子 cab no: %s", cab->no);

                    }
                }

                for (int i = 0; i < dev_var->channels_size; i++)
                {
                    ems_syslog(LOG_DEBUG, "channel:%s", dev_var->channels[i]->channel);
                    for (int j = 0; j < dev_var->channels[i]->devs_size; j++)
                    {
                        device_t *dev = dev_var->channels[i]->devs[j];
                        if (cJSON_IsString(no) && 0 == strcmp(dev->no, no->valuestring))
                        {
                            if(0 == strcmp(dev->dev_type, "PCS") && (cab->pcs.num < DEV_NUM_MAX))
                            {
                                cab->pcs.pcs_param[cab->pcs.num].no = calloc(DEV_NO_LEN + 2, 1);
                                if(mp)
                                    snprintf(cab->pcs.pcs_param[cab->pcs.num].no, DEV_NO_LEN, "%s.%s", mp->valuestring, no->valuestring);
                                else
                                    snprintf(cab->pcs.pcs_param[cab->pcs.num].no, DEV_NO_LEN, "%s", no->valuestring);
                                
                                cab->pcs.pcs_param[cab->pcs.num].ptr = dev;
                                BUSINESS_LOG(LOG_NOTICE, INIT_ID_0001, "ini",  "[微网初始化]: PCS设备注册 %s:  dev_no: %s", cab->pcs.pcs_param[cab->pcs.num].no, dev->dev_type);
                                cab->pcs.num++;
                            }
                            else if(0 == strcmp(dev->dev_type, "BMS") && (cab->bms.num < DEV_NUM_MAX))
                            {
                                cab->bms.bms_param[cab->bms.num].no = calloc(DEV_NO_LEN + 2, 1);
                                if(mp)
                                    snprintf(cab->bms.bms_param[cab->bms.num].no, DEV_NO_LEN, "%s.%s", mp->valuestring, no->valuestring);
                                else
                                    snprintf(cab->bms.bms_param[cab->bms.num].no, DEV_NO_LEN, "%s", no->valuestring);
                                cab->bms.bms_param[cab->bms.num].ptr = dev;
                                cab->bms.num++;
                                BUSINESS_LOG(LOG_NOTICE, INIT_ID_0001, "ini",  "[微网初始化]: BMS设备注册 %s:  dev_no: %s", cab->bms.bms_param[cab->bms.num].no, dev->dev_type);
                            }
                            else if (strcmp(dev->dev_type, "MPPT") == 0 && (cab->bms.num < DEV_NUM_MAX)){
                                cab->mppt.mppt_param[cab->mppt.num].no = calloc(DEV_NO_LEN + 2, 1);
                                if(mp)
                                    snprintf(cab->mppt.mppt_param[cab->mppt.num].no, DEV_NO_LEN, "%s.%s", mp->valuestring, no->valuestring);
                                else
                                    snprintf(cab->mppt.mppt_param[cab->mppt.num].no, DEV_NO_LEN, "%s", no->valuestring);
                                cab->mppt.mppt_param[cab->mppt.num].ptr = dev;
                                BUSINESS_LOG(LOG_NOTICE, INIT_ID_0001, "ini",  "[微网初始化]: MPPT设备注册 %s:  dev_no: %s", cab->mppt.mppt_param[cab->mppt.num].no, dev->dev_type);
                                cab->mppt.num++;
                            }
                            else if(0 == strcmp(dev->dev_type, "METER"))
                            {
                                if (strcmp(dev->dev_child_type, "MPPT") == 0){
                                    if (dev_info_all.meter_pv.num < DEV_NUM_MAX){
                                        if(mp)
                                            snprintf(cab->meter_mppt.meter_mppt_param[cab->meter_mppt.num].no, DEV_NO_LEN, "%s.%s", mp->valuestring, no->valuestring);
                                        else
                                            snprintf(cab->meter_mppt.meter_mppt_param[cab->meter_mppt.num].no, DEV_NO_LEN, "%s", no->valuestring);
                                        cab->meter_mppt.meter_mppt_param[cab->meter_mppt.num].ptr = dev;
                                        cab->meter_mppt.num++;
                                        BUSINESS_LOG(LOG_NOTICE, INIT_ID_0001, "ini",  "[微网初始化]: MPPT表设备注册 %s:  dev_no: %s",cab->meter_mppt.meter_mppt_param[cab->meter_mppt.num].no, dev->dev_type);
                                    }
                                    else
                                        ems_syslog(LOG_ERR,"created meter_pv device[%s] error, num=%d", dev->no, dev_info_all.meter_pv.num);
                                }
                                else if (strcmp(dev->dev_child_type, "PCS") == 0){
    
                                    if (cab->meter_pcs.num < DEV_NUM_MAX){
                                        if(mp)
                                            snprintf(cab->meter_pcs.meter_pcs_param[cab->meter_pcs.num].no, DEV_NO_LEN, "%s.%s", mp->valuestring, no->valuestring);
                                        else
                                            snprintf(cab->meter_pcs.meter_pcs_param[cab->meter_pcs.num].no, DEV_NO_LEN, "%s", no->valuestring);
                                        cab->meter_pcs.meter_pcs_param[cab->meter_pcs.num].ptr = dev;
                                        cab->meter_pcs.num++;
                                        BUSINESS_LOG(LOG_NOTICE, INIT_ID_0001, "ini",  "[微网初始化]: PCS表设备注册 %s:  dev_no: %s", cab->meter_pcs.meter_pcs_param[cab->meter_pcs.num].no, dev->dev_type);
                                    }else
                                        ems_syslog(LOG_ERR,"cabinet[%s] created meter_pcs device[%s] error, num=%d", cab->no, dev->no, cab->meter_pcs.num);
                                }
                            
                            }
                            
                            goto next;
                        }
                    }
                }
        next: 
        ;               
            }
        }
    }
    
    // 清理
    cJSON_Delete(root);
}

// static void scale_init(void) 
// {
//     int i = 0 ;
//     float cab_scale = 0;
//     // float df_pcs_scale = 0;

//     dev_info_all_t *temp_dev_info_all = &dev_info_all;
//     // enum MODE_MICROGRID mode = get_cabinet_info()->mode_ec_;
//     int pcs_num = 0;
//     for (i = 0 ; i < temp_dev_info_all->cabinet_info.num; i++){
//         cabinet_inside_t *_cabinet_inside  = temp_dev_info_all->cabinet_info.cabinet_inside[i];
//         pcs_num += _cabinet_inside->pcs.num; // 总PCS个数
//     }
//     if (pcs_num != 0) df_pcs_scale = 1.0f / (float)pcs_num;
//     for (i = 0 ; i < temp_dev_info_all->cabinet_info.num; i++)
//     {
//         cab_scale = 0;
//         cabinet_inside_t *_cabinet_inside  = temp_dev_info_all->cabinet_info.cabinet_inside[i];//

//         /**///ems_syslog(LOG_ERR,"dc, cabinet[%d] cabinet:%s, pcs_num %d", i, _cabinet_inside->no, _cabinet_inside->pcs.num);
//         // for (j = 0 ; j < _cabinet_inside->pcs.num; j++){
//         //     struct ec_pcs_t *_pcs = &_cabinet_inside->pcs.pcs_param[j];//
            
//         //     device_t *dev = (device_t *)_pcs->ptr;
//         //     _pcs->info.pcs_cfg.scale = find_float_in_user_def(dev, "scale", df_pcs_scale);
//         //     cab_scale += _pcs->info.pcs_cfg.scale;
//         // }

//         _cabinet_inside->cab_cfg.scale = cab_scale; //>>柜scale
//     }
// }

// static int extractBeforeDot(const char *input, char *output) {
//     int find = 0;
//     const char *dotPos = strchr(input, '.');
    
//     if (dotPos != NULL) {
//         size_t length = dotPos - input;
//         strncpy(output, input, length);
//         output[length] = '\0';
//         find = 1;
//     } else {
//         strcpy(output, input); // 如果没有找到'.', 则将整个输入字符串复制到输出字符串
//     }

//     return find;
// }


int microgrid_load_device_info(proto_forward_t *var, Cabinet_t *_cabinet_info)
{
    ems_syslog(LOG_NOTICE, "%s", "ec_load_device_info load start...");
    
    proto_forward_t *dev_var = get_proto_forward_var();
    int cab_num_max = dev_group_cfg_get_cab_num(DEV_GROUP_CFG_PATH);
    dev_info_all.cabinet_info.num = cab_num_max;
    for (int i = 0 ; i < cab_num_max; i++) {
        dev_info_all.cabinet_info.cabinet_inside[i] = calloc(sizeof(cabinet_inside_t), 1);
    }

    BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 柜外设备信息注册...");
    // 注册柜外设备
    for (int i = 0; i < dev_var->channels_size; i++)
    {
        ems_syslog(LOG_DEBUG, "channel:%s", dev_var->channels[i]->channel);
        for (int j = 0; j < dev_var->channels[i]->devs_size; j++)
        {
            device_t *dev = dev_var->channels[i]->devs[j];
            dev_info_all_t *_dev_info_all = &dev_info_all;
            if (strcmp(dev->dev_type, "METER") == 0)
            {
                if (strcmp(dev->dev_child_type, "GRID") == 0){

                    if (_dev_info_all->meter_grid.num < DEV_NUM_MAX){
                        _dev_info_all->meter_grid.meter_grid_param[_dev_info_all->meter_grid.num].no = strdup(dev->no);
                        _dev_info_all->meter_grid.meter_grid_param[_dev_info_all->meter_grid.num].ptr = dev;
                        _dev_info_all->meter_grid.num++;  
                        BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 关口表设备注册 %s: type:%s", dev->no, dev->dev_type);
                    }else
                        ems_syslog(LOG_ERR,"created meter_grid device[%s] error, num=%d", dev->no, _dev_info_all->meter_grid.num);
                }
                else if (strcmp(dev->dev_child_type, "TRAS_LV") == 0){

                    if (_dev_info_all->meter_grid_lv.num < DEV_NUM_MAX){
                        _dev_info_all->meter_grid_lv.meter_grid_param[_dev_info_all->meter_grid_lv.num].no = strdup(dev->no);
                        _dev_info_all->meter_grid_lv.meter_grid_param[_dev_info_all->meter_grid_lv.num].ptr = dev;
                        _dev_info_all->meter_grid_lv.num++;  
                        BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 低压侧表设备注册 %s: type:%s", dev->no, dev->dev_type);
                    }else
                        ems_syslog(LOG_ERR,"created meter_grid_lv device[%s] error, num=%d", dev->no, _dev_info_all->meter_grid_lv.num);
                }
                else if (strcmp(dev->dev_child_type, "PV") == 0){
                    if (_dev_info_all->meter_pv.num < DEV_NUM_MAX){
                            _dev_info_all->meter_pv.meter_pv_param[_dev_info_all->meter_pv.num].no = strdup(dev->no);
                            _dev_info_all->meter_pv.meter_pv_param[_dev_info_all->meter_pv.num].ptr = dev;
                            _dev_info_all->meter_pv.num++;
                        BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: PV设备注册 %s: type:%s", dev->no, dev->dev_type);
                    }
                    else
                        ems_syslog(LOG_ERR,"created meter_pv device[%s] error, num=%d", dev->no, _dev_info_all->meter_pv.num);
                }
                else if (strcmp(dev->dev_child_type, "LOAD") == 0){
                    if (_dev_info_all->meter_load.num < DEV_NUM_MAX){
                        _dev_info_all->meter_load.meter_load_param[_dev_info_all->meter_load.num].no = strdup(dev->no);
                        _dev_info_all->meter_load.meter_load_param[_dev_info_all->meter_load.num].ptr = dev;
                        _dev_info_all->meter_load.num++; 
                        BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 负载表设备注册 %s: type:%s", dev->no, dev->dev_type);
                    }
                    else
                        ems_syslog(LOG_ERR,"created meter_load device[%s] error, num=%d", dev->no, _dev_info_all->meter_load.num);
                }
                else if (strcmp(dev->dev_child_type, "DG") == 0){
                    if (_dev_info_all->meter_dg.num < DEV_NUM_MAX){
                        _dev_info_all->meter_dg.meter_dg_param[_dev_info_all->meter_dg.num].no = strdup(dev->no);
                        _dev_info_all->meter_dg.meter_dg_param[_dev_info_all->meter_dg.num].ptr = dev;
                        _dev_info_all->meter_dg.num++;
                        microgrid_cfg.en_dg_meter = 1;
                        BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 柴发表设备注册 %s: type:%s", dev->no, dev->dev_type);
                    }
                    else
                        ems_syslog(LOG_ERR,"created meter_dg device[%s] error, num=%d", dev->no, _dev_info_all->meter_load.num);
                }
            }
            else if (strcmp(dev->dev_type, "PV") == 0){
                if (_dev_info_all->pv.num < DEV_NUM_MAX){
                    _dev_info_all->pv.pv_param[_dev_info_all->pv.num].no = strdup(dev->no); 
                    _dev_info_all->pv.pv_param[_dev_info_all->pv.num].ptr = dev;			
                    _dev_info_all->pv.num++;
                    BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: PV表设备注册 %s: type:%s", dev->no, dev->dev_type);
                }
                else
                    ems_syslog(LOG_ERR,"created pv device[%s] error, num=%d", dev->no, _dev_info_all->pv.num);
            }  
        }
    }

    // 注册柜内设备
    BUSINESS_LOG(LOG_NOTICE, DC_ID_0001, "ini", "[微网初始化]: 柜内设备信息注册...");

    cab_dev_regist(DEV_GROUP_CFG_PATH);

    microgrid_scale_init();
    microgrid_print_device_info();
    return 0;
}



int start_dc_microgrid(void){
    state_machine_Init();       // 状态机工作模式
    return 0;
}

STRATAGY_TYPE mode_select()
{
    STRATAGY_TYPE choose_func = -1;
    if (microgrid_ctrl.choose_func == STRATAGY_TYPE_TOU && microgrid_ctrl.current_tou_info)
    {
        ems_syslog(LOG_NOTICE,"当前是TOU");
        switch (microgrid_ctrl.current_tou_info->strategy)//0：自发自用;1:上网优先;2:应急备电 3:动态增容 4:自定义
        {
        case 0:
            choose_func = STRATAGY_TYPE_PV_STORAGE;
            break;
        case 1:
            choose_func = STRATAGY_TYPE_SURPLUS2GRID;
            break;
        case 2:
            choose_func = STRATAGY_TYPE_STANDBY;
            break;
        case 3:
            choose_func = STRATAGY_TYPE_DEMAND_FIXED;
            break;
        case 4:
            choose_func = -1; //什么都不执行
            break;
        default:
            break;
        }
    }
    else
    {
        ems_syslog(LOG_NOTICE,"当前不是TOU");
        choose_func = microgrid_ctrl.choose_func;
    }
    ems_syslog(LOG_NOTICE,"当前的策略模式:%d",choose_func);
    return choose_func;
}
static int set_micro_log_en(struct UD_log *self)
{
    // return ud_log_Level & UD_LOG_MICRO ? TRUE : FALSE;

    return ud_log_Level & 0x002 ? TRUE : FALSE;
}

/**
 * @description: 微网初始化
 * @param {pcs_ctrl_var_t} *var
 * @return {*}
 */
int MicrogridtopologyIni(pcs_ctrl_var_t *var)
{
    pthread_t pid[4];
    pthread_rwlock_init(&dev_log_rwlock, NULL);
    microgrid_load_device_info(get_proto_forward_var(), &dev_info_all.cabinet_info);
    micro_log = UD_log_creat("dc_micro.log", set_micro_log_en);
    microgrid_cfg_flush(var);
    dev_cfg_flush();

#if TEST_CASE
    test_func();
    return 0;
#endif
    
    microgrid_ac_init_check();

    if (microgrid_cfg.mode_microgrid == MODE_MICROGRID_DC){
        start_dc_microgrid();
    }
    else if (microgrid_cfg.mode_microgrid == MODE_MICROGRID_AC){
        start_ac_microgrid();
    }
    // pthread_create(&pid[1], NULL, ctrl_data_refresh, NULL); // 放进main
    // pthread_create(&pid[2], NULL, emms2_plan_flush, NULL);// TODO: 删除 
    pthread_create(&pid[3], NULL, flush_screen_control_data, NULL); //TODO:放进main

    //微网打印测试线程
    pthread_t thread_id;
    pthread_create(&thread_id, NULL, microgrid_ac_init_check_loop, NULL); //TODO:放进main

    return 0;
}


int dev_all_info_ptr_json(struct lnxall_buff *lbuf)
{

    int i = 0;
    // 创建info对象
    cJSON *info = cJSON_CreateObject();
    if (!info) 
    {
        ems_syslog(LOG_ERR, "[zxf]Failed to create info object");
        goto ERR;
    }

    // meter
    {
        cJSON *tags = cJSON_CreateArray();
        if (!tags) 
        {
            goto ERR;
        }
        cJSON_AddItemToObject(info, "meter_grid", tags);

        for(i = 0; i < dev_info_all.meter_grid.num;i++)
        {
            cJSON *info_dev = cJSON_CreateObject();
            
            struct _meter_grid_t *dev = &dev_info_all.meter_grid.meter_grid_param[i];
            cJSON_AddStringToObject(info_dev, "no", dev->no);
            cJSON_AddNumberToObject(info_dev, "act_power", dev->info.meter_grid_data.act_power);
            cJSON_AddNumberToObject(info_dev, "rea_power", dev->info.meter_grid_data.rea_power);
            cJSON_AddNumberToObject(info_dev, "appr_power", dev->info.meter_grid_data.appr_power);
            cJSON_AddNumberToObject(info_dev, "factor", dev->info.meter_grid_data.factor);
            cJSON_AddNumberToObject(info_dev, "AphaseVoltage", dev->info.meter_grid_data.AphaseVoltage);
            cJSON_AddNumberToObject(info_dev, "BphaseVoltage", dev->info.meter_grid_data.BphaseVoltage);
            cJSON_AddNumberToObject(info_dev, "CphaseVoltage", dev->info.meter_grid_data.CphaseVoltage);
            cJSON_AddItemToArray(tags, info_dev);

        }
    }

    //PV
    {
        cJSON *tags = cJSON_CreateArray();
        if (!tags) 
        {
            goto ERR;
        }
        cJSON_AddItemToObject(info, "PV", tags);

        for(i = 0; i < dev_info_all.pv.num;i++)
        {
            cJSON *info_dev = cJSON_CreateObject();
            if (!info_dev) 
            {
                goto ERR;
            }

            struct _pv_t *dev = &dev_info_all.pv.pv_param[i];
            cJSON_AddStringToObject(info_dev, "no", dev->no);
            cJSON_AddNumberToObject(info_dev, "pv_data.power", dev->info.pv_data.power);
            cJSON_AddNumberToObject(info_dev, "pv_data.on_line", dev->info.pv_data.on_line);
            cJSON_AddNumberToObject(info_dev, "pv_cfg.scale", dev->info.pv_cfg.scale);
            cJSON_AddNumberToObject(info_dev, "pv_ctrl.power_set", dev->info.pv_ctrl.power_set);
            cJSON_AddItemToArray(tags, info_dev);
        }
    }

    // 
    {
        
        for(i = 0; i < dev_info_all.cabinet_info.num;i++)
        {   
            cJSON *tags = cJSON_CreateArray();
            if (!tags) 
            {
                ems_syslog(LOG_ERR, "[zxf]Failed to create tags array");
                return -1;
            }
            cJSON *info_dev = cJSON_CreateObject();
            if (!info_dev)  
            {
                ems_syslog(LOG_ERR, "[zxf]Failed to create tags array");
                return -1;
            }
            char tmp_buf[10] = "";
            snprintf(tmp_buf, sizeof(tmp_buf), "cab[%.2d]", i);

            cJSON_AddItemToObject(info, tmp_buf, tags);
            cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];

            cJSON_AddNumberToObject(info_dev, "ctrl.pcs_exp_power", cab->cab_ctrl.pcs_exp_power);
            cJSON_AddNumberToObject(info_dev, "ctrl.bms_exp_power", cab->cab_ctrl.bms_exp_power);
            cJSON_AddNumberToObject(info_dev, "ctrl.mppt_exp_power", cab->cab_ctrl.mppt_exp_power);
            cJSON_AddNumberToObject(info_dev, "ctrl.onoff", cab->cab_ctrl.onoff);
            cJSON_AddNumberToObject(info_dev, "ctrl.connect", cab->cab_ctrl.connect);
            cJSON_AddNumberToObject(info_dev, "ctrl.RTM_EN", cab->cab_ctrl.RTM_EN);
            cJSON_AddNumberToObject(info_dev, "ctrl.discharge_max_cfg", cab->cab_ctrl.discharge_max_cfg);
            cJSON_AddNumberToObject(info_dev, "ctrl.charge_max_cfg", cab->cab_ctrl.charge_max_cfg);
            cJSON_AddNumberToObject(info_dev, "ctrl.scale", cab->cab_ctrl.scale);
            cJSON_AddNumberToObject(info_dev, "ctrl.mppt_power_max", cab->cab_ctrl.mppt_power_max);
            cJSON_AddNumberToObject(info_dev, "ctrl.pcs_charge_max_set", cab->cab_ctrl.pcs_charge_max_set);
            cJSON_AddNumberToObject(info_dev, "ctrl.pcs_discharge_max_set", cab->cab_ctrl.pcs_discharge_max_set);
            cJSON_AddNumberToObject(info_dev, "ctrl.bms_charge_enabled", cab->cab_ctrl.bms_charge_enabled);
            cJSON_AddNumberToObject(info_dev, "ctrl.bms_discharge_enabled", cab->cab_ctrl.bms_discharge_enabled);

            cJSON_AddNumberToObject(info_dev, "cfg.mppt_power_max", cab->cab_cfg.mppt_power_max);
            cJSON_AddNumberToObject(info_dev, "cfg.scale", cab->cab_cfg.scale);

            cJSON_AddNumberToObject(info_dev, "data.SOC_average", cab->cab_data.SOC_average);
            cJSON_AddNumberToObject(info_dev, "data.SOC_ceiling", cab->cab_data.SOC_ceiling);
            cJSON_AddNumberToObject(info_dev, "data.SOC_floor", cab->cab_data.SOC_floor);
            cJSON_AddNumberToObject(info_dev, "data.pcs_output_power", cab->cab_data.pcs_output_power);
            cJSON_AddNumberToObject(info_dev, "data.pcs_output_repower", cab->cab_data.pcs_output_repower);
            cJSON_AddNumberToObject(info_dev, "data.mppt_out_power", cab->cab_data.mppt_out_power);
            cJSON_AddNumberToObject(info_dev, "data.battery_sta", cab->cab_data.battery_sta);
            cJSON_AddNumberToObject(info_dev, "data.en", cab->cab_data.en);
            cJSON_AddNumberToObject(info_dev, "data.prohibited_char", cab->cab_data.prohibited_char);
            cJSON_AddNumberToObject(info_dev, "data.prohibited_dischar", cab->cab_data.prohibited_dischar);
            cJSON_AddNumberToObject(info_dev, "data.connect", cab->cab_data.connect);
            cJSON_AddItemToArray(tags, info_dev);
            
            //PCS
            {
                cJSON *tags_dev_pcs = cJSON_CreateObject();
                if (!tags_dev_pcs)  
                {
                    ems_syslog(LOG_ERR, "[zxf]Failed to create tags array");
                    return -1;
                }

                for(int j = 0; j < cab->pcs.num; j++)
                {
                    cJSON *info_dev_pcs = cJSON_CreateObject();
                    if (!info_dev_pcs)  
                    {
                        ems_syslog(LOG_ERR, "[zxf]Failed to create tags array");
                        return -1;
                    }

                    struct _pcs_t *pcs = &cab->pcs.pcs_param[j];
                    cJSON_AddNumberToObject(info_dev_pcs, "data.out_power", pcs->info.pcs_data.out_power);
                    cJSON_AddNumberToObject(info_dev_pcs, "data.out_repower", pcs->info.pcs_data.out_repower);
                    cJSON_AddNumberToObject(info_dev_pcs, "data.statu", pcs->info.pcs_data.statu);
                    cJSON_AddNumberToObject(info_dev_pcs, "data.PF_network", pcs->info.pcs_data.PF_network);
                    cJSON_AddNumberToObject(info_dev_pcs, "ctrl.out_power_set", pcs->info.pcs_ctrl.out_power_set);
                    cJSON_AddNumberToObject(info_dev_pcs, "cfg.scale", pcs->info.pcs_cfg.scale);
                    cJSON_AddStringToObject(info_dev_pcs, "pcs_no", pcs->no);
                    cJSON_AddItemToArray(tags_dev_pcs, info_dev_pcs);
                    
                }
                cJSON_AddItemToObject(tags, "PCS", tags_dev_pcs);
            }

            {
                cJSON *tags_dev_bms = cJSON_CreateObject();
                if (!tags_dev_bms)  
                {
                    ems_syslog(LOG_ERR, "[zxf]Failed to create tags array");
                    return -1;
                }
                for(int j = 0; j < cab->bms.num; j++)
                {
                    cJSON *tags_dev = cJSON_CreateObject();
                    if (!tags_dev)  
                    {
                        ems_syslog(LOG_ERR, "[zxf]Failed to create tags array");
                        return -1;
                    }
                    struct _bms_t *bms = &cab->bms.bms_param[j];
                    cJSON_AddNumberToObject(tags_dev, "data.SOC", bms->info.bms_data.SOC);
                    cJSON_AddNumberToObject(tags_dev, "data.charging_power_max", bms->info.bms_data.charging_power_max);
                    cJSON_AddNumberToObject(tags_dev, "data.discharging_power_max", bms->info.bms_data.discharging_power_max);
                    cJSON_AddNumberToObject(tags_dev, "data.Cur", bms->info.bms_data.Cur);
                    cJSON_AddNumberToObject(tags_dev, "data.Vol", bms->info.bms_data.Vol);
                    cJSON_AddNumberToObject(tags_dev, "cfg.scale", bms->info.bms_cfg.scale);
                    cJSON_AddStringToObject(tags_dev, "no", bms->no);
                    
                    cJSON_AddItemToArray(tags_dev_bms, tags_dev);
                }
                cJSON_AddItemToObject(tags, "BMS", tags_dev_bms);
            }

            {
                cJSON *tags_dev_mppt = cJSON_CreateObject();

                for(int j = 0; j < cab->mppt.num; j++)
                {
                    cJSON *tags_dev = cJSON_CreateObject();
                    struct _mppt_t *mppt = &cab->mppt.mppt_param[j];
                    cJSON_AddNumberToObject(tags_dev, "data.power", mppt->info.mppt_data.power);
                    cJSON_AddNumberToObject(tags_dev, "data.statu", mppt->info.mppt_data.statu);
                    cJSON_AddNumberToObject(tags_dev, "data.mode", mppt->info.mppt_data.mode);
                    cJSON_AddNumberToObject(tags_dev, "ctrl.power_set", mppt->info.mppt_ctrl.power_set);
                    cJSON_AddNumberToObject(tags_dev, "cfg.scale", mppt->info.mppt_cfg.scale);
                    cJSON_AddStringToObject(tags_dev, "no", mppt->no);
                    
                    cJSON_AddItemToArray(tags_dev_mppt, tags_dev);
                }
                cJSON_AddItemToObject(tags, "mppt", tags_dev_mppt);
            }
        }
    }
    char *data = cJSON_PrintUnformatted(info);
    lbuff_sprintf(lbuf, "%s", data);
    free(data);
ERR:
    cJSON_free(info);

    return 0;
}

int micro_dev_function(function_data *input, int input_num, function_data *output, int *output_num)
{
    if (input_num < 1 || 0 == atoi(input->data))
    {
        output[0].data     = strdup(("1:读写锁安全,-1:强制获取,无视读写锁风险 其他无效"));
        output[0].data_len = strlen(output[0].data);
        *output_num = 1;
        return -1;
    }
    struct lnxall_buff lbuf;
    lbuff_init(&lbuf, 1024);
    
    int mode = atoi(input->data);

    if(mode == 1)
    {
        pthread_rwlock_rdlock(&dev_log_rwlock);
        dev_all_info_ptr_json(&lbuf);
        pthread_rwlock_unlock(&dev_log_rwlock);
    }
    else if(mode == -1)
    {
        dev_all_info_ptr_json(&lbuf);
    }
    else
    {
        lbuff_sprintf(&lbuf, "mode ERR 1:读写锁安全,-1:强制获取,无视读写锁风险 其他无效");
    }


    output[0].data     = strdup(lbuf.bufptr);
    output[0].data_len = strlen(output[0].data);
    *output_num = 1;
    return 0;
}


double antiReflux_Reverse_A(double grid_check, double grid_power, double anti_reflux, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, int flag)
{

    // 检查是否逆流,异步计时
    static double pcs_power_reverse = 0;
    static int cnt = 0, delay_cnt = 0, anti_reflux_EN = 0, anti_reflux_cnt = 0;
    static struct UD_log * log_antiReflux = NULL;
    
    
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_reflux_EN 防逆流功率调整记录器
    // anti_reflux_cnt 防逆流执行后 记录多个点位 用于解决防逆流后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_output_last = 0, arr[10] = {0}, min = 0, grid_check_last = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    static double arr_min = 0, pcs_power_tmp = 0;
    // 记录最小值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 


    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        min = 0;
        cnt = 0;
        anti_reflux_EN = 0;
        anti_reflux_cnt = 0;
        time_new = time(NULL);
        return 0;

    }
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: Grid Power: %.2f\n"
       "Anti Reflux: %.2f\n"
       "Filter: %.2f\n"
       "PCS Max Output: %.2f\n"
       "PCS Min Output: %.2f\n"
       "PCS Output: %.2f\n"
       "Flag: %d\n",
       grid_power,          // double 用 %f 格式
       anti_reflux,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       flag);
    pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
    pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_min用于计算窗口期内关口表有几次功率低于min
    // cnt_max 则用于计算 有多少次 窗口功率是大于 min + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if((grid_check_last != grid_check && grid_power != arr[cnt]) || (time(NULL) - time_new > 10) || (grid_power < anti_reflux && grid_power >= 0 && anti_reflux_EN)) //
    {
        if((time(NULL) - time_new) > 10)
        { 
            en_over_time = 1;
            /**///ems_syslog(LOG_ERR,""); // 对内部功率校准
            /**///ems_syslog(LOG_ERR,"连续log标志:超时刷新");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "antiReflux, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_min = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "antiReflux, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power < 0 || anti_reflux_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "antiReflux, adverse current data coverage, grid_power = %lf", grid_power);
            }
            
            if(arr_min > arr[i])
            {
                arr_min = arr[i]; // 拿到最小值
            }

            if(((arr[i]<(min))) || (arr[i] < anti_reflux && arr[i] > 0 )) // 记录不在滤波范围内的次数 且功率小于逆流阈值
            {
                cnt_min++;
            }
            else if(arr[i] > min)  
            {
                cnt_max++;
            }
            else {
                cnt_range++;
            }
        }
        //ems_syslog(LOG_ERR, "antiReflux,  最小值: %lf", arr_min);

        if(anti_reflux_EN)
        {
            anti_reflux_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power > 0 || pcs_output_last == pcs_output)) // 调回 /刷新6个点位后再进行新的平衡点计算 
        {
            //ems_syslog(LOG_ERR, "antiReflux, 刷新6个点位后再进行新的平衡点计算~~, anti_reflux_cnt:%d", anti_reflux_cnt);
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] < 0 || pcs_output < 0)    // 如果说当前就是逆流状态 触发防逆流机制 
        {
            /**///ems_syslog(LOG_ERR,"防逆流触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:防逆流触发");
            time_new = time(NULL);
            pcs_power_reverse = arr_min - anti_reflux + pcs_output;
            min = arr_min;
            anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 逆流触发 time_new = %ld", time_new);
            //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:arr_min = %lf, pcs_output = %lf", arr_min, pcs_output);
        }
        else if(cnt_min >= 3 || cnt_max == WINDOW_SIZE || (cnt_max == WINDOW_SIZE && arr_min > anti_reflux) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power_reverse + filter)) && (pcs_output > (pcs_power_reverse - filter)) && (grid_power >= anti_reflux) && (pcs_power_reverse < anti_reflux))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power_reverse;
            }

            pcs_power_reverse = arr_min - anti_reflux + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "antiReflux, ~~连续log标志:arr_min  = %lf  pcs_output = %lf", arr_min, pcs_output);

            min = arr_min ; // 刷新底限
            if(min < anti_reflux)
                anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 功率调整");
            /**////ems_syslog(LOG_ERR,"刷新底限:%lf", min);
        }

        if(time(NULL) - time_new > 10){
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 超时重置");

        }

        pcs_output_last = pcs_output;
    }
END:
    if (pcs_power_reverse > 0)
        pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
    if(pcs_power_reverse < 0)
        pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
    pcs_power_tmp = pcs_power_reverse;
    ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power = %lf", pcs_power_reverse);

    // 计算新的PCS输出功率
    if(pcs_output < pcs_power_reverse)
    {
        double val = pcs_power_reverse - pcs_output;
        if(val > 1)
        {
            int num = get_discover_dev_num();
            num = num <= 0 ? 1 : num;
            pcs_power_tmp = val > ((arr_min - anti_reflux) / num) ? (pcs_output + (arr_min - anti_reflux) / num) : pcs_power_reverse;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);

        }
        else {
            pcs_power_tmp = pcs_power_reverse;
        }
    }
    if(pcs_power_reverse < 0)
    {
        pcs_power_tmp = pcs_power_reverse;
        if(pcs_output > pcs_power_tmp)
        {
            double val = pcs_output - pcs_power_reverse;
            if(val > 1)
            {
                int num = get_discover_dev_num();
                num = num <= 0 ? 1 : num;
                pcs_power_tmp = pcs_output + (-val / num);
                ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);
            }
            
        }

    }
    grid_check_last = grid_check;
    if(pcs_power_tmp > pcs_output_last)
    {
        double tmp = fabs(pcs_power_tmp) - fabs(pcs_output_last);
        if(tmp > fabs(pcs_max_output * 0.2))
        {
            pcs_power_tmp = pcs_output_last + fabs(pcs_max_output) * 0.2;
        }
    }
UD_log_sprintf(log_antiReflux, "\n期望功率:%lf", pcs_power_tmp);

    if (pcs_power_tmp > 0)
        pcs_power_tmp = (pcs_power_tmp > pcs_max_output ? pcs_max_output : pcs_power_tmp);
    if(pcs_power_tmp < 0)
        pcs_power_tmp = (pcs_power_tmp < pcs_min_output ? pcs_min_output : pcs_power_tmp);
UD_log_sprintf(log_antiReflux, "\n限制后功率:%lf", pcs_power_tmp);
    fwrite_flush_UD_log(log_antiReflux);
    
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: return power = %lf", pcs_power_tmp);
    //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power_tmp;
}


double antiReflux_Reverse_B(double grid_check, double grid_power, double anti_reflux, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, int flag)
{

    // 检查是否逆流,异步计时
    static double pcs_power_reverse = 0;
    static int cnt = 0, delay_cnt = 0, anti_reflux_EN = 0, anti_reflux_cnt = 0;
    static struct UD_log * log_antiReflux = NULL;
    
    
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_reflux_EN 防逆流功率调整记录器
    // anti_reflux_cnt 防逆流执行后 记录多个点位 用于解决防逆流后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_output_last = 0, arr[10] = {0}, min = 0, grid_check_last = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    static double arr_min = 0, pcs_power_tmp = 0;
    // 记录最小值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 


    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        min = 0;
        cnt = 0;
        anti_reflux_EN = 0;
        anti_reflux_cnt = 0;
        time_new = time(NULL);
        return 0;

    }
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: Grid Power: %.2f\n"
       "Anti Reflux: %.2f\n"
       "Filter: %.2f\n"
       "PCS Max Output: %.2f\n"
       "PCS Min Output: %.2f\n"
       "PCS Output: %.2f\n"
       "Flag: %d\n",
       grid_power,          // double 用 %f 格式
       anti_reflux,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       flag);
    pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
    pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_min用于计算窗口期内关口表有几次功率低于min
    // cnt_max 则用于计算 有多少次 窗口功率是大于 min + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if((grid_check_last != grid_check && grid_power != arr[cnt]) || (time(NULL) - time_new > 10) || (grid_power < anti_reflux && grid_power >= 0 && anti_reflux_EN)) //
    {
        if((time(NULL) - time_new) > 10)
        { 
            en_over_time = 1;
            /**///ems_syslog(LOG_ERR,""); // 对内部功率校准
            /**///ems_syslog(LOG_ERR,"连续log标志:超时刷新");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "antiReflux, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_min = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "antiReflux, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power < 0 || anti_reflux_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "antiReflux, adverse current data coverage, grid_power = %lf", grid_power);
            }
            
            if(arr_min > arr[i])
            {
                arr_min = arr[i]; // 拿到最小值
            }

            if(((arr[i]<(min))) || (arr[i] < anti_reflux && arr[i] > 0 )) // 记录不在滤波范围内的次数 且功率小于逆流阈值
            {
                cnt_min++;
            }
            else if(arr[i] > min)  
            {
                cnt_max++;
            }
            else {
                cnt_range++;
            }
        }
        //ems_syslog(LOG_ERR, "antiReflux,  最小值: %lf", arr_min);

        if(anti_reflux_EN)
        {
            anti_reflux_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power > 0 || pcs_output_last == pcs_output)) // 调回 /刷新6个点位后再进行新的平衡点计算 
        {
            //ems_syslog(LOG_ERR, "antiReflux, 刷新6个点位后再进行新的平衡点计算~~, anti_reflux_cnt:%d", anti_reflux_cnt);
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] < 0 || pcs_output < 0)    // 如果说当前就是逆流状态 触发防逆流机制 
        {
            /**///ems_syslog(LOG_ERR,"防逆流触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:防逆流触发");
            time_new = time(NULL);
            pcs_power_reverse = arr_min - anti_reflux + pcs_output;
            min = arr_min;
            anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 逆流触发 time_new = %ld", time_new);
            //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:arr_min = %lf, pcs_output = %lf", arr_min, pcs_output);
        }
        else if(cnt_min >= 3 || cnt_max == WINDOW_SIZE || (cnt_max == WINDOW_SIZE && arr_min > anti_reflux) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power_reverse + filter)) && (pcs_output > (pcs_power_reverse - filter)) && (grid_power >= anti_reflux) && (pcs_power_reverse < anti_reflux))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power_reverse;
            }

            pcs_power_reverse = arr_min - anti_reflux + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "antiReflux, ~~连续log标志:arr_min  = %lf  pcs_output = %lf", arr_min, pcs_output);

            min = arr_min ; // 刷新底限
            if(min < anti_reflux)
                anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 功率调整");
            /**////ems_syslog(LOG_ERR,"刷新底限:%lf", min);
        }

        if(time(NULL) - time_new > 10){
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 超时重置");

        }

        pcs_output_last = pcs_output;
    }
END:
    if (pcs_power_reverse > 0)
        pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
    if(pcs_power_reverse < 0)
        pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
    pcs_power_tmp = pcs_power_reverse;
    ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power = %lf", pcs_power_reverse);

    // 计算新的PCS输出功率
    if(pcs_output < pcs_power_reverse)
    {
        double val = pcs_power_reverse - pcs_output;
        if(val > 1)
        {
            int num = get_discover_dev_num();
            num = num <= 0 ? 1 : num;
            pcs_power_tmp = val > ((arr_min - anti_reflux) / num) ? (pcs_output + (arr_min - anti_reflux) / num) : pcs_power_reverse;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);

        }
        else {
            pcs_power_tmp = pcs_power_reverse;
        }
    }
    if(pcs_power_reverse < 0)
    {
        pcs_power_tmp = pcs_power_reverse;
        if(pcs_output > pcs_power_tmp)
        {
            double val = pcs_output - pcs_power_reverse;
            if(val > 1)
            {
                int num = get_discover_dev_num();
                num = num <= 0 ? 1 : num;
                pcs_power_tmp = pcs_output + (-val / num);
                ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);
            }
            
        }

    }
    grid_check_last = grid_check;
    if(pcs_power_tmp > pcs_output_last)
    {
        double tmp = fabs(pcs_power_tmp) - fabs(pcs_output_last);
        if(tmp > fabs(pcs_max_output * 0.2))
        {
            pcs_power_tmp = pcs_output_last + fabs(pcs_max_output) * 0.2;
        }
    }
UD_log_sprintf(log_antiReflux, "\n期望功率:%lf", pcs_power_tmp);

    if (pcs_power_tmp > 0)
        pcs_power_tmp = (pcs_power_tmp > pcs_max_output ? pcs_max_output : pcs_power_tmp);
    if(pcs_power_tmp < 0)
        pcs_power_tmp = (pcs_power_tmp < pcs_min_output ? pcs_min_output : pcs_power_tmp);
UD_log_sprintf(log_antiReflux, "\n限制后功率:%lf", pcs_power_tmp);
    fwrite_flush_UD_log(log_antiReflux);
    
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: return power = %lf", pcs_power_tmp);
    //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power_tmp;
}


double antiReflux_Reverse_C(double grid_check, double grid_power, double anti_reflux, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, int flag)
{

    // 检查是否逆流,异步计时
    static double pcs_power_reverse = 0;
    static int cnt = 0, delay_cnt = 0, anti_reflux_EN = 0, anti_reflux_cnt = 0;
    static struct UD_log * log_antiReflux = NULL;
    
    
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_reflux_EN 防逆流功率调整记录器
    // anti_reflux_cnt 防逆流执行后 记录多个点位 用于解决防逆流后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_output_last = 0, arr[10] = {0}, min = 0, grid_check_last = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    static double arr_min = 0, pcs_power_tmp = 0;
    // 记录最小值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 


    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        min = 0;
        cnt = 0;
        anti_reflux_EN = 0;
        anti_reflux_cnt = 0;
        time_new = time(NULL);
        return 0;

    }
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: Grid Power: %.2f\n"
       "Anti Reflux: %.2f\n"
       "Filter: %.2f\n"
       "PCS Max Output: %.2f\n"
       "PCS Min Output: %.2f\n"
       "PCS Output: %.2f\n"
       "Flag: %d\n",
       grid_power,          // double 用 %f 格式
       anti_reflux,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       flag);
    pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
    pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_min用于计算窗口期内关口表有几次功率低于min
    // cnt_max 则用于计算 有多少次 窗口功率是大于 min + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if((grid_check_last != grid_check && grid_power != arr[cnt]) || (time(NULL) - time_new > 10) || (grid_power < anti_reflux && grid_power >= 0 && anti_reflux_EN)) //
    {
        if((time(NULL) - time_new) > 10)
        { 
            en_over_time = 1;
            /**///ems_syslog(LOG_ERR,""); // 对内部功率校准
            /**///ems_syslog(LOG_ERR,"连续log标志:超时刷新");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "antiReflux, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_min = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "antiReflux, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power < 0 || anti_reflux_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "antiReflux, adverse current data coverage, grid_power = %lf", grid_power);
            }
            
            if(arr_min > arr[i])
            {
                arr_min = arr[i]; // 拿到最小值
            }

            if(((arr[i]<(min))) || (arr[i] < anti_reflux && arr[i] > 0 )) // 记录不在滤波范围内的次数 且功率小于逆流阈值
            {
                cnt_min++;
            }
            else if(arr[i] > min)  
            {
                cnt_max++;
            }
            else {
                cnt_range++;
            }
        }
        //ems_syslog(LOG_ERR, "antiReflux,  最小值: %lf", arr_min);

        if(anti_reflux_EN)
        {
            anti_reflux_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power > 0 || pcs_output_last == pcs_output)) // 调回 /刷新6个点位后再进行新的平衡点计算 
        {
            //ems_syslog(LOG_ERR, "antiReflux, 刷新6个点位后再进行新的平衡点计算~~, anti_reflux_cnt:%d", anti_reflux_cnt);
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] < 0 || pcs_output < 0)    // 如果说当前就是逆流状态 触发防逆流机制 
        {
            /**///ems_syslog(LOG_ERR,"防逆流触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:防逆流触发");
            time_new = time(NULL);
            pcs_power_reverse = arr_min - anti_reflux + pcs_output;
            min = arr_min;
            anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 逆流触发 time_new = %ld", time_new);
            //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:arr_min = %lf, pcs_output = %lf", arr_min, pcs_output);
        }
        else if(cnt_min >= 3 || cnt_max == WINDOW_SIZE || (cnt_max == WINDOW_SIZE && arr_min > anti_reflux) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power_reverse + filter)) && (pcs_output > (pcs_power_reverse - filter)) && (grid_power >= anti_reflux) && (pcs_power_reverse < anti_reflux))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power_reverse;
            }

            pcs_power_reverse = arr_min - anti_reflux + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "antiReflux, ~~连续log标志:arr_min  = %lf  pcs_output = %lf", arr_min, pcs_output);

            min = arr_min ; // 刷新底限
            if(min < anti_reflux)
                anti_reflux_EN = 1;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 功率调整");
            /**////ems_syslog(LOG_ERR,"刷新底限:%lf", min);
        }

        if(time(NULL) - time_new > 10){
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: 超时重置");

        }

        pcs_output_last = pcs_output;
    }
END:
    if (pcs_power_reverse > 0)
        pcs_power_reverse = (pcs_power_reverse > pcs_max_output ? pcs_max_output : pcs_power_reverse);
    if(pcs_power_reverse < 0)
        pcs_power_reverse = (pcs_power_reverse < pcs_min_output ? pcs_min_output : pcs_power_reverse);
    pcs_power_tmp = pcs_power_reverse;
    ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power = %lf", pcs_power_reverse);

    // 计算新的PCS输出功率
    if(pcs_output < pcs_power_reverse)
    {
        double val = pcs_power_reverse - pcs_output;
        if(val > 1)
        {
            int num = get_discover_dev_num();
            num = num <= 0 ? 1 : num;
            pcs_power_tmp = val > ((arr_min - anti_reflux) / num) ? (pcs_output + (arr_min - anti_reflux) / num) : pcs_power_reverse;
            ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);

        }
        else {
            pcs_power_tmp = pcs_power_reverse;
        }
    }
    if(pcs_power_reverse < 0)
    {
        pcs_power_tmp = pcs_power_reverse;
        if(pcs_output > pcs_power_tmp)
        {
            double val = pcs_output - pcs_power_reverse;
            if(val > 1)
            {
                int num = get_discover_dev_num();
                num = num <= 0 ? 1 : num;
                pcs_power_tmp = pcs_output + (-val / num);
                ems_syslog(LOG_NOTICE,"function:<double antiReflux(...)>: pcs_power_tmp = %lf, arr_min = %lf, anti_reflux = %lf", pcs_power_tmp, arr_min, anti_reflux);
            }
            
        }

    }
    grid_check_last = grid_check;
    if(pcs_power_tmp > pcs_output_last)
    {
        double tmp = fabs(pcs_power_tmp) - fabs(pcs_output_last);
        if(tmp > fabs(pcs_max_output * 0.2))
        {
            pcs_power_tmp = pcs_output_last + fabs(pcs_max_output) * 0.2;
        }
    }
UD_log_sprintf(log_antiReflux, "\n期望功率:%lf", pcs_power_tmp);

    if (pcs_power_tmp > 0)
        pcs_power_tmp = (pcs_power_tmp > pcs_max_output ? pcs_max_output : pcs_power_tmp);
    if(pcs_power_tmp < 0)
        pcs_power_tmp = (pcs_power_tmp < pcs_min_output ? pcs_min_output : pcs_power_tmp);
UD_log_sprintf(log_antiReflux, "\n限制后功率:%lf", pcs_power_tmp);
    fwrite_flush_UD_log(log_antiReflux);
    
    ems_syslog(LOG_NOTICE, "function:<double antiReflux(...)>: return power = %lf", pcs_power_tmp);
    //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power_tmp;
}



double antiReflux_A(double grid_power, double anti_reflux, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, int flag)
{

    // 检查是否逆流,异步计时

    static int cnt = 0, delay_cnt = 0, anti_reflux_EN = 0, anti_reflux_cnt = 0;
    static struct UD_log * log_antiReflux = NULL;
    
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_reflux_EN 防逆流功率调整记录器
    // anti_reflux_cnt 防逆流执行后 记录多个点位 用于解决防逆流后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_power = 0, pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, min = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    double arr_min = 0;
    // 记录最小值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
    if(NULL != log_antiReflux)
    {
        UD_log_sprintf(log_antiReflux, 
            "grid_power = %lf, anti_reflux = %lf, filter = %lf, pcs_max_output = %lf, pcs_min_output = %lf, pcs_output = %lf, flag = %d\n", 
            grid_power, anti_reflux, filter, pcs_max_output, pcs_min_output, pcs_output, flag);
        
    }
    else 
    {
        log_antiReflux = UD_log_creat("antiReflux.log", set_antiReflux_log_en);
    }


    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        pcs_power = 0;
        min = 0;
        cnt = 0;
        anti_reflux_EN = 0;
        anti_reflux_cnt = 0;
    }
    ems_syslog(LOG_DEBUG, "function:<double antiReflux(...)>: Grid Power: %.2f\n"
       "Anti Reflux: %.2f\n"
       "Filter: %.2f\n"
       "PCS Max Output: %.2f\n"
       "PCS Min Output: %.2f\n"
       "PCS Output: %.2f\n"
       "Flag: %d\n",
       grid_power,          // double 用 %f 格式
       anti_reflux,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       flag);
    pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_min用于计算窗口期内关口表有几次功率低于min
    // cnt_max 则用于计算 有多少次 窗口功率是大于 min + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if(grid_power != arr[cnt] || time(NULL) - time_new > 10 || (grid_power < anti_reflux && grid_power >= 0 && anti_reflux_EN)) //
    {
        if((time(NULL) - time_new) > 10)
        {
            en_over_time = 1;
            /**///ems_syslog(LOG_ERR,""); // 对内部功率校准
            /**///ems_syslog(LOG_ERR,"连续log标志:超时刷新");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "antiReflux, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_min = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "antiReflux, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power < 0 || anti_reflux_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "antiReflux, adverse current data coverage, grid_power = %lf", grid_power);
            }
            
            if(arr_min > arr[i])
            {
                arr_min = arr[i]; // 拿到最小值
            }

            if(((arr[i]<(min))) || (arr[i] < anti_reflux && arr[i] > 0 )) // 记录不在滤波范围内的次数 且功率小于逆流阈值
            {
                cnt_min++;
            }
            else if(arr[i] > min)  
            {
                cnt_max++;
            }
            else {
                cnt_range++;
            }
        }
        //ems_syslog(LOG_ERR, "antiReflux,  最小值: %lf", arr_min);

        if(anti_reflux_EN)
        {
            anti_reflux_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power > 0 || pcs_output_last == pcs_output)) // 调回 /刷新6个点位后再进行新的平衡点计算 
        {
            //ems_syslog(LOG_ERR, "antiReflux, 刷新6个点位后再进行新的平衡点计算~~, anti_reflux_cnt:%d", anti_reflux_cnt);
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] < 0)    // 如果说当前就是逆流状态 触发防逆流机制 
        {
            /**///ems_syslog(LOG_ERR,"防逆流触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:防逆流触发");
            time_new = time(NULL);
            pcs_power = arr_min - anti_reflux + pcs_output;
            min = arr_min;
            anti_reflux_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double antiReflux(...)>: 逆流触发 time_new = %ld", time_new);
            //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:arr_min = %lf, pcs_output = %lf", arr_min, pcs_output);
        }
        else if(cnt_min >= 3 || cnt_max == WINDOW_SIZE || (cnt_max == WINDOW_SIZE && arr_min > anti_reflux) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power + filter)) && (pcs_output > (pcs_power - filter)) && (grid_power >= anti_reflux) && (pcs_power < anti_reflux))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power;
            }

            pcs_power = arr_min - anti_reflux + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "antiReflux, ~~连续log标志:arr_min  = %lf  pcs_output = %lf", arr_min, pcs_output);

            min = arr_min ; // 刷新底限
            if(min < anti_reflux)
                anti_reflux_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double antiReflux(...)>: 功率调整");
            /**////ems_syslog(LOG_ERR,"刷新底限:%lf", min);
        }

        if(time(NULL) - time_new > 10){
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;
            ems_syslog(LOG_DEBUG,"function:<double antiReflux(...)>: 超时重置");

        }

        pcs_output_last = pcs_output;
    }

END:
UD_log_sprintf(log_antiReflux, "\n期望功率:%lf", pcs_power);

    if (pcs_power > 0)
        pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    if(pcs_power < 0)
        pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
UD_log_sprintf(log_antiReflux, "\n限制后功率:%lf", pcs_power);
    fwrite_flush_UD_log(log_antiReflux);
    
    ems_syslog(LOG_DEBUG, "function:<double antiReflux(...)>: return power = %lf", pcs_power);
    //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power;
}

double antiReflux_B(double grid_power, double anti_reflux, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, int flag)
{

    // 检查是否逆流,异步计时

    static int cnt = 0, delay_cnt = 0, anti_reflux_EN = 0, anti_reflux_cnt = 0;
    static struct UD_log * log_antiReflux = NULL;
    
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_reflux_EN 防逆流功率调整记录器
    // anti_reflux_cnt 防逆流执行后 记录多个点位 用于解决防逆流后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_power = 0, pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, min = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    double arr_min = 0;
    // 记录最小值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
    if(NULL != log_antiReflux)
    {
        UD_log_sprintf(log_antiReflux, 
            "grid_power = %lf, anti_reflux = %lf, filter = %lf, pcs_max_output = %lf, pcs_min_output = %lf, pcs_output = %lf, flag = %d\n", 
            grid_power, anti_reflux, filter, pcs_max_output, pcs_min_output, pcs_output, flag);
        
    }
    else 
    {
        log_antiReflux = UD_log_creat("antiReflux.log", set_antiReflux_log_en);
    }


    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        pcs_power = 0;
        min = 0;
        cnt = 0;
        anti_reflux_EN = 0;
        anti_reflux_cnt = 0;
    }
    ems_syslog(LOG_DEBUG, "function:<double antiReflux(...)>: Grid Power: %.2f\n"
       "Anti Reflux: %.2f\n"
       "Filter: %.2f\n"
       "PCS Max Output: %.2f\n"
       "PCS Min Output: %.2f\n"
       "PCS Output: %.2f\n"
       "Flag: %d\n",
       grid_power,          // double 用 %f 格式
       anti_reflux,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       flag);
    pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_min用于计算窗口期内关口表有几次功率低于min
    // cnt_max 则用于计算 有多少次 窗口功率是大于 min + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if(grid_power != arr[cnt] || time(NULL) - time_new > 10 || (grid_power < anti_reflux && grid_power >= 0 && anti_reflux_EN)) //
    {
        if((time(NULL) - time_new) > 10)
        {
            en_over_time = 1;
            /**///ems_syslog(LOG_ERR,""); // 对内部功率校准
            /**///ems_syslog(LOG_ERR,"连续log标志:超时刷新");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "antiReflux, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_min = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "antiReflux, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power < 0 || anti_reflux_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "antiReflux, adverse current data coverage, grid_power = %lf", grid_power);
            }
            
            if(arr_min > arr[i])
            {
                arr_min = arr[i]; // 拿到最小值
            }

            if(((arr[i]<(min))) || (arr[i] < anti_reflux && arr[i] > 0 )) // 记录不在滤波范围内的次数 且功率小于逆流阈值
            {
                cnt_min++;
            }
            else if(arr[i] > min)  
            {
                cnt_max++;
            }
            else {
                cnt_range++;
            }
        }
        //ems_syslog(LOG_ERR, "antiReflux,  最小值: %lf", arr_min);

        if(anti_reflux_EN)
        {
            anti_reflux_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power > 0 || pcs_output_last == pcs_output)) // 调回 /刷新6个点位后再进行新的平衡点计算 
        {
            //ems_syslog(LOG_ERR, "antiReflux, 刷新6个点位后再进行新的平衡点计算~~, anti_reflux_cnt:%d", anti_reflux_cnt);
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] < 0)    // 如果说当前就是逆流状态 触发防逆流机制 
        {
            /**///ems_syslog(LOG_ERR,"防逆流触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:防逆流触发");
            time_new = time(NULL);
            pcs_power = arr_min - anti_reflux + pcs_output;
            min = arr_min;
            anti_reflux_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double antiReflux(...)>: 逆流触发 time_new = %ld", time_new);
            //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:arr_min = %lf, pcs_output = %lf", arr_min, pcs_output);
        }
        else if(cnt_min >= 3 || cnt_max == WINDOW_SIZE || (cnt_max == WINDOW_SIZE && arr_min > anti_reflux) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power + filter)) && (pcs_output > (pcs_power - filter)) && (grid_power >= anti_reflux) && (pcs_power < anti_reflux))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power;
            }

            pcs_power = arr_min - anti_reflux + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "antiReflux, ~~连续log标志:arr_min  = %lf  pcs_output = %lf", arr_min, pcs_output);

            min = arr_min ; // 刷新底限
            if(min < anti_reflux)
                anti_reflux_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double antiReflux(...)>: 功率调整");
            /**////ems_syslog(LOG_ERR,"刷新底限:%lf", min);
        }

        if(time(NULL) - time_new > 10){
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;
            ems_syslog(LOG_DEBUG,"function:<double antiReflux(...)>: 超时重置");

        }

        pcs_output_last = pcs_output;
    }

END:
UD_log_sprintf(log_antiReflux, "\n期望功率:%lf", pcs_power);

    if (pcs_power > 0)
        pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    if(pcs_power < 0)
        pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
UD_log_sprintf(log_antiReflux, "\n限制后功率:%lf", pcs_power);
    fwrite_flush_UD_log(log_antiReflux);
    
    ems_syslog(LOG_DEBUG, "function:<double antiReflux(...)>: return power = %lf", pcs_power);
    //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power;
}

double antiReflux_C(double grid_power, double anti_reflux, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, int flag)
{

    // 检查是否逆流,异步计时

    static int cnt = 0, delay_cnt = 0, anti_reflux_EN = 0, anti_reflux_cnt = 0;
    static struct UD_log * log_antiReflux = NULL;
    
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_reflux_EN 防逆流功率调整记录器
    // anti_reflux_cnt 防逆流执行后 记录多个点位 用于解决防逆流后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_power = 0, pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, min = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    double arr_min = 0;
    // 记录最小值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
    if(NULL != log_antiReflux)
    {
        UD_log_sprintf(log_antiReflux, 
            "grid_power = %lf, anti_reflux = %lf, filter = %lf, pcs_max_output = %lf, pcs_min_output = %lf, pcs_output = %lf, flag = %d\n", 
            grid_power, anti_reflux, filter, pcs_max_output, pcs_min_output, pcs_output, flag);
        
    }
    else 
    {
        log_antiReflux = UD_log_creat("antiReflux.log", set_antiReflux_log_en);
    }


    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        pcs_power = 0;
        min = 0;
        cnt = 0;
        anti_reflux_EN = 0;
        anti_reflux_cnt = 0;
    }
    ems_syslog(LOG_DEBUG, "function:<double antiReflux(...)>: Grid Power: %.2f\n"
       "Anti Reflux: %.2f\n"
       "Filter: %.2f\n"
       "PCS Max Output: %.2f\n"
       "PCS Min Output: %.2f\n"
       "PCS Output: %.2f\n"
       "Flag: %d\n",
       grid_power,          // double 用 %f 格式
       anti_reflux,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       flag);
    pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_min用于计算窗口期内关口表有几次功率低于min
    // cnt_max 则用于计算 有多少次 窗口功率是大于 min + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if(grid_power != arr[cnt] || time(NULL) - time_new > 10 || (grid_power < anti_reflux && grid_power >= 0 && anti_reflux_EN)) //
    {
        if((time(NULL) - time_new) > 10)
        {
            en_over_time = 1;
            /**///ems_syslog(LOG_ERR,""); // 对内部功率校准
            /**///ems_syslog(LOG_ERR,"连续log标志:超时刷新");
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "antiReflux, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_min = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "antiReflux, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power < 0 || anti_reflux_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "antiReflux, adverse current data coverage, grid_power = %lf", grid_power);
            }
            
            if(arr_min > arr[i])
            {
                arr_min = arr[i]; // 拿到最小值
            }

            if(((arr[i]<(min))) || (arr[i] < anti_reflux && arr[i] > 0 )) // 记录不在滤波范围内的次数 且功率小于逆流阈值
            {
                cnt_min++;
            }
            else if(arr[i] > min)  
            {
                cnt_max++;
            }
            else {
                cnt_range++;
            }
        }
        //ems_syslog(LOG_ERR, "antiReflux,  最小值: %lf", arr_min);

        if(anti_reflux_EN)
        {
            anti_reflux_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power > 0 || pcs_output_last == pcs_output)) // 调回 /刷新6个点位后再进行新的平衡点计算 
        {
            //ems_syslog(LOG_ERR, "antiReflux, 刷新6个点位后再进行新的平衡点计算~~, anti_reflux_cnt:%d", anti_reflux_cnt);
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] < 0)    // 如果说当前就是逆流状态 触发防逆流机制 
        {
            /**///ems_syslog(LOG_ERR,"防逆流触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:防逆流触发");
            time_new = time(NULL);
            pcs_power = arr_min - anti_reflux + pcs_output;
            min = arr_min;
            anti_reflux_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double antiReflux(...)>: 逆流触发 time_new = %ld", time_new);
            //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:arr_min = %lf, pcs_output = %lf", arr_min, pcs_output);
        }
        else if(cnt_min >= 3 || cnt_max == WINDOW_SIZE || (cnt_max == WINDOW_SIZE && arr_min > anti_reflux) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power + filter)) && (pcs_output > (pcs_power - filter)) && (grid_power >= anti_reflux) && (pcs_power < anti_reflux))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power;
            }

            pcs_power = arr_min - anti_reflux + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "antiReflux, ~~连续log标志:arr_min  = %lf  pcs_output = %lf", arr_min, pcs_output);

            min = arr_min ; // 刷新底限
            if(min < anti_reflux)
                anti_reflux_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double antiReflux(...)>: 功率调整");
            /**////ems_syslog(LOG_ERR,"刷新底限:%lf", min);
        }

        if(time(NULL) - time_new > 10){
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;
            ems_syslog(LOG_DEBUG,"function:<double antiReflux(...)>: 超时重置");

        }

        pcs_output_last = pcs_output;
    }

END:
UD_log_sprintf(log_antiReflux, "\n期望功率:%lf", pcs_power);

    if (pcs_power > 0)
        pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    if(pcs_power < 0)
        pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
UD_log_sprintf(log_antiReflux, "\n限制后功率:%lf", pcs_power);
    fwrite_flush_UD_log(log_antiReflux);
    
    ems_syslog(LOG_DEBUG, "function:<double antiReflux(...)>: return power = %lf", pcs_power);
    //ems_syslog(LOG_ERR, "antiReflux, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power;
}


double xl_antiReflux_A(double grid_power, double Pmlmax, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, double _Pmlmax, int flag)
{
    static int cnt = 0, delay_cnt = 0, anti_exceed_EN = 0, anti_reflux_cnt = 0;
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_exceed_EN 超需量功率调整记录器
    // anti_reflux_cnt 超需量执行后 记录多个点位 用于解决超需量后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_power = 0, pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, max = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    double arr_max = 0;
    // 记录最大值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>: Grid Power: %.2f\n"
       "Pmlmax: %.2f\n"
       "Filter: %.2f\n"
       "PCS Max Output: %.2f\n"
       "PCS Min Output: %.2f\n"
       "PCS Output: %.2f\n"
       "_Pmlmax: %.2f\n"
       "Flag: %d\n",
       grid_power,          // double 用 %f 格式
       Pmlmax,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       _Pmlmax,
       flag);
    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        pcs_power = 0;
        max = 0;
        cnt = 0;
        anti_exceed_EN = 0;
        anti_reflux_cnt = 0;
    }

    pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_max用于计算窗口期内关口表有几次功率高于max
    // cnt_min 则用于计算 有多少次 窗口功率是小于 max + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if(grid_power != arr[cnt] || time(NULL) - time_new > 10 || (grid_power < Pmlmax && (grid_power >= _Pmlmax)  && anti_exceed_EN)) //
    {
        if (time(NULL) - time_new > 10)
        {
            en_over_time = 1;
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "algorithm, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_max = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "algorithm, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power > Pmlmax || anti_exceed_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "algorithm, over capacity data coverage, grid_power = %lf", grid_power);
            }

            if(arr_max < arr[i])
            {
                arr_max = arr[i]; // 拿到最大值
            }

            if(arr[i] > max || (arr[i] < Pmlmax && arr[i] >_Pmlmax)) // 记录不在滤波范围内的次数 且功率大于需量阈值_Pmlmax
            {
                cnt_max++;
            }
            else if(arr[i] < max)  
            {
                cnt_min++;
            }
            else {
                cnt_range++;
            }

        }
        //ems_syslog(LOG_ERR, "algorithm, 最大值: %lf", arr_max);

        if(anti_exceed_EN)
        {
            anti_exceed_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power < Pmlmax || pcs_output_last == pcs_output))
        {
            //ems_syslog(LOG_ERR, "algorithm, 刷新6个点位后再进行新的平衡点计算~~");
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] > Pmlmax)    // 如果说当前就是超需量状态 触发超需量机制 
        {
            /**////**///ems_syslog(LOG_ERR,"超需量触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:超需量触发");
            time_new = time(NULL);
            pcs_power = arr_max - _Pmlmax + pcs_output;
            max = arr_max;
            anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 过需量触发 time_new = %ld", time_new);
        }
        else if(cnt_max >= 3 || cnt_min == WINDOW_SIZE || (cnt_min == WINDOW_SIZE && arr_max < _Pmlmax) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power + filter)) && (pcs_output > (pcs_power - filter)) && (grid_power <= _Pmlmax))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power;
            }

            pcs_power = arr_max - _Pmlmax + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "algorithm, ~~连续log标志:arr_max  = %lf  pcs_output = %lf", arr_max, pcs_output);

            max = arr_max ; // 刷新底限
            if(max > _Pmlmax)
                anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 功率调整");

           /**///ems_syslog(LOG_ERR,"刷新底限:%lf", max);

        }

        if(time(NULL) - time_new > 10) {
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;           
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 超时重置");
        }

        pcs_output_last = pcs_output;  
    }

END:
    if (pcs_power > 0)
        pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    if(pcs_power < 0)
        pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);

    //ems_syslog(LOG_ERR, "algorithm, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power;
}

double xl_antiReflux_B(double grid_power, double Pmlmax, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, double _Pmlmax, int flag)
{
    static int cnt = 0, delay_cnt = 0, anti_exceed_EN = 0, anti_reflux_cnt = 0;
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_exceed_EN 超需量功率调整记录器
    // anti_reflux_cnt 超需量执行后 记录多个点位 用于解决超需量后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_power = 0, pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, max = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    double arr_max = 0;
    // 记录最大值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>: Grid Power: %.2f\n"
       "Pmlmax: %.2f\n"
       "Filter: %.2f\n"
       "PCS Max Output: %.2f\n"
       "PCS Min Output: %.2f\n"
       "PCS Output: %.2f\n"
       "_Pmlmax: %.2f\n"
       "Flag: %d\n",
       grid_power,          // double 用 %f 格式
       Pmlmax,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       _Pmlmax,
       flag);
    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        pcs_power = 0;
        max = 0;
        cnt = 0;
        anti_exceed_EN = 0;
        anti_reflux_cnt = 0;
    }

    pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_max用于计算窗口期内关口表有几次功率高于max
    // cnt_min 则用于计算 有多少次 窗口功率是小于 max + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if(grid_power != arr[cnt] || time(NULL) - time_new > 10 || (grid_power < Pmlmax && (grid_power >= _Pmlmax)  && anti_exceed_EN)) //
    {
        if (time(NULL) - time_new > 10)
        {
            en_over_time = 1;
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "algorithm, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_max = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "algorithm, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power > Pmlmax || anti_exceed_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "algorithm, over capacity data coverage, grid_power = %lf", grid_power);
            }

            if(arr_max < arr[i])
            {
                arr_max = arr[i]; // 拿到最大值
            }

            if(arr[i] > max || (arr[i] < Pmlmax && arr[i] >_Pmlmax)) // 记录不在滤波范围内的次数 且功率大于需量阈值_Pmlmax
            {
                cnt_max++;
            }
            else if(arr[i] < max)  
            {
                cnt_min++;
            }
            else {
                cnt_range++;
            }

        }
        //ems_syslog(LOG_ERR, "algorithm, 最大值: %lf", arr_max);

        if(anti_exceed_EN)
        {
            anti_exceed_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power < Pmlmax || pcs_output_last == pcs_output))
        {
            //ems_syslog(LOG_ERR, "algorithm, 刷新6个点位后再进行新的平衡点计算~~");
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] > Pmlmax)    // 如果说当前就是超需量状态 触发超需量机制 
        {
            /**////**///ems_syslog(LOG_ERR,"超需量触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:超需量触发");
            time_new = time(NULL);
            pcs_power = arr_max - _Pmlmax + pcs_output;
            max = arr_max;
            anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 过需量触发 time_new = %ld", time_new);
        }
        else if(cnt_max >= 3 || cnt_min == WINDOW_SIZE || (cnt_min == WINDOW_SIZE && arr_max < _Pmlmax) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power + filter)) && (pcs_output > (pcs_power - filter)) && (grid_power <= _Pmlmax))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power;
            }

            pcs_power = arr_max - _Pmlmax + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "algorithm, ~~连续log标志:arr_max  = %lf  pcs_output = %lf", arr_max, pcs_output);

            max = arr_max ; // 刷新底限
            if(max > _Pmlmax)
                anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 功率调整");

           /**///ems_syslog(LOG_ERR,"刷新底限:%lf", max);

        }

        if(time(NULL) - time_new > 10) {
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;           
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 超时重置");
        }

        pcs_output_last = pcs_output;  
    }

END:
    if (pcs_power > 0)
        pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    if(pcs_power < 0)
        pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);

    //ems_syslog(LOG_ERR, "algorithm, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power;
}

double xl_antiReflux_C(double grid_power, double Pmlmax, double filter, double pcs_max_output, double pcs_min_output, double pcs_output, double _Pmlmax, int flag)
{
    static int cnt = 0, delay_cnt = 0, anti_exceed_EN = 0, anti_reflux_cnt = 0;
    // cnt 窗节点       
    // delay_cnt 超时计数器 长时间关口表功率不变动将通过此计数
    // anti_exceed_EN 超需量功率调整记录器
    // anti_reflux_cnt 超需量执行后 记录多个点位 用于解决超需量后算法震荡问题
    /**///ems_syslog(LOG_ERR,"连续log标志:函数antiReflux刷新");
    static double pcs_power = 0, pcs_output_last = 0, arr[WINDOW_SIZE] = {0}, max = 0;
    // pcs_power PCS的当前输出功率 
    // arr 关口表功率窗

    int en_over_time = 0;
    
    static time_t time_new = 0;
    // 时间记录节点

    double arr_max = 0;
    // 记录最大值
    
    int cnt_min = 0, cnt_max = 0, cnt_range = 0; 
    // 计算滤波后的最小值和最大值出现次数 以及在滤波内的次数
ems_syslog(LOG_DEBUG, "function:<double xl_antiReflux(...)>: Grid Power: %.2f\n"
       "Pmlmax: %.2f\n"
       "Filter: %.2f\n"
       "PCS Max Output: %.2f\n"
       "PCS Min Output: %.2f\n"
       "PCS Output: %.2f\n"
       "_Pmlmax: %.2f\n"
       "Flag: %d\n",
       grid_power,          // double 用 %f 格式
       Pmlmax,         // 保持变量顺序与格式字符串一致
       filter,
       pcs_max_output,
       pcs_min_output,
       pcs_output,
       _Pmlmax,
       flag);
    if(1 == flag)       // 算法重置 状态清空
    {
        for(int i=0;i<WINDOW_SIZE;i++)
        {
            arr[i] = 0;
        }
        pcs_power = 0;
        max = 0;
        cnt = 0;
        anti_exceed_EN = 0;
        anti_reflux_cnt = 0;
    }

    pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);
    // pcs_power = (pcs_power < Micro_data_buf->PCS_data.out_power_min_set ? Micro_data_buf->PCS_data.out_power_min_set : pcs_power);
    
    // 规限解释: cnt_max用于计算窗口期内关口表有几次功率高于max
    // cnt_min 则用于计算 有多少次 窗口功率是小于 max + filter(滤波范围)
    // cnt_range 是范围内的计数 用于在功率波syste动不大时 周期刷新功率 

    // if为真条件: 超时 关口功率变化 关口表功率低于 防逆流参数
    if(grid_power != arr[cnt] || time(NULL) - time_new > 10 || (grid_power < Pmlmax && (grid_power >= _Pmlmax)  && anti_exceed_EN)) //
    {
        if (time(NULL) - time_new > 10)
        {
            en_over_time = 1;
            for (int i = 0; i < WINDOW_SIZE; i++) 
            {
                arr[i] = grid_power;    // 全数据覆盖
            }
            //ems_syslog(LOG_ERR, "algorithm, Timeout full data coverage, grid_power = %lf", grid_power);    
        }
        
        if(grid_power != arr[cnt])
        {
            time_new = time(NULL);
            delay_cnt = 0;
        }
        if(++cnt >= WINDOW_SIZE)
            cnt = 0;
        
        arr_max = grid_power;
        arr[cnt] = grid_power; // 数据录入
        //ems_syslog(LOG_ERR, "algorithm, type-in grid_power = %lf arr[%d]: %lf", grid_power, cnt, arr[cnt]);

        for(int i = 0; i < WINDOW_SIZE; i++)
        {
            if(grid_power > Pmlmax || anti_exceed_EN)
            {
                arr[i] = grid_power;
                //ems_syslog(LOG_ERR, "algorithm, over capacity data coverage, grid_power = %lf", grid_power);
            }

            if(arr_max < arr[i])
            {
                arr_max = arr[i]; // 拿到最大值
            }

            if(arr[i] > max || (arr[i] < Pmlmax && arr[i] >_Pmlmax)) // 记录不在滤波范围内的次数 且功率大于需量阈值_Pmlmax
            {
                cnt_max++;
            }
            else if(arr[i] < max)  
            {
                cnt_min++;
            }
            else {
                cnt_range++;
            }

        }
        //ems_syslog(LOG_ERR, "algorithm, 最大值: %lf", arr_max);

        if(anti_exceed_EN)
        {
            anti_exceed_EN = 0;
            anti_reflux_cnt = 1;
        }

        if(anti_reflux_cnt && (grid_power < Pmlmax || pcs_output_last == pcs_output))
        {
            //ems_syslog(LOG_ERR, "algorithm, 刷新6个点位后再进行新的平衡点计算~~");
            anti_reflux_cnt++;
            if(anti_reflux_cnt < 6) // 刷新6个点位后再进行新的平衡点计算 
            {
                goto END;
            }
            else 
            {
                anti_reflux_cnt = 0;
            }
        }
        /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
        /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

        // if(arr_min < 0 || cnt >= WINDOW_SIZE * 0.3 || cnt_max >= WINDOW_SIZE * 0.9)
        if(arr[cnt] > Pmlmax)    // 如果说当前就是超需量状态 触发超需量机制 
        {
            /**////**///ems_syslog(LOG_ERR,"超需量触发");
            /**///ems_syslog(LOG_ERR,"连续log标志:超需量触发");
            time_new = time(NULL);
            pcs_power = arr_max - _Pmlmax + pcs_output;
            max = arr_max;
            anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 过需量触发 time_new = %ld", time_new);
        }
        else if(cnt_max >= 3 || cnt_min == WINDOW_SIZE || (cnt_min == WINDOW_SIZE && arr_max < _Pmlmax) || en_over_time)       // 功率增加/减少的调整机制
        {
            /**///ems_syslog(LOG_ERR,"min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);
            /**///ems_syslog(LOG_ERR,"连续log标志:min = %lf, arr[cnt] = %lf, cnt_min = %d, cnt_max = %d", min,  arr[cnt], cnt_min, cnt_max);

            time_new = time(NULL);
            if((pcs_output < (pcs_power + filter)) && (pcs_output > (pcs_power - filter)) && (grid_power <= _Pmlmax))   // 对PCS功率滤波
            {
                /**///ems_syslog(LOG_ERR,"连续log标志:pcs_output = pcs_power = %lf", pcs_power);
                pcs_output = pcs_power;
            }

            pcs_power = arr_max - _Pmlmax + pcs_output;  // 40 - 5 + 40 = 
            //ems_syslog(LOG_ERR, "algorithm, ~~连续log标志:arr_max  = %lf  pcs_output = %lf", arr_max, pcs_output);

            max = arr_max ; // 刷新底限
            if(max > _Pmlmax)
                anti_exceed_EN = 1;
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 功率调整");

           /**///ems_syslog(LOG_ERR,"刷新底限:%lf", max);

        }

        if(time(NULL) - time_new > 10) {
            delay_cnt++;
        }

        if(delay_cnt >= 10){
            time_new = time(NULL);
            delay_cnt = 0;           
            ems_syslog(LOG_DEBUG,"function:<double xl_antiReflux(...)>: 超时重置");
        }

        pcs_output_last = pcs_output;  
    }

END:
    if (pcs_power > 0)
        pcs_power = (pcs_power > pcs_max_output ? pcs_max_output : pcs_power);
    if(pcs_power < 0)
        pcs_power = (pcs_power < pcs_min_output ? pcs_min_output : pcs_power);

    //ems_syslog(LOG_ERR, "algorithm, 连续log标志:计算新的PCS输出功率 :%lf", pcs_power);

    return pcs_power;
}