#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "cJSON.h"
#include <pthread.h>
#include <time.h>
#include <math.h>

#include "jsonp.h"
#include "emsctrl.h"
#include "emsctrlProc.h"

extern CHARGE_MNG_INFO_T g_charge_mng_info;
extern PCS_CFG_T g_pcs_cfg_info;
extern STRATEGY_MNG_T g_strategr_mng_info;
extern DEMAND_CHARGE_INFO_T air_cond_planInfo_before;
extern  DEMAND_CHARGE_INFO_T air_cond_planInfo_after;

char *state_string[E_MAIN_STATE_MAX]={
    "init",
    "fault",
    "off",
    "idle",
    "charge",
    "discharge",
    "any",
};

static int *main_state = NULL;
static main_state_action_t *main_state_action_tabs = NULL;
static main_state_condition_t *main_state_condition_tabs = NULL;
static int main_state_action_tabs_size = 0;
static int main_state_condition_tabs_size = 0;
int kb_wrap_standby(pcs_ctrl_var_t *var,act_func_param_t param);
int kb_wrap_off(pcs_ctrl_var_t *var,act_func_param_t param);

//************************************************************//
//************   手动模式状态机反转配置 ************************//
//************************************************************//
//切换状态后需要处理器的事情
static main_state_action_t manu_main_state_action_tabs[] = {
    {E_MAIN_STATE_ANY,E_MAIN_STATE_FAULT,       {{wrap_pcs_zero_power,},{wrap_pcs_onoff,{NULL,E_OFF},}}},
};

//切换状态的条件配置
static main_state_condition_t manu_main_state_condition_tabs[] = {
    {E_MAIN_STATE_INIT,E_MAIN_STATE_IDLE,       {}},// 没条件,直接跳转,
 //   {E_MAIN_STATE_INIT,E_MAIN_STATE_FAULT,      {is_aux_fault,}},
 //  {E_MAIN_STATE_INIT,E_MAIN_STATE_FAULT,      {is_pcs_fault,}},

 //  {E_MAIN_STATE_IDLE,E_MAIN_STATE_FAULT,      {is_aux_fault,}},
 //  {E_MAIN_STATE_IDLE,E_MAIN_STATE_FAULT,      {is_pcs_fault,}},

 //  {E_MAIN_STATE_FAULT,E_MAIN_STATE_IDLE,      {is_not_pcs_fault,is_not_aux_fault,is_not_bms_fault}},
};

//************************************************************//
//************   自动模式状态机反转配置 ************************//
//************************************************************//

//切换状态后需要处理器的事情
static main_state_action_t auto_main_state_action_tabs[] = {
//   {E_MAIN_STATE_ANY,E_MAIN_STATE_FAULT,       {{wrap_pcs_zero_power,},{wrap_pcs_onoff,{NULL,E_OFF},}}},
    
//    {E_MAIN_STATE_IDLE,E_MAIN_STATE_CHANGE,     {{wrap_pcs_onoff,{NULL,E_ON},}}},
//    {E_MAIN_STATE_IDLE,E_MAIN_STATE_DISCHANGE,  {{wrap_pcs_onoff,{NULL,E_ON},}}},

    {E_MAIN_STATE_ANY,E_MAIN_STATE_IDLE,        {{kb_wrap_standby,{NULL,E_OFF},}}},  //快卜在这两种状态下延时操作
    {E_MAIN_STATE_ANY,E_MAIN_STATE_OFF,         {{kb_wrap_off,{NULL,E_OFF},}}},   //快卜在这两种状态下延时操作

  //  {E_MAIN_STATE_ANY,E_MAIN_STATE_IDLE,        {{wrap_standby,{NULL,E_OFF},}}},
  //  {E_MAIN_STATE_ANY,E_MAIN_STATE_OFF,         {{wrap_pcs_onoff,{NULL,E_OFF},}}},
                                                       
    {E_MAIN_STATE_ANY,E_MAIN_STATE_CHANGE,        {{wrap_pcs_onoff,{NULL,E_ON},},}},    
    {E_MAIN_STATE_ANY,E_MAIN_STATE_DISCHANGE,        {{wrap_pcs_onoff,{NULL,E_ON},},}},

    //comment by ghzhang
    // {E_MAIN_STATE_CHANGE,E_MAIN_STATE_IDLE,        {{wrap_do_delay_clr,{"linkage7",FAN_OFF_DELAY},}}},
    // {E_MAIN_STATE_DISCHANGE,E_MAIN_STATE_IDLE,        {{wrap_do_delay_clr,{"linkage7",FAN_OFF_DELAY},}}},

        //状态没变  放在最后防止对其他异常操作
 //   {E_MAIN_STATE_IDLE,E_MAIN_STATE_IDLE,           {{wrap_pcs_onoff,{NULL,E_OFF},}}},
 //   {E_MAIN_STATE_DISCHANGE,E_MAIN_STATE_DISCHANGE, {{wrap_pcs_onoff,{NULL,E_ON},},}},
 //   {E_MAIN_STATE_CHANGE,E_MAIN_STATE_CHANGE,       {{wrap_pcs_onoff,{NULL,E_ON},},}},
};

//切换状态的条件配置
static main_state_condition_t auto_main_state_condition_tabs[] = {
//   {E_MAIN_STATE_ANY,E_MAIN_STATE_FAULT,       {is_bms_fault,}},

    {E_MAIN_STATE_INIT,E_MAIN_STATE_IDLE,{}},// 没条件,直接跳转,

    {E_MAIN_STATE_CHANGE,E_MAIN_STATE_DISCHANGE,  {is_discharge,}},
    {E_MAIN_STATE_CHANGE,E_MAIN_STATE_IDLE,       {is_idle,}},
    {E_MAIN_STATE_CHANGE,E_MAIN_STATE_OFF,        {is_off,}},

    {E_MAIN_STATE_DISCHANGE,E_MAIN_STATE_CHANGE,     {is_charge,}},
    {E_MAIN_STATE_DISCHANGE,E_MAIN_STATE_IDLE,       {is_idle,}},
    {E_MAIN_STATE_DISCHANGE,E_MAIN_STATE_OFF,        {is_off,}},

    {E_MAIN_STATE_IDLE,E_MAIN_STATE_CHANGE,     {is_charge,}},
    {E_MAIN_STATE_IDLE,E_MAIN_STATE_DISCHANGE,  {is_discharge,}},
    {E_MAIN_STATE_IDLE,E_MAIN_STATE_OFF,        {is_off,}},

    {E_MAIN_STATE_OFF,E_MAIN_STATE_CHANGE,     {is_charge,}},
    {E_MAIN_STATE_OFF,E_MAIN_STATE_DISCHANGE,  {is_discharge,}},
    {E_MAIN_STATE_OFF,E_MAIN_STATE_IDLE,       {is_idle,}},

//    {E_MAIN_STATE_FAULT,E_MAIN_STATE_IDLE,      {is_not_pcs_fault,is_not_aux_fault,is_not_bms_fault}},

     //状态没变  放在最后防止对其他异常操作
 //   {E_MAIN_STATE_IDLE,E_MAIN_STATE_IDLE,       {is_connect,}},  
 //   {E_MAIN_STATE_DISCHANGE,E_MAIN_STATE_DISCHANGE,{is_charge,}},
 //   {E_MAIN_STATE_CHANGE,E_MAIN_STATE_CHANGE,   {is_idle,}}, 
};

/*快卜用延时关机 防止逆流*/
int tun_off = 0,turn_standby = 0;

int kb_wrap_standby(pcs_ctrl_var_t *var,act_func_param_t param)
{
    if(g_pcs_cfg_info.PVmax>0)
    {
        turn_standby = 1;
        g_charge_mng_info.PvCurrent = 0;
        pv_pcs_dev_yggl_set(var,g_charge_mng_info.PvCurrent,PV_FLAG);
        return 0;
    }
    else
    {
        pcs_dev_standby_set_by_config(var);
        return 0;
    }
}

int kb_wrap_off(pcs_ctrl_var_t *var,act_func_param_t param)
{   
    if(g_pcs_cfg_info.PVmax>0)
    {
        tun_off = 1;
        g_charge_mng_info.PvCurrent = 0;
        pv_pcs_dev_yggl_set(var,g_charge_mng_info.PvCurrent,PV_FLAG);
        return 0;
    }else
    {
        pcs_dev_close(var);
        return 0;
    }
}


static double getpv_v2() //削峰填谷用
{
    dbg_syslog(LOG_DEBUG,"pvget :%f", (double)(g_pcs_cfg_info.PVmax*g_charge_mng_info.PvCurrent)/100);
    return (double)(g_pcs_cfg_info.PVmax*g_charge_mng_info.PvCurrent)/100;
}
static void setpv_per2(double pv_v) //削峰填谷用
{
   if(g_pcs_cfg_info.PVmax <= 0)return;
   double PvCurrent_t = abs(pv_v*100/g_pcs_cfg_info.PVmax);
   if(PvCurrent_t<1)g_charge_mng_info.PvCurrent = 0;
   else if(PvCurrent_t>99)g_charge_mng_info.PvCurrent =100;
   else g_charge_mng_info.PvCurrent = PvCurrent_t;
}

static double getpv_v()
{
    dbg_syslog(LOG_DEBUG,"pvget :%f", (double)(g_pcs_cfg_info.pvMaxPower*g_charge_mng_info.PvCurrent)/100);
    return (double)(g_pcs_cfg_info.pvMaxPower*g_charge_mng_info.PvCurrent)/100;
}
static void setpv_per(double pv_v)
{
   if(g_pcs_cfg_info.pvMaxPower <= 0)return;
   double PvCurrent_t = abs(pv_v*100/g_pcs_cfg_info.pvMaxPower);
   if(PvCurrent_t<1)g_charge_mng_info.PvCurrent = 0;
   else if(PvCurrent_t>99)g_charge_mng_info.PvCurrent =100;
   else g_charge_mng_info.PvCurrent = PvCurrent_t;
}


static int ems_fault_state_analysis(pcs_ctrl_var_t *var)
{
    if (g_charge_mng_info.fireAlarm || g_charge_mng_info.waterImAlarm || g_charge_mng_info.smogAlarm)
    {
        g_charge_mng_info.actionnew = E_FIRE_W_G_FAULT_STATE;
    }
    else if (g_charge_mng_info.tempVal > g_pcs_cfg_info.tempThreshold)
    {
        g_charge_mng_info.actionnew = E_TEMP_FAULT_STATE;
    }
    else if (g_charge_mng_info.pcserr || g_charge_mng_info.bmserr)
    {
        g_charge_mng_info.actionnew = E_PCS_BMS_FAULT_STATE;
    }
    else
    {
        if (var->mastswitch_lingageInfo.cont)
        {
            if (g_charge_mng_info.mastSwitch == 1)
            {
                // io输出 24v
                mastSwitch_set_linkage(var, E_LINGAGE_ON);
            }
            else
            {
                // io输出 0v
                dbg_syslog(LOG_INFO, "mastSwitch Off");
                mastSwitch_set_linkage(var, E_LINGAGE_OFF);
                g_charge_mng_info.actionnew = E_CHARGE_IDLE; // bms高压箱未接通不进行充放电；
                return 0;
            }
        }
        // dbg_syslog(LOG_INFO, "actionnew:%d",g_charge_mng_info.actionnew);
        return 1;
    }
    // dbg_syslog(LOG_INFO, "actionnew:%d",g_charge_mng_info.actionnew);
    return 0;
}
//英博PCS故障恢复自动运行
void ems_pcs_fault_check(pcs_ctrl_var_t *var){
    // dbg_syslog(LOG_INFO,"chargeType:%d,g_charge_mng_info.action:%d,g_charge_mng_info.actionnew",var->chargeType,g_charge_mng_info.action,g_charge_mng_info.actionnew);
    if(var->chargeType == 1)
    if (g_charge_mng_info.pcserr == 0 &&  g_charge_mng_info.action == E_PCS_BMS_FAULT_STATE){
        if (g_charge_mng_info.ctrlMode != g_pcs_cfg_info.runState){
            g_charge_mng_info.ctrlMode = g_pcs_cfg_info.runState;
            g_charge_mng_info.action = E_CHARGE_IDLE;
        }
    }
}

static void ems_charge_state_analysis(pcs_ctrl_var_t *var)
{
    int ret = 0;
    ret = ems_fault_state_analysis(var);
    if (ret)
    {
        g_charge_mng_info.actionnew = E_CHARGE_DOING;
    }
}

static void ems_discharge_state_analysis(pcs_ctrl_var_t *var)
{
    int ret = 0;
    ret = ems_fault_state_analysis(var);
    if (ret)
    {
        g_charge_mng_info.actionnew = E_CHAREG_DISCH;
    }
}

static void ems_idlecharge_state_analysis(pcs_ctrl_var_t *var)
{
    int ret = 0;
    ret = ems_fault_state_analysis(var);
    if (ret)
    {
        g_charge_mng_info.actionnew = E_CHARGE_IDLE;
    }
}

static void ems_stopcharge_state_analysis(pcs_ctrl_var_t *var)
{
    int ret = 0;
    ret = ems_fault_state_analysis(var);
    if (ret)
    {
        g_charge_mng_info.actionnew = E_CHARGE_STOP;
    }
}
static void ems_state_analysis(pcs_ctrl_var_t *var)
{
    CHAR timer[TIME_VAL_LEN] = {0};
    get_time_p(timer);
    // dbg_syslog(LOG_INFO, "cutime:%s,timer:%s", var->cutimer, timer);    

    if (g_strategr_mng_info.update)
    {
        pcs_charge_plan_process(timer, &g_charge_mng_info.planInfo);
        g_strategr_mng_info.update = 0;
    }
    else if(strcmp(var->cutimer, timer) != 0)
    {
         pcs_charge_plan_process(timer, &g_charge_mng_info.planInfo);
         strcpy(var->cutimer, timer);

    }
    else  {       //load tracing
        }

    dbg_syslog(LOG_INFO, "time:%s option:%d power:%d", g_charge_mng_info.planInfo.time,
              g_charge_mng_info.planInfo.option,
              g_charge_mng_info.planInfo.power);
    switch (g_charge_mng_info.planInfo.option)
    {
    case E_CHARGE_DOING:
        ems_charge_state_analysis(var);
        break;
    case E_CHAREG_DISCH:
        ems_discharge_state_analysis(var);
        break;
    case E_CHARGE_IDLE:
        ems_idlecharge_state_analysis(var);
        break;
    case E_CHARGE_STOP:
        ems_stopcharge_state_analysis(var);
        break;
    }
    dbg_syslog(LOG_INFO, "actionnew:%d", g_charge_mng_info.actionnew);
}

