/*
 * @Author: zchuo zhengchen.huo@lnxall.com
 * @Date: 2024-12-05 11:17:42
 * @LastEditors: zchuo zhengchen.huo@lnxall.com
 * @LastEditTime: 2025-05-12 22:53:38
 * @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 <sys/syslog.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#define TEST_CASE 0

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

pthread_mutex_t variable_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t variable_cond = PTHREAD_COND_INITIALIZER;

int state_machine_Init();
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 decision_data_flush();
int traverse_pcs_callback_set_connect(struct _pcs_t *pcs, const char *tag, void* val);
// 尽量少用全局变量 缓冲区数据生命周期与控制器进程共生死 不再设计释放情况 如若被恶意变动 本程序无法负责


// 各项参数
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;
}


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 < NUM_TOU_SEG_MAX; 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; 
    struct tm * timeinfo; 
    time(&rawtime); 
    timeinfo = localtime(&rawtime); 
    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 < NUM_TOU_SEG_MAX; 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_all_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);
    pe_set_power(dev, power_exp);     // 功率下发走适配器不用点位映射
    // set_lc_power(power_exp);

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

    return 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;

    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);
        if(ret)
        {
            return BMS_ERR;
        }

        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);
        if(ret)
        {
            return BMS_ERR;
        }
        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;
        }

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

        cab->cab_ctrl.bms_of_charge |= BMS_charge_power == 0 ? 0 : 1;   // 如果有一个BMS可充，均可充 全不可充则不充
        cab->cab_ctrl.bms_of_discharge |= BMS_discharge_power == 0 ? 0 : 1; 

        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;

    }

    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_ctrl.pcs_charge_max_actual = cab_charge_power;
    cab->cab_ctrl.pcs_discharge_max_actual = cab_discharge_power;
    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;
    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);
        //TODO: 最好是用适配器获取功率确保接口稳定
        if(ret)
        {
            dev->info.pcs_data.out_power = 0;
        }

        dev->info.pcs_data.statu = pe_get_onoff(no);
        if(dev->info.pcs_data.statu < 0)
        {
            ret |= dev->info.pcs_data.statu;
        }
        
        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;
            return PCS_ERR;
        }

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

    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;
    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;

    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);

        if( dev_get_function_double(no, "get_power", &dev->info.meter_pcs_data.power))
        {
            return METER_PCS_ERR;  
        }
        if(( dev_get_function_double(no, "get_A_busvol", &dev->info.meter_pcs_data.AphaseVoltage)) ||\
            ( dev_get_function_double(no, "get_B_busvol", &dev->info.meter_pcs_data.BphaseVoltage)) ||\
            ( dev_get_function_double(no, "get_C_busvol", &dev->info.meter_pcs_data.CphaseVoltage)))
        {
            return METER_PCS_ERR;  
        }
    }
    return _SUCCESS;
 }

int lc_flush_data(cabinet_inside_t *cab)
{
    cab->cab_data.onoff = dev_get_dev_tag_int(cab->no, GET_ON_OFF);
    cab->cab_data.connect = dev_get_dev_tag_int(cab->no, GET_CONNECT);
    cab->cab_data.pcs_output_power = dev_get_dev_tag_float(cab->no, GET_ACT_POWER);
    cab->cab_data.pcs_output_repower = dev_get_dev_tag_float(cab->no, GET_REACTPOWER);
    cab->cab_data.SOC_average = dev_get_dev_tag_float(cab->no, GET_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_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);
	return _SUCCESS;
}

static int flush_cabinet_onoff(int onoff) { // 关注： 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];
        if (onoff){
            if (cabinets->cab_data.en == 0 && cabinets->cab_data.onoff == 0) {
                return 0; // 未知状态
            }  
        }
        else{
            if (cabinets->cab_data.en == 0 && cabinets->cab_data.onoff == 1) {
                return 0; 
            }  
        }      
    }
    return 1;
}

static int flush_cabinet_grid_offgrid(int grid_offgrid) { // 关注： 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];
        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; 
            }  
        }      
    }
    return 1;
}

static int flush_pv_onoff(int onoff) { // 关注： 0:关机 1:开机
    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 (onoff){
            if (_pv->info.pv_data.on_line == 1 && _pv->info.pv_data.statu == 0) {
                return 0; // 未知状态
            }  
        }
        else{
            if (_pv->info.pv_data.on_line == 1 && _pv->info.pv_data.statu == 1) {
                return 0; 
            }  
        }      
    }
    return 1;
}


 /**
  * @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;
            /**///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;
 
	 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);
 
		 if(pe_get_power(no, &dev->info.meter_mppt_data.power) ||
          dev_get_function_double(no, "get_vol", &dev->info.meter_mppt_data.Vol) ||
          dev_get_function_double(no, "get_cur", &dev->info.meter_mppt_data.Cur)
        )
		 {
			 return METER_MPPT_ERR;	
		 }
	 }
	 return _SUCCESS;
 }

 
 /**
  * @description: meter_pv 设备数据刷新
  * @param {cabinet_inside_t} cab
  * @return {*} 0:正常 1:报错
  */
