#include "iso_check.h"
#include "version_manager.h"
#include "fault_manager.h"
#include "signal_manager.h"
#include "dido_manager.h"
#include "eeprom_manager.h"
#include "hv_adc_manager.h"
#include "logic_ctrl.h"


//确保在继电器断开时调用
bool logic_adhesion_check(uint32_t base_time, DoType type)
{
	static uint16_t adhesion_dly = 0;
    bool is_chekc = true;
	uint16_t tv, hv, rate;
    FaultLevel  fault = kFaultLevel_Normal;
    DoErrSrc do_err_src = bms_get_do_err_src(type);
    
	//do_err_src += 1;
	
    if(bms_get_run_status() == kRunStatus_Init)
    {
        return false;
    }
    switch(do_err_src)
    {
        case kDoErrSrc_HV1:
        case kDoErrSrc_HV2:
            //母线簇用电压检测粘连
            tv = bms_get_high_volt(kHvType_Bat);
            if((tv >= 300) && (bms_get_circuit_cmd_status() == kCircuitStatus_On))
            {
                if(bms_get_bus_bar_bcu() == bms_get_tag_data(kTagData_DevAddr))
                {
                    hv = bms_get_high_volt((HvType)(kHvType_Hv1 + do_err_src - 1));
                    rate = get_eeprom_data(kEep_HV2_HV1VoltRate, (EepromDataType)(kEepromDataType_Low + do_err_src - 1));
                    if(hv >= ((uint32_t)tv * rate / 100))
                    {
                        fault = kFaultLevel_Third;
                    }
                }
            }
            else
            {
                is_chekc = false;
            }
            break;
        case kDoErrSrc_DI1:
        case kDoErrSrc_DI2:
        case kDoErrSrc_DI3:
        case kDoErrSrc_DI4:
		case kDoErrSrc_DI5:
        case kDoErrSrc_DI6:
        case kDoErrSrc_DI7:
        case kDoErrSrc_DI8:
		case kDoErrSrc_DI9:
            //if(bms_get_signal((SignalIdx)(do_err_src - kDoErrSrc_DI1)) == kSignalStatus_High)
            if(bms_get_signal((SignalIdx)(do_err_src - kDoErrSrc_DI1)) != bms_get_di_polarity(do_err_src - kDoErrSrc_DI1))
            {
                fault = kFaultLevel_Third;
            }
            break;
        default:
            break;
    }
    //通过电流判断粘连
    if((fault != kFaultLevel_Third) && (KIT_ABS(bms_get_current()) > 50))
    {
        fault = kFaultLevel_Third;
    }
    
	//gary 增加连续3秒粘连问题在报粘连故障
    if(fault == kFaultLevel_Third && is_chekc == true)
    {
		adhesion_dly += base_time;
		
		if(adhesion_dly > 3000)
		{
			adhesion_dly = 0;
			bms_set_do_fault(type, kDoStatus_Adhesion);
			bms_set_fault_level(kFaultCode_DoAdhesion, fault, kFaultHandle_CutNoRelIdx);
		}
		else
		{
			return false;
		}
    }
    return is_chekc;
}

void logic_open_check(uint32_t base_time)
{
    uint16_t tv, hv, rate;
    DoErrSrc do_err_src = bms_get_do_err_src(kDoType_Positive);
    FaultLevel  fault = kFaultLevel_Normal;
    static uint16_t dly;
    
    switch(do_err_src)
    {
        case kDoErrSrc_HV1:
        case kDoErrSrc_HV2:
            tv = bms_get_high_volt(kHvType_Bat);
            hv = bms_get_high_volt((HvType)(kHvType_Hv1 + do_err_src - 1));
            rate = get_eeprom_data(kEep_HV2_HV1VoltRate, (EepromDataType)(kEepromDataType_Low + do_err_src - 1));
            if((tv >= 300 && (hv + 200 <= ((uint32_t)tv * rate / 100))) || (tv<100))
            {
                dly += base_time;
                if(dly >= 1000)
                {
                    fault = kFaultLevel_Third;
                }
            }
            else
            {
                dly = 0;
            }
            break;
        
        case kDoErrSrc_DI1:
        case kDoErrSrc_DI2:
        case kDoErrSrc_DI3:
        case kDoErrSrc_DI4:
		case kDoErrSrc_DI5:
        case kDoErrSrc_DI6:
        case kDoErrSrc_DI7:
        case kDoErrSrc_DI8:	
		case kDoErrSrc_DI9:				
            //if(bms_get_signal((SignalIdx)(do_err_src - kDoErrSrc_DI1)) == kSignalStatus_High)
            if(bms_get_signal((SignalIdx)(do_err_src - kDoErrSrc_DI1)) == bms_get_di_polarity(do_err_src - kDoErrSrc_DI1))
            {
                fault = kFaultLevel_Third;
            }
            break;
        default:
            break;
    }
    bms_set_fault_level(kFaultCode_DoOpen, fault, kFaultHandle_CutNoRelIdx);
}