static void ems_pcs_bms_fault_proc(pcs_ctrl_var_t *var)
{
    pcs_dev_yggl_set(var, 0);
    pcs_dev_close(var); // 关机
    // pcs_dev_disconect_set(var);//不需要离网，只要关机
    ems_mode_set(E_CTRL_MANUAL);
}

static void ems_temp_fault_proc(pcs_ctrl_var_t *var)
{
    pcs_dev_yggl_set(var, 0);
    ems_mode_set(E_CTRL_MANUAL);
    report_option(var, "temp alarm:%f switch to manual mode", g_charge_mng_info.tempVal);
}

static void ems_newold_charge_state_analysis(pcs_ctrl_var_t *var)
{
    switch (g_charge_mng_info.actionnew)
    {
    case E_CHARGE_DOING:
        break;
    case E_CHAREG_DISCH:
    case E_CHARGE_IDLE:
        pcs_dev_yggl_set(var, 0);
        break;
    case E_PCS_BMS_FAULT_STATE:
        ems_pcs_bms_fault_proc(var);
        break;
    case E_TEMP_FAULT_STATE:
        ems_temp_fault_proc(var);
        break;
    case E_FIRE_W_G_FAULT_STATE:
        //fire_w_g_set_linkage(var, E_LINGAGE_ON);
        break;
    default:
        break;
    }
}

static void ems_newold_discharge_state_analysis(pcs_ctrl_var_t *var)
{
    switch (g_charge_mng_info.actionnew)
    {
    case E_CHARGE_DOING:
        pcs_dev_yggl_set(var, 0);
        break;
    case E_CHAREG_DISCH:
        break;
    case E_CHARGE_IDLE:
        pcs_dev_yggl_set(var, 0);
        break;
    case E_PCS_BMS_FAULT_STATE:
        ems_pcs_bms_fault_proc(var);
        break;
    case E_TEMP_FAULT_STATE:
        ems_temp_fault_proc(var);
        break;
    case E_FIRE_W_G_FAULT_STATE:
       // fire_w_g_set_linkage(var, E_LINGAGE_ON);
        break;
    default:
        break;
    }
}

static void ems_newold_idlecharge_state_analysis(pcs_ctrl_var_t *var)
{
    switch (g_charge_mng_info.actionnew)
    {
    case E_CHARGE_DOING:
        break;
    case E_CHAREG_DISCH:
        break;
    case E_CHARGE_IDLE:
        break;
    case E_PCS_BMS_FAULT_STATE:
        ems_pcs_bms_fault_proc(var);
        break;
    case E_TEMP_FAULT_STATE:
        break;
    case E_FIRE_W_G_FAULT_STATE:
       // fire_w_g_set_linkage(var, E_LINGAGE_ON);
        break;
    default:
        break;
    }
}

static void ems_newold_pcsbms_state_analysis(pcs_ctrl_var_t *var)
{
    switch (g_charge_mng_info.actionnew)
    {
    case E_CHARGE_DOING:
        break;
    case E_CHAREG_DISCH:
        break;
    case E_CHARGE_IDLE:
        break;
    case E_PCS_BMS_FAULT_STATE:
        break;
    case E_TEMP_FAULT_STATE:
        break;
    case E_FIRE_W_G_FAULT_STATE:
       // fire_w_g_set_linkage(var, E_LINGAGE_ON);
        break;
    default:
        break;
    }
}

static void ems_newold_temp_state_analysis(pcs_ctrl_var_t *var)
{
    switch (g_charge_mng_info.actionnew)
    {
    case E_CHARGE_DOING:
        break;
    case E_CHAREG_DISCH:
        break;
    case E_CHARGE_IDLE:
        break;
    case E_PCS_BMS_FAULT_STATE:
        break;
    case E_TEMP_FAULT_STATE:
        break;
    case E_FIRE_W_G_FAULT_STATE:
       // fire_w_g_set_linkage(var, E_LINGAGE_ON);
        break;
    default:
        break;
    }
}

static void ems_newold_fwg_state_analysis(pcs_ctrl_var_t *var)
{
    switch (g_charge_mng_info.actionnew)
    {
    case E_CHARGE_DOING:
        // fire_w_g_set_linkage(E_LINGAGE_OFF);
        break;
    case E_CHAREG_DISCH:
        // fire_w_g_set_linkage(E_LINGAGE_OFF);
        break;
    case E_CHARGE_IDLE:
        // fire_w_g_set_linkage(E_LINGAGE_OFF);
        break;
    case E_PCS_BMS_FAULT_STATE:
        // fire_w_g_set_linkage(E_LINGAGE_OFF);
        break;
    case E_TEMP_FAULT_STATE:
        // fire_w_g_set_linkage(E_LINGAGE_OFF);
        break;
    case E_FIRE_W_G_FAULT_STATE:
        break;
    default:
        break;
    }
}

static void ems_newold_state_analysis(pcs_ctrl_var_t *var)
{
    // dbg_syslog(LOG_INFO, "entry action:%d", g_charge_mng_info.action);
    switch (g_charge_mng_info.action)
    {
    case E_CHARGE_DOING:
        ems_newold_charge_state_analysis(var);
        break;
    case E_CHAREG_DISCH:
        ems_newold_discharge_state_analysis(var);
        break;
    case E_CHARGE_IDLE:
    case E_CHARGE_STOP:
        ems_newold_idlecharge_state_analysis(var);
        break;
    case E_PCS_BMS_FAULT_STATE:
        ems_newold_pcsbms_state_analysis(var);
        g_charge_mng_info.ctrlMode = E_CTRL_MANUAL;
        break;
    case E_TEMP_FAULT_STATE:
        ems_newold_temp_state_analysis(var);
        g_charge_mng_info.ctrlMode = E_CTRL_MANUAL;
        break;
    case E_FIRE_W_G_FAULT_STATE:
        ems_newold_fwg_state_analysis(var);
        g_charge_mng_info.ctrlMode = E_CTRL_MANUAL;
        break;
    }
    if (g_charge_mng_info.action != g_charge_mng_info.actionnew)
    {
        report_option(var, "switch state:%s =>:%s", var->switchStateStr[g_charge_mng_info.action].stateStr, var->switchStateStr[g_charge_mng_info.actionnew].stateStr);
        dbg_syslog(LOG_INFO, "switch state:%s =>:%s", var->switchStateStr[g_charge_mng_info.action].stateStr, var->switchStateStr[g_charge_mng_info.actionnew].stateStr);
        g_charge_mng_info.action = g_charge_mng_info.actionnew;
    }
    // dbg_syslog(LOG_INFO, "exit action:%d", g_charge_mng_info.action);
} 
#define NEW 1 //配置为1使用新的策略 0使用旧的
 static void ems_discharge_demand_process(pcs_ctrl_var_t *var, WORD *power)
 {
    double demandPower = 0;
	double usr_p1 = 0;
#if NEW
    #if 1
    if (g_charge_mng_info.demandState == 1)
    {
        if (g_pcs_cfg_info.EDD == 1)
        {
            if(g_pcs_cfg_info.Dylmax > g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100)
				demandPower = g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100;
			else
				demandPower = g_pcs_cfg_info.Dylmax;
        }
		else
	        demandPower = g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100;

		usr_p1 = 1 ? g_charge_mng_info.P1_2 : g_charge_mng_info.P1; // 视在功率
        double pcha = usr_p1 - demandPower;
		dbg_syslog(LOG_DEBUG, "P1:%f - demandPower:%f = pcha:%f ", usr_p1, demandPower, pcha);
        if(pcha>0)
        {
            if(pcha*g_pcs_cfg_info.KM < 1) pcha = 1;
            else
            pcha = pcha*g_pcs_cfg_info.KM;
           *power = g_charge_mng_info.currentDischaPower+pcha;
        }
	    dbg_syslog(LOG_DEBUG, "power:%d, g_charge_mng_info.currentDischaPower:%d", *power, g_charge_mng_info.currentDischaPower);
    }
    if(*power < 0) *power = 0;
    #endif
#else
    if (g_charge_mng_info.demandState)
    {
        if (g_charge_mng_info.P1 > g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100)
        {
            *power = g_charge_mng_info.P3 - g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100 + g_pcs_cfg_info.Pset;
        }
    }
#endif
 }




static int ems_idle_demand_process(pcs_ctrl_var_t *var)
{
    int ret = 1;
    //if (g_charge_mng_info.soc > g_pcs_cfg_info.SOCmin)
    {
        if (g_charge_mng_info.demandState)
        {
            if (g_charge_mng_info.P1 > g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100)
            {
                g_charge_mng_info.currentDischaPower = g_charge_mng_info.P3 - g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100 + g_pcs_cfg_info.Pset;

                if (g_charge_mng_info.currentDischaPower < 0)
                {
                    g_charge_mng_info.currentDischaPower = 0;
                }
            }
            else
            {
                ret = 0;
                return ret;
            }

            if (g_pcs_cfg_info.PDiscMax != 0)
            {
                if (g_charge_mng_info.currentDischaPower > g_pcs_cfg_info.PDiscMax)
                {
                    g_charge_mng_info.currentDischaPower = g_pcs_cfg_info.PDiscMax;
                }
            }
            dbg_syslog(LOG_INFO, "idle demand currentDischaPower:%d", g_charge_mng_info.currentDischaPower);
            if (var->chargeType == 0)
            {
                pcs_dev_yggl_set(var, g_charge_mng_info.currentDischaPower);
            }
            else
            {
                pcs_dev_yggl_set(var, -g_charge_mng_info.currentDischaPower);
            }
        }
        else
        {
            ret = 0;
        }
    }
    return ret;
}

 static void ems_charge_demand_process(pcs_ctrl_var_t *var, WORD *power)
 {
    double demandPower = 0;
	double usr_p1 = 0;
	
    if (g_charge_mng_info.demandState == 1)
     {
#if NEW
		if (g_pcs_cfg_info.EDD == 1)
        {
            if(g_pcs_cfg_info.Dylmax > g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100)
				demandPower = g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100;
			else
				demandPower = g_pcs_cfg_info.Dylmax;
        }
		else
	        demandPower = g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100;
		
		usr_p1 = 1 ? g_charge_mng_info.P1_2 : g_charge_mng_info.P1; // 视在功率
        double pcha = usr_p1 - demandPower;
        dbg_syslog(LOG_DEBUG, "P1:%f - demandPower:%f = pcha:%f  Perr:%d ", usr_p1, demandPower, pcha, g_pcs_cfg_info.Perr);
        if (abs(pcha) >= g_pcs_cfg_info.Perr)
        {
            if(abs(pcha*g_pcs_cfg_info.KM) < 1)
            {
                if(pcha>0)pcha = 1;
                else pcha = -1;
            }
            else pcha = pcha*g_pcs_cfg_info.KM;
           *power = g_charge_mng_info.currentCharPower-pcha;
         }
        else *power = g_charge_mng_info.currentCharPower;
        dbg_syslog(LOG_DEBUG, "power:%d, g_charge_mng_info.currentCharPower:%d", *power, g_charge_mng_info.currentCharPower);
#else 
        demandPower = g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100;
        if (g_charge_mng_info.P1 >= demandPower)
        {
            if ((demandPower - g_charge_mng_info.P3) > 0)
            {
                if (g_charge_mng_info.planInfo.power > (demandPower - g_charge_mng_info.P3))
                {
                    *power = demandPower - g_charge_mng_info.P3;
                }
            }
            else
            {
                *power = 0;
            }
        }
        else
        {
            if (g_charge_mng_info.P3 > demandPower)
            {
                *power = 0;
            }
            else if (*power > demandPower - g_charge_mng_info.P3)
            {
                *power = demandPower - g_charge_mng_info.P3;
            }
        }
#endif
     }
    if(*power < 0) *power = 0;
 }

#if 0
void pv_set_val_charge(pcs_ctrl_var_t *var,WORD power_charge) 
{
    if( power_charge >=  g_pcs_cfg_info.PVmax ) //充电功率大于光伏最大容量光伏直接满量
    g_charge_mng_info.PvCurrent = 100;
    else
    {       
        if(g_charge_mng_info.AgainstState == 1)
        {
            dbg_syslog(LOG_INFO, "P1:%f Pset:%d",g_charge_mng_info.P1,g_pcs_cfg_info.Pset);
            if(g_charge_mng_info.Pv+g_pcs_cfg_info.Pset < power_charge )g_charge_mng_info.PvCurrent++;
            else g_charge_mng_info.PvCurrent--;
            if(g_charge_mng_info.P1 < 0 ) g_charge_mng_info.PvCurrent = 0;
        }
        else g_charge_mng_info.PvCurrent++;
        dbg_syslog(LOG_INFO, "pv_write_v_t:%f",g_charge_mng_info.PvCurrent);
    }
    if(g_charge_mng_info.PvCurrent>=100)
    g_charge_mng_info.PvCurrent = 100;
    else if(g_charge_mng_info.PvCurrent<=0)
    g_charge_mng_info.PvCurrent = 0;
    pv_pcs_dev_yggl_set(var,g_charge_mng_info.PvCurrent);
}
#endif

#define CHARGE_STEP_UP 5
#define CHARGE_STEP_DOWN 5