int pv_flush_data(void)
{
	char *no;
    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);
        if(
            ( dev_get_function_double(pv->no, "get_power", &pv->info.pv_data.power)) ||\
            ( dev_get_function_double(pv->no, "get_repower", &pv->info.pv_data.repower)) ||\
            ( dev_get_function_int(pv->no, "get_mode", &pv->info.pv_data.mode)) ||\
            ( dev_get_function_int(pv->no, "get_onoff", &pv->info.pv_data.statu)) ||\
            ( dev_get_function_double(pv->no, "get_A_busvol", &pv->info.pv_data.AphaseVoltage)) ||\
            ( dev_get_function_double(pv->no, "get_B_busvol", &pv->info.pv_data.BphaseVoltage)) ||\
            ( dev_get_function_double(pv->no, "get_C_busvol", &pv->info.pv_data.CphaseVoltage)))
        {
            return PV_ERR;
        }
    }
    return _SUCCESS;
}



  /**
   * @description: meter_pv 设备数据刷新
   * @param {cabinet_inside_t} cab
   * @return {*} 0:正常 1:报错
   */
 int meter_pv_flush_data(void)
 {
	 char *no;
	 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);
		 if(
			 ( dev_get_function_double(meter_pv->no, "get_power", &meter_pv->info.meter_pv_data.power)) ||\
			 ( dev_get_function_double(meter_pv->no, "get_repower", &meter_pv->info.meter_pv_data.repower)) ||\
			 ( dev_get_function_double(meter_pv->no, "get_A_busvol", &meter_pv->info.meter_pv_data.AphaseVoltage)) ||\
			 ( dev_get_function_double(meter_pv->no, "get_B_busvol", &meter_pv->info.meter_pv_data.BphaseVoltage)) ||\
			 ( dev_get_function_double(meter_pv->no, "get_C_busvol", &meter_pv->info.meter_pv_data.CphaseVoltage)))
		 {
			 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;
    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);
        if(
            ( dev_get_function_double(grid->no, "get_power", &grid->info.meter_grid_data.act_power)) ||\
            ( dev_get_function_double(grid->no, "get_repower", &grid->info.meter_grid_data.rea_power)) ||\
            ( dev_get_function_double(grid->no, "get_apprpower", &grid->info.meter_grid_data.appr_power)) ||\
            ( dev_get_function_double(grid->no, "get_factor", &grid->info.meter_grid_data.factor)) ||\
            ( dev_get_function_double(grid->no, "get_A_busvol", &grid->info.meter_grid_data.AphaseVoltage)) ||\
            ( dev_get_function_double(grid->no, "get_B_busvol", &grid->info.meter_grid_data.BphaseVoltage)) ||\
            ( dev_get_function_double(grid->no, "get_C_busvol", &grid->info.meter_grid_data.CphaseVoltage)))
        {
            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];

        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];

        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];

        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];

        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)
{  
    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 (microgrid_cfg.RTM_EN == 0)
    {
        if (soc <= RTM_min_SOC)
            microgrid_cfg.RTM_EN = 1;
        else if (soc >= RTM_max_SOC)
            microgrid_cfg.RTM_EN = 2;
       /**////**///ems_syslog(LOG_ERR,"连续log标志:RTM_EN = %d", microgrid_cfg.RTM_EN);

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

            goto END;
        }
        else if (microgrid_cfg.RTM_EN == 2 &&  (soc <= soc_max))
        {
            microgrid_cfg.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保护函数: 通过PCS功率期望功率 得到BMS充放电功率 利用SOC下限回差的保护函数 本函数会限制PCS最大充放电功率参数 以便后续逻辑对PCS功率约束合理
                 实际上 本函数只有下限回差参与了实际限制 上限回差被用于homingAlgorithmSOC函数 
                 <<在当前版本中 该函数调用于针对单个柜子系统的调控>>
 * @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(double SOC, double SOC_min, double SOC_max, double *pcs_discharge, double *pcs_charge, double out_power_discharge, double out_power_charge, enum ENERGY_DIRECTION flag)
{
    // 放电或者过充后 将PCS最大输出功率按比例衰减 根据SOC实际状态来设置衰减值
    // 例如 SOC = 10 进行50的衰减
    // 这样SOC达到 下限时 PCS的功率将被限制为0
    /**////**///ems_syslog(LOG_ERR,"\n==============>\n信息保护参数\n");
    double difference = 1;
    double return_soc_max = SOC_min + microgrid_ctrl.SOCminReturnDiff;
    double return_soc_min= SOC_min + microgrid_ctrl.SOCminReturnDiff;
    if(microgrid_ctrl.SOCminReturnDiff <= 0)
    {
        microgrid_ctrl.SOCminReturnDiff = 5;
    }
    
    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;
    }
    


    if (SOC <= return_soc_max || SOC >= return_soc_min)
    {
        if (DISCHARGE_DIRECTION == flag && (SOC <= return_soc_min))
        {
            difference = SOC - SOC_min;
            difference = difference < 0 ? 0: difference;

            difference = difference / microgrid_ctrl.SOCminReturnDiff;
            /**////**///ems_syslog(LOG_ERR,"SOC过放保护:%lf", difference);
        }
        else if (CHARGE_DIRECTION == flag && (SOC >= return_soc_max))
        {
            difference = 0;
            /**////**///ems_syslog(LOG_ERR,"SOC过充保护:%lf", difference); 
        }
    }
    if(difference <= 0.01) // 精度调整
        difference = 0;
    
    if(DISCHARGE_DIRECTION == flag)
    {
        /**////**///ems_syslog(LOG_ERR,"放电"); 
        *pcs_discharge = out_power_discharge * difference; // 最大放电限制
        *pcs_charge = -fabs(out_power_charge);
    }
    else if(CHARGE_DIRECTION == flag)
    {
        /**////**///ems_syslog(LOG_ERR,"充电"); 
        *pcs_charge = -fabs(out_power_charge * difference); // 最大充电限制
        *pcs_discharge = out_power_discharge;
    }
    else {  // 静置逻辑时 ems_plan 设置待机 故而PCS应不可充放 算法最终得到0期望功率
        *pcs_charge = 0;
        *pcs_discharge = 0;
    }
    UD_log_sprintf(micro_log, "\n<最大放电限制:%lf>\n", pcs_discharge); 
    UD_log_sprintf(micro_log, "\n<最大充电限制:%lf>\n", pcs_charge); 

    /**////**///ems_syslog(LOG_ERR,"最大放电功率:%lf", 
    /**////**///ems_syslog(LOG_ERR,"最小放电功率:%lf", Micro_data_buf->PCS_data.out_power_min_set); 
    return 0;       // 返回状态值 0 正常，1 最大充电限制执行 2 最大放电限制执行
}



 /*
 防逆流算法:
 特性: 
 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期望功率
 */

// 逆流状态判断

// 将逆流超时的时间记录到文件中
static void update_reflux_times_file()
{
    char   time_ms[64] = {0};
    char*  data        = NULL;
    cJSON* root        = NULL;
    cJSON* item        = NULL;
    char*  str         = NULL;
    snprintf(time_ms, sizeof(time_ms), "%lld", get_time_stamp_ms());

    data = read_file_data(REFLUX_TIMES_FILE);

    root = cJSON_Parse(data);
    if (root == NULL)
    {
        root = cJSON_CreateObject();
        item = cJSON_CreateArray();
        cJSON_AddItemToObject(root, REFLUX_FEILD, item);
    }
    else
    {
        item = cJSON_GetObjectItem(root, REFLUX_FEILD);
        if (item == NULL || cJSON_IsArray(item) == false)
        {
            item = cJSON_CreateArray();
            cJSON_AddItemToObject(root, REFLUX_FEILD, item);
        }
        else
        {
            if (cJSON_GetArraySize(item) > 3)
                server_add_new_log(LOG_CODE_REFLUX, DEV_NO_EMS, LOG_MODE_TRIG, 3, NULL); // 3: 系统锁定, 30 天内超过 3 次逆流锁定
        }
    }

    cJSON_AddItemToArray(item, cJSON_CreateString(time_ms));
    str = cJSON_Print(root);
    write_file_data(REFLUX_TIMES_FILE, str, strlen(str));

    if (data != NULL)
        free(data);
    if (root != NULL)
        cJSON_Delete(root);
    if (str != NULL)
        free(str);
}

static void discharge_reflux_state_check(double grid)
{
    tag_t* reflux_state_tag = find_tag_by_dev_and_node(get_proto_forward_var(), DEV_NO_EMS, REFLUX_STATE);
    if (reflux_state_tag == NULL)
    {
        return;
    }
    int state = reflux_state_tag->data_type == 0 ? reflux_state_tag->read_cache.to_int : reflux_state_tag->read_cache.to_float;
    if (state == EMS_REFLUX_STATE_FAILED)
    {
        return;
    }
    long long curtime = clock_get_ms(); //当前时间
    if (grid < 0.0)
    {
        if (state == EMS_REFLUX_STATE_NORMAL)
        {
            dev_set_dev_tag_int(DEV_NO_EMS, REFLUX_STATE, EMS_REFLUX_STATE_OCCASIONAL_EXCURSION);
            ems_syslog(LOG_WARNING, "reflux state changed to occasional excursion, %llu", curtime);
        }
        else if (state == EMS_REFLUX_STATE_OCCASIONAL_EXCURSION)
        {
            if (curtime - reflux_state_tag->read_cache_time > MAX_REFLUX_DURATION_MS)
            {
                ems_syslog(LOG_WARNING, "reflux state changed to failed, %llu", curtime);
                dev_set_dev_tag_int(DEV_NO_EMS, REFLUX_STATE, EMS_REFLUX_STATE_FAILED);
                update_reflux_times_file();
                server_add_new_log(LOG_CODE_REFLUX, DEV_NO_EMS, LOG_MODE_TRIG, 1, NULL); // 逆流锁定, 长时间未限制输出
            }
        }
    }
    else
    {
        ems_syslog(LOG_INFO, "reflux_state set to normal, %llu", curtime);
        dev_set_dev_tag_int(DEV_NO_EMS, REFLUX_STATE, EMS_REFLUX_STATE_OCCASIONAL_EXCURSION);
    }
}

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)
{

    // 检查是否逆流,异步计时
    discharge_reflux_state_check(grid_power);

    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(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_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\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;
}


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

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);
    if(microgrid_ctrl.en_DOD == 1)
    {
        microgrid_ctrl.SOC_max_combin = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMAX); //  = SOCmax;
        microgrid_ctrl.SOC_min_combin = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMIN); //  = SOcMin;
        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 = 101;
        microgrid_ctrl.SOC_min_combin = -1;
        microgrid_ctrl.SOC_max_netdead = 101;
        microgrid_ctrl.SOC_min_netdead = -1;
    }    
    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.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.DgDiff = g_usercfg_variant.DgDiff;
    microgrid_ctrl.SocAlarmThreshold = g_usercfg_variant.SocAlarmThreshold;
    microgrid_ctrl.en_ac_c2d = g_usercfg_variant.en_ac_c2d;
    microgrid_ctrl.en_ac_d2c = g_usercfg_variant.en_ac_d2c;
    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_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_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.en == 0 && cab->pcs.num > 0)
        *(int *)num  += 1;
    return 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;

    //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;

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

    //pcs--------------------------------------------------------------------
    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_average = (double)_soc / num;

    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.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;
            }
        }  
    }
    microgrid_data.SOC_average = SOC_average;
    microgrid_data.SOC_ceiling = SOC_ceiling;
    microgrid_data.SOC_floor = SOC_floor;    
}

