#include "drv_gpio.h"

#include "gpio_manager.h"
#include "dido_manager.h"
#include "flash_manager.h"
#include "signal_manager.h"
#include "eeprom_manager.h"

#include "kit_debug.h"

typedef struct
{
    uint8_t map[kDiType_End];
    uint32_t dly[MAX_DI_NUM];
    uint16_t tick[MAX_DI_NUM];
    DiType   type[MAX_DI_NUM];
    DiStatus status[MAX_DI_NUM];
    DiPolarity polarity[MAX_DI_NUM];
    DiFun      fun[MAX_DI_NUM];
}DiItem;
DiItem di_item  __attribute__((section (".CCM_RAM")));

typedef struct 
{
    uint8_t         relay_start_io;
	uint8_t		    map[kDoType_End];
	uint16_t	    tick[APP_CFG_RELAY_NUM];
    DoCtrlStrategy  main_ctrl;
    DoType          type[APP_CFG_RELAY_NUM];
	DoStatus        ctrl_status[APP_CFG_RELAY_NUM];
	DoStatus        actual_status[APP_CFG_RELAY_NUM];
    DoErrSrc        err_src[APP_CFG_RELAY_NUM]; //DO故障检测源
    DoLogic      bmsCircuitCtrl;
    DoLogic      doLogicArray[APP_CFG_RELAY_NUM];
    uint32_t	    off_tick[APP_CFG_RELAY_NUM];
}DoItem;
DoItem do_item  __attribute__((section (".UNINIT_RAM"), zero_init));


DiStatus bms_get_di_status(DiType type)
{
    uint8_t idx;
    DiStatus st = kDiStatus_None;
    if(type < kDiType_End)
    {
        idx = di_item.map[type];
        if(idx < MAX_DI_NUM)
        {
            st = di_item.status[idx];
        }
    }
    
    return st;
}


DiType bms_get_di_type(uint8_t idx)
{
    DiType st = kDiType_Unused;

    if(idx < MAX_DI_NUM)
    {
        st = di_item.type[idx];
    }
    return st;
}


DiPolarity bms_get_di_polarity(uint8_t idx)
{
    DiPolarity st = kDiPolarity_Start;

    if(idx < MAX_DI_NUM)
    {
        st = di_item.polarity[idx];
    }

    return st;
}

DoCtrlStrategy bms_get_main_ctrl_strategy(void)
{
    return do_item.main_ctrl;
}

DoStatus bms_get_do_status_by_idx(uint8_t idx)
{
	DoStatus res = kDoStatus_Off;
	KIT_ASSERT_PARAM((idx < APP_CFG_RELAY_NUM) || (idx == 0xFF));
	if (idx < APP_CFG_RELAY_NUM)
    {
        res = do_item.actual_status[idx];
    }
	return res;
}

DoStatus bms_get_do_status_by_type(DoType type)
{
    DoStatus res = kDoStatus_Off;
    KIT_ASSERT_PARAM(type < kDoType_End);
    
    if(type < kDoType_End)
    {
        res = bms_get_do_status_by_idx(do_item.map[type]);
    }
    return res;
}

DoType bms_get_do_type(uint8_t idx)
{
    DoType res = kDoType_Unused;
    KIT_ASSERT_PARAM(idx < APP_CFG_RELAY_NUM);
    if (idx < APP_CFG_RELAY_NUM)
    {
        res = do_item.type[idx];
    }
    return res;
}

bool bms_is_do_config(DoType type)
{
    bool res = false;
    
    if(type < kDoType_End)
    {
        res = (do_item.map[type] != 0xFF);
    }
    
    return res;
}

DoErrSrc bms_get_do_err_src(DoType type)
{
	DoErrSrc res = kDoErrSrc_None; 
    KIT_ASSERT_PARAM(type < kDoType_End);
    
    if((type < kDoType_End) && (do_item.map[type] < APP_CFG_RELAY_NUM))
    {
        res = do_item.err_src[do_item.map[type]];
    }
    return res;
}

void bms_set_do_fault(DoType type, DoStatus status)
{
    uint8_t relay_idx = 0;
    KIT_ASSERT_PARAM((type < kDoType_End) && ((status == kDoStatus_Adhesion) || (status == kDoStatus_Open)));

    if((type < kDoType_End) && ((status == kDoStatus_Adhesion) || (status == kDoStatus_Open)))
    {
        relay_idx = do_item.map[type];
        if(relay_idx < APP_CFG_RELAY_NUM)
        {
            do_item.tick[relay_idx] = 0;
            do_item.actual_status[relay_idx] = status;
        }
    }
}