void pv_set_val_charge_pv_percent(pcs_ctrl_var_t *var, WORD expend_power) 
{
	int i = 0, pv_flag = 1;

    if( expend_power > g_pcs_cfg_info.PVmax ) //消耗功率(储能+负载)大于光伏最大容量光伏直接拉满
    {
	    g_charge_mng_info.PvCurrent = 100;
	    dbg_syslog(LOG_INFO, "hundred - pv percent:%d", g_charge_mng_info.PvCurrent);
    }
	else if (expend_power == 0)
	{
		g_charge_mng_info.PvCurrent = 0;
	}
    else
    {       
        if(g_charge_mng_info.AgainstState == 1)
        {
			double sum = g_pcs_cfg_info.Pset + g_pcs_cfg_info.Perr;
			double poor = g_pcs_cfg_info.Pset - g_pcs_cfg_info.Perr;
			dbg_syslog(LOG_INFO, "sum %f, poor %f, g_charge_mng_info.P1 %f", sum, poor, g_charge_mng_info.P1);
            if(g_charge_mng_info.P1 < poor) 
            {
				if(g_charge_mng_info.P1 < 0) // 逆流，光伏直接0功率
				{
					g_charge_mng_info.PvCurrent = 0;
					dbg_syslog(LOG_INFO, "zero - pv percent:%d", g_charge_mng_info.PvCurrent);
				}else{
					g_charge_mng_info.PvCurrent -= CHARGE_STEP_DOWN;
					dbg_syslog(LOG_DEBUG, "pv auto-increment percent: %d", g_charge_mng_info.PvCurrent);
				}
            }
			else if(g_charge_mng_info.P1 > sum)
			{
				g_charge_mng_info.PvCurrent += CHARGE_STEP_UP;
				dbg_syslog(LOG_DEBUG, "pv auto-decrement percent: %d", g_charge_mng_info.PvCurrent);
			}
			else // p1 稳定，不需要调光伏百分比
			{
				dbg_syslog(LOG_DEBUG, "P1 Steady state, Pv off-key: %d", g_charge_mng_info.PvCurrent);
			}
        }
        else{ 
			g_charge_mng_info.PvCurrent += CHARGE_STEP_UP;
			dbg_syslog(LOG_INFO, "Against switch off, ->100 pv percent:%d", g_charge_mng_info.PvCurrent);
        }
    }

	if(g_charge_mng_info.PvCurrent >= 100)
	    g_charge_mng_info.PvCurrent = 100;
    else if(g_charge_mng_info.PvCurrent <= 0)
	    g_charge_mng_info.PvCurrent = 0;

    pv_pcs_dev_yggl_set(var, g_charge_mng_info.PvCurrent, pv_flag);
}

void pv_set_val_charge_pv_power(pcs_ctrl_var_t *var, WORD expend_power) 
{
    int i = 0, pv_flag = 0;
	
    if( expend_power > g_pcs_cfg_info.PVmax ) //消耗功率(储能+负载)大于光伏最大容量光伏直接拉满
    {
	    g_charge_mng_info.PvCurrent = g_pcs_cfg_info.PVmax;
	    dbg_syslog(LOG_INFO, "hundred - pv percent:%d", g_charge_mng_info.PvCurrent);
    }
	else if (expend_power == 0)
	{
		g_charge_mng_info.PvCurrent = 0;
	}
    else
    {       
        if(g_charge_mng_info.AgainstState == 1) // 注意：光伏每次调节的功率步长，不能大于等于 sum 与 poor 的差值，否则会导致频繁调节(曲线一直波动)，可把区间稍微右移，增大P1调节上限，会损耗点电网电
        {
			double sum = g_pcs_cfg_info.Pset + g_pcs_cfg_info.Perr + 3;
			double poor = g_pcs_cfg_info.Pset - g_pcs_cfg_info.Perr - 1;
			dbg_syslog(LOG_INFO, "sum %f, ppor %f, g_charge_mng_info.P1 %f", sum, poor, g_charge_mng_info.P1);
            if(g_charge_mng_info.P1 < poor) 
            {
				if(g_charge_mng_info.P1 < 0) // 逆流，光伏直接0功率
				{
					g_charge_mng_info.PvCurrent = 0;
					dbg_syslog(LOG_INFO, "zero - pv percent:%d", g_charge_mng_info.PvCurrent);
				}else{
					g_charge_mng_info.PvCurrent -= CHARGE_STEP_DOWN;
					dbg_syslog(LOG_DEBUG, "pv auto-decrement percent: %d", g_charge_mng_info.PvCurrent);
				}
            }
			else if(g_charge_mng_info.P1 > sum)
			{
				g_charge_mng_info.PvCurrent += CHARGE_STEP_UP;
				dbg_syslog(LOG_DEBUG, "pv auto-increment percent: %d", g_charge_mng_info.PvCurrent);
			}
			else // p1 稳定，不需要调光伏功率
			{
				dbg_syslog(LOG_DEBUG, "P1 Steady state, Pv off-key: %d", g_charge_mng_info.PvCurrent);
			}
        }
        else{ 
			g_charge_mng_info.PvCurrent += CHARGE_STEP_UP;
			dbg_syslog(LOG_INFO, "Against switch off, ->100 pv percent:%d", g_charge_mng_info.PvCurrent);
        }
    }

	if(g_charge_mng_info.PvCurrent >= g_pcs_cfg_info.PVmax)
	    g_charge_mng_info.PvCurrent = g_pcs_cfg_info.PVmax;
    else if(g_charge_mng_info.PvCurrent <= 0)
	    g_charge_mng_info.PvCurrent = 0;
	
    pv_pcs_dev_yggl_set(var, g_charge_mng_info.PvCurrent, pv_flag);
}

static void ems_start_charge_process(pcs_ctrl_var_t *var)
{
    WORD power = 0;
    WORD expend_power = 0;
	
    dbg_syslog(LOG_NOTICE, "soc:%f socmax:%f Pmlmax:%d demandState:%d",
              g_charge_mng_info.soc, g_pcs_cfg_info.SOCmax, g_pcs_cfg_info.Pmlmax, g_charge_mng_info.demandState);

    // 开机
    pcs_dev_open(var);

    ems_charge_demand_process(var, &power);

    switch (g_pcs_cfg_info.CLCha)
    {
    case E_CHARGE_FIXED:
        if(g_pcs_cfg_info.Pcha < abs(power))power = g_pcs_cfg_info.Pcha;
        break;
    case E_CHARGE_PLAN:
        if((g_charge_mng_info.demandState == 0)||(g_charge_mng_info.planInfo.power < abs(power)))power = g_charge_mng_info.planInfo.power;
        break;
    }

    if (g_pcs_cfg_info.PchaMax > 0)
    {
        if (power > g_pcs_cfg_info.PchaMax)
        {
            power = g_pcs_cfg_info.PchaMax;
        }
    }
    g_charge_mng_info.currentCharPower = power;

    if (var->chargeType == 0)
    {
        pcs_dev_yggl_set(var, -g_charge_mng_info.currentCharPower);
    }
    else
    {
        pcs_dev_yggl_set(var, g_charge_mng_info.currentCharPower);
    }
	
#if 1		
	expend_power = g_charge_mng_info.P2 + g_charge_mng_info.P3;
	if (expend_power < 0) expend_power = 0;
    if(g_pcs_cfg_info.PVmax > 0)
    { 
		dbg_syslog(LOG_NOTICE, "PV Switch open and enter pv logic, need expend_power:%d", expend_power);
		pv_set_val_charge_pv_power(var, expend_power);
    }else
		dbg_syslog(LOG_NOTICE, "PV Switch close");
#endif

}

#if 0

static void ems_start_charge_process(pcs_ctrl_var_t *var)
{
    WORD power = 0;
    double demandPower = 0;
    dbg_syslog(LOG_INFO, "soc:%f socmax:%f Pmlmax:%d demandState:%d",
              g_charge_mng_info.soc, g_pcs_cfg_info.SOCmax, g_pcs_cfg_info.Pmlmax, g_charge_mng_info.demandState);
    if (g_pcs_cfg_info.SOCmax == -1 || g_charge_mng_info.soc < g_pcs_cfg_info.SOCmax)
    {
        // 开机
        pcs_dev_open(var);
        if (g_charge_mng_info.socmaxreport)
        {
            g_charge_mng_info.socmaxreport = 0;
        }
        switch (g_pcs_cfg_info.CLCha)
        {
        case E_CHARGE_FIXED:
            power = g_pcs_cfg_info.Pcha;
        case E_CHARGE_PLAN:
            power = g_charge_mng_info.planInfo.power;
        }
        ems_charge_demand_process(var, &power);
        g_charge_mng_info.currentCharPower = power;

        if (g_pcs_cfg_info.PchaMax > 0)
        {
            if (g_charge_mng_info.currentCharPower > g_pcs_cfg_info.PchaMax)
            {
                g_charge_mng_info.currentCharPower = g_pcs_cfg_info.PchaMax;
            }
        }
        if (g_charge_mng_info.demandState == 1)
        {
            dbg_syslog(LOG_INFO, "currentCharPower:%d;demandPower:%d", g_charge_mng_info.currentCharPower, demandPower);
        }
        else
        {
            dbg_syslog(LOG_INFO, "currentCharPower:%d;", g_charge_mng_info.currentCharPower);
        }
        if (var->chargeType == 0)
        {
            pcs_dev_yggl_set(var, -g_charge_mng_info.currentCharPower);
        }
        else
        {
            pcs_dev_yggl_set(var, g_charge_mng_info.currentCharPower);
        }
    }
    else
    {
        if (g_charge_mng_info.socmaxreport == 0)
        {
            g_charge_mng_info.socmaxreport = 1;
            report_option(var, "soc:%f >= socmax:%f", g_charge_mng_info.soc, g_pcs_cfg_info.SOCmax);
        }
#ifdef KB_EMS_CTRL
        // 待机
        //  pcs_dev_standby_set(var);
        pcs_dev_close(var);
#endif

        pcs_dev_yggl_set(var, power);
    }
}

#endif

static void ems_start_idlecharge_process(pcs_ctrl_var_t *var)
{
    if (!ems_idle_demand_process(var))
    {
        // 待机
        pcs_dev_standby_set(var);
        pcs_dev_yggl_set(var, 0);
    }
}

static void ems_start_stopcharge_process(pcs_ctrl_var_t *var)
{
    pcs_dev_yggl_set(var, 0);
    pcs_dev_close(var);
}

#if 0
void pv_set_val_discharge(pcs_ctrl_var_t *var,WORD *power_discharge) 
{
    WORD pwer_t = *power_discharge;
    if(pwer_t > g_pcs_cfg_info.PVmax)
    {
        *power_discharge = pwer_t - g_pcs_cfg_info.PVmax;
        if(g_charge_mng_info.PvCurrent>=100)
        {
            if((pwer_t - g_charge_mng_info.Pv)>0)
            *power_discharge = (pwer_t - g_charge_mng_info.Pv)/2; //稍微缓慢一点增加
            else
            *power_discharge = pwer_t - g_charge_mng_info.Pv;
            g_charge_mng_info.PvCurrent = 100;
        }
        g_charge_mng_info.PvCurrent++;
    }
    else
    {
        if(pwer_t > g_charge_mng_info.Pv+(double)g_pcs_cfg_info.PVmax/100) //超过最大容量1%在变化
        {
            if(g_charge_mng_info.PvCurrent==100) *power_discharge = pwer_t - g_charge_mng_info.Pv;
            else 
            {
                *power_discharge = *power_discharge - g_charge_mng_info.Pv;
                g_charge_mng_info.PvCurrent++;
            }
        }
        else if(pwer_t < g_charge_mng_info.Pv-(double)g_pcs_cfg_info.PVmax/100)
        {
            g_charge_mng_info.PvCurrent--;
            *power_discharge = 0;
        }
    }
    if(g_charge_mng_info.PvCurrent>=100)
    g_charge_mng_info.PvCurrent = 100;
    else if(g_charge_mng_info.PvCurrent<=0)
    g_charge_mng_info.PvCurrent = 0;
    pv_pcs_dev_yggl_set(var,g_charge_mng_info.PvCurrent);
}
#endif

#define DISCHARGE_STEP_UP 5
#define DISCHARGE_STEP_DOWN 5

void pv_set_val_discharge_pv_percent(pcs_ctrl_var_t *var, WORD *power_discharge) 
{
    WORD pwer_t = *power_discharge;
	int pv_flag = 1;
	
    if(pwer_t > g_pcs_cfg_info.PVmax)
    {
        *power_discharge = pwer_t - g_pcs_cfg_info.PVmax;
        if(g_charge_mng_info.PvCurrent >= 100)
        {
            WORD poor = pwer_t - g_charge_mng_info.P2 - g_charge_mng_info.Pv;
			g_charge_mng_info.PvCurrent = 100;
			dbg_syslog(LOG_DEBUG, "hundred - PvCurrent: %d, poor %d = pwer_t %d - g_charge_mng_info.P2 %d - g_charge_mng_info.Pv %d", g_charge_mng_info.PvCurrent, poor, pwer_t, g_charge_mng_info.P2, g_charge_mng_info.Pv);
            if(poor > 0)
            {
                dbg_syslog(LOG_DEBUG, "start power_discharge: %d", *power_discharge);
	            *power_discharge = *power_discharge + poor/2; // 稍微缓慢一点增加储能功率（储能补充）
	            dbg_syslog(LOG_DEBUG, "end power_discharge: %d", *power_discharge);
            }
        }else {
	        g_charge_mng_info.PvCurrent += DISCHARGE_STEP_UP;
			dbg_syslog(LOG_DEBUG, "pv auto-increment percent: %d", g_charge_mng_info.PvCurrent);
        }
    }
	else if (pwer_t == 0)
    {
		g_charge_mng_info.PvCurrent = 0;
		*power_discharge = 0;
	}
    else
    {
        if(pwer_t > g_charge_mng_info.Pv + (double)g_pcs_cfg_info.PVmax*3/100) //超过最大容量3%再变化
        {
            if(g_charge_mng_info.PvCurrent >= 100){
				*power_discharge = pwer_t - g_charge_mng_info.Pv;
				g_charge_mng_info.PvCurrent = 100;
			    dbg_syslog(LOG_DEBUG, "hundred - PvCurrent: %d, power_discharge: %d", g_charge_mng_info.PvCurrent, *power_discharge);
            }else {
                *power_discharge = pwer_t - g_charge_mng_info.Pv;
                g_charge_mng_info.PvCurrent += DISCHARGE_STEP_UP;
				dbg_syslog(LOG_DEBUG, "pv auto-increment percent: %d, power_discharge: %d", g_charge_mng_info.PvCurrent, *power_discharge);
            }
        }
        else if(pwer_t < g_charge_mng_info.Pv - (double)g_pcs_cfg_info.PVmax*3/100)
        {
            g_charge_mng_info.PvCurrent -= DISCHARGE_STEP_DOWN;
            *power_discharge = 0;
			dbg_syslog(LOG_DEBUG, "pv auto-decrement percent: %d, power_discharge: %d", g_charge_mng_info.PvCurrent, *power_discharge);
        }
		else  // 需要放电功率 “约等于” 当前光伏功率，此时不调整光伏百分比/功率，只调储能
		{
            if (pwer_t > g_charge_mng_info.Pv) *power_discharge = pwer_t - g_charge_mng_info.Pv;
            else *power_discharge = 0;
			dbg_syslog(LOG_DEBUG, "Steady state, Pv off-key: %d, power_discharge: %d", g_charge_mng_info.PvCurrent, *power_discharge);
		}
    }

    if(g_charge_mng_info.PvCurrent >= 100)
	    g_charge_mng_info.PvCurrent = 100;
    else if(g_charge_mng_info.PvCurrent <= 0)
	    g_charge_mng_info.PvCurrent = 0;

    pv_pcs_dev_yggl_set(var, g_charge_mng_info.PvCurrent, pv_flag);
}