/**
 * @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;
}

/**
 * @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_all_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,
            1, 
            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;
        }
        else if(1 == *(int *)flag && 1 == ret)
        {
            i--;
        }
    }

    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);

    *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>\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);
    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);

    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_of_charge)
        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);

    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];
        ret = set_power_all_dev(
            mppt->no,
            mppt->info.mppt_ctrl.power_set,
            mppt->info.mppt_ctrl.last_set_power, 
            mppt->info.mppt_ctrl.last_time,
            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;
        }
        else if(1 == *(int *)flag && 1 == ret)  // ret = 2表上次设置值与本次一致 无需设置
        {
            i--;
        }
    }

    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)
{
    for (int i = 0; i < cab->mppt.num; i++) {

        struct _mppt_t *mppt = &cab->mppt.mppt_param[i];
        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;
        mppt->info.mppt_ctrl.power_set = mppt->info.mppt_cfg.scale * cab->cab_ctrl.mppt_exp_power; // 给每个设备分配功率
    }
    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_of_charge)
        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;
    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(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;

}

/**
 * @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;
}


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

/**
 * @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);
            }
            else 
            {
                UD_log_sprintf(micro_log, " \n<设置并离网断路器已[%d] 1:设置闭合 0:设置断开>\n", 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;

    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
        );
    }
    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);

    microgrid_ctrl.pcs_exp_power = power_exp;
    dev_set_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER, power_exp);
    dev_set_dev_tag_float(DEV_NO_EMS, EXPECT_ACT_POWER, power_exp);

    traverse_cab_dev_func_arg(set_all_pcs_exp_power, &flag);
    return 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.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.MaxDemand = dev_get_dev_tag_int(DEV_NO_EMS, MAX_DEMAND);

        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"));
        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);
        if(microgrid_ctrl.en_DOD == 1)
        {
            microgrid_ctrl.SOC_max_combin = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMAX); //  = SOCmax;
            microgrid_ctrl.SOC_min_combin = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMIN); //  = SOcMin;
            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 = 101;
            microgrid_ctrl.SOC_min_combin = -1;
            microgrid_ctrl.SOC_max_netdead = 101;
            microgrid_ctrl.SOC_min_netdead = -1;
        }
        
        // microgrid_ctrl.DemandErr = g_usercfg_variant.Pmlmax; // TODO
        microgrid_ctrl.Pmlmax = dev_get_dev_tag_int(DEV_NO_EMS, EMS_PMLMAX);
        // 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_AC_C2D);
        microgrid_ctrl.en_ac_d2c = dev_get_dev_tag_int(DEV_NO_EMS, EN_AC_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.ControlMode = g_usercfg_variant.ControlMode;
    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) { // 对等模式刷新柜内数据（直流侧耦合）
        
        traverse_cab_dev_func(pcs_flush_data);
        traverse_cab_dev_func(bms_flush_data);
        traverse_cab_dev_func(mppt_flush_data);

        traverse_cab_dev_func(meter_mppt_flush_data);
        traverse_cab_dev_func(meter_pcs_flush_data);
    }
    else if(MODE_MICROGRID_AC == microgrid_cfg.mode_microgrid){ // 主从模式刷新柜内数据（交流侧耦合）
        traverse_cab_dev_func(lc_flush_data);
    }
    
    // 柜外数据刷新
    if(MODE_MICROGRID_AC == microgrid_cfg.mode_microgrid)
    {
        meter_pv_flush_data();
        pv_flush_data();
    }
    if(meter_grid_flush_data()) // 关口表功率刷新有误 终止业务
    {
    }
    if(meter_load_flush_data()) // 负载表功率刷新有误 终止业务
    {
    }
    if(meter_dg_flush_data()) // 柴发表功率刷新有误 终止业务
    {
    }

    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);
    }
    
    microgrid_ctrl.plan_set_power = (double)get_now_plan_power();
    if (microgrid_ctrl.ControlMode == EMS_AUTO_MODE)  dev_set_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER, microgrid_ctrl.plan_set_power);
    /**///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;
            traverse_cab_dev_func_arg(get_all_cab_out_power, &temp_power);
            traverse_cab_dev_func_arg(get_all_cab_out_repower, &temp_repower);
            microgrid_data.pcs_power = temp_power;
            microgrid_data.pcs_repower = temp_repower;
            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;
        
        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_repower);
    dev_set_dev_tag_float(DEV_NO_EMS, LOAD_ACT_POWER, microgrid_data.grid_repower + 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];
        BMS_protect_to_ctrl_PCS(\
        cab->cab_data.SOC_average, \
        microgrid_ctrl.SOC_min,\
        microgrid_ctrl.SOC_max, \
        &cab->cab_ctrl.pcs_discharge_max_set, \
        &cab->cab_ctrl.pcs_charge_max_set, \
        cab->cab_ctrl.discharge_max_cfg, \
        cab->cab_ctrl.charge_max_cfg, \
        microgrid_ctrl.plan_statu);
    
    }
    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);
    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);

    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);
        }
        else 
        {
            UD_log_sprintf(micro_log, "\n<PCS 设置开关机已[%d]  0:关机 1:开机>\n", 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);
        }
        else 
        {
            UD_log_sprintf(micro_log, "\n<PCS 设置并离网已[%d]  0:离网 1:并网>\n", 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,  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))
        {
            return decision_table[i].result;
        }
        
    
    }
    
    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);

    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);

    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);
    
    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));
}