void bms_crtl_do_status(DoType type, DoCtrlStatus status, uint16_t dly)
{
    uint8_t relay_idx = 0;
    KIT_ASSERT_PARAM((type < kDoType_End) && ((status == kDoStatus_Off) || (status == kDoStatus_On)));
	
    if((type < kDoType_End) && (status < kDoCtrlStatus_None))
    {
        relay_idx = do_item.map[type];
        if((relay_idx < APP_CFG_RELAY_NUM) 
        && (do_item.ctrl_status[relay_idx] < kDoStatus_ForceOff))
        {
            do_item.tick[relay_idx] = dly;
            do_item.ctrl_status[relay_idx] = (DoStatus)status;
        }
    }
}

void bms_crtl_do_status_by_idx(uint8_t idx, DoCtrlStatus status, uint16_t dly)
{
    KIT_ASSERT_PARAM((idx < APP_CFG_RELAY_NUM) && ((status == kDoStatus_Off) || (status == kDoStatus_On)));

    if((idx < APP_CFG_RELAY_NUM) 
    && (do_item.ctrl_status[idx] < kDoStatus_ForceOff))
    {
        do_item.tick[idx] = dly;
        do_item.ctrl_status[idx] = (DoStatus)status;
    }
}

void bms_force_crtl_do_status(uint8_t idx, DoCtrlStatus status)
{
    KIT_ASSERT_PARAM((idx < APP_CFG_RELAY_NUM) && (status < kDoCtrlStatus_End));

    if((idx < APP_CFG_RELAY_NUM) && (status < kDoCtrlStatus_End))
    {
        if(status < kDoCtrlStatus_None)
        {
            do_item.tick[idx] = RELAY_CTRL_NO_DLY;
			//@wagnk，2-17，这里原本的status加了2，取消了
            do_item.ctrl_status[idx] = (DoStatus)(status);
        }
        else
        {
            //取消强控时判断之前是强控状态,是则复位
            if(do_item.actual_status[idx] > kDoStatus_On)
            {
                do_item.tick[idx] = RELAY_CTRL_NO_DLY;
                do_item.ctrl_status[idx] = kDoStatus_Off;
            }
        }
    }
}

void bms_cut_all_relay(void)
{
    uint32_t i;
    for(i = 0; i < APP_CFG_RELAY_NUM; i++)
	{
        do_item.tick[i] = 0;
        do_item.ctrl_status[i] = kDoStatus_ForceOff;
        do_item.actual_status[i] = kDoStatus_ForceOff;
        drv_gpio_set_pin_status(do_item.relay_start_io + i, kGpioStatus_Low);
    }
}

const GpioStatus relay_status_to_ctrl[kDoStatus_End] ={kGpioStatus_Low, kGpioStatus_High, kGpioStatus_Low, kGpioStatus_High, kGpioStatus_Low, kGpioStatus_Low};

void bms_poll_di_do(uint32_t base_time)
{
	uint32_t i,j = 0;
    DoStatus rly_st;
    
    if(do_item.bmsCircuitCtrl != NULL)
    {
        do_item.bmsCircuitCtrl(base_time, 0);
    }
    
	//DO
	for(i = 0; i < APP_CFG_RELAY_NUM; i++)
	{
		if(do_item.doLogicArray[i] != NULL)
		{
			do_item.doLogicArray[i](base_time, i);
		}
		if(do_item.tick[i] > 0)
		{
			if(do_item.tick[i] <= base_time)
			{
				do_item.tick[i] = 0;
				rly_st = do_item.ctrl_status[i];
				do_item.actual_status[i] = rly_st;
				if((relay_status_to_ctrl[rly_st] == kGpioStatus_Low) && (i == 1))
				{
					j = 1;
				}
				drv_gpio_set_pin_status(do_item.relay_start_io + i, relay_status_to_ctrl[rly_st]);			
			}
			else
			{
				do_item.tick[i] -= base_time;
			}
		}
	}

    for (i = 0; i < MAX_DI_NUM; i++)
    {
        if(bms_get_signal((SignalIdx)(kSignalIdx_Di1 + i)) != di_item.polarity[i])
        {
            di_item.tick[i] += base_time;
            if(di_item.tick[i] >= di_item.dly[i])
            {
                di_item.tick[i] = 0;
                di_item.status[i] = kDiStatus_Trigger;
            }
        }
        else
        {
            di_item.tick[i] = 0;
            di_item.status[i] = kDiStatus_None;
        }

        if(di_item.fun[i] != NULL)
        {
            di_item.fun[i](base_time, di_item.status[i], di_item.type[i]);
        }
    }
}

/*****************************************************************************
 *函数名称:relay_init
 *函数功能:继电器初始化
 *参    数:无
 *返 回 值:无
 *修订信息:
 ******************************************************************************/