void pv_set_val_discharge_pv_power(pcs_ctrl_var_t *var, WORD *power_discharge) 
{
    static int flag = 0;
	int pv_flag = 0;
    WORD pwer_t = *power_discharge;
	
    if(pwer_t > g_pcs_cfg_info.PVmax)
    {
        //if (pv_flag != 1) g_charge_mng_info.PvCurrent = g_charge_mng_info.Pv;
        *power_discharge = pwer_t - g_pcs_cfg_info.PVmax;
        if(g_charge_mng_info.PvCurrent >= g_pcs_cfg_info.PVmax)
        {
            WORD poor = pwer_t - g_charge_mng_info.P2 - g_charge_mng_info.Pv;
			g_charge_mng_info.PvCurrent = g_pcs_cfg_info.PVmax;
			dbg_syslog(LOG_DEBUG, "hundred - PvCurrent: %d, poor %d = pwer_t %d - g_charge_mng_info.P2 %d - g_charge_mng_info.Pv %d", g_charge_mng_info.PvCurrent, poor, pwer_t, g_charge_mng_info.P2, g_charge_mng_info.Pv);
            if(poor > 0)
            {
                dbg_syslog(LOG_DEBUG, "start power_discharge: %d", *power_discharge);
	            *power_discharge = *power_discharge + poor/2; // 稍微缓慢一点增加储能功率（储能补充）
	            dbg_syslog(LOG_DEBUG, "end power_discharge: %d", *power_discharge);
            }
        }else {
	        g_charge_mng_info.PvCurrent += DISCHARGE_STEP_UP;
			dbg_syslog(LOG_DEBUG, "pv auto-increment percent: %d", g_charge_mng_info.PvCurrent);
        }
		flag = 1;
    }
	else if (pwer_t == 0)
    {
		g_charge_mng_info.PvCurrent = 0;
		*power_discharge = 0;
		flag = 3;
	}
    else // 注意：光伏每次调节的功率步长，不能大于等于 "上限" 与 "下限" 的差值，否则会导致频繁调节(曲线一直波动)，会损耗点储能电
    {
        if(pwer_t > g_charge_mng_info.Pv + (double)g_pcs_cfg_info.PVmax*5/100) //超过最大容量3%再变化
        {
            //if (pv_flag != 1) g_charge_mng_info.PvCurrent = g_charge_mng_info.Pv;
            if(g_charge_mng_info.PvCurrent >= g_pcs_cfg_info.PVmax){
				*power_discharge = pwer_t - g_charge_mng_info.Pv;
				g_charge_mng_info.PvCurrent = g_pcs_cfg_info.PVmax;
			    dbg_syslog(LOG_DEBUG, "hundred - PvCurrent: %d, power_discharge: %d", g_charge_mng_info.PvCurrent, *power_discharge);
            }else {
                *power_discharge = pwer_t - g_charge_mng_info.Pv;
                g_charge_mng_info.PvCurrent += DISCHARGE_STEP_UP;
				dbg_syslog(LOG_DEBUG, "pv auto-increment percent: %d, power_discharge: %d", g_charge_mng_info.PvCurrent, *power_discharge);
            }
			flag = 1;
        }
        else if(pwer_t < g_charge_mng_info.Pv - (double)g_pcs_cfg_info.PVmax*5/100)
        {
            if (flag != 0) g_charge_mng_info.PvCurrent = g_charge_mng_info.Pv;
            g_charge_mng_info.PvCurrent -= DISCHARGE_STEP_DOWN;
            *power_discharge = 0;
			dbg_syslog(LOG_DEBUG, "pv auto-decrement percent: %d, power_discharge: %d", g_charge_mng_info.PvCurrent, *power_discharge);
			flag = 0;
        }
		else  // 需要放电功率 “约等于” 当前光伏功率，此时不调整光伏百分比/功率，只调储能
		{
            if (pwer_t > g_charge_mng_info.Pv) *power_discharge = pwer_t - g_charge_mng_info.Pv;
            else *power_discharge = 0;
			dbg_syslog(LOG_DEBUG, "Steady state, Pv off-key: %d, power_discharge: %d", g_charge_mng_info.PvCurrent, *power_discharge);
			flag = 2;
		}
    }

    if(g_charge_mng_info.PvCurrent >= g_pcs_cfg_info.PVmax)
	    g_charge_mng_info.PvCurrent = g_pcs_cfg_info.PVmax;
    else if(g_charge_mng_info.PvCurrent <= 0)
	    g_charge_mng_info.PvCurrent = 0;
	
    pv_pcs_dev_yggl_set(var, g_charge_mng_info.PvCurrent, pv_flag);
}

// 计算无功功率补偿
static double calculate_wwgl_power(double P, double current, double target) 
{
    double Qc = 0;
	if ((current >= -1 && current <= 1) && (target >= -1 && target <= 1))
	    Qc = P * (tan(acos(current)) - tan(acos(target)));
    return Qc;
}

static void ems_start_discharge_process(pcs_ctrl_var_t *var)
{
	WORD power = 0;
	double tmp_power = 0;
	WORD power_add = 0;
	WORD pv_power = 0;
	double usr_p1 = 0;
	dbg_syslog(LOG_NOTICE, "soc:%f SOCmin:%f P1:%f P3:%f k2:%d Dischamode:%d loadTrackingLimit:%d",
			  g_charge_mng_info.soc, g_pcs_cfg_info.SOCmin, g_charge_mng_info.P1,g_charge_mng_info.P3,
			  g_pcs_cfg_info.K2, g_pcs_cfg_info.CLDischa, g_pcs_cfg_info.loadTrackingLimit);

	// 开机
	pcs_dev_open(var);
	
	switch (g_pcs_cfg_info.CLDischa)
	{
	case E_CHARGE_FIXED:
		power = g_pcs_cfg_info.PDisc;
		break;
	case E_CHARGE_PLAN:
		if (g_charge_mng_info.AgainstState == 1)
		{
			power_add = (g_charge_mng_info.planInfo.power + g_pcs_cfg_info.PVmax) - (g_charge_mng_info.P2 + g_charge_mng_info.Pv);
			if((power_add != 0) && (power_add*g_pcs_cfg_info.KM < 1)) 
				power = 1;
			else 
				power = (power_add) * g_pcs_cfg_info.KM;
			
			dbg_syslog(LOG_DEBUG, "power1:%d", power);
			power = power + g_charge_mng_info.P2 + g_charge_mng_info.Pv; // 计划放电功率
			dbg_syslog(LOG_DEBUG, "power2:%d", power);

			usr_p1 = 1 ? g_charge_mng_info.P1_1 : g_charge_mng_info.P1;
			tmp_power = usr_p1 - (g_pcs_cfg_info.Pset - g_pcs_cfg_info.Perr); // 在不逆流的前提下，实际可放功率
			dbg_syslog(LOG_DEBUG, "tmp_power:%f, plan: %d ", tmp_power, g_charge_mng_info.planInfo.power);
			
			power = MIN(g_charge_mng_info.P2 + g_charge_mng_info.Pv + tmp_power, power);
			dbg_syslog(LOG_DEBUG, "power3:%d", power);
		}else{
			power = g_charge_mng_info.planInfo.power + g_pcs_cfg_info.PVmax;
		}
		break;
	case E_CHARGE_TRACK:
		tmp_power = (g_charge_mng_info.P3 * g_pcs_cfg_info.K2 / 100 - g_charge_mng_info.P2 - g_charge_mng_info.Pv) * g_pcs_cfg_info.KM;
		if (abs(tmp_power) < 1)
		{
			if(tmp_power >= 0) tmp_power = 1;
			else  tmp_power = -1;
		}
		power = tmp_power + g_charge_mng_info.P2 + g_charge_mng_info.Pv;
		if (g_pcs_cfg_info.loadTrackingLimit == 1)
		{
			if (power > (g_charge_mng_info.planInfo.power + g_pcs_cfg_info.PVmax))
			{
				power = g_charge_mng_info.planInfo.power + g_pcs_cfg_info.PVmax;
			}
		}
		break;
	default:
		break;
	}
	
	ems_discharge_demand_process(var, &power);
	
	if (g_charge_mng_info.AgainstState == 1)
	{
	    usr_p1 = 1 ? g_charge_mng_info.P1_1 : g_charge_mng_info.P1;
		if (usr_p1 < g_pcs_cfg_info.Pset - g_pcs_cfg_info.Perr)
		{
			double pcha =  abs(g_pcs_cfg_info.Pset - g_pcs_cfg_info.Perr - usr_p1);
			if(pcha < 1 )pcha = 1;
			power = g_charge_mng_info.P2 + g_charge_mng_info.Pv - pcha;
		}
	}
	if (power < 0) power = 0;

#if 1
	if(g_pcs_cfg_info.PVmax > 0)
	{	
		dbg_syslog(LOG_NOTICE, "PV Switch open and enter pv logic, need diccha_power:%d", power);
		pv_set_val_discharge_pv_power(var, &power);
	}
	else
		dbg_syslog(LOG_NOTICE, "PV Switch close");
	if (power < 0) power = 0;
#endif
	
	if ((g_pcs_cfg_info.CLDischa == E_CHARGE_PLAN) && (power > g_charge_mng_info.planInfo.power))
	{
		power = g_charge_mng_info.planInfo.power;
	}
	
	if (g_pcs_cfg_info.loadTrackingLimit == 1 && g_pcs_cfg_info.CLDischa == E_CHARGE_TRACK)
	{
		if (power > g_charge_mng_info.planInfo.power)
		{
			power = g_charge_mng_info.planInfo.power;
		}
	}
	
	if (g_pcs_cfg_info.PDiscMax != 0)
	{
		if (power >= g_pcs_cfg_info.PDiscMax)
		{
			power = g_pcs_cfg_info.PDiscMax;
		}
	}

	g_charge_mng_info.currentDischaPower = power;
	if (var->chargeType == 0)
	{
		pcs_dev_yggl_set(var, g_charge_mng_info.currentDischaPower);
	}
	else
	{
		pcs_dev_yggl_set(var, -g_charge_mng_info.currentDischaPower);
	}
}
# if 0
static void ems_start_discharge_process(pcs_ctrl_var_t *var)
{
    WORD power = 0;
    dbg_syslog(LOG_INFO, "soc:%f SOCmin:%f P3:%f k2:%d Dischamode:%d loadTrackingLimit:%d",
              g_charge_mng_info.soc, g_pcs_cfg_info.SOCmin, g_charge_mng_info.P3,
              g_pcs_cfg_info.K2, g_pcs_cfg_info.CLDischa, g_pcs_cfg_info.loadTrackingLimit);

    if (g_pcs_cfg_info.SOCmin == -1 || g_charge_mng_info.soc > g_pcs_cfg_info.SOCmin)
    {
        if (g_charge_mng_info.socminreport)
        {
            g_charge_mng_info.socminreport = 0;
        }
        // 开机
        pcs_dev_open(var);
        switch (g_pcs_cfg_info.CLDischa)
        {
        case E_CHARGE_FIXED:
            power = g_pcs_cfg_info.PDisc;
            break;
        case E_CHARGE_PLAN:
            power = g_charge_mng_info.planInfo.power;
            break;
        case E_CHARGE_TRACK:
            power = g_charge_mng_info.P3 * g_pcs_cfg_info.K2 / 100;
            if (g_pcs_cfg_info.loadTrackingLimit == 1)
            {
                if (power > g_charge_mng_info.planInfo.power)
                {
                    power = g_charge_mng_info.planInfo.power;
                }
            }
            break;
        default:
            break;
        }
        ems_discharge_demand_process(var, &power);
        if (g_charge_mng_info.AgainstState == 1)
        {
            dbg_syslog(LOG_INFO, "P1:%f pset:%d", g_charge_mng_info.P1, g_pcs_cfg_info.Pset);
            if (g_charge_mng_info.P1 < 0)
            {
                if (g_charge_mng_info.P3 + g_charge_mng_info.P1 - g_pcs_cfg_info.Pset > 0)
                    power = g_charge_mng_info.P3 + g_charge_mng_info.P1 - g_pcs_cfg_info.Pset;
                else
                    power = 0;
            }
            else if (g_charge_mng_info.P1 < g_pcs_cfg_info.Pset)
            {
                if (g_charge_mng_info.P3 > g_pcs_cfg_info.Pset)
                {
                    power = g_charge_mng_info.P3 - g_pcs_cfg_info.Pset;
                }
                else
                {
                    power = 0;
                }
            }
            else
            {
                if (g_charge_mng_info.P3 > g_pcs_cfg_info.Pset)
                {
                    if (power > (g_charge_mng_info.P3 - g_pcs_cfg_info.Pset))
                    {
                        power = g_charge_mng_info.P3 - g_pcs_cfg_info.Pset;
                    }
                }
                else
                {
                    power = 0;
                }
            }
        }

        dbg_syslog(LOG_INFO, "PDiscMax :%d power:%d", g_pcs_cfg_info.PDiscMax, power);
        if (g_pcs_cfg_info.PDiscMax != 0)
        {
            if (power >= g_pcs_cfg_info.PDiscMax)
            {
                power = g_pcs_cfg_info.PDiscMax;
            }
        }
        g_charge_mng_info.currentDischaPower = power;
        dbg_syslog(LOG_INFO, "currentDischaPower:%d", g_charge_mng_info.currentDischaPower);
        if (var->chargeType == 0)
        {
            pcs_dev_yggl_set(var, g_charge_mng_info.currentDischaPower);
        }
        else
        {
            pcs_dev_yggl_set(var, -g_charge_mng_info.currentDischaPower);
        }
    }
    else
    {
        if (g_charge_mng_info.socminreport == 0)
        {
            g_charge_mng_info.socminreport = 1;
            report_option(var, "soc:%f <= SOCmin:%f", g_charge_mng_info.soc, g_pcs_cfg_info.SOCmin);
        }
#ifdef KB_EMS_CTRL
        // 待机
        //  pcs_dev_standby_set(var);
        pcs_dev_close(var);
#endif
        pcs_dev_yggl_set(var, power);
    }
}
#endif
// 0 SUCCESS ; 1: FAIL 
static int io_call_function(pcs_ctrl_var_t *var,act_func_t act_cb,act_func_param_t act_func_param)
{
    if(act_cb){
        if(act_cb(var,act_func_param) != 0) //执行成功下一个, 失败,从group首个运行
        {
            dbg_syslog(LOG_INFO, "failed on function execute, function piont %p",act_cb);
            return 1;
        }
    }
    return 0;
}