/**
 * @description: 状态机主线程 校验状态并执行状态函数
 * @param {void} *args 状态机指针
 * @return {*}
 */
void *state_machine_pthread(void *args)
{
    int ret = 0;
    current_stat_t *state_machine = (current_stat_t *)args;
    RELEVANCE_STATE ret_state;
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;
    }

    while (1)
    {
        usleep(400 * 1000);
        Relevant_data_refresh();
        
        if(g_usercfg_variant.ControlMode == 0)
        {
            UD_log_sprintf(micro_log, "手动模式\n");
            fwrite_flush_UD_log(micro_log);
            sleep(1);
            continue;
        }
        if(dev_get_dev_tag_float(DEV_NO_EMS, SYSTEM_STATUS))
        {
            pcs_stop();
            mppt_stop();
            UD_log_sprintf(micro_log, "系统异常字段\n");
            fwrite_flush_UD_log(micro_log);
            sleep(3);
            continue;
        }
        
        /**///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:
    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;
	}
	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", pcs_num, df_pcs_scale, pv_num, df_pv_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];//

        /**///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];
            
            device_t *dev = (device_t *)_mppt->ptr;
            _mppt->info.mppt_cfg.scale = find_float_in_user_def(dev, "scale", df_mppt_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);
        }
        
        _cabinet_inside->cab_cfg.scale = cab_scale; //>>柜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);
	}	
}

