#include "public.h"
#define AUTO_STANBY_DELAY 60 //S


static data_ctrl_thread_var_t threads_var[ENG_ASS_GRP_MAX] = {0};
static hash_intptr_t *tag_map_hash = NULL;

static struct 
{
    int runmode;
    data_event_cb_t data_event_cb;
    alarm_event_cb_t alarm_event_cb;
}item_var;

static tag_info_t tag_info_table_stack[] = {
    //总故障状态 *****
    {"TAG_4E22",  offsetof(eng_ass_grp_data_t, pcs_fault),            E_TAG_INT},
    //离网模式电压期望
    {"TAG_4E94",  offsetof(eng_ass_grp_data_t, disconnect_v),            E_TAG_INT},
    //正向总功率 ---PCS 总输出有功功率
    {"TAG_4E88",  offsetof(eng_ass_grp_data_t, pcs_active_power),     E_TAG_FLOAT},
    //反向总功率 -----PCS 总输出无功功率
    {"TAG_4E89",  offsetof(eng_ass_grp_data_t, pcs_reactive_power),   E_TAG_FLOAT},
    //并网状态 *****
    {"TAG_4E25",  offsetof(eng_ass_grp_data_t, pcs_connect_state),    E_TAG_INT},
    ////可并网状态 --- 并离网设置 0：并网模式 1：离网模式
    {"TAG_4F65",  offsetof(eng_ass_grp_data_t, pcs_conenable),        E_TAG_INT},
    {"TAG_4F30",  offsetof(eng_ass_grp_data_t, pcs_remote),           E_TAG_INT},
    //bms soc ----BMS/CMS SOC
    {"TAG_75E7",  offsetof(eng_ass_grp_data_t, bms_soc),              E_TAG_FLOAT},
    {"TAG_9C83",  offsetof(eng_ass_grp_data_t, bms_soc),              E_TAG_FLOAT},
    //bms总电压-----BMS/CMS 总电压
    {"TAG_75E5",  offsetof(eng_ass_grp_data_t, bms_total_voltage),    E_TAG_FLOAT},
    {"TAG_9C80",  offsetof(eng_ass_grp_data_t, bms_total_voltage),    E_TAG_FLOAT},
    //bms总电流-----BMS/CMS 总电流
    {"TAG_75E6",  offsetof(eng_ass_grp_data_t, bms_total_current),    E_TAG_FLOAT},
    {"TAG_9C81",  offsetof(eng_ass_grp_data_t, bms_total_current),    E_TAG_FLOAT},
    //电表
    {"TAG_2730",  offsetof(eng_ass_grp_data_t, meter_reactive_power), E_TAG_FLOAT},
    {"TAG_2734",  offsetof(eng_ass_grp_data_t, meter_positive_energy),E_TAG_FLOAT},
    {"TAG_2739",  offsetof(eng_ass_grp_data_t, meter_negtive_energy), E_TAG_FLOAT},
    //主正接触器状态 0：断开 1：闭合
    {"TAG_9D89",  offsetof(eng_ass_grp_data_t, bms_relay_p),  E_TAG_INT},
    //主负接触器状态 0：断开 1：闭合
    {"TAG_9D8A",  offsetof(eng_ass_grp_data_t, bms_relay_n),  E_TAG_INT} ,
    //停机
    {"TAG_4E24",  offsetof(eng_ass_grp_data_t, pcs_stop_flag),        E_TAG_INT},
    //运行
    {"TAG_4F2F",  offsetof(eng_ass_grp_data_t, pcs_run_flag),        E_TAG_INT},
    //待机
    {"TAG_4E29",  offsetof(eng_ass_grp_data_t, pcs_standby_flag),        E_TAG_INT},
    //bms欠压告警   放电单体二级告警
    //{"TAG_9C60",  offsetof(eng_ass_grp_data_t, bms_under_vol_alarm),        E_TAG_INT},
    //bms过压告警   充电单体二级告警
    //{"TAG_9C5F",  offsetof(eng_ass_grp_data_t, bms_over_vol_alarm),        E_TAG_INT},
	/****************************************************************************************/
    //充电单体过压一级报警
    {"TAG_9C52",  offsetof(eng_ass_grp_data_t, char_cell_over_vol1_alarm),        E_TAG_INT},
    {"TAG_760C",  offsetof(eng_ass_grp_data_t, char_cell_over_vol1_alarm),        E_TAG_INT},
    //放电单体欠压一级报警
    {"TAG_9C53",  offsetof(eng_ass_grp_data_t, dischar_cell_under_vol1_alarm),        E_TAG_INT},
    {"TAG_760D",  offsetof(eng_ass_grp_data_t, dischar_cell_under_vol1_alarm),        E_TAG_INT},
    
    //放电单体过温一级报警
    {"TAG_9C56",  offsetof(eng_ass_grp_data_t, dischar_cell_overtmp1_alarm),        E_TAG_INT},
    {"TAG_7610",  offsetof(eng_ass_grp_data_t, dischar_cell_overtmp1_alarm),        E_TAG_INT},
    //放电单体欠温一级报警
    {"TAG_9C57",  offsetof(eng_ass_grp_data_t, dischar_cell_undertmp1_alarm),        E_TAG_INT},
    {"TAG_7611",  offsetof(eng_ass_grp_data_t, dischar_cell_undertmp1_alarm),        E_TAG_INT},
    
    //充电单体过温一级报警
    {"TAG_9C58",  offsetof(eng_ass_grp_data_t, char_cell_overtmp1_alarm),        E_TAG_INT},
    {"TAG_7612",  offsetof(eng_ass_grp_data_t, char_cell_overtmp1_alarm),        E_TAG_INT},
    //充电单体欠温一级报警
    {"TAG_9C59",  offsetof(eng_ass_grp_data_t, char_cell_undertmp1_alarm),        E_TAG_INT},
	{"TAG_7613",  offsetof(eng_ass_grp_data_t, char_cell_undertmp1_alarm),        E_TAG_INT},

    //充电总电压过压一级报警
    {"TAG_9C50",  offsetof(eng_ass_grp_data_t, char_total_over_vol1_alarm),        E_TAG_INT},
	{"TAG_760A",  offsetof(eng_ass_grp_data_t, char_total_over_vol1_alarm),        E_TAG_INT},
    //放电总电压欠压一级报警
    {"TAG_9C51",  offsetof(eng_ass_grp_data_t, dischar_total_under_vol1_alarm),        E_TAG_INT},
    {"TAG_760B",  offsetof(eng_ass_grp_data_t, dischar_total_under_vol1_alarm),        E_TAG_INT},


    /****************************************************************************************/
    //充电单体过压二级报警
    {"TAG_9C5F",  offsetof(eng_ass_grp_data_t, char_cell_over_vol2_alarm),        E_TAG_INT},
    {"TAG_7619",  offsetof(eng_ass_grp_data_t, char_cell_over_vol2_alarm),        E_TAG_INT},
    //放电单体欠压二级报警
    {"TAG_9C60",  offsetof(eng_ass_grp_data_t, dischar_cell_under_vol2_alarm),        E_TAG_INT},
    {"TAG_761A",  offsetof(eng_ass_grp_data_t, dischar_cell_under_vol2_alarm),        E_TAG_INT},
    
    //放电单体过温二级报警
    {"TAG_9C63",  offsetof(eng_ass_grp_data_t, dischar_cell_overtmp2_alarm),        E_TAG_INT},
    {"TAG_761D",  offsetof(eng_ass_grp_data_t, dischar_cell_overtmp2_alarm),        E_TAG_INT},
    //放电单体欠温二级报警
    {"TAG_9C64",  offsetof(eng_ass_grp_data_t, dischar_cell_undertmp2_alarm),        E_TAG_INT},
    {"TAG_761E",  offsetof(eng_ass_grp_data_t, dischar_cell_undertmp2_alarm),        E_TAG_INT},
    
    //充电单体过温二级报警
    {"TAG_9C65",  offsetof(eng_ass_grp_data_t, char_cell_overtmp2_alarm),        E_TAG_INT},  
    {"TAG_761F",  offsetof(eng_ass_grp_data_t, char_cell_overtmp2_alarm),        E_TAG_INT},
    //充电单体欠温二级报警
    {"TAG_9C66",  offsetof(eng_ass_grp_data_t, char_cell_undertmp2_alarm),        E_TAG_INT},
    {"TAG_7620",  offsetof(eng_ass_grp_data_t, char_cell_undertmp2_alarm),        E_TAG_INT},

    //充电总电压过压二级报警
    {"TAG_9C5D",  offsetof(eng_ass_grp_data_t, char_total_over_vol2_alarm),        E_TAG_INT},
	{"TAG_7617",  offsetof(eng_ass_grp_data_t, char_total_over_vol2_alarm),        E_TAG_INT},
    //放电总电压欠压二级报警
    {"TAG_9C5E",  offsetof(eng_ass_grp_data_t, dischar_total_under_vol2_alarm),        E_TAG_INT},
    {"TAG_7618",  offsetof(eng_ass_grp_data_t, dischar_total_under_vol2_alarm),        E_TAG_INT},
    /****************************************************************************************/
    //充电单体过压三级报警
    {"TAG_9C6C",  offsetof(eng_ass_grp_data_t, char_cell_over_vol3_alarm),        E_TAG_INT},
    {"TAG_7626",  offsetof(eng_ass_grp_data_t, char_cell_over_vol3_alarm),        E_TAG_INT},
    //放电单体欠压三级报警
    {"TAG_9C6D",  offsetof(eng_ass_grp_data_t, dischar_cell_under_vol3_alarm),        E_TAG_INT},
    {"TAG_7627",  offsetof(eng_ass_grp_data_t, dischar_cell_under_vol3_alarm),        E_TAG_INT},
    
    //放电单体过温三级报警
    {"TAG_9C70",  offsetof(eng_ass_grp_data_t, dischar_cell_overtmp3_alarm),        E_TAG_INT}, 
    {"TAG_762A",  offsetof(eng_ass_grp_data_t, dischar_cell_overtmp3_alarm),        E_TAG_INT},   
    //放电单体欠温三级报警
    {"TAG_9C71",  offsetof(eng_ass_grp_data_t, dischar_cell_undertmp3_alarm),        E_TAG_INT},
    {"TAG_762B",  offsetof(eng_ass_grp_data_t, dischar_cell_undertmp3_alarm),        E_TAG_INT},

    //充电单体过温三级报警
    {"TAG_9C72",  offsetof(eng_ass_grp_data_t, char_cell_overtmp3_alarm),        E_TAG_INT},  
    {"TAG_762C",  offsetof(eng_ass_grp_data_t, char_cell_overtmp3_alarm),        E_TAG_INT},
    //充电单体欠温三级报警
    {"TAG_9C73",  offsetof(eng_ass_grp_data_t, char_cell_undertmp3_alarm),        E_TAG_INT},
    {"TAG_762D",  offsetof(eng_ass_grp_data_t, char_cell_undertmp3_alarm),        E_TAG_INT},

    //充电总电压过压三级报警
    {"TAG_9C6A",  offsetof(eng_ass_grp_data_t, char_total_over_vol3_alarm),        E_TAG_INT},
	{"TAG_7624",  offsetof(eng_ass_grp_data_t, char_total_over_vol3_alarm),        E_TAG_INT},
    //放电总电压欠压一级报警
    {"TAG_9C6B",  offsetof(eng_ass_grp_data_t, dischar_total_under_vol3_alarm),        E_TAG_INT},
    {"TAG_7625",  offsetof(eng_ass_grp_data_t, dischar_total_under_vol3_alarm),        E_TAG_INT},
	/****************************************************************************************/

    //系统允许最大充电电流：TAG_9D77 高特点位  TAG_9C88协能点位
    {"TAG_9D77",  offsetof(eng_ass_grp_data_t, bms_avaiable_cha_curr),  E_TAG_FLOAT} , 
    {"TAG_9C88",  offsetof(eng_ass_grp_data_t, bms_avaiable_cha_curr),  E_TAG_FLOAT} ,
    {"TAG_75EC",  offsetof(eng_ass_grp_data_t, bms_avaiable_cha_curr),  E_TAG_FLOAT} , 
    //系统允许最大放电电流:TAG_9D78 高特点位  TAG_9C89协能点位
    {"TAG_9D78",  offsetof(eng_ass_grp_data_t, bms_avaiable_disc_curr),  E_TAG_FLOAT} , 
    {"TAG_9C89",  offsetof(eng_ass_grp_data_t, bms_avaiable_disc_curr),  E_TAG_FLOAT} ,
    {"TAG_75ED",  offsetof(eng_ass_grp_data_t, bms_avaiable_disc_curr),  E_TAG_FLOAT} ,
    //最高电池电压和最低电池电压
    {"TAG_75F3",  offsetof(eng_ass_grp_data_t, bms_single_max), E_TAG_FLOAT},
    {"TAG_9C8B",  offsetof(eng_ass_grp_data_t, bms_single_max), E_TAG_FLOAT},
    {"TAG_75F7",  offsetof(eng_ass_grp_data_t, bms_single_min), E_TAG_FLOAT},
    {"TAG_9C8D",  offsetof(eng_ass_grp_data_t, bms_single_min), E_TAG_FLOAT},
};