static bool do_state_actions(pcs_ctrl_var_t *var,int src ,int dest)
{
    int n,m;
    for(m = 0;m < main_state_action_tabs_size; m++)
    {
        main_state_action_t *tabs = &main_state_action_tabs[m];
        if((tabs->src == src  || tabs->src == E_MAIN_STATE_ANY) && tabs->dest == dest)
        {
            for(n = 0;n < E_CB_FUNC_MAX; n++)
            {
                func_with_param_t func = tabs->funcs[n];
                if (func.act_func == NULL) break;
                io_call_function(var,func.act_func,func.act_func_param);
            }
            break;//跳出只执行种状态
        }
    }
}

// static void ems_state_process(pcs_ctrl_var_t *var)
// {
//     if (g_charge_mng_info.ctrlMode != E_CTRL_AUTO)
//     {
//         return;
//     }
//     g_charge_mng_info.switchCounter++;
//     dbg_syslog(LOG_INFO,"g_charge_mng_info.switchCounter:%lld",g_charge_mng_info.switchCounter); 
//     // pcs_dev_open(var);
//     switch (g_charge_mng_info.action)
//     {
//     case E_CHARGE_DOING:
//         ems_start_charge_process(var);
//         break;
//     case E_CHARGE_IDLE:
//         ems_start_idlecharge_process(var);
//         break;
//     case E_CHAREG_DISCH:
//         ems_start_discharge_process(var);
//         break;
//     case E_CHARGE_STOP:
//         ems_start_stopcharge_process(var);
//     default:
//         break;
//     }
// }

static void state_select(pcs_ctrl_var_t *var)
{
    if(g_charge_mng_info.lastCtrlMode != g_charge_mng_info.ctrlMode)
    {
        if(g_charge_mng_info.ctrlMode == E_CTRL_AUTO)
        {
            main_state = &var->auto_state;
            main_state_action_tabs = auto_main_state_action_tabs;
            main_state_action_tabs_size = ARRAY_SIZE(auto_main_state_action_tabs);
            main_state_condition_tabs = auto_main_state_condition_tabs;
            main_state_condition_tabs_size = ARRAY_SIZE(auto_main_state_condition_tabs);
            dbg_syslog(LOG_NOTICE, "Switch to automatic mode");
            //切换成自动模式，需要并网一次，防止网关重启后多个模块启动时间不一样造成乱发离网命令
            //pcs_dev_connect_set(var);
        }
        g_charge_mng_info.lastCtrlMode = g_charge_mng_info.ctrlMode;
        *main_state = E_MAIN_STATE_INIT; //发现切换每次重置状态机
        dbg_syslog(LOG_NOTICE, "Reset main state to init");
    }
}

static void ems_check_condition(pcs_ctrl_var_t *var)
{
    int n,m;
    // 故障检查这里没地方放了,先放这里
    for(m = 0;m < main_state_condition_tabs_size; m++)
    {
        main_state_condition_t *act_obj = &main_state_condition_tabs[m];
        int option = *main_state;
        if (act_obj->src == act_obj->dest) {
            dbg_syslog(LOG_WARNING, "invalid config state %d",m);
            continue;
        }
        if(act_obj->src == option || act_obj->src == E_MAIN_STATE_ANY) //匹配到当前状态
        {
            //尝试执行跳转条件
            bool all_success = false;
            for(n = 0;n < E_CB_FUNC_MAX; n++)
            {
                is_cond_t func = act_obj->act_funcs[n];
                if (func == NULL) { //所有表达式都走完
                    //如果匹配到一条不再往下匹配
                    all_success = true;
                    break;
                }
                act_func_param_t param = {0};
                if(!func(var)){break; //不执行下一个表达式,在前一次出错时
                }
            }
            if(all_success)
            {
                do_state_actions(var,act_obj->src,act_obj->dest);
                dbg_syslog(LOG_NOTICE, "All of condition be complated, current %s atction %s->%s",stastring(option) ,stastring(act_obj->src),stastring(act_obj->dest));
                *main_state = act_obj->dest;
                break;
            }
            else{ //如果执行失败,而且是fault 状态执行回调,用户故障上报/反馈等
                if(act_obj->src == E_MAIN_STATE_FAULT)
                {
                    do_state_actions(var,act_obj->src,act_obj->dest);
                }
            }
        }
    }
    
    g_charge_mng_info.switchCounter++;
    dbg_syslog(LOG_INFO,"g_charge_mng_info.switchCounter:%lld,main_state:%s",g_charge_mng_info.switchCounter,stastring(*main_state)); 
        /*if((*main_state == E_MAIN_STATE_DISCHANGE )||(*main_state == E_MAIN_STATE_CHANGE ))
            pcs_dev_open(var);*/
        if(*main_state == E_MAIN_STATE_OFF)
        {
            pcs_dev_close(var);
			pcs_dev_yggl_set(var, 0);
        }
        else if(*main_state == E_MAIN_STATE_IDLE)
        {
            pcs_dev_standby_set_by_config(var);
        }
}

void ems_update_plan_option_aircond(pcs_ctrl_var_t *var)
{
    //char string[1024];
    if(g_charge_mng_info.ctrlMode != E_CTRL_AUTO )
    {
        // snprintf(string,sizeof(string), "ctrlmode:%d pcserr:%d bmserr:%d protact:%d chawarn:%d dischwarn:%d\n",\
        // g_charge_mng_info.ctrlMode, g_charge_mng_info.pcserr, g_charge_mng_info.bmserr, g_charge_mng_info.ex_protact,\
        // g_charge_mng_info.chawarn,g_charge_mng_info.dischwarn);
        // write_file_data(PLAN_CACHE_FILE, string, strlen(string));   
        //g_charge_mng_info.planInfo.option == E_MAIN_STATE_IDLE;
        return;
    }

    CHAR timer[TIME_VAL_LEN] = {0};
    CHAR timer_after[TIME_VAL_LEN] = {0};
    get_time_p_for_air_cond(g_pcs_cfg_info.aircond_set_timeout_before,g_pcs_cfg_info.aircond_set_timeout_after,timer,timer_after); 

    pcs_charge_plan_process(timer, &air_cond_planInfo_before);
    pcs_charge_plan_process(timer_after, &air_cond_planInfo_after);
    dbg_syslog(LOG_NOTICE, "aircond_set planInfo_before time:%s option:%d power:%d", air_cond_planInfo_before.time,air_cond_planInfo_before.option,air_cond_planInfo_before.power);
    dbg_syslog(LOG_NOTICE, "aircond_set planInfo_after time:%s option:%d power:%d", air_cond_planInfo_after.time,air_cond_planInfo_after.option,air_cond_planInfo_after.power);
    
}



static void ems_update_plan_option(pcs_ctrl_var_t *var)
{
    char string[1024];
    if(g_charge_mng_info.ctrlMode != E_CTRL_AUTO )
    {
        // snprintf(string,sizeof(string), "ctrlmode:%d pcserr:%d bmserr:%d protact:%d chawarn:%d dischwarn:%d\n",\
        // g_charge_mng_info.ctrlMode, g_charge_mng_info.pcserr, g_charge_mng_info.bmserr, g_charge_mng_info.ex_protact,\
        // g_charge_mng_info.chawarn,g_charge_mng_info.dischwarn);
        // write_file_data(PLAN_CACHE_FILE, string, strlen(string));   
        g_charge_mng_info.planInfo.option == E_MAIN_STATE_IDLE;
        return;
    }

    CHAR timer[TIME_VAL_LEN] = {0};
    get_time_p(timer); 
    DEMAND_CHARGE_INFO_T tempPlanInfo = {0};
    pcs_charge_plan_process(timer, &tempPlanInfo);
 //  dbg_syslog(LOG_INFO, "cutime:%s,timer:%s timeAdj:%d", var->cutimer, timer,var->timeAdj);
    if (strcmp(var->cutimer, timer) != 0)
    {
        if (tempPlanInfo.option == E_CHARGE_IDLE)
        {
            if (strcmp(var->cutimer, timer) != 0)
            {
                strcpy(var->cutimer, timer);
                pcs_charge_plan_process(timer, &g_charge_mng_info.planInfo);
            }
        }
        else
        {
            if (strcmp(var->cutimer, timer) != 0)
            {
                strcpy(var->cutimer, timer);
                pcs_charge_plan_process(timer, &g_charge_mng_info.planInfo);
            }
        }
    }

    if (g_strategr_mng_info.update)
    {
        if (tempPlanInfo.option == E_CHARGE_IDLE)
        {
            strcpy(var->cutimer, timer);
            pcs_charge_plan_process(timer, &g_charge_mng_info.planInfo);
        }
        else
        {
            strcpy(var->cutimer, timer);
            pcs_charge_plan_process(timer, &g_charge_mng_info.planInfo);
        }
        g_strategr_mng_info.update = 0;
    }

    dbg_syslog(LOG_INFO, "time:%s option:%d power:%d", g_charge_mng_info.planInfo.time,g_charge_mng_info.planInfo.option,g_charge_mng_info.planInfo.power);
    
    int state = -1;
    char *str_state = NULL;
    if(main_state)
    {
        state = *main_state;
        str_state = state_string[state];
    }
    // snprintf(string,sizeof(string), "ctrlmode:%d state:%s[%d] now:%s time:%s option:%d power:%d pcserr:%d bmserr:%d protact:%d chawarn:%d dischwarn:%d\n",\
    g_charge_mng_info.ctrlMode, str_state,state,var->cutimer,g_charge_mng_info.planInfo.time,g_charge_mng_info.planInfo.option,g_charge_mng_info.planInfo.power, g_charge_mng_info.pcserr, g_charge_mng_info.bmserr, g_charge_mng_info.ex_protact,\
    g_charge_mng_info.chawarn,g_charge_mng_info.dischwarn);
    // 一种调试手段
    //write_file_data(PLAN_CACHE_FILE, string, strlen(string));   
}


static void ems_state_process(pcs_ctrl_var_t *var)
{
    //ems_update_plan_option_aircond(var);
    ems_update_plan_option(var);
    ems_check_condition(var);
}

void pv_folow_p1(pcs_ctrl_var_t *var)
{
    if(g_charge_mng_info.P1>g_pcs_cfg_info.Pset+g_pcs_cfg_info.Perr)
    g_charge_mng_info.PvCurrent++;
    else if(g_charge_mng_info.P1<0)g_charge_mng_info.PvCurrent = 0;
    else if(g_charge_mng_info.P1<g_pcs_cfg_info.Pset-g_pcs_cfg_info.Perr)
    g_charge_mng_info.PvCurrent--;

    if(g_charge_mng_info.PvCurrent>=100)
    g_charge_mng_info.PvCurrent = 100;
    else if(g_charge_mng_info.PvCurrent<=0)
    g_charge_mng_info.PvCurrent = 0;
    pv_pcs_dev_yggl_set(var,g_charge_mng_info.PvCurrent,PV_FLAG);
}

static void ems_power_process(pcs_ctrl_var_t *var)
{    
    static int turn_time = 0;  //光伏的防止逆流
    // if(g_pcs_cfg_info.PVmax>0)
    // {
    //     if(tun_off == 1) 
    //     {
    //         turn_time++;
    //         if(turn_time>5) 
    //         {
    //             g_charge_mng_info.pcs_openState = E_ON;
    //             pcs_dev_close(var);
    //             if(turn_time>4)
    //             {
    //                 tun_off = 0;
    //                 turn_time = 0; 
    //             }
    //         }
    //         dbg_syslog(LOG_NOTICE, "turn_time = %d",turn_time);
    //         return;
    //     }
    //     else if(turn_standby == 1) 
    //     {
    //         turn_time++;
    //         if(turn_time>5) 
    //         {
    //             g_charge_mng_info.pcs_openState = E_ON;
    //             pcs_dev_standby_set_by_config(var);
    //             if(turn_time>4)
    //             {
    //                 turn_standby = 0;
    //                 turn_time = 0;
    //             } 
    //         }
    //         dbg_syslog(LOG_NOTICE, "turn_time = %d",turn_time);
    //         return;
    //     }
    // }
    dbg_syslog(LOG_DEBUG, "KM:%f, savestate:%d",g_pcs_cfg_info.KM,g_pcs_cfg_info.savestate);
    switch (*main_state)
    {
    case E_MAIN_STATE_CHANGE:
        ems_start_charge_process(var);
        break;
    case E_MAIN_STATE_DISCHANGE:
        ems_start_discharge_process(var);
        break;
    default:
        break;
    }
    //if((g_pcs_cfg_info.PVmax>0)&&(*main_state!=E_MAIN_STATE_DISCHANGE))
    //pv_folow_p1(var);
}

void ems_process_main(pcs_ctrl_var_t *var)
{
    
    state_select(var);
    ems_state_process(var);
    ems_power_process(var);
}


void ems_process_main_bak(pcs_ctrl_var_t *var)
{
    // printf("[%s:%d->%s] \r\n" , __FILE__, __LINE__, __func__);
    ems_state_analysis(var);  //按照计划置 状态标志位
    ems_newold_state_analysis(var); //算是保护 在状态切换的时候 功率先写0 对异常状态的处理
    ems_state_process(var); //按照ems_state_analysis 的一些计划执行
}