static int dev_add_to_cabinet(device_t *dev, cabinet_inside_t *cabinet_ptr, int ctrl_mode)
{
    if ((dev == NULL) || (ctrl_mode == 0 && cabinet_ptr == NULL))
    {
        return -1;
    }

    if( ((strcmp(dev->dev_type, "METER") == 0 && (strcmp(dev->dev_child_type, "PCS") == 0 || strcmp(dev->dev_child_type, "MPPT") == 0)) || \
         (strcmp(dev->dev_type, "PCS") == 0) || (strcmp(dev->dev_type, "BMS") == 0) || (strcmp(dev->dev_type, "MPPT") == 0)) && cabinet_ptr == NULL)
    {
	    return -1;
    }
	dev_info_all_t *_dev_info_all = get_dev_info_all_var();

    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++;  
            }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, "PCS") == 0){

			if (cabinet_ptr->meter_pcs.num < DEV_NUM_MAX){
				cabinet_ptr->meter_pcs.meter_pcs_param[cabinet_ptr->meter_pcs.num].no = strdup(dev->no);
				cabinet_ptr->meter_pcs.meter_pcs_param[cabinet_ptr->meter_pcs.num].ptr = dev;
				cabinet_ptr->meter_pcs.num++;
			}else
				ems_syslog(LOG_ERR,"cabinet[%s] created meter_pcs device[%s] error, num=%d", cabinet_ptr->no, dev->no, cabinet_ptr->meter_pcs.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++;
            }
            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, "MPPT") == 0){
			if (_dev_info_all->meter_pv.num < DEV_NUM_MAX){
					cabinet_ptr->meter_mppt.meter_mppt_param[cabinet_ptr->meter_mppt.num].no = strdup(dev->no);
					cabinet_ptr->meter_mppt.meter_mppt_param[cabinet_ptr->meter_mppt.num].ptr = dev;
					cabinet_ptr->meter_mppt.num++;
			}
            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++; 
            }
			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;
            }
			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, "PCS") == 0){
		if (cabinet_ptr->pcs.num < DEV_NUM_MAX){
			cabinet_ptr->pcs.pcs_param[cabinet_ptr->pcs.num].no = strdup(dev->no);
			cabinet_ptr->pcs.pcs_param[cabinet_ptr->pcs.num].ptr = dev;
			cabinet_ptr->pcs.num++;    
		}
		else
			ems_syslog(LOG_ERR,"cabinet[%s] created pcs device[%s] error, num=%d", cabinet_ptr->no, dev->no, cabinet_ptr->pcs.num);
	}
	else if (strcmp(dev->dev_type, "BMS") == 0){
		if (cabinet_ptr->bms.num < DEV_NUM_MAX){
			cabinet_ptr->bms.bms_param[cabinet_ptr->bms.num].no = strdup(dev->no);
			cabinet_ptr->bms.bms_param[cabinet_ptr->bms.num].ptr = dev;
			cabinet_ptr->bms.num++;  
		}
		else
			ems_syslog(LOG_ERR,"cabinet[%s] created pcs device[%s] error, num=%d", cabinet_ptr->no, dev->no, cabinet_ptr->bms.num);
	}
	else if (strcmp(dev->dev_type, "MPPT") == 0){
        if (cabinet_ptr->mppt.num < DEV_NUM_MAX){
            cabinet_ptr->mppt.mppt_param[cabinet_ptr->mppt.num].no = strdup(dev->no);
            cabinet_ptr->mppt.mppt_param[cabinet_ptr->mppt.num].ptr = dev;
            cabinet_ptr->mppt.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++;
        }
        else
            ems_syslog(LOG_ERR,"created pv device[%s] error, num=%d", dev->no, _dev_info_all->pv.num);
	}
	
    return 0;
}

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;
}