extern const DiFun di_func[kDiType_End];
void bms_init_di_do(const DoLogic *do_main_poll_array, uint8_t do_main_poll_len, const DoLogic *do_poll_array)
{
    uint32_t idx;
    DiType di_type;
    DoType do_type;
    EepromDataType data_type;
    DoErrSrc do_err_src_type;
    
	//	//上电前先断开所有继电器
	//#if defined(BIUxxB) || defined(BSE1B) || defined(BSE2B)
	//	drv_gpio_set_pin_status(kGpioType_RlyEn, kGpioStatus_High);
	//    drv_gpio_set_pin_status(kGpioType_RlyEn, kGpioStatus_Low);
	//#endif    
	bsp_eeprom_set_data(kRelay2_1ForceCtrlStatus, 0x0202, kEepromDataType_Full);
    bsp_eeprom_set_data(kRelay4_3ForceCtrlStatus, 0x0202, kEepromDataType_Full);
    bsp_eeprom_set_data(kRelay6_5ForceCtrlStatus, 0x0202, kEepromDataType_Full);
    bsp_eeprom_set_data(kRelay8_7ForceCtrlStatus, 0x0202, kEepromDataType_Full);
    bsp_eeprom_set_data(kRelay10_9ForceCtrlStatus, 0x0202, kEepromDataType_Full);
	
	for(idx = kDoType_Start; idx < kDoType_End; idx++)
	{
		do_item.map[idx] = 0xFF;
	}
    for (idx = 0; idx < APP_CFG_RELAY_NUM; idx++)
    {
		do_item.tick[idx] = 0;
		do_item.off_tick[idx] = 0;
        do_item.relay_start_io = kGpioType_DO1;
        if(get_eeprom_data(kEep_IsSoftReset, kEepromDataType_Low) == 0)
        {
            do_item.ctrl_status[idx] = kDoStatus_Off;
            do_item.actual_status[idx] = kDoStatus_Off;
        }
        else
        {
            if(do_item.ctrl_status[idx] < kDoStatus_End)
            {
                drv_gpio_set_pin_status(do_item.relay_start_io + idx, relay_status_to_ctrl[do_item.ctrl_status[idx]]);
            }
            else
            {
                do_item.ctrl_status[idx] = kDoStatus_Off;
            }
        }
		//sfj 7.23新加 DO9 DO10
		if(idx == 8 || idx == 9)
		{
            do_type = (DoType)(get_eeprom_data(kEep_Relay10_9Type, (EepromDataType)(idx % 2)));
			if (do_type < kDoType_End)
			{
				do_item.map[do_type] = idx;
				do_item.type[idx] = do_type;
				do_item.doLogicArray[idx] = do_poll_array[do_type];
			}
			do_err_src_type = (DoErrSrc)get_eeprom_data(kEep_DO10_DO9_ErrSrc, (EepromDataType)(idx % 2));
			if(do_err_src_type < kDoErrSrc_End)
			{
				do_item.err_src[idx] = do_err_src_type;
			}
		}
		else//do1-do8
		{
			do_type = (DoType)(get_eeprom_data(kEep_Relay2_1Type + (idx >> 1), (EepromDataType)(idx % 2)));
			if (do_type < kDoType_End)
			{
				do_item.map[do_type] = idx;
				do_item.type[idx] = do_type;
				do_item.doLogicArray[idx] = do_poll_array[do_type];
			}
			do_err_src_type = (DoErrSrc)get_eeprom_data(kEep_DO2_DO1_ErrSrc + (idx >> 1), (EepromDataType)(idx % 2));
			if(do_err_src_type < kDoErrSrc_End)
			{
				do_item.err_src[idx] = do_err_src_type;
			}
		}	
    }
	
    //初始化订单继电器策略=本地和远方
    idx = get_eeprom_data(kEep_ChgDisMode_HighVoltStrategy, kEepromDataType_Low);
    if(idx < do_main_poll_len)
    {
        do_item.main_ctrl = (DoCtrlStrategy)idx;
        do_item.bmsCircuitCtrl = do_main_poll_array[idx];
    }
    
    for(idx = kDiType_Start; idx < kDiType_End; idx++)
	{
		di_item.map[idx] = 0xFF;
	}
    
    for (idx = 0; idx < MAX_DI_NUM; idx++)
    {
        data_type = (EepromDataType)(idx % 2);
        di_item.dly[idx] = get_eeprom_data(kEep_Di2_1Delay + (idx >> 1), data_type) * 100;
        di_type = (DiType)get_eeprom_data(kEep_Di2_1Type + (idx >> 1), data_type);
        if (di_type < kDiType_End)
        {
            di_item.map[di_type] = idx;
            di_item.type[idx] = di_type;
            di_item.fun[idx] = di_func[di_type];
        }     
        di_item.polarity[idx] = (DiPolarity)get_eeprom_data(kEep_Di2_1Polarity + (idx >> 1), data_type);
    }	
}