static void ems_demand_ctrl_state_analysis(pcs_ctrl_var_t *var)
{
    // dbg_syslog(LOG_INFO, "entry action:%d", g_charge_mng_info.action);
    //double P1upthrhld=400;
    //double P1downthrhld=300;
    double P1upoffset=0;
    double Power=0;      
    dbg_syslog(LOG_INFO, "dischargeThreshold = %d",g_pcs_cfg_info.dischargeThreshold);
    dbg_syslog(LOG_INFO, "chargeStartPower = %d",g_pcs_cfg_info.chargeStartPower);

    if (g_charge_mng_info.P1 >= g_pcs_cfg_info.dischargeThreshold+P1upoffset && g_charge_mng_info.action!= E_CHAREG_DISCH)
    {
          g_charge_mng_info.action= E_CHAREG_DISCH;
          dbg_syslog(LOG_INFO, "ondemand discharge starts");
          g_charge_mng_info.currentDischaPower=0;
    }    
    if (g_charge_mng_info.P1<= g_pcs_cfg_info.chargeStartPower- P1upoffset && g_charge_mng_info.action!= E_CHARGE_DOING)
    {       
        g_charge_mng_info.action= E_CHARGE_DOING;
        dbg_syslog(LOG_INFO, "ondemand charge starts");
        g_charge_mng_info.currentCharPower=0;
    }
    
    if (g_charge_mng_info.action==E_CHAREG_DISCH)
    {         
        Power=g_pcs_cfg_info.K2*(g_charge_mng_info.P1- g_pcs_cfg_info.dischargeThreshold)/100 + g_charge_mng_info.currentDischaPower;//P2=K(P1-threhold)+P2'
        dbg_syslog(LOG_INFO, "ondemand discharge P2=%lf K2=%d",Power,g_pcs_cfg_info.K2);
        g_charge_mng_info.currentDischaPower = Power;
        if (Power<=0.5)
        {
            g_charge_mng_info.currentDischaPower = 0;
        }
        if (Power>=g_pcs_cfg_info.PDiscMax)
        {
            g_charge_mng_info.currentDischaPower =g_pcs_cfg_info.PDiscMax;
        }
        dbg_syslog(LOG_INFO, "currentDischaPower:%d", g_charge_mng_info.currentDischaPower);
        if (var->chargeType == 0)
        {
            pcs_dev_yggl_set(var, g_charge_mng_info.currentDischaPower);
        }
        else
        {
            pcs_dev_yggl_set(var, -g_charge_mng_info.currentDischaPower);
        }        
    }
    if (g_charge_mng_info.action==E_CHARGE_DOING)
    {
        Power=g_pcs_cfg_info.K2* (g_charge_mng_info.P1-g_pcs_cfg_info.chargeStartPower)/100 + (-g_charge_mng_info.currentCharPower);//K(P1-threhold)+P2'
        dbg_syslog(LOG_INFO, "ondemand charge P2= %lf K2=%d",Power,g_pcs_cfg_info.K2);
        g_charge_mng_info.currentCharPower = -Power;
        if(Power>=-0.5)
        {
            g_charge_mng_info.currentCharPower=0;
        }
        if(Power<=-g_pcs_cfg_info.PchaMax)
        {
            g_charge_mng_info.currentCharPower=g_pcs_cfg_info.PchaMax;
        }
        dbg_syslog(LOG_INFO, "currentchaPower:%d", g_charge_mng_info.currentCharPower);
        dbg_syslog(LOG_INFO,"charge type:%d",var->chargeType);
        if (var->chargeType == 0)
        {               
            pcs_dev_yggl_set(var, -g_charge_mng_info.currentCharPower);
        }   
        else
        {                
            pcs_dev_yggl_set(var, g_charge_mng_info.currentCharPower);
        }
    }
}

static void ems_charge_idle_process(pcs_ctrl_var_t *var)
{
	pcs_dev_yggl_set(var, 0);
}

static void ems_charge_doing_process(pcs_ctrl_var_t *var)
{
	WORD target_power = 0;
	WORD active_power = 0;
	//if (g_pcs_cfg_info.SOCmax == -1 || g_charge_mng_info.soc < g_pcs_cfg_info.SOCmax)
	//{
		if (g_charge_mng_info.socminreport)
		{
			g_charge_mng_info.socminreport = 0;
		}
		// 开机
		pcs_dev_open(var);
		
		//ems_charge_demand_process(var, &power);

		switch (g_pcs_cfg_info.CLCha)
		{
			case E_CHARGE_FIXED:
				target_power = g_pcs_cfg_info.Pcha;
				break;
			case E_CHARGE_PLAN:
				target_power = g_charge_mng_info.planInfo.power;
				break;
		}
		
        double pcha = g_charge_mng_info.currentCharPower - target_power;
        dbg_syslog(LOG_DEBUG, "pcha %f = target_power %d - g_charge_mng_info.currentCharPower:%f ", pcha, target_power, g_charge_mng_info.currentCharPower);
        if (abs(pcha) > 0)
        {
            if(abs(pcha*g_pcs_cfg_info.KM) < 1)
            {
                if(pcha > 0) pcha = 1;
                else pcha = -1;
            }
            else 
				pcha = pcha*g_pcs_cfg_info.KM;
            active_power = g_charge_mng_info.currentCharPower - pcha;
        }
        else 
			active_power = g_charge_mng_info.currentCharPower;
        dbg_syslog(LOG_DEBUG, "active_power:%d, g_charge_mng_info.currentCharPower:%d", active_power, g_charge_mng_info.currentCharPower);

		if (g_pcs_cfg_info.PchaMax > 0)
		{
			if (active_power > g_pcs_cfg_info.PchaMax)
			{
				active_power = g_pcs_cfg_info.PchaMax;
			}
		}

		g_charge_mng_info.currentCharPower = active_power;

		if (var->chargeType == 0)
		{
			pcs_dev_yggl_set(var, -g_charge_mng_info.currentCharPower);
		}
		else
		{
			pcs_dev_yggl_set(var, g_charge_mng_info.currentCharPower);
		}
    //}
	/*
	else
	{
		if (g_charge_mng_info.socmaxreport == 0)
		{
			g_charge_mng_info.socmaxreport = 1;
			report_option(var, "soc:%f >= socmax:%f", g_charge_mng_info.soc, g_pcs_cfg_info.SOCmax);
		}
#ifdef KB_EMS_CTRL
		// 待机
		//	pcs_dev_standby_set(var);
		if(g_pcs_cfg_info.alarmClose == 1)
		pcs_dev_close(var);
#endif

		pcs_dev_yggl_set(var, power);
	}*/
}

static void ems_load_charge_discharge_process(pcs_ctrl_var_t *var)
{
	WORD power = 0;
	double tmp_power = 0;
	
	dbg_syslog(LOG_NOTICE, "for load demand...");

	//if (g_pcs_cfg_info.SOCmin == -1 || g_charge_mng_info.soc > g_pcs_cfg_info.SOCmin)
	//{
		if (g_charge_mng_info.socminreport)
		{
			g_charge_mng_info.socminreport = 0;
		}
		// 开机
		pcs_dev_open(var);
		switch (g_pcs_cfg_info.CLDischa)
		{
			case E_CHARGE_FIXED:
				power = g_pcs_cfg_info.PDisc;
				break;
			case E_CHARGE_PLAN:
				power = g_charge_mng_info.planInfo.power;
				break;
			case E_CHARGE_TRACK:
				tmp_power = (g_charge_mng_info.P3 * g_pcs_cfg_info.K2 / 100 - g_charge_mng_info.currentDischaPower) * g_pcs_cfg_info.KM;
				if (abs(tmp_power) < 1)
				{
					if(tmp_power >= 0) tmp_power = 1;
					else  tmp_power = -1;
				}
				power = tmp_power + g_charge_mng_info.currentDischaPower;
				if (g_pcs_cfg_info.loadTrackingLimit == 1)
				{
					if (power > g_charge_mng_info.planInfo.power)
					{
						power = g_charge_mng_info.planInfo.power;
					}
				}
				break;
			default:
				break;
		}
		
		// if (g_charge_mng_info.P3 - g_pcs_cfg_info.dischargeThreshold > 0)
		// {
		// 	power = g_charge_mng_info.P3 - g_pcs_cfg_info.dischargeThreshold;
		// 	if (power < g_pcs_cfg_info.dischareeEndThresholdVal)
		// 	{
		// 		power = g_pcs_cfg_info.dischareeEndThresholdVal;
		// 	}
		// }
		// else if (g_charge_mng_info.P3 - g_pcs_cfg_info.dischargeEndThreshold > 0)  // 放电阀值和放电结束阀值，负载在此之间时，放电功率=放电阀值补放电
		// {
		// 	power = g_pcs_cfg_info.dischareeEndThresholdVal;
		// }
		
		if (g_pcs_cfg_info.PDiscMax != 0)
		{
			if (power >= g_pcs_cfg_info.PDiscMax)
			{
				power = g_pcs_cfg_info.PDiscMax;
			}
		}

		g_charge_mng_info.currentDischaPower = power;
		
		if (var->chargeType == 0)
		{
			pcs_dev_yggl_set(var, g_charge_mng_info.currentDischaPower);
		}
		else
		{
			pcs_dev_yggl_set(var, -g_charge_mng_info.currentDischaPower);
		}
    //}
	/*	  else
		{
			if (g_charge_mng_info.socminreport == 0)
			{
				g_charge_mng_info.socminreport = 1;
				report_option(var, "soc:%f < SOCmin:%f", g_charge_mng_info.soc, g_pcs_cfg_info.SOCmin);
			}
#ifdef KB_EMS_CTRL
			// 待机
			//	pcs_dev_standby_set(var);
			if(g_pcs_cfg_info.alarmClose == 1)
			pcs_dev_close(var);
#endif
			if(g_pcs_cfg_info.PVmax>0)//电池不放了光伏就跟随
			pv_folow_p1(var);
	
			pcs_dev_yggl_set(var, power);
		}
	*/
}
static void ems_grid_charge_discharge_process(pcs_ctrl_var_t *var)
{
	WORD target_power = 0;
	WORD active_power = 0;
	double tmp_power = 0;
	
	dbg_syslog(LOG_NOTICE, "for grid demand...");

	//if (g_pcs_cfg_info.SOCmin == -1 || g_charge_mng_info.soc > g_pcs_cfg_info.SOCmin)
	//{
		if (g_charge_mng_info.socminreport)
		{
			g_charge_mng_info.socminreport = 0;
		}
		// 开机
		pcs_dev_open(var);
		switch (g_pcs_cfg_info.CLDischa)
		{
			case E_CHARGE_FIXED:
				target_power = g_pcs_cfg_info.PDisc;
				break;
			case E_CHARGE_PLAN:
				target_power = g_charge_mng_info.planInfo.power;
				break;
			case E_CHARGE_TRACK: // P3负荷跟踪
				tmp_power = (g_charge_mng_info.P3 * g_pcs_cfg_info.K2 / 100 - g_charge_mng_info.currentDischaPower) * g_pcs_cfg_info.KM;
				if (abs(tmp_power) < 1)
				{
					if(tmp_power >= 0) tmp_power = 1;
					else  tmp_power = -1;
				}
				active_power = tmp_power + g_charge_mng_info.currentDischaPower;
				if (g_pcs_cfg_info.loadTrackingLimit == 1)
				{
					if (active_power > g_charge_mng_info.planInfo.power)
					{
						active_power = g_charge_mng_info.planInfo.power;
					}
				}
				break;
			default:
				break;
		}

        if ((g_pcs_cfg_info.CLDischa == E_CHARGE_FIXED) || (g_pcs_cfg_info.CLDischa == E_CHARGE_PLAN))
        {
			double pcha = g_charge_mng_info.currentDischaPower - target_power;
	        dbg_syslog(LOG_DEBUG, "pcha %f = target_power %d - g_charge_mng_info.currentDischaPower:%f ", pcha, target_power, g_charge_mng_info.currentDischaPower);
	        if (abs(pcha) > 0)
	        {
	            if(abs(pcha*g_pcs_cfg_info.KM) < 1)
	            {
	                if(pcha > 0) pcha = 1;
	                else pcha = -1;
	            }
	            else 
					pcha = pcha*g_pcs_cfg_info.KM;
	            active_power = g_charge_mng_info.currentDischaPower - pcha;
	        }
	        else 
				active_power = g_charge_mng_info.currentDischaPower;
	        dbg_syslog(LOG_DEBUG, "active_power:%d, g_charge_mng_info.currentDischaPower:%d", active_power, g_charge_mng_info.currentDischaPower);
        }
		
		if (g_pcs_cfg_info.PDiscMax != 0)
		{
			if (active_power >= g_pcs_cfg_info.PDiscMax)
			{
				active_power = g_pcs_cfg_info.PDiscMax;
			}
		}
        
		g_charge_mng_info.currentDischaPower = active_power;
		
		if (var->chargeType == 0)
		{
			pcs_dev_yggl_set(var, g_charge_mng_info.currentDischaPower);
		}
		else
		{
			pcs_dev_yggl_set(var, -g_charge_mng_info.currentDischaPower);
		}
    //}
	/*	  else
		{
			if (g_charge_mng_info.socminreport == 0)
			{
				g_charge_mng_info.socminreport = 1;
				report_option(var, "soc:%f < SOCmin:%f", g_charge_mng_info.soc, g_pcs_cfg_info.SOCmin);
			}
#ifdef KB_EMS_CTRL
			// 待机
			//	pcs_dev_standby_set(var);
			if(g_pcs_cfg_info.alarmClose == 1)
			pcs_dev_close(var);
#endif
			if(g_pcs_cfg_info.PVmax>0)//电池不放了光伏就跟随
			pv_folow_p1(var);
	
			pcs_dev_yggl_set(var, power);
		}
	*/
}
static void exist_time_line_process(double now_demand)
{
	static char last_state = 0;
	dbg_syslog(LOG_NOTICE, "exist_time_line_process");

	if (now_demand >= g_pcs_cfg_info.dischargeThreshold)
	{
	    if (*main_state == E_MAIN_STATE_DISCHANGE) 
	    {
		    if (g_charge_mng_info.action != E_MAIN_STATE_DISCHANGE)
		    {
			    g_charge_mng_info.action = E_MAIN_STATE_DISCHANGE;
	            dbg_syslog(LOG_NOTICE, "switch to discharging P1/P3:%f", now_demand);
			}
	    }else  g_charge_mng_info.action = E_MAIN_STATE_IDLE;
		last_state = 2;
	}
	else if (now_demand >= g_pcs_cfg_info.dischargeEndThreshold)
	{
        //what to do? -- keep
        if (last_state == 1) g_charge_mng_info.action = E_MAIN_STATE_IDLE; // 预防不可控跳变
        if (*main_state != E_MAIN_STATE_DISCHANGE) g_charge_mng_info.action = E_MAIN_STATE_IDLE;
	}
	else if (now_demand <= g_pcs_cfg_info.chargeStartPower)
	{
		if (*main_state == E_MAIN_STATE_CHANGE) 
	    {
			if (g_charge_mng_info.action != E_MAIN_STATE_CHANGE)
			{
				g_charge_mng_info.action = E_MAIN_STATE_CHANGE;
				dbg_syslog(LOG_NOTICE, "switch to charging P1/P3:%f", now_demand);
			}
		}else g_charge_mng_info.action = E_MAIN_STATE_IDLE;
		last_state = 1;
	}
	else if (now_demand <= g_pcs_cfg_info.chargeEndPower)
	{
		//what to do? -- keep
		if(last_state == 2) g_charge_mng_info.action = E_MAIN_STATE_IDLE;
        if (*main_state != E_MAIN_STATE_CHANGE) g_charge_mng_info.action = E_MAIN_STATE_IDLE;
	}
	
	if ((now_demand > g_pcs_cfg_info.chargeEndPower) && (now_demand < g_pcs_cfg_info.dischargeEndThreshold))
	{    
        // 切换成idle状态
        if (g_charge_mng_info.action != E_MAIN_STATE_IDLE)
        {
            g_charge_mng_info.action = E_MAIN_STATE_IDLE;
			dbg_syslog(LOG_NOTICE, "switch to idle P1/P3:%f", now_demand);
        }
	}
	if (*main_state == E_MAIN_STATE_IDLE)  g_charge_mng_info.action = E_MAIN_STATE_IDLE;

}