// 微网交流耦合，主从模式，若主机上挂有PCS\BMS\PCS METER\ 此时必须使能主从一体，否则微网设备录入会出问题，若没有，可根据需要使能或失能主从一体
static cabinet_inside_t *microgrid_cabinet_create(proto_forward_t *var, Cabinet_t *cabinet_info, device_t *dev)
{
	int idx = 0;
	char cabinet_no[32] = {0};
	cabinet_inside_t *cabinet_ptr = NULL;

    if (cabinet_info->num >= CABINET_NUM_MAX)
    {
        ems_syslog(LOG_ERR,"created cabinet_info[%d] error", idx);
        goto ERR;
    }
	ems_syslog(LOG_NOTICE, " cabinet_info->num:%d!", cabinet_info->num);

	cabinet_info_t *cab = get_cabinet_info(); 
	if(cab->ctrl_mode)// 0:对等模式,1:主从模式
	{
		if(extractBeforeDot(dev->no, cabinet_no) == 0) goto ADD;
		for (int i = 0; i < cabinet_info->num; i++)
		{
			if (strcmp(cabinet_no, cabinet_info->cabinet_inside[i]->no) == 0)
			{
				cabinet_ptr = cabinet_info->cabinet_inside[i];
				ems_syslog(LOG_INFO, "find cabinet no:%s as same as others", cabinet_ptr->no);
			}
		}
				
		idx = cabinet_info->num;
		if (!cabinet_ptr)
		{
			if (idx >= CABINET_NUM_MAX)
			{
				ems_syslog(LOG_ERR,"created cabinet[%d] error", idx);
				goto ERR;
			}
			// 创建新的结构体
			cabinet_ptr = calloc(sizeof(cabinet_inside_t), 1);    
			cabinet_ptr->no = strdup(cabinet_no);

			cabinet_info->cabinet_inside[idx] = cabinet_ptr;
			ems_syslog(LOG_NOTICE, "m-s created cabinet[%d] success, name:%s", idx, cabinet_ptr->no);
			// 存储柜子信息
			cabinet_info->num++;
		}
		else
		{
	        if (strcmp(cabinet_ptr->no, cabinet_no) != 0)
	        {
	            cabinet_ptr = NULL;
	        }
		}
	}
	else{
		if (cabinet_info->cabinet_inside[idx] == NULL){
			cabinet_ptr = calloc(sizeof(cabinet_inside_t), 1);    
			cabinet_ptr->no = strdup("equity"); //>>>对等柜
			cabinet_info->cabinet_inside[idx] = cabinet_ptr;
			ems_syslog(LOG_NOTICE, "equity created cabinet[%d] success, name:%s", idx, cabinet_ptr->no);
		}else
			cabinet_ptr = cabinet_info->cabinet_inside[idx];
        cabinet_info->num = 1;//const
	}
ADD:
	dev_add_to_cabinet(dev, cabinet_ptr, cab->ctrl_mode);	

	return cabinet_ptr;
ERR:
	_free_memory(cabinet_ptr);
	return NULL;
}