void logic_same_circuit_ctrl(uint32_t base_time)
{
    HvType prechg_type;
    uint16_t prechg_volt = 0;
    static uint16_t dly = 0;
    static uint8_t prechg_cnt = 0;
    static DoLogicStatus status = kDoLogicStatus_Reset;
	
    uint16_t prechg_time = get_eeprom_data(kEep_PreChgTimeout_Count, kEepromDataType_Full);
    uint8_t prechg_max_cnt = prechg_time & 0x00FF;
    prechg_time = (prechg_time >> 8) * 1000;

    switch(status)
    {
        case kDoLogicStatus_Reset:
            if((get_eeprom_data(kEep_IsSoftReset, kEepromDataType_High) == 1)
            && (get_eeprom_data(kEep_IsSoftReset, kEepromDataType_Low) != 0))
            {
                dly += base_time;
                //kEep_IsSoftReset高低只能清楚一个，否则断电下带无法保存0
                if(((bms_get_run_status() != kRunStatus_Init) && (bms_get_circuit_cmd_status() == kCircuitStatus_On)) || (dly >= 10000))
                {
                    bms_crtl_do_status(kDoType_Positive, kDoCtrlStatus_On, RELAY_CTRL_NO_DLY);
                    bms_crtl_do_status(kDoType_Negative, kDoCtrlStatus_On, 100);
                    dly = 0;
                    status = kDoLogicStatus_On;
                }
            }
            else
            {
                dly = 0;
                status = kDoLogicStatus_Init;
            }
            break;
        case kDoLogicStatus_Init:
				//增加init状态，防止预充中反复检测粘连 建议增加多次检测
				//Gary 2024-07-25 连续粘连3秒才报粘连故障
                dly += base_time;
				if(logic_adhesion_check(base_time, kDoType_Positive) == true)
				{
					dly = 0;
					status = kDoLogicStatus_Off;
				}
            break;
        case kDoLogicStatus_Off:
            if ((bms_is_dis_allow() == true) && (bms_is_chg_allow() == true))
            {
                if (prechg_max_cnt == 0)	//读取配置：不预充
				{
				   status = kDoLogicStatus_On;
				   bms_crtl_do_status(kDoType_Negative, kDoCtrlStatus_On, RELAY_CTRL_NO_DLY);
                   bms_crtl_do_status(kDoType_Positive, kDoCtrlStatus_On, 100);
				}
				else //读取配置：预充
				{                   
					if (prechg_cnt++ < prechg_max_cnt) //判断预充次数
					{
						status = kDoLogicStatus_Prechg;
						//bms_crtl_do_status(kDoType_Positive, kDoCtrlStatus_On, RELAY_CTRL_NO_DLY); //闭合总正继电器		
						bms_crtl_do_status(kDoType_Negative, kDoCtrlStatus_On, RELAY_CTRL_NO_DLY);
						bms_crtl_do_status(kDoType_PreChg, kDoCtrlStatus_On, 100);
						
					}
					else
					{
						bms_crtl_do_status(kDoType_Negative, kDoCtrlStatus_Off, 100);
						bms_set_fault_level(kFaultCode_PreChg, kFaultLevel_Third, kFaultHandle_CutNoRelIdx);
					}   
				}
            }
            break;
		case kDoLogicStatus_Prechg:
            dly += base_time;
            if ((bms_is_dis_allow() == false) || (bms_is_chg_allow() == false))
            {
                prechg_cnt = 0;
				status = kDoLogicStatus_Off;
                bms_crtl_do_status(kDoType_PreChg, kDoCtrlStatus_Off, RELAY_CTRL_NO_DLY);
                bms_crtl_do_status(kDoType_Negative, kDoCtrlStatus_Off, 100);
            }
            else if (dly >= prechg_time)//预充超时
			{
                dly = 0;
                status = kDoLogicStatus_PrechgFail;
				bms_crtl_do_status(kDoType_PreChg, kDoCtrlStatus_Off, RELAY_CTRL_NO_DLY);               
            }
            else
            {
                prechg_volt = bms_get_high_volt(kHvType_Bat);//sfj 获取B+B-电压
                if (prechg_volt >= 300)
                {
                    prechg_type = (HvType)get_eeprom_data(kEep_PreChgVoltType_Rate,kEepromDataType_High);
                    prechg_volt = prechg_volt * get_eeprom_data(kEep_PreChgVoltType_Rate,kEepromDataType_Low) / 100;
                    if(bms_get_high_volt(prechg_type) >= prechg_volt)
                    {
                        dly = 0;
                        prechg_cnt = 0;
                        status = kDoLogicStatus_On;				
                        bms_crtl_do_status(kDoType_Positive, kDoCtrlStatus_On, RELAY_CTRL_NO_DLY); //闭合总正继电器												
                        bms_crtl_do_status(kDoType_PreChg, kDoCtrlStatus_Off, 500); //延时500ms断开预充继电器
                    }
                }
            }
            break;
		case kDoLogicStatus_PrechgFail:
            dly += base_time;  	
            if (dly >= KIT_SECOND_CONVERT(1))
            {
                dly = 0;
                status = kDoLogicStatus_Off;
            }
            break;  
		 case kDoLogicStatus_On:
            dly += base_time;
            if(dly >= 10000)
            {
                dly = 10000;
                logic_open_check(base_time);
            }
			if((bms_is_dis_allow() == false) || (bms_is_chg_allow() == false))
            {
                dly = 0;
				status = kDoLogicStatus_WaitOff;
            }
            break;  
        case kDoLogicStatus_WaitOff:
			dly += base_time;
            if ((KIT_ABS(bms_get_current() / 10) <= get_eeprom_data(kEep_CutOffCurrent, kEepromDataType_Full)) //电流阈值可配置，分辨率 1A
            && (dly >= get_eeprom_data(kEep_PwrOffDly_MinOnlineCluster, kEepromDataType_High) * 1000)) //高压下电延迟
            {
                dly = 0;
                status = kDoLogicStatus_WaitAdhesion;
                bms_crtl_do_status(kDoType_Positive, kDoCtrlStatus_Off, RELAY_CTRL_NO_DLY);
                bms_crtl_do_status(kDoType_Negative, kDoCtrlStatus_Off, 100);
            }
			break;
        case kDoLogicStatus_WaitAdhesion:
            dly += base_time;
            if(dly >= KIT_SECOND_CONVERT(5))
            {
                dly = 0;
                status = kDoLogicStatus_Init;
            }
            break;
        default:
            dly = 0;
            status = kDoLogicStatus_Init;			
            break;
	}
}

void logic_same_circuit_poll(uint32_t base_time, uint8_t idx)
{
    DoStatus pos_rly_st, neg_rly_st;
    CircuitStatus circuit_st = kCircuitStatus_On;
    
    logic_same_circuit_ctrl(base_time);
    pos_rly_st = bms_get_do_status_by_type(kDoType_Positive);
    neg_rly_st = (bms_is_do_config(kDoType_Negative) == true) ? bms_get_do_status_by_type(kDoType_Negative) : kDoStatus_On;
    //neg_rly_st = kDoStatus_On;
	
    if(((pos_rly_st != kDoStatus_On) && (pos_rly_st != kDoStatus_ForceOn))
    || ((neg_rly_st != kDoStatus_On) && (neg_rly_st != kDoStatus_ForceOn)))
    {
        circuit_st = kCircuitStatus_Off;
    }
       
    bms_set_circuit_status(kCircuitType_Dis, circuit_st);
    bms_set_circuit_status(kCircuitType_Chg, circuit_st);
    bms_set_circuit_status(kCircuitType_Main, circuit_st);
}