static void no_time_line_process(double now_demand)
{
    static char last_state = 0;
	dbg_syslog(LOG_NOTICE, "no_time_line_process");

	if (now_demand >= g_pcs_cfg_info.dischargeThreshold)
	{
	    if (g_charge_mng_info.action != E_MAIN_STATE_DISCHANGE)
	    {
		    g_charge_mng_info.action = E_MAIN_STATE_DISCHANGE;
            dbg_syslog(LOG_NOTICE, "switch to discharging P1/P3:%f", now_demand);
		}
		last_state = 2;
	}
	else if (now_demand >= g_pcs_cfg_info.dischargeEndThreshold)
	{
        //what to do? -- keep
        if (last_state == 1) g_charge_mng_info.action = E_MAIN_STATE_IDLE; // 预防不可控跳变
	}
	else if (now_demand <= g_pcs_cfg_info.chargeStartPower)
	{
		if (g_charge_mng_info.action != E_MAIN_STATE_CHANGE)
		{
			g_charge_mng_info.action = E_MAIN_STATE_CHANGE;
			dbg_syslog(LOG_NOTICE, "switch to charging P1/P3:%f", now_demand);
		}
		last_state = 1;
	}
	else if (now_demand <= g_pcs_cfg_info.chargeEndPower)
	{
		//what to do? -- keep
		if(last_state == 2) g_charge_mng_info.action = E_MAIN_STATE_IDLE;
	}
	
	if ((now_demand > g_pcs_cfg_info.chargeEndPower) && (now_demand < g_pcs_cfg_info.dischargeEndThreshold))
	{    
        // 切换成idle状态
        if (g_charge_mng_info.action != E_MAIN_STATE_IDLE)
        {
            g_charge_mng_info.action = E_MAIN_STATE_IDLE;
			dbg_syslog(LOG_NOTICE, "switch to idle P1/P3:%f", now_demand);
        }
	}
}

static void ems_demand_state_process(pcs_ctrl_var_t *var)
{
	E_TIMELINE tim_line = T_TIMELINE_NO;
	double now_demand = 0;

    if (g_charge_mng_info.lgState == 1)
        now_demand = g_charge_mng_info.P1;
    else
		now_demand = g_charge_mng_info.P3;
	
	dbg_syslog(LOG_NOTICE, "P1:%f, P3:%f, now_demand:%f, main_state:%d", g_charge_mng_info.P1, g_charge_mng_info.P3, now_demand, *main_state);
    dbg_syslog(LOG_NOTICE, "chargeStartPower :%d, chargeEndPower :%d", g_pcs_cfg_info.chargeStartPower, g_pcs_cfg_info.chargeEndPower);
    dbg_syslog(LOG_NOTICE, "dischargeThreshold :%d, dischargeEndThreshold :%d", g_pcs_cfg_info.dischargeThreshold, g_pcs_cfg_info.dischargeEndThreshold);

    for (int i = 0; i < MAX_DEMAND_NUMBER; i++) // 判断有无时间线，24h全E_CHARGE_IDLE表示无时间线(时间线无效)
    {
        if (g_pcs_cfg_info.demand_table[i].option != E_CHARGE_IDLE)
        {
            tim_line = T_TIMELINE_EXIST;
			break;
		}
	}

    switch (tim_line)
    {
	    case T_TIMELINE_NO:
	        no_time_line_process(now_demand);
	        break;
	    case T_TIMELINE_EXIST:
	        exist_time_line_process(now_demand);
	        break;
	    default:
	        break;
    }
}

static void ems_demand_power_process(pcs_ctrl_var_t *var)
{
	dbg_syslog(LOG_NOTICE, "charge/discharge/idle status %d", g_charge_mng_info.action);

    switch (g_charge_mng_info.action)
    {
	    case E_MAIN_STATE_IDLE:
	        ems_charge_idle_process(var);
	        break;
	    case E_MAIN_STATE_CHANGE:
	        ems_charge_doing_process(var);
	        break;
	    case E_MAIN_STATE_DISCHANGE:
			if (g_charge_mng_info.lgState == 1)
				ems_grid_charge_discharge_process(var);
			else
				ems_load_charge_discharge_process(var);
	        break;
	    default:
	        break;
    }
}

static void ems_demand_ctrl_analysis(pcs_ctrl_var_t *var)
{
    ems_demand_state_process(var);
	ems_demand_power_process(var);	
}

#define PerrorPace 2  //防逆流的死区值 防止稳定后一直调整

static void pv_demand_ctrl_state_analysis2(pcs_ctrl_var_t *var)
{
    double pv_write_v_t = 0; //将要写入的光伏功率
    double pv_write_v_t2 = getpv_v();  //读出来已经写入的值
    double accum_err_pv = g_charge_mng_info.P3 - g_charge_mng_info.Pv - g_pcs_cfg_info.p1Margin;
    static int first_charge = 1;
    static char need_discharge = 0,need_charge = 0,last_discharge = 0,needchange = 0;
    int min_change_val = 0;
    dbg_syslog(LOG_NOTICE, "P1:%f P3:%f PV:%f SOC:%f SOCMAX:%f SOCMIN:%f", g_charge_mng_info.P1,g_charge_mng_info.P3,g_charge_mng_info.Pv,g_charge_mng_info.soc,g_pcs_cfg_info.SOCmax,g_pcs_cfg_info.SOCmin);

    if(needchange > 0) //负载断掉后等待10秒钟稳定
    {
        needchange++;
        if(needchange>10)
        {
            needchange = 0;
        }
        return;
    }

    if((g_pcs_cfg_info.PvSwitch == E_OFF)||(accum_err_pv>0)) //如果没有开启光伏则直接进来
    {
        if( g_charge_mng_info.P3 > g_pcs_cfg_info.pvMaxPower+g_pcs_cfg_info.p1Margin) //负载大于光伏了直接光伏全开
        pv_write_v_t = g_pcs_cfg_info.pvMaxPower;
        else
        pv_write_v_t = pv_write_v_t2+(accum_err_pv*g_pcs_cfg_info.K2)/100;
        setpv_per(pv_write_v_t);
        if((g_charge_mng_info.PvCurrent == 100)||(g_pcs_cfg_info.PvSwitch == E_OFF))
        {
            double accum_err_st;
            if(g_pcs_cfg_info.dischargeThreshold>g_pcs_cfg_info.p1Margin)
            accum_err_st = g_charge_mng_info.P1 - g_pcs_cfg_info.dischargeThreshold;           //accum_err_st储能累计误差
            else
            accum_err_st = g_charge_mng_info.P1 - g_pcs_cfg_info.dischargeThreshold - g_pcs_cfg_info.p1Margin; 
            if ((g_charge_mng_info.soc >= g_pcs_cfg_info.SOCmax)||(first_charge == 1) )   //放电
            {
                first_charge = 0;
                need_discharge = 1;
                need_charge = 0;
            }
            if (g_charge_mng_info.soc <= g_pcs_cfg_info.SOCmin)   //充电
            {
                need_discharge = 0;
                need_charge = 1;
            }
            if(need_discharge == 1)
            {
                last_discharge = 1;
                if(g_charge_mng_info.last_charge_stat == 1)
                {
                    g_charge_mng_info.P2ToWrite = 0;
                    g_charge_mng_info.last_charge_stat = 0;
                }
                else
                {
                    g_charge_mng_info.last_charge_stat = 0;
                    // if(abs(accum_err_st)>g_pcs_cfg_info.forbidden)
                    //{
                        #if 1
                        //if(accum_err_st > 0)
                        //dbg_syslog(LOG_INFO, "P2ToWrite:%d,%f,%d", g_charge_mng_info.P2ToWrite,accum_err_st,g_pcs_cfg_info.K2);
                        if(accum_err_st>g_pcs_cfg_info.PDiscMax)
                            accum_err_st=g_pcs_cfg_info.PDiscMax;
                        if(accum_err_st >= PerrorPace) //这个算是一个防逆流死区防止频繁调整  最小调整区间是1kw所以保留个2kw的区间 暂时写死不让配置
                        {
                            if(((accum_err_st)*g_pcs_cfg_info.K2)/100<1)min_change_val = 1;
                            else min_change_val = ((accum_err_st)*g_pcs_cfg_info.K2)/100;
                            g_charge_mng_info.P2ToWrite = g_charge_mng_info.P2ToWrite + min_change_val ;
                        }
                        else if(accum_err_st < -PerrorPace) g_charge_mng_info.P2ToWrite = g_charge_mng_info.P2ToWrite + accum_err_st; //防逆流
                        //dbg_syslog(LOG_INFO, "P2ToWrite2:%d", g_charge_mng_info.P2ToWrite);
                        if(g_charge_mng_info.P2ToWrite > g_charge_mng_info.P3-g_charge_mng_info.Pv)g_charge_mng_info.P2ToWrite = g_charge_mng_info.P3-g_charge_mng_info.Pv;//防逆流
                        //dbg_syslog(LOG_INFO, "P2ToWrite3:%d", g_charge_mng_info.P2ToWrite);
                        #else
                        if(accum_err_st>g_pcs_cfg_info.PDiscMax)
                        {
                            accum_err_st=g_pcs_cfg_info.PDiscMax;
                            g_charge_mng_info.P2ToWrite = g_charge_mng_info.P2ToWrite + ((accum_err_st - g_charge_mng_info.P2ToWrite)*g_pcs_cfg_info.K2)/100;
                        }
                        else
                        {
                            g_charge_mng_info.P2ToWrite = g_charge_mng_info.P2ToWrite + (accum_err_st*g_pcs_cfg_info.K2)/100;
                        }
                        #endif
                        if(abs(g_charge_mng_info.P2ToWrite)>g_pcs_cfg_info.PDiscMax)
                        g_charge_mng_info.P2ToWrite = g_pcs_cfg_info.PDiscMax;
                        if(g_charge_mng_info.P2ToWrite < 0 ) g_charge_mng_info.P2ToWrite = 0;
                        //dbg_syslog(LOG_INFO, "P2ToWrite2:%d", g_charge_mng_info.P2ToWrite);
                   // }
                }
            }
            else if(need_charge == 1)
            {
                last_discharge = 0;
                if(g_charge_mng_info.last_charge_stat == 0)
                {
                    g_charge_mng_info.P2ToWrite = 0;
                    g_charge_mng_info.last_charge_stat = 1;
                }
                else
                {
                    g_charge_mng_info.last_charge_stat = 1;

                    double chargeVal = g_pcs_cfg_info.Pmlmax - g_charge_mng_info.P1;
                    dbg_syslog(LOG_INFO, "chargeVal:%f", chargeVal);
                    if(chargeVal < 0)
                    {
                        g_charge_mng_info.P2ToWrite =  g_charge_mng_info.P2ToWrite - chargeVal;
                        //dbg_syslog(LOG_INFO, "chargeVal1:%d", g_charge_mng_info.P2ToWrite);
                    }
                    else if (chargeVal > -(-(WORD)(g_pcs_cfg_info.MAXSupplementP +  g_charge_mng_info.P2ToWrite)))
                    {
                         //dbg_syslog(LOG_INFO, "chargeVal2:%d", g_charge_mng_info.P2ToWrite);
                         if(((-(WORD)(g_pcs_cfg_info.MAXSupplementP +  g_charge_mng_info.P2ToWrite))* g_pcs_cfg_info.K2)/100 > -1)min_change_val = 1;
                         else min_change_val = ((-(WORD)(g_pcs_cfg_info.MAXSupplementP +  g_charge_mng_info.P2ToWrite))* g_pcs_cfg_info.K2)/100;
                         g_charge_mng_info.P2ToWrite =  g_charge_mng_info.P2ToWrite + min_change_val;
                         //dbg_syslog(LOG_INFO, "chargeVal2:%d", g_charge_mng_info.P2ToWrite);
                    }
                    else if (chargeVal < -(-(WORD)(g_pcs_cfg_info.MAXSupplementP +  g_charge_mng_info.P2ToWrite)))
                    {
                         if((chargeVal* g_pcs_cfg_info.K2)/100<1) min_change_val = 1;
                         else min_change_val = (chargeVal* g_pcs_cfg_info.K2)/100;
                         g_charge_mng_info.P2ToWrite =  g_charge_mng_info.P2ToWrite - min_change_val;
                         //dbg_syslog(LOG_INFO, "chargeVal3:%d", g_charge_mng_info.P2ToWrite);
                    }
                    //dbg_syslog(LOG_INFO, "g_charge_mng_info.P2ToWrite:%d", g_charge_mng_info.P2ToWrite);
                    if(g_charge_mng_info.P2ToWrite > 0 ) g_charge_mng_info.P2ToWrite = 0;
                }
            }
        }
        else 
        g_charge_mng_info.P2ToWrite = 0; 
    }
    else
    {
        #if 1  //这个地方是新的 负载过小就全用光伏充电

        if(last_discharge == 1) //防逆流
        {
            dbg_syslog(LOG_WARNING, "need change ,write 0 to pv and p2");
            last_discharge = 0;
            g_charge_mng_info.P2ToWrite = 0;
            pv_write_v_t = 0;
            needchange = 1;
        }else
        {
        
            if(g_charge_mng_info.soc < g_pcs_cfg_info.SOCpv)
            {
                //dbg_syslog(LOG_INFO, "charge!!!!");
                g_charge_mng_info.P2ToWrite = -(g_charge_mng_info.Pv + g_pcs_cfg_info.p1Margin - g_charge_mng_info.P3);
                if(g_pcs_cfg_info.pvMaxPower+g_pcs_cfg_info.p1Margin <= g_pcs_cfg_info.PchaMax+g_charge_mng_info.P3)
                {
                    pv_write_v_t =pv_write_v_t2 + (float)g_pcs_cfg_info.pvMaxPower*1/100;  //光伏逐渐加到最大
                    if(pv_write_v_t2 < g_pcs_cfg_info.pvMaxPower)  g_charge_mng_info.P2ToWrite = -g_pcs_cfg_info.pvMaxPower; //光伏未开到最大就  先用光伏的满量充电 防止开始波动逆流
                }
                else if (g_pcs_cfg_info.pvMaxPower+g_pcs_cfg_info.p1Margin > g_pcs_cfg_info.PchaMax+g_charge_mng_info.P3)
                {
                    if( g_charge_mng_info.P1 >= g_pcs_cfg_info.p1Margin + PerrorPace) pv_write_v_t =pv_write_v_t2 + (float)g_pcs_cfg_info.pvMaxPower/100; //1%的比例增加
                    else if(g_charge_mng_info.P1<0) pv_write_v_t = 0;
                    else if(g_charge_mng_info.P1 <= g_pcs_cfg_info.p1Margin - PerrorPace) pv_write_v_t =pv_write_v_t2 - (float)g_pcs_cfg_info.pvMaxPower*1/100;
                }
                if(g_charge_mng_info.P2ToWrite > 0 ) g_charge_mng_info.P2ToWrite = 0;
            }
            else 
            {

        // else{ 
            //光伏固定比率增加

                //dbg_syslog(LOG_INFO, "nocharge!!!!");
                g_charge_mng_info.P2ToWrite = 0;
                if(g_charge_mng_info.P1 >= g_pcs_cfg_info.p1Margin+PerrorPace)
                pv_write_v_t =pv_write_v_t2 + (float)g_pcs_cfg_info.pvMaxPower*1/100;
                //pv_write_v_t = pv_write_v_t2 + (double)(g_charge_mng_info.P1 - g_pcs_cfg_info.p1Margin)*g_pcs_cfg_info.K2/100;
                else if(g_charge_mng_info.P1<0) pv_write_v_t = 0;
                else if(g_charge_mng_info.P1 <= g_pcs_cfg_info.p1Margin-PerrorPace)
                {
                    if(g_charge_mng_info.P3 < g_pcs_cfg_info.p1Margin)
                    pv_write_v_t = 0;
                    else
                    //pv_write_v_t =pv_write_v_t2 - (float)g_pcs_cfg_info.pvMaxPower*1/100;
                    pv_write_v_t = pv_write_v_t2 - (double)(g_pcs_cfg_info.p1Margin - g_charge_mng_info.P1);//直接变到防止逆流 往小了调整在慢慢加
                    //pv_write_v_t = pv_write_v_t2 - (double)(g_pcs_cfg_info.p1Margin - g_charge_mng_info.P1)*g_pcs_cfg_info.K2/100;
                }

            }
                
        }
        setpv_per(pv_write_v_t);

        #else
        pv_write_v_t2 = getpv_v();
        double pv_odd_p =  g_charge_mng_info.Pv - g_charge_mng_info.P3;  //v_odd_p 光伏剩余功率
        double p1_add_p =  g_pcs_cfg_info.PchaMax - pv_odd_p;                      //p1_add_p 电网需要补电功率
        if(p1_add_p>g_pcs_cfg_info.MAXSupplementP)
        p1_add_p=g_pcs_cfg_info.MAXSupplementP;
        g_charge_mng_info.P2ToWrite = -(p1_add_p+pv_odd_p);
        if(g_charge_mng_info.P1 > g_pcs_cfg_info.p1Margin)
        pv_write_v_t = pv_write_v_t2 + (g_pcs_cfg_info.pvMaxPower - pv_write_v_t2)*g_pcs_cfg_info.K2/100;
        else if(g_charge_mng_info.P1 < g_pcs_cfg_info.p1Margin)
        {
            if(g_charge_mng_info.P3 < g_pcs_cfg_info.p1Margin)
            pv_write_v_t = 0;
            else
            pv_write_v_t = pv_write_v_t2 - (g_pcs_cfg_info.p1Margin - g_charge_mng_info.P1)*g_pcs_cfg_info.K2/100;
        }
        setpv_per(pv_write_v_t);
        #endif
    }
    
    if(g_charge_mng_info.P2ToWrite>0)
    {
        g_charge_mng_info.action==E_CHAREG_DISCH;
        g_charge_mng_info.currentDischaPower = g_charge_mng_info.P2ToWrite;
        if (g_charge_mng_info.P2ToWrite<=0.5)
        {
            g_charge_mng_info.currentDischaPower = 0;
            g_charge_mng_info.P2ToWrite = 0;
        }
        if (g_charge_mng_info.P2ToWrite>=g_pcs_cfg_info.PDiscMax)
        {
            g_charge_mng_info.currentDischaPower = g_pcs_cfg_info.PDiscMax;
            g_charge_mng_info.P2ToWrite = g_pcs_cfg_info.PDiscMax;
        }
    }
    if(g_charge_mng_info.P2ToWrite<0)
    {
        g_charge_mng_info.action==E_CHARGE_DOING;
        g_charge_mng_info.currentCharPower = -g_charge_mng_info.P2ToWrite;
        if(g_charge_mng_info.P2ToWrite>=-0.5)
        {
            g_charge_mng_info.currentCharPower=0;
            g_charge_mng_info.P2ToWrite = 0;
        }
        if(g_charge_mng_info.P2ToWrite<=-g_pcs_cfg_info.PchaMax)
        {
            g_charge_mng_info.currentCharPower=g_pcs_cfg_info.PchaMax;
            g_charge_mng_info.P2ToWrite = -g_pcs_cfg_info.PchaMax;
        }
    }
    dbg_syslog(LOG_DEBUG, "g_pcs_cfg_info.PvSwitch:%d", g_pcs_cfg_info.PvSwitch);
    //dbg_syslog(LOG_INFO, "P2ToWrite:%d", g_charge_mng_info.P2ToWrite);
    //dbg_syslog(LOG_INFO, "PvToWrite:%d", g_charge_mng_info.PvCurrent);
    if(g_charge_mng_info.P2ToWrite == 0) pcs_dev_standby_set_by_config(var); //功率0 待机
    else 
    {
        pcs_dev_open(var);
        pcs_dev_yggl_set(var,g_charge_mng_info.P2ToWrite);
    }
    if(g_pcs_cfg_info.PvSwitch == E_ON)
    pv_pcs_dev_yggl_set(var,g_charge_mng_info.PvCurrent,PV_FLAG);
}