int microgrid_load_device_info(proto_forward_t *var, Cabinet_t *_cabinet_info)
{
    ems_syslog(LOG_NOTICE, "%s", "microgrid_load_device_info load start...");
	
    proto_forward_t *dev_var = get_proto_forward_var();
    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];
            template_t *p = dev->use_template;
            ems_syslog(LOG_DEBUG, "dev: %s->template info:model->%s, adapter->%s", dev->no, p->model, p->adapter);

            // 根据配置信息自动创建柜子信息,如果重复不创建
            cabinet_inside_t *cabinet_inside = microgrid_cabinet_create(var, _cabinet_info, dev);
            if (!cabinet_inside)
            {
                ems_syslog(LOG_ERR,"failed to create cabinet_inside!!!");
            }
        }
    }
	microgrid_scale_init();
	microgrid_print_device_info();

	return 0;
}


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

/**
 * @description: 微网初始化
 * @param {pcs_ctrl_var_t} *var
 * @return {*}
 */
int MicrogridtopologyIni(pcs_ctrl_var_t *var)
{
    pthread_t pid[4];
    microgrid_load_device_info(get_proto_forward_var(), &dev_info_all.cabinet_info);
    microgrid_cfg_flush(var);
    dev_cfg_flush();

#if TEST_CASE
    test_func();
    return 0;
#endif
    
    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

    return 0;
}