static int chk_bms_high_voltage(energy_var_t *var,int grp,int value)
{
    if(var->grp[grp].eng_ass_grp_data.bms_conn_high_power != value) {
        var->grp[grp].eng_ass_grp_data.bms_conn_high_power = value;
        return ENG_ASS_CONDITION_NO_MATCH;
    }
    return ENG_ASS_CONDITION_OK;
    //if(value == ENG_ASS_ACTION_TYPE_INIT || var->grp[grp].eng_ass_grp_data.bms_conn_high_power == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
    //else return (var->grp[grp].eng_ass_grp_data.bms_conn_high_power == value)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
}

static int chk_bms_electric_switch(energy_var_t *var,int grp,int value)
{
    if(value == ENG_ASS_ACTION_TYPE_INIT || var->grp[grp].eng_ass_grp_data.bms_switch_on_state == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
    else return (var->grp[grp].eng_ass_grp_data.bms_switch_on_state == value)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
}

static int chk_pcs_diconnect_v(energy_var_t *var,int grp,int value)
{
    if(var->grp[grp].eng_ass_grp_data.disconnect_v == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
    else return (var->grp[grp].eng_ass_grp_data.disconnect_v == value)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
}

static int chk_pcs_switch_public(energy_var_t *var,int grp,int value)
{
    //eng_ass_grp_data_t 中的 pcs_run_state现在被拆分成如下三种状态，因此对应的TAG_517D 删除
    //但是eng_ass_grp_ctrl_t中的 run_state还是继续使用，三个值代表三种状态
    dbg_syslog(LOG_INFO,"grp[%d] pcs status stop:%d,staby:%d,run:%d",grp,var->grp[grp].eng_ass_grp_data.pcs_stop_flag,var->grp[grp].eng_ass_grp_data.pcs_standby_flag,var->grp[grp].eng_ass_grp_data.pcs_run_flag);
    if(value == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
    if(0 == value)//停机
    {
        if(var->grp[grp].eng_ass_grp_data.pcs_stop_flag == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
        return (var->grp[grp].eng_ass_grp_data.pcs_stop_flag == 1)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
    }
    else if ((1 == value) && (1 == var->supportStandy))//待机
    {
        if(var->grp[grp].eng_ass_grp_data.pcs_standby_flag == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
        return (var->grp[grp].eng_ass_grp_data.pcs_standby_flag == 1)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
    }
    else if (2 == value)//运行
    {
        if(var->grp[grp].eng_ass_grp_data.pcs_run_flag == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
        return (var->grp[grp].eng_ass_grp_data.pcs_run_flag == 1 || (var->supportStandy == 0 && var->grp[grp].eng_ass_grp_data.pcs_standby_flag == 1))?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
    }
    return ENG_ASS_CONDITION_SKIP;
}

static int chk_bms_relay(energy_var_t *var,int grp,int value)
{
    if(value == ENG_ASS_ACTION_TYPE_INIT || var->grp[grp].eng_ass_grp_data.bms_relay_p == ENG_ASS_ACTION_TYPE_INIT || var->grp[grp].eng_ass_grp_data.bms_relay_n == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
    else return ((var->grp[grp].eng_ass_grp_data.bms_relay_p && var->grp[grp].eng_ass_grp_data.bms_relay_n) == value)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
}

static int chk_pcs_connection(energy_var_t *var,int grp,int value)
{
    //dbg_syslog(LOG_WARNING,"chk grp[%d] pcs connection=%d ,%d ",grp,value,var->grp[grp].eng_ass_grp_data.pcs_connect_state);
    if(value == ENG_ASS_ACTION_TYPE_INIT || var->grp[grp].eng_ass_grp_data.pcs_connect_state == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
    else return (var->grp[grp].eng_ass_grp_data.pcs_connect_state == value)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
}


static int chk_pcs_remote_mode(energy_var_t *var,int grp,int value)
{
    if(var->grp[grp].eng_ass_grp_data.pcs_remote == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
    else return (var->grp[grp].eng_ass_grp_data.pcs_remote == value)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
}

static void update_bms_high_voltage(energy_var_t *var,int grp,int value)
{
    var->grp[grp].eng_ass_grp_ctrl.conn_high_power = value;
}

static void update_bms_electric_switch(energy_var_t *var,int grp,int value)
{
    var->grp[grp].eng_ass_grp_ctrl.switch_on_state = value;
}

static void update_pcs_switch_public(energy_var_t *var,int grp,int value)
{
    var->grp[grp].eng_ass_grp_ctrl.run_state = value;
}

//上高压
static void send_cmd_set_bms_high_voltage(energy_var_t *var,int grp_index,int value)
{
    data_ctrl_dev_action(var,GROUP_BMS_INDEX(var,grp_index,0),"shangxiagaoya","TAG_76C4",value);
    dbg_syslog(LOG_WARNING,"Set grp[%d] bms high voltage=%d",grp_index,value);
}
//电操闸
static void send_cmd_set_bms_electric_switch(energy_var_t *var,int grp_index,int value)//value 只传0，1 ，平台映射
{
    data_ctrl_dev_action(var,GROUP_BMS_INDEX(var,grp_index,0),"fenzaheza","TAG_76C3",value);
    dbg_syslog(LOG_WARNING,"Set grp[%d] bms electric switch=%d",grp_index,value);
}

//PCS 开机关机
static void send_cmd_set_pcs_switch_public(energy_var_t *var,int grp_index,int value)
{
    if (value == 2)
    {
        data_ctrl_dev_action(var, var->grp[grp_index].eng_ass_grp_cfg.pcs_sn, "kaiji", "TAG_4EAE", 1);
        dbg_syslog(LOG_WARNING, "Set grp[%d] pcs run mode=%s", grp_index, "run");
    }
    if (value == 1)
    {
        data_ctrl_dev_action(var, var->grp[grp_index].eng_ass_grp_cfg.pcs_sn, "daiji", "TAG_4EB3", 1);
        dbg_syslog(LOG_WARNING, "Set grp[%d] pcs run mode=%s", grp_index, "stanby");
    }
    else if (value == 0)
    {
        data_ctrl_dev_action(var, var->grp[grp_index].eng_ass_grp_cfg.pcs_sn, "guanji", "TAG_4EAF", 1);
        dbg_syslog(LOG_WARNING, "Set grp[%d] pcs run mode=%s", grp_index, "stop");
    }
}

//PCS 并离网
static void send_cmd_set_pcs_connection(energy_var_t *var,int grp_index,int value)
{
    if (value == 1){//并网
        data_ctrl_dev_action(var,var->grp[grp_index].eng_ass_grp_cfg.pcs_sn,"grid_connect","TAG_4EB1",1);
        //data_ctrl_dev_action(var,var->grp[grp_index].eng_ass_grp_cfg.pcs_sn,"Off_grid","TAG_4EB2",0);
    }
    else if (value == 0){//离网
        //data_ctrl_dev_action(var,var->grp[grp_index].eng_ass_grp_cfg.pcs_sn,"grid_connect","TAG_4EB1",0);
        data_ctrl_dev_action(var,var->grp[grp_index].eng_ass_grp_cfg.pcs_sn,"Off_grid","TAG_4EB2",1);
    }
    dbg_syslog(LOG_WARNING,"SN %s :Set grp[%d] pcs connection=%d",var->grp[grp_index].eng_ass_grp_cfg.pcs_sn,grp_index,value);
}

static int chk_bms_warn(energy_var_t *var,int grp_idx,int value)
{
	int i = 0;

	if (value > 0) // 放电过程只关注 放电过程中可能触发的告警
	{
	    // 1级
	    if ((var->grp[grp_idx].eng_ass_grp_data.dischar_cell_under_vol1_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.dischar_cell_overtmp1_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.dischar_cell_undertmp1_alarm > 0) || \
            (var->grp[grp_idx].eng_ass_grp_data.dischar_total_under_vol1_alarm > 0))
			
			var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_one = 1;
        // 2级
	    if ((var->grp[grp_idx].eng_ass_grp_data.dischar_cell_under_vol2_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.dischar_cell_overtmp2_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.dischar_cell_undertmp2_alarm > 0) || \
            (var->grp[grp_idx].eng_ass_grp_data.dischar_total_under_vol2_alarm > 0))
			
			var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_two = 1;
		// 3级
	    if ((var->grp[grp_idx].eng_ass_grp_data.dischar_cell_under_vol3_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.dischar_cell_overtmp3_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.dischar_cell_undertmp3_alarm > 0) || \
            (var->grp[grp_idx].eng_ass_grp_data.dischar_total_under_vol3_alarm > 0))
			
			var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_three = 1;
	}
	else if (value < 0) // 充电过程只关注 充电过程中可能触发的告警
	{
	    // 1级
	    if ((var->grp[grp_idx].eng_ass_grp_data.char_cell_over_vol1_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.char_cell_overtmp1_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.char_cell_undertmp1_alarm > 0) || \
            (var->grp[grp_idx].eng_ass_grp_data.char_total_over_vol1_alarm > 0))
			
			var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_one = 1;
	    // 2级
	    if ((var->grp[grp_idx].eng_ass_grp_data.char_cell_over_vol2_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.char_cell_overtmp2_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.char_cell_undertmp2_alarm > 0) || \
            (var->grp[grp_idx].eng_ass_grp_data.char_total_over_vol2_alarm > 0))
			
			var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_two = 1;
	    // 3级
	    if ((var->grp[grp_idx].eng_ass_grp_data.char_cell_over_vol3_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.char_cell_overtmp3_alarm > 0) || \
			(var->grp[grp_idx].eng_ass_grp_data.char_cell_undertmp3_alarm > 0) || \
            (var->grp[grp_idx].eng_ass_grp_data.char_total_over_vol3_alarm > 0))
			
			var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_three = 1;
	}
	else 
	{ 
	
    } 
}

//单位是0.1KW
static int chk_bms_avail_power_modified(energy_var_t *var,int grp_idx,int value,int zero_flag)
{
    //簇允许充电最大电流 -101 A 
    //簇允许放电最大电流 263 A 
    //EMS 充电 -50
    //EMS 放电 50
    float avail_power = 0; //和PCS写入功率一样单位都是0.1KW
    int tmp = value;
    time_t now = time(NULL);

	chk_bms_warn(var, grp_idx, value);

    if(value > 0){//放电
        var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_one = 0;
        var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_two = 0;
		var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_three = 0;
	
	    //if (var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_one == 1) tmp = tmp*50/100;
		if ((var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_two == 1) || \
			(var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_three == 1))
			tmp = 0;
        avail_power = var->grp[grp_idx].eng_ass_grp_data.bms_avaiable_disc_curr * var->grp[grp_idx].eng_ass_grp_data.bms_total_voltage/100;
        if(var->grp[grp_idx].eng_ass_grp_data.bms_avaiable_disc_curr < 0) avail_power = -avail_power;         //自动纠正方向
        
		dbg_syslog(LOG_DEBUG, "grp[%d] bms_dischar_hold_one[%d] bms_char_hold_two[%d] bms_dischar_hold_three[%d]",grp_idx,var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_one,var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_two,var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_three);
        dbg_syslog(LOG_DEBUG, "grp[%d] avaiable discharge current:%f,[avail_power,ems_power][%f,%d]",grp_idx,var->grp[grp_idx].eng_ass_grp_data.bms_avaiable_disc_curr,avail_power,tmp);
        tmp = MIN(avail_power,tmp);
        if(zero_flag == 1) tmp = 0;
    }
    else if(value < 0)    //充电
    {
        var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_one = 0;
        var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_two = 0;
		var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_three = 0;
		
	    //if (var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_one == 1) tmp = tmp*50/100;
		if ((var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_two == 1) || \
			(var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_three == 1))
			tmp = 0;
		
        avail_power = var->grp[grp_idx].eng_ass_grp_data.bms_avaiable_cha_curr * var->grp[grp_idx].eng_ass_grp_data.bms_total_voltage/100;
        if(var->grp[grp_idx].eng_ass_grp_data.bms_avaiable_cha_curr > 0) avail_power = -avail_power;    //自动纠正方向

		dbg_syslog(LOG_DEBUG, "grp[%d] bms_char_hold_one[%d] bms_char_hold_two[%d] bms_char_hold_three[%d]",grp_idx,var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_one,var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_two,var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_three);
        dbg_syslog(LOG_DEBUG, "grp[%d] avaiable charge current:%f,[avail_power,ems_power][%f,%d]",grp_idx,var->grp[grp_idx].eng_ass_grp_data.bms_avaiable_cha_curr,avail_power,tmp);
        tmp = MAX(avail_power,tmp);
        if(zero_flag == 1) tmp = 0;
    }
    else { 

    } 
    return tmp;
}

//有功功率
static void def_send_cmd_set_pcs_active_power(energy_var_t *var,int grp_index,int value)
{
    dbg_syslog(LOG_INFO, "Set grp[%d] pcs power=%d KW", grp_index,value);
    data_ctrl_dev_action(var,var->grp[grp_index].eng_ass_grp_cfg.pcs_sn,"WritePExpect","TAG_4E92",value);
}

//离网电压
static void def_send_cmd_set_disconnect_active_v(energy_var_t *var,int grp_index,int value)
{
    dbg_syslog(LOG_INFO, "Set grp[%d] disconnect v=%d v", grp_index,value);
    data_ctrl_dev_action(var,var->grp[grp_index].eng_ass_grp_cfg.pcs_sn,"write_disconnect_v","TAG_4E94",value);
}


//无功功率
static void def_send_cmd_set_pcs_wggl_power(energy_var_t *var,int grp_index,int value)
{
    dbg_syslog(LOG_INFO, "Set grp[%d] pcs wggl power=%d KW", grp_index,value);
    data_ctrl_dev_action(var,var->grp[grp_index].eng_ass_grp_cfg.pcs_sn,"WriteWggl","TAG_4E93",value);
}

static void set_pcs_remote_mode(energy_var_t *var,int grp_index,int value)
{
    data_ctrl_dev_action(var, var->grp[grp_index].eng_ass_grp_cfg.pcs_sn,"remoteMode","TAG_4F30",value);
    dbg_syslog(LOG_WARNING,"Set grp[%d] pcs_remote=%d",grp_index,value);
}

//清故障
static void def_send_cmd_set_pcs_reset_err(energy_var_t *var)
{
    int grp_idx = 0;
    for (grp_idx = 0; grp_idx < var->eng_ass_grp_num; grp_idx++)
    {
        data_ctrl_dev_action(var,var->grp[grp_idx].eng_ass_grp_cfg.pcs_sn,"ClearError","TAG_4EB0",1);
        dbg_syslog(LOG_WARNING, "Set grp[%d] pcs clear error", grp_idx);
    }

}

static action_and_check_t start_action_chk[] = {
    // {"PCS模式=1", update_pcs_switch_public,                  1, chk_pcs_switch_public,                  1},
    {"PCS模式=2", update_pcs_switch_public,                  2, chk_pcs_switch_public,                  2},
};

static action_and_check_t stop_action_chk[] = {
    {"PCS模式", update_pcs_switch_public,                     0,      chk_pcs_switch_public,                     0},
};

static action_and_check_t staby_action_chk[] = {
    {"PCS模式=0", update_pcs_switch_public,                     1,      chk_pcs_switch_public,                     1},
};

static int protect_action_chk_size[ENG_ASS_ACTION_CHECK_LEVEL_MAX]={0};
//停机todo_list
static action_and_check_t protect_action_chk[][ENG_ASS_ACTION_CHECK_MAX] = {
    //描述
    //检查回调,0:数据比较通过;否则失败
    //检查匹配的参数
    //如果不匹配需要做的事情
    //需要做事情的参数
    {//protection level 1 :清安短期关机
        {"PCS模式", update_pcs_switch_public,                     0,      chk_pcs_switch_public,                     0},
    },
    {//protection level 2 :清安长期关机
        {"PCS模式", update_pcs_switch_public,                     0,      chk_pcs_switch_public,                     0},      
    },
    {//protection level 3 :清安系统关机,其余关闭操作在联动保护模块执行
        {"PCS模式", update_pcs_switch_public,                     0,      chk_pcs_switch_public,                     0},
        //保护联动系统,在这里负责关并网点断路器
        //保护联动系统,在这里负责关UPS
    }
};
//设备充放电告警
int data_grp_current_ctrl(energy_var_t *var,eng_ass_grp_t *grp)
{
    abstract_item_t *item = var->module_item;
    //簇允许充电最大电流 -101 A 
    //簇允许放电最大电流 263 A 
    //EMS 充电 -50
    //EMS 放电 50
    float bms_charge_current = grp->eng_ass_grp_data.bms_charge_current;
    float bms_discharge_current = grp->eng_ass_grp_data.bms_discharge_current;
    int bms_under_vol_alarm=grp->eng_ass_grp_data.bms_under_vol_alarm;
    int bms_over_vol_alarm = grp->eng_ass_grp_data.bms_over_vol_alarm;

    if(grp->eng_ass_grp_ctrl.active_power<0)
    {   
        if(var->eng_ass_data->last_ch_state == 2) 
        { 
            if((var->eng_ass_data->happen_state == 1)&&(var->eng_ass_data->last_run_state != ENG_ASS_MODE_TYPE_INIT))
            {
                dbg_syslog(LOG_WARNING, "action change !!");
                var->eng_ass_data->expect_run_state = var->eng_ass_data->last_run_state;
                item->set_runmode(var,var->eng_ass_data->expect_run_state);
            }
            var->eng_ass_data->happen_state = 0;
        }
        var->eng_ass_data->last_ch_state = 1;
        if(( bms_over_vol_alarm != 0)||( bms_charge_current > 0)||(var->eng_ass_data->happen_state == 1))
        {
            if(var->eng_ass_data->expect_run_state != ENG_ASS_MODE_TYPE_STOP)
            {
                if(var->eng_ass_data->happen_state == 1) //不是第一次进来保留最后运行状态
                var->eng_ass_data->last_run_state = var->eng_ass_data->expect_run_state;
                else  //第一次进来清除运行出状态
                var->eng_ass_data->last_run_state = ENG_ASS_MODE_TYPE_INIT;

                var->eng_ass_data->happen_state = 1;
                dbg_syslog(LOG_WARNING, "charge do stop action!!!!");
                var->eng_ass_data->expect_run_state = ENG_ASS_MODE_TYPE_STOP;
                item->set_runmode(var,var->eng_ass_data->expect_run_state);
                //do stop action
            }
        }
    }
    else if(grp->eng_ass_grp_ctrl.active_power>0){
        if(var->eng_ass_data->last_ch_state == 1) 
        { 
            if((var->eng_ass_data->happen_state == 1)&&(var->eng_ass_data->last_run_state != ENG_ASS_MODE_TYPE_INIT))
            {
                dbg_syslog(LOG_WARNING, "action change !!");
                var->eng_ass_data->expect_run_state = var->eng_ass_data->last_run_state;
                item->set_runmode(var,var->eng_ass_data->expect_run_state);
            }
            var->eng_ass_data->happen_state = 0;
        }
        var->eng_ass_data->last_ch_state = 2;
        if(( bms_under_vol_alarm != 0)||( bms_discharge_current < 0)||(var->eng_ass_data->happen_state == 1))
        {
            if(var->eng_ass_data->expect_run_state != ENG_ASS_MODE_TYPE_STOP)
            {
                if(var->eng_ass_data->happen_state == 1) //不是第一次进来保留最后一次运行状态
                var->eng_ass_data->last_run_state = var->eng_ass_data->expect_run_state;
                else  //第一次进来清除运行出状态
                var->eng_ass_data->last_run_state = ENG_ASS_MODE_TYPE_INIT;

                var->eng_ass_data->happen_state = 1;

                dbg_syslog(LOG_WARNING, "discharge do stop action!!!!");
                var->eng_ass_data->expect_run_state = ENG_ASS_MODE_TYPE_STOP;
                item->set_runmode(var,var->eng_ass_data->expect_run_state);
                //do stop action
            }
        }
    }
}
void soc_report_exec(energy_var_t *var,int grp_idx,int is_over_max)
{
    char *data_tmp1 = NULL;
    char key[64] = {0};
    cJSON *tag_data = cJSON_CreateObject();
    if (is_over_max == 1) snprintf(key, sizeof(key), "BMS[%d]soc:%f>SOCmax:%f",grp_idx+1,var->grp[grp_idx].eng_ass_grp_data.bms_soc,var->eng_ass_data->SOCMAX);
    else snprintf(key, sizeof(key), "BMS[%d]soc:%f<SOCmin:%f",grp_idx+1,var->grp[grp_idx].eng_ass_grp_data.bms_soc,var->eng_ass_data->SOCMIN);
    cJSON_AddStringToObject(tag_data, "info",key);
    cJSON_AddNumberToObject(tag_data, "result", 0);
    data_tmp1 = cJSON_PrintUnformatted(tag_data);
    data_publish_to_dev(var,var->emsctrl_sn_str,"VINTF_TCP","report_info",data_tmp1);
    cJSON_Delete(tag_data);
    free(data_tmp1);
}
void warn_report_exec(energy_var_t *var, int grp_idx)
{
    char *data_tmp1 = NULL;
    char key[64] = {0};
    cJSON *tag_data = cJSON_CreateObject();
    if ((var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_two == 1)|| (var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_three == 1))
    {
        if (var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_two == 1) snprintf(key, sizeof(key), "dischar Level two alarm, power 0 off");
        else snprintf(key, sizeof(key), "dischar Level three alarm, power 0 off");
    }
    else if ((var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_two == 1) || (var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_three == 1))
    {
        if (var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_two == 1)snprintf(key, sizeof(key), "char Level two alarm, power 0 off");
        else snprintf(key, sizeof(key), "char Level three alarm, power 0 off");
    }
    cJSON_AddStringToObject(tag_data, "info",key);
    cJSON_AddNumberToObject(tag_data, "result", 0);
    data_tmp1 = cJSON_PrintUnformatted(tag_data);
    data_publish_to_dev(var,var->emsctrl_sn_str,"VINTF_TCP","report_info",data_tmp1);
    cJSON_Delete(tag_data);
    free(data_tmp1);
}

static void *ctrl_process_loop_public(void *param)
{
    energy_var_t *var = ((data_ctrl_thread_var_t *)param)->var;
    eng_ass_grp_t *grp = ((data_ctrl_thread_var_t *)param)->grp;
    int grp_idx = ((void*)grp - (void*)var->grp)/sizeof(eng_ass_grp_t);
    int last_run_state = -1;
    int last_protect_level = ENG_ASS_PROTECT_LEVEL_INIT;
    action_and_check_t *action_steps = NULL;
    int action_steps_max = 0;
    int action_step_idx = 0;
    int zero_power_flag[ENG_ASS_GRP_MAX] = {0};
    static int last_grp_bms_status[ENG_ASS_GRP_MAX] = {0};
    int last_action_step_idx;
    time_t last_update_status = 0;
    time_t last_update_power = 0;

    while (1)
    {  
        grp->eng_ass_grp_ctrl.disconnect_v = 220;//暂时固定220v 接口预留上行ems_ctrl需要修改就删除这部分
        sleep(1);
        time_t now = time(NULL);
        int protect_level = 0;
        zero_power_flag[grp_idx] = 0;
        if(var->eng_ass_data->protect_level > protect_level)
            protect_level = var->eng_ass_data->protect_level;
        else if(grp->eng_ass_grp_ctrl.protect_level > protect_level)
            protect_level = grp->eng_ass_grp_ctrl.protect_level;
        
        if(last_protect_level != protect_level)
        {
            last_protect_level = protect_level;
            action_step_idx = 0; //状态变了执行序列从0开始
            action_steps = NULL;
        }
        //data_grp_current_ctrl(var,grp);

        if(protect_level > ENG_ASS_PROTECT_LEVEL_NONE)
        {
            int protect_level_idx = protect_level - 1;
            if(!action_steps)dbg_syslog(LOG_NOTICE,"grp[%d] action: protect level %d!",grp_idx,protect_level);
            if (protect_level != 1)//1级告警不关机，只写0，二级三级关机写0
            {
                action_steps = protect_action_chk[protect_level_idx];
                action_steps_max = protect_action_chk_size[protect_level_idx];
            }
            last_run_state = -1;
            zero_power_flag[grp_idx] = 1;//功率写0
        }
        else{
            if ((((var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_two == 1)|| (var->grp[grp_idx].eng_ass_grp_data.bms_dischar_hold_three == 1)) && (grp->eng_ass_grp_ctrl.active_power > 0)) || \
				(((var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_two == 1) || (var->grp[grp_idx].eng_ass_grp_data.bms_char_hold_three == 1)) && (grp->eng_ass_grp_ctrl.active_power < 0)))
            {
                action_step_idx = 0; //状态变了执行序列从0开始
                action_steps = NULL;
                if(!action_steps)dbg_syslog(LOG_NOTICE,"grp[%d] action: recv cmd stop.bms_under:%d,bms_over:%d.",grp_idx,var->grp[grp_idx].eng_ass_grp_data.bms_under_hold,var->grp[grp_idx].eng_ass_grp_data.bms_over_hold);
                action_steps = stop_action_chk;
                action_steps_max = ARRAY_SIZE(stop_action_chk);
                //grp->eng_ass_grp_ctrl.active_power = 0; //功率写0
                zero_power_flag[grp_idx] = 1;//功率写0
                if (last_grp_bms_status[grp_idx] == 0)
                {
                    warn_report_exec(var,grp_idx);
                }
                last_grp_bms_status[grp_idx] = 1;
            }
            else if ((var->eng_ass_data->SOCMIN >= 0) && (var->grp[grp_idx].eng_ass_grp_data.bms_soc <= var->eng_ass_data->SOCMIN) && (grp->eng_ass_grp_ctrl.active_power > 0))
            {
                action_step_idx = 0; //状态变了执行序列从0开始
                action_steps = NULL;
                if(!action_steps)dbg_syslog(LOG_WARNING, "grp[%d] soc:%f < soc min:%f ", grp_idx, var->grp[grp_idx].eng_ass_grp_data.bms_soc,var->eng_ass_data->SOCMIN);
                action_steps = stop_action_chk;
                action_steps_max = ARRAY_SIZE(stop_action_chk);
                //grp->eng_ass_grp_ctrl.active_power = 0; //功率写0
                zero_power_flag[grp_idx] = 1;//功率写0
                if (last_grp_bms_status[grp_idx] == 0)
                {
                    soc_report_exec(var,grp_idx,0);
                }
                last_grp_bms_status[grp_idx] = 1;
            }
            else if ((var->eng_ass_data->SOCMAX >= 0) && (var->grp[grp_idx].eng_ass_grp_data.bms_soc >= var->eng_ass_data->SOCMAX) && (grp->eng_ass_grp_ctrl.active_power < 0))
            {
                action_step_idx = 0; //状态变了执行序列从0开始
                action_steps = NULL;
                if(!action_steps)dbg_syslog(LOG_WARNING, "grp[%d] soc:%f > soc max:%f", grp_idx,var->grp[grp_idx].eng_ass_grp_data.bms_soc,var->eng_ass_data->SOCMAX);
                action_steps = stop_action_chk;
                action_steps_max = ARRAY_SIZE(stop_action_chk);
                //grp->eng_ass_grp_ctrl.active_power = 0; //功率写0
                zero_power_flag[grp_idx] = 1;
                if (last_grp_bms_status[grp_idx] == 0)
                {
                    soc_report_exec(var,grp_idx,1);
                }
                last_grp_bms_status[grp_idx] = 1;//充放交换需要按照开始
            }
			else if ((var->eng_ass_data->SINGLE_MAX > 0 && var->eng_ass_data->SINGLE_MIN > 0) && \
				     ((var->grp[grp_idx].eng_ass_grp_data.bms_single_max >= var->eng_ass_data->SINGLE_MAX && grp->eng_ass_grp_ctrl.active_power < 0) || \
				      (var->grp[grp_idx].eng_ass_grp_data.bms_single_min <= var->eng_ass_data->SINGLE_MIN && grp->eng_ass_grp_ctrl.active_power > 0)))
            {
                action_step_idx = 0; //状态变了执行序列从0开始
                action_steps = NULL;
                if(!action_steps)dbg_syslog(LOG_WARNING, "grp[%d] SINGLE_MAX:%f SINGLE_MIN:%f ,bms_single_max:%f bms_single_min:%f", grp_idx,var->eng_ass_data->SINGLE_MAX,var->eng_ass_data->SINGLE_MIN,var->grp[grp_idx].eng_ass_grp_data.bms_single_max,var->grp[grp_idx].eng_ass_grp_data.bms_single_min);
                action_steps = stop_action_chk;
                action_steps_max = ARRAY_SIZE(stop_action_chk);
                //grp->eng_ass_grp_ctrl.active_power = 0; //功率写0
                zero_power_flag[grp_idx] = 1;
            }
            else if((last_run_state != item_var.runmode) || (last_grp_bms_status[grp_idx] == 1 && grp->eng_ass_grp_ctrl.active_power != 0))
            {
                last_run_state = item_var.runmode;
                last_grp_bms_status[grp_idx] = 0;
                action_step_idx = 0; //状态变了执行序列从0开始
                action_steps = NULL;
                if(item_var.runmode == 1)//待机
                {
                    if(!action_steps)dbg_syslog(LOG_NOTICE,"grp[%d] action: recv cmd staby!",grp_idx);
                    action_steps = staby_action_chk;
                    action_steps_max = ARRAY_SIZE(staby_action_chk);
                }
                else if(item_var.runmode == 2)//开机
                {
                    if(!action_steps)dbg_syslog(LOG_NOTICE,"grp[%d] action: recv cmd run!",grp_idx);
                    action_steps = start_action_chk;
                    action_steps_max = ARRAY_SIZE(start_action_chk);
                }
                else                                        //关机
                {
                    if(!action_steps)dbg_syslog(LOG_NOTICE,"grp[%d] action: recv cmd stop!",grp_idx);
                    action_steps = stop_action_chk;
                    action_steps_max = ARRAY_SIZE(stop_action_chk);
                    //grp->eng_ass_grp_ctrl.active_power = 0; 
                    zero_power_flag[grp_idx] = 1;//功率写0
                }
            }
        }
        //找到由于一键启动/禁用/保护需要做的事情
        if(action_steps && action_step_idx < action_steps_max){
            action_and_check_t *step = &action_steps[action_step_idx];
            step->update_cb(var,grp_idx,step->update_param);
            dbg_syslog(LOG_INFO,"grp[%d] waiting %s response!",grp_idx,step->desc);
            if(cond_wait_signal(grp) == 0)//等待数据变化
            {
                int ret = step->condition_cb(var,grp_idx,step->condition_param);
                //That callback of condition return zero means this check passed and to do next step.
                if(ret == ENG_ASS_CONDITION_OK || ret == ENG_ASS_CONDITION_SKIP) 
                {
                    if(ret == ENG_ASS_CONDITION_SKIP)
                        dbg_syslog(LOG_INFO,"grp[%d] ignore step,invalid feedback data:%s [%d]!",grp_idx,step->desc,action_step_idx);
                    action_step_idx++;
                    dbg_syslog(LOG_INFO,"grp[%d] go to step:%s [%d]!",grp_idx,step->desc,action_step_idx);
                }
            }
        }


        int changed = 0;
        if(action_step_idx >= action_steps_max && action_step_idx != last_action_step_idx)
        {
            last_action_step_idx = action_step_idx;
            changed = 1;
        }

        int avail_power = chk_bms_avail_power_modified(var,grp_idx,grp->eng_ass_grp_ctrl.active_power,zero_power_flag[grp_idx]);
        if(avail_power != grp->eng_ass_grp_ctrl.last_active_power) 
        {
            grp->eng_ass_grp_ctrl.last_active_power = avail_power;
            changed = 1;
        }
        int changed_wggl = 0;
        if (grp->eng_ass_grp_ctrl.last_wggl_power != grp->eng_ass_grp_ctrl.wggl_power)
        {
            grp->eng_ass_grp_ctrl.last_wggl_power = grp->eng_ass_grp_ctrl.wggl_power;
            changed_wggl = 1;
        }

        //检查远程模式 last_update_status
        if (chk_pcs_remote_mode(var,grp_idx,ENG_ASS_REMOTE_MODE) == ENG_ASS_CONDITION_NO_MATCH)
        {
            if(now >= last_update_status + 3)
            {
                last_update_status = now;
                set_pcs_remote_mode(var,grp_idx,ENG_ASS_REMOTE_MODE);
            }
        }
        //检查离网并网 
        else if(chk_pcs_connection(var,grp_idx,grp->eng_ass_grp_ctrl.connect) == ENG_ASS_CONDITION_NO_MATCH)
        {
            if(now >= last_update_status + 3)
            {
                last_update_status = now;
                send_cmd_set_pcs_connection(var,grp_idx,grp->eng_ass_grp_ctrl.connect);
            }
        }
        //检查PCS 运行状态
        else if(chk_pcs_switch_public(var,grp_idx,grp->eng_ass_grp_ctrl.run_state) == ENG_ASS_CONDITION_NO_MATCH)
        {
            if(now >= last_update_status + 3)
            {
                last_update_status = now;
                send_cmd_set_pcs_switch_public(var,grp_idx,grp->eng_ass_grp_ctrl.run_state);
            }
        }  
        if(chk_pcs_diconnect_v(var,grp_idx,grp->eng_ass_grp_ctrl.disconnect_v) == ENG_ASS_CONDITION_NO_MATCH)//离网电压期望改变就写入
        {
            def_send_cmd_set_disconnect_active_v(var,grp_idx, grp->eng_ass_grp_ctrl.disconnect_v);
        } 
        
        if(changed || now >= last_update_power + 30)
        {
            last_update_power = now;
            def_send_cmd_set_pcs_active_power(var,grp_idx,avail_power);
        }

        if(changed_wggl)
        {
            def_send_cmd_set_pcs_wggl_power(var,grp_idx,grp->eng_ass_grp_ctrl.wggl_power);
        }
    }

    return NULL;
}

static int protect_action_chk_init(void)
{
    for (size_t i = 0; i < ARRAY_SIZE(protect_action_chk) ; i++)
    {
        for (size_t m = 0; m < ENG_ASS_ACTION_CHECK_MAX; m++)
        {
            if(!protect_action_chk[i][m].desc){//如果没有表述当作结束
                if(protect_action_chk_size[i] == 0)
                {
                    protect_action_chk_size[i] = m;
                    break;
                }
            }
        }
    }
    return 0;
}

// TODO 初始化静态的TAG
static void data_col_tag_map_init(tag_info_t *tag_info,size_t size)
{
    int tag_index = 0;
    for (tag_index = 0; tag_index < size; tag_index++)
    {
        char *tag = tag_info[tag_index].tag;
        int ret = hash_intptr_addptr(&tag_map_hash, tag, strlen(tag), &tag_info[tag_index]);
        if (ret < 0)
        {
            dbg_syslog(LOG_ERR, "hash_intptr_addptr failed, key: %s", tag_info[tag_index].tag);
            return;
        }
        dbg_syslog(LOG_INFO, "Add success: %s\n", tag_info[tag_index].tag);
    }
}

static int def_item_init(energy_var_t *var,void *param)
{
    int grp_idx = 0;
    //初始化tag映射链表
    data_col_tag_map_init(tag_info_table_stack,ARRAY_SIZE(tag_info_table_stack));
    //保护动作动态初始化
    protect_action_chk_init();
    for(grp_idx = 0;grp_idx<var->eng_ass_grp_num;grp_idx++)
    {
        eng_ass_grp_t *grp = &var->grp[grp_idx];
        threads_var[grp_idx].var = var;
        threads_var[grp_idx].grp = grp;
        pthread_cond_init(&grp->action_cond,NULL);
        pthread_mutex_init(&grp->action_mutex,NULL);
        /* 创建一个单独的线程, 专用于执行aiot_mqtt_process, 它会自动发送心跳保活, 以及重发QoS1的未应答报文 */
        int res = pthread_create(&grp->action_thread, NULL, ctrl_process_loop_public, &threads_var[grp_idx]);
        if (res < 0) {
            dbg_syslog(LOG_WARNING, "failed to created pthread for data process %s\n", strerror(errno));
            return -1;
        }
    }
    return 0;
}

static void def_item_set_runmode(energy_var_t *var,int mode)
{
    item_var.runmode = mode;
}

static void def_item_set_pcs_connect(energy_var_t *var,int mode)
{
    int grp_idx = 0;
    //dbg_syslog(LOG_INFO,"emspcs_connect:%d",mode);
    for(grp_idx = 0;grp_idx<var->eng_ass_grp_num;grp_idx++)
    {
        var->grp[grp_idx].eng_ass_grp_ctrl.connect = mode;
    }
}

static void def_item_set_data_event_cb(energy_var_t *var,data_event_cb_t cb)
{
    item_var.data_event_cb = cb;
}

static void def_set_bms_relay(energy_var_t *var,int state)
{
    var->grp[0].eng_ass_grp_ctrl.relay = var->eng_ass_data->expect_relay_state;
}

static void def_item_set_alarm_event_cb(energy_var_t *var,data_event_cb_t cb)
{
    item_var.alarm_event_cb = cb;
}

static void def_set_total_power(energy_var_t *var,int power,int is_wggl)
{
    int grp_idx = 0;

        for(grp_idx = 0;grp_idx<var->eng_ass_grp_num;grp_idx++)
        {
            if (is_wggl == 1)
            {
                //无功功率
                var->grp[grp_idx].eng_ass_grp_ctrl.wggl_power = data_grp_get_assign_power(var,grp_idx,power);
                dbg_syslog(LOG_INFO, "update grp[%d] wggl_power=%d scale_factor = %d/%d",grp_idx,var->grp[grp_idx].eng_ass_grp_ctrl.wggl_power,var->grp[grp_idx].eng_ass_grp_cfg.scale_factor,var->scale_factor_total_num);
            }
            else
            {
                //有功功率
                var->grp[grp_idx].eng_ass_grp_ctrl.active_power = data_grp_get_assign_power(var,grp_idx,power);
                dbg_syslog(LOG_INFO, "update grp[%d] active_power=%d scale_factor = %d/%d",grp_idx,var->grp[grp_idx].eng_ass_grp_ctrl.active_power,var->grp[grp_idx].eng_ass_grp_cfg.scale_factor,var->scale_factor_total_num);
            } 
        }
    
}

static void def_on_dev_data_updata(energy_var_t *var,void *json_ptr,int grp_idx) 
{
    int i = 0;
    int tag_num = 0;
    cJSON *sub = json_ptr;
    tag_num = cJSON_GetArraySize(sub);
    void *ptr = &var->grp[grp_idx].eng_ass_grp_data;
    for (i = 0; i < tag_num; i++)
    {
        cJSON *item = cJSON_GetArrayItem(sub, i);
        if (item == NULL)
        {
            dbg_syslog(LOG_ERR, "cJSON_GetArrayItem failed");
            continue;
        }
        if (item->type != cJSON_Number)
        {
            continue;
        }

        tag_info_t *info_p = NULL;
        if (hash_intptr_findptr(tag_map_hash, item->string, strlen(item->string), (void **)&info_p) < 0)
        {
            continue;
        }
        switch (info_p->type)
        {
        case E_TAG_INT:
            *((int *)(ptr + info_p->member_ofs)) = item->valueint;
            break;
        case E_TAG_FLOAT:
            *((float *)(ptr + info_p->member_ofs)) = item->valuedouble;
            break;
        default:
            dbg_syslog(LOG_ERR, "unsupported this type on tag:%s", item->string);
            break;
        }
        // if(strcmp("TAG_9D77",item->string) == 0 || strcmp("TAG_9D78",item->string) == 0 || strcmp("TAG_9C80",item->string) == 0)dbg_syslog(LOG_INFO, "DEBUG tag:%s = %f", item->string,*((float *)(ptr + info_p->member_ofs)));
    }
    if(item_var.data_event_cb)item_var.data_event_cb(var,NULL);
}


int energy_services_load(energy_var_t *var,char *module)
{
    abstract_item_t *info = _data2_part_start;
    dbg_syslog(LOG_INFO, "Select module:%s",module);
    fprintf (stderr, "Select module:%s\n",module);
    do {
        //fprintf (stderr, "start: %p  -> end %p\n", _data2_part_start,_data2_part_end);
        // fprintf (stderr, "call_ptr: %p  ,%s-> %s\n", info,info->alias,info->name);
        if(strcmp(module,info->name) == 0 || strcmp(module,info->alias) == 0)
        {
            if(info->init == NULL)info->init = def_item_init;
            info->init(var,NULL);
            if(info->set_runmode == NULL)info->set_runmode = def_item_set_runmode;
            if(info->set_pcs_connect == NULL)info->set_pcs_connect = def_item_set_pcs_connect;
            if(info->set_total_power == NULL)info->set_total_power = def_set_total_power;
            if(info->set_data_event_cb == NULL)info->set_data_event_cb = def_item_set_data_event_cb;
            if(info->clr_pcs_error == NULL)info->clr_pcs_error = def_send_cmd_set_pcs_reset_err;
            if(info->on_dev_data_updata == NULL)info->on_dev_data_updata = def_on_dev_data_updata;
            if(info->set_bms_relay == NULL)info->set_bms_relay = def_set_bms_relay;
            if(info->set_alarm_event_cb == NULL)info->set_alarm_event_cb = def_item_set_alarm_event_cb;
            dbg_syslog(LOG_INFO, "Run with:%s", module);
            fprintf (stderr, "Run with:%s\n",module);
            var->module_item = (void*)info;
            break;
        }
        ++info;
    } while (info < _data2_part_end);
    return 0;
}

int cond_wait_signal(eng_ass_grp_t *grp)
{
    int ret;
    struct timeval tv;
    struct timespec ts;
    pthread_mutex_lock(&grp->action_mutex);
    gettimeofday(&tv, NULL);
    ts.tv_sec  = tv.tv_sec;
    ts.tv_nsec = tv.tv_usec * 1000;
    ts.tv_sec += 2;
    ret = pthread_cond_timedwait(&grp->action_cond, &grp->action_mutex, &ts); 
    pthread_mutex_unlock(&grp->action_mutex);     
    return ret;  
}

void warp_ipc_session_publish(energy_var_t *var,char *dev_sn, char *topic, char *str)
{
    if( var->runMode == E_ONIOTBOX_MODE){
        snprintf(topic, TOPIC_MAX_LEN, "/ems/%s/service/set",  dev_sn);
        ipc_session_publish(var->exsession, topic, (unsigned char*)str, strlen(str));
    }else{
        char *gw_sn = NULL;
        if (hash_intptr_findptr(var->sub_gw_sn_map, dev_sn, strlen(dev_sn), (void **)&gw_sn) < 0)
        {
            return;
        }
        snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/Set_Rglt", gw_sn, "NULL", dev_sn);
        // dbg_syslog(LOG_INFO, "topic:%s", topic);
        ipc_session_publish(var->session, topic, (unsigned char*)str, strlen(str));
    }
}
//----------------------------南向控制设备接口----------------------------------------------------
int data_ctrl_dev_action(energy_var_t *var,char *dev_sn,char *identifier,char *key,int val)
{
    assert(dev_sn);
    assert(identifier);
    assert(key);
    char topic[TOPIC_MAX_LEN] = {0};
    char *str = NULL;
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "sn", dev_sn);
    cJSON_AddNumberToObject(root, "timestamp", time(NULL));
    cJSON_AddNumberToObject(root, "mi", 0);
    cJSON_AddStringToObject(root, "identifier", identifier);
    cJSON_AddNumberToObject(root, key, val);
    str = cJSON_Print(root);
    warp_ipc_session_publish(var, dev_sn, topic, str);
    free(str);
    cJSON_Delete(root);
    return 0;
}

int data_ctrl_dev_action_muti_tag(energy_var_t *var,char *dev_sn,char *identifier,eng_ass_tag_kv_t *kv,int size)
{
    assert(dev_sn);
    assert(identifier);
    assert(key);
    char topic[TOPIC_MAX_LEN] = {0};
    char *str = NULL;
    int i = 0;
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "sn", dev_sn);
    cJSON_AddNumberToObject(root, "timestamp", time(NULL));
    cJSON_AddNumberToObject(root, "mi", 0);
    cJSON_AddStringToObject(root, "identifier", identifier);
    for(i = 0;i<size;i++)
        cJSON_AddNumberToObject(root, kv[i].key, kv[i].value);
    str = cJSON_Print(root);
    warp_ipc_session_publish(var, dev_sn, topic, str);
    free(str);
    cJSON_Delete(root);
    return 0;
}

//通过识别内置
int data_grp_get_assign_power(energy_var_t *var,int grp,int total_power)
{
    static last = 0;
    int power = 0;
    //簇允许充电最大电流 -101 A 
    //簇允许放电最大电流 263 A 
    //EMS 充电 -50
    //EMS 放电 50
    float avail_power = 0;
    int tmp = total_power;
    if(total_power > 0){//放电
        tmp = MIN(ENG_ASS_POWER_MAX,tmp);
    }
    else if(total_power < 0)    //充电
    {
        tmp = MAX(-ENG_ASS_POWER_MAX,tmp);
    }
    //if(var->power_assign_mode == ENG_ASS_ASSIGN_MODE_AVERAGE)
    {
        power = tmp * ENG_ASS_POWER_EMS2PCS_SCALE * var->grp[grp].eng_ass_grp_cfg.scale_factor/var->scale_factor_total_num;
    }
    return power;
}