static void pv_demand_ctrl_state_analysis(pcs_ctrl_var_t *var)
{
    double pv_write_v_t = 0; //将要写入的光伏功率
    double pv_write_v_t2 = getpv_v();  //读出来已经写入的值
    double accum_err_pv = 0;
    
    if(g_pcs_cfg_info.PvSwitch == E_OFF)
    accum_err_pv = g_charge_mng_info.P3 - g_pcs_cfg_info.p1Margin;
    else 
    accum_err_pv = g_charge_mng_info.P3 - g_charge_mng_info.Pv - g_pcs_cfg_info.p1Margin;
    
    if (g_charge_mng_info.last_discharge_null != g_charge_mng_info.dischNull)
    {
      if (g_charge_mng_info.dischNull == 1) 
      {
            g_charge_mng_info.can_discharge = 0;
      }
      g_charge_mng_info.last_discharge_null = g_charge_mng_info.dischNull;
    }
    if (( g_charge_mng_info.dischNull == 1 )&&( g_charge_mng_info.soc >=g_pcs_cfg_info.socThreshold ))
    g_charge_mng_info.can_discharge = 1;

    dbg_syslog(LOG_NOTICE, "P1:%f P3:%f PV:%f SOC:%f FULL_STATE:%d NULL_STATE:%d", g_charge_mng_info.P1,g_charge_mng_info.P3,g_charge_mng_info.Pv,g_charge_mng_info.soc,g_charge_mng_info.chFull,g_charge_mng_info.dischNull);

    if((g_pcs_cfg_info.PvSwitch == E_OFF)||(accum_err_pv>0)) //如果没有开启光伏则直接进来
    {
        if( g_charge_mng_info.P3 > g_pcs_cfg_info.pvMaxPower+g_pcs_cfg_info.p1Margin) //负载大于光伏了直接光伏全开
        pv_write_v_t = g_pcs_cfg_info.pvMaxPower;
        else
        pv_write_v_t = pv_write_v_t2+(accum_err_pv*g_pcs_cfg_info.K2)/100;
        setpv_per(pv_write_v_t);
        if((g_charge_mng_info.PvCurrent == 100)||(g_pcs_cfg_info.PvSwitch == E_OFF))
        {
            double accum_err_st = g_charge_mng_info.P1 - g_pcs_cfg_info.dischargeThreshold;           //accum_err_st储能累计误差
            if(accum_err_st>0)
            {
                if(g_charge_mng_info.last_charge_stat == 1)
                {
                    g_charge_mng_info.P2ToWrite = 0;
                    g_charge_mng_info.last_charge_stat = 0;
                }
                else
                {
                    g_charge_mng_info.last_charge_stat = 0;
                    //if((g_charge_mng_info.chFull == 1)||(g_charge_mng_info.can_discharge == 1))
                   // {
                        if(abs(accum_err_st)>g_pcs_cfg_info.forbidden) 
                        {
                            g_charge_mng_info.P2ToWrite = g_charge_mng_info.P2ToWrite + (accum_err_st*g_pcs_cfg_info.K2)/100;
                            if(abs(g_charge_mng_info.P2ToWrite)>g_pcs_cfg_info.PDiscMax)
                            g_charge_mng_info.P2ToWrite = g_pcs_cfg_info.PDiscMax;
                        }
                   // }else g_charge_mng_info.P2ToWrite = 0;
                }
            }
            else
            {
                if(g_charge_mng_info.last_charge_stat == 0)
                {
                    g_charge_mng_info.P2ToWrite = 0;
                    g_charge_mng_info.last_charge_stat = 1;
                }
                else
                {
                    g_charge_mng_info.last_charge_stat = 1;
                    if(abs(accum_err_st)>g_pcs_cfg_info.forbidden)
                    {
                        g_charge_mng_info.P2ToWrite = g_charge_mng_info.P2ToWrite + (accum_err_st*g_pcs_cfg_info.K2)/100;
                        if(abs(g_charge_mng_info.P2ToWrite)>g_pcs_cfg_info.MAXSupplementP)
                        g_charge_mng_info.P2ToWrite = -g_pcs_cfg_info.MAXSupplementP;
                    }
                }
            }
        }
    }
    else
    {
        pv_write_v_t2 = getpv_v();
        double pv_odd_p =  g_charge_mng_info.Pv - g_charge_mng_info.P3;  //v_odd_p 光伏剩余功率
        double p1_add_p =  g_pcs_cfg_info.PchaMax - pv_odd_p;                      //p1_add_p 电网需要补电功率
        if(p1_add_p>g_pcs_cfg_info.MAXSupplementP)
        p1_add_p=g_pcs_cfg_info.MAXSupplementP;
        g_charge_mng_info.P2ToWrite = -(p1_add_p+pv_odd_p);
        if(g_charge_mng_info.P1 > g_pcs_cfg_info.p1Margin)
        pv_write_v_t = pv_write_v_t2 + (g_pcs_cfg_info.pvMaxPower - pv_write_v_t2)*g_pcs_cfg_info.K2/100;
        else if(g_charge_mng_info.P1 < g_pcs_cfg_info.p1Margin)
        {
            if(g_charge_mng_info.P3 < g_pcs_cfg_info.p1Margin)
            pv_write_v_t = 0;
            else
            pv_write_v_t = pv_write_v_t2 - (g_pcs_cfg_info.p1Margin - g_charge_mng_info.P1)*g_pcs_cfg_info.K2/100;
        }
        setpv_per(pv_write_v_t);
    }

    if(g_charge_mng_info.P2ToWrite>0)
    {
        g_charge_mng_info.action==E_CHAREG_DISCH;
        g_charge_mng_info.currentDischaPower = g_charge_mng_info.P2ToWrite;
        if (g_charge_mng_info.P2ToWrite<=0.5)
        {
            g_charge_mng_info.currentDischaPower = 0;
            g_charge_mng_info.P2ToWrite = 0;
        }
        if (g_charge_mng_info.P2ToWrite>=g_pcs_cfg_info.PDiscMax)
        {
            g_charge_mng_info.currentDischaPower = g_pcs_cfg_info.PDiscMax;
            g_charge_mng_info.P2ToWrite = g_pcs_cfg_info.PDiscMax;
        }
    }
    if(g_charge_mng_info.P2ToWrite<0)
    {
        g_charge_mng_info.action==E_CHARGE_DOING;
        g_charge_mng_info.currentCharPower = -g_charge_mng_info.P2ToWrite;
        if(g_charge_mng_info.P2ToWrite>=-0.5)
        {
            g_charge_mng_info.currentCharPower=0;
            g_charge_mng_info.P2ToWrite = 0;
        }
        if(g_charge_mng_info.P2ToWrite<=-g_pcs_cfg_info.PchaMax)
        {
            g_charge_mng_info.currentCharPower=g_pcs_cfg_info.PchaMax;
            g_charge_mng_info.P2ToWrite = -g_pcs_cfg_info.PchaMax;
        }
    }
    //dbg_syslog(LOG_INFO, "g_pcs_cfg_info.PvSwitch:%d", g_pcs_cfg_info.PvSwitch);
    //dbg_syslog(LOG_INFO, "P2ToWrite:%d", g_charge_mng_info.P2ToWrite);
    //dbg_syslog(LOG_INFO, "PvToWrite:%d", g_charge_mng_info.PvCurrent);
    pcs_dev_yggl_set(var,g_charge_mng_info.P2ToWrite);
    if(g_pcs_cfg_info.PvSwitch == E_ON)
    pv_pcs_dev_yggl_set(var,g_charge_mng_info.PvCurrent,PV_FLAG);
}
   

void ems_demand_ctrl_main(pcs_ctrl_var_t *var)
{
	state_select(var);
    ems_state_process(var);
    //ems_demand_ctrl_state_analysis(var);
    ems_demand_ctrl_analysis(var);
}

void ems_max_demand_ctrl_main(pcs_ctrl_var_t *var)
{
    //dbg_syslog(LOG_INFO, "ondemand action:%d", g_charge_mng_info.action);
    if(g_pcs_cfg_info.PvSwitch == E_OFF)
    pv_demand_ctrl_state_analysis(var);
    else
    pv_demand_ctrl_state_analysis2(var);
}

