#include "UDS_DTC.h"
#include "CAN_CFG.h"
#include "NM_Config.h"
#include "fuelconfig.h"
#include "DataProcess.h"
uint8_t isNeedSaveDTC = 0u;
uint8_t HVoltageStatus = 0u;
uint8_t LVoltageStatus = 0u;
uint8_t BUS_OFF_FLAG;
/**
  *DTC列表
  */
const uint32_t DTCList[9][2] = 
{
    {B111717, 1u},
    {B111716, 1u},
    {U007488, 1u},
    {U010087, 1u},
    {U014087, 1u},
    {U220D00, 1u},
    {B100017, 1u},
    {B100016, 1u},
    {B100018, 1u},
};

/**
  *DTC发生时间
  */
uint32_t DTCTimerList[9] = {0u};

/**
  *msg列表
  */
uint32_t msgList[2][4] = 
{
    {0x0CF00400ul, 8u,  10u , 0u},
    {0x10FF7521ul, 8u,  250u ,0u},
};

/**
  *测试DTC
  *@param timer 计时器增加的时间，单位：ms
  */
void TestDTC(uint16_t timer)
{
    if(getKL15Status())
    {
        if(!getEngStatus())
        {
            TestDTC_B111716(timer);                                         /*检测控制模块输入电压低*/
            TestDTC_B111717(timer);                                         /*检测控制模块输入电压高*/
            if(!getPowerStatus())
            {
                TestDTC_U007488();                                          /*检测can总线关闭*/   
                TestDTC_B100017(timer);                                     /*fuel sensor resistance high*/
                TestDTC_B100016(timer);                                     /*fuel sensor resistance low*/
                TestDTC_B100018(timer);                                     /*MCU Unusual reset*/
                
                if(!getBusoffStatus())
                {
                    if(isDTCEnable())
                    {
                        TestDTC_U010087();                                 /*Missing EDC*/
                        TestDTC_U014087();                                 /*Missing BCM*/
                        TestDTC_U220D00();                                 /*LimpHome*/
                    }
                }
            }
            if(isNeedSaveDTC)
            {
                SaveDTCData();
                isNeedSaveDTC = 0u;
            }
        }
    }
}
uint8_t getBUS_OFF_FLAG(void)
{
    uint8_t FLAG = 0;//BUS_OFF_FLAG;
    if(NM_GetCanBusoffOccurCnt() >= 8)
    {
        FLAG = 1;
    }
    else
    {
        FLAG = 0; 
    }
    //if(!GetBusOffState())
    //{
    //    BUS_OFF_FLAG = 0u;
    //}
    return FLAG;
}
/**
  *检测can总线关闭
  */
void TestDTC_U007488(void)
{
    if(DTCList[cnU007488][1u])
    {
        if(getBUS_OFF_FLAG())
        {
            ChangeDTCData(cnU007488, DTCError);
        }
        else
        {
            ChangeDTCData(cnU007488, DTCNoError);
        }
    }
}

/**
  *检测控制模块输入电压低
  *@param timer 计时器增加的时间，单位：ms
  */
void TestDTC_B111716(uint16_t timer)
{
    uint16_t KL30Voltage = 0u;
    if(DTCList[cnB111716][1u])
    {
        KL30Voltage = getKL30Voltage();
        if(KL30Voltage <= MinimumVoltage)
        {
            if(DTCTimerList[cnB111716] == LowVoltageTimer)
            {
                ChangeDTCData(cnB111716, DTCError);
            }
            else
            {
                DTCTimerList[cnB111716] += timer;
            }
        }
        if(KL30Voltage >= RestoreMinimumVoltage)
        {
            if(DTCTimerList[cnB111716] == 0u)
            {
                ChangeDTCData(cnB111716, DTCNoError);
            }
            else
            {
                if(DTCTimerList[cnB111716] > timer)
                {
                    DTCTimerList[cnB111716] -= timer;
                }
                else
                {
                    DTCTimerList[cnB111716] = 0u;
                }
            }
        }
    }
}

/**
  *检测控制模块输入电压高
  *@param timer 计时器增加的时间，单位：ms
  */
void TestDTC_B111717(uint16_t timer)
{
    uint16_t KL30Voltage = 0u;
    if(DTCList[cnB111717][1u])
    {
        KL30Voltage = getKL30Voltage();
        if(KL30Voltage >= MaximumVoltage)
        {
            if(DTCTimerList[cnB111717] == HightVoltageTimer)
            {
                ChangeDTCData(cnB111717, DTCError);
            }
            else
            {
                DTCTimerList[cnB111717] += timer;
            }
        }
        if(KL30Voltage <= RestoreMaximumVoltage)
        {
            if(DTCTimerList[cnB111717] == 0u)
            {
                ChangeDTCData(cnB111717, DTCNoError);
            }
            else
            {
                if(DTCTimerList[cnB111717] > timer)
                {
                    DTCTimerList[cnB111717] -= timer;
                }
                else
                {
                    DTCTimerList[cnB111717] = 0u;
                }
            }
        }
    }
}

/**
  *Missing EDC
  */
void TestDTC_U010087(void)
{
    if(DTCList[cnU010087][1u])
    {
        //if(Val_EOL_F110_ABS())
        {
            if(getMSGStatus(cnMSG400))
            {
                ChangeDTCData(cnU010087, DTCError);
            }
            else
            {
                ChangeDTCData(cnU010087, DTCNoError);
            }
        }
    }
}

/**
  *Missing BCM
  */
void TestDTC_U014087(void)
{
    if(DTCList[cnU014087][1u])
    {
        //if(Val_EOL_F110_ABS())
        {
            if(getMSGStatus(cnMSG521))
            {
                ChangeDTCData(cnU014087, DTCError);
            }
            else
            {
                ChangeDTCData(cnU014087, DTCNoError);
            }
        }
    }
}

/**
  *LimpHome
  */
void TestDTC_U220D00(void)
{
    if(DTCList[cnU220D00][1u])
    {
        //if(Val_EOL_F101_Ota())
        {
            if(GetLimphomeState())
            {
                ChangeDTCData(cnU220D00, DTCError);
            }
            else
            {
                ChangeDTCData(cnU220D00, DTCNoError);
            }
        }
    }
}

/**
  *fuel sensor resistance high
  */
void TestDTC_B100017(uint16_t timer)
{
    if(DTCList[cnB100017][1u])
    {
        if(GET_Fuel_Sensor_Resistance_High())
        {
            if(DTCTimerList[cnB100017] < 1000)
            {
                DTCTimerList[cnB100017] += timer;
            }
            else
            {
                ChangeDTCData(cnB100017, DTCError); 
            }
        }
        else
        {
            if(DTCTimerList[cnB100017] >= 100)
            {
                DTCTimerList[cnB100017] = 100;
            }
            if(DTCTimerList[cnB100017] >= timer)
            {
                DTCTimerList[cnB100017] -= timer;
            }
            else
            {
                DTCTimerList[cnB100017] = 0;
                ChangeDTCData(cnB100017, DTCNoError);
            }
        }
    }
}

/**
  *fuel sensor resistance low
  */
void TestDTC_B100016(uint16_t timer)
{
    if(DTCList[cnB100016][1u])
    {
        if(GET_Fuel_Sensor_Resistance_Low())
        {
            if(DTCTimerList[cnB100016] < 1000)
            {
                DTCTimerList[cnB100016] += timer;
            }
            else
            {
                ChangeDTCData(cnB100016, DTCError); 
            }
        }
        else
        {
            if(DTCTimerList[cnB100016] >= 100)
            {
                DTCTimerList[cnB100016] = 100;
            }
            if(DTCTimerList[cnB100016] >= timer)
            {
                DTCTimerList[cnB100016] -= timer;
            }
            else
            {
                DTCTimerList[cnB100016] = 0;
                ChangeDTCData(cnB100016, DTCNoError);
            }
        }
    }
}

/**
  *MCU Unusual reset
  */
void TestDTC_B100018(uint16_t timer)
{
    if(DTCList[cnB100018][1u])
    {
        if(Get_Mcu_Abnormal_Reset())
        {
            if(DTCTimerList[cnB100018] < 1000)
            {
                DTCTimerList[cnB100018] += timer;
            }
            else
            {
                ChangeDTCData(cnB100018, DTCError); 
            }
        }
        else
        {
            if(DTCTimerList[cnB100018] >= 100)
            {
                DTCTimerList[cnB100018] = 100;
            }
            if(DTCTimerList[cnB100018] >= timer)
            {
                DTCTimerList[cnB100018] -= timer;
            }
            else
            {
                DTCTimerList[cnB100018] = 0;
                ChangeDTCData(cnB100018, DTCNoError);
            }
        }
    }
}

/**
  *获取30电电压状态
  *@return 30电电压状态 0为电压正常,1为低压,2为高压
  */
uint8_t getPowerStatus(void)
{
    uint8_t  enResult = NormalVottage;
    uint16_t KL30Voltage = getKL30Voltage();
    
    if((KL30Voltage >= 9000u) && (KL30Voltage <= 16000u))
    {
        if(LVoltageStatus == 1u)
        {
            if(KL30Voltage < 10000u)
            {
                enResult = LowVottage;
                setDTCEnableTimer(H_LVoltageDTCEnableTimer);
            }
            else
            {
                LVoltageStatus = 0u;
                enResult = NormalVottage;
            }
        }
        else if(HVoltageStatus == 1u)
        {
            if(KL30Voltage > 15000u)
            {
                enResult = HightVottage;
                setDTCEnableTimer(H_LVoltageDTCEnableTimer);
            }
            else
            {
                HVoltageStatus = 0u;
                enResult = NormalVottage;
            }
        }
        else
        {
            enResult = NormalVottage;
        }
    }
    else if(KL30Voltage > 16000u)
    {
        HVoltageStatus = 1u;
        enResult = HightVottage;
        setDTCEnableTimer(H_LVoltageDTCEnableTimer);
    }
    else
    {
        LVoltageStatus = 1u;
        enResult = LowVottage;
        setDTCEnableTimer(H_LVoltageDTCEnableTimer);
    }
    return enResult;
}

/**
  *获取busoff状态
  *@return busoff状态 0为正常,1为异常
  */
uint8_t getBusoffStatus(void)
{
    if(GetBusOffState())
    {
      setDTCEnableTimer(BusOffDTCEnableTimer);
    }
    return GetBusOffState();
}

/**
  *获取发动机启动状态
  *@return EngStatus 0为未启动,1为启动
  */
uint8_t getEngStatus(void)
{
    return 0u;
}

/**
  *获取报文状态
  *@param cnMsgID 报文数组下标
  *@return 报文状态 0为在线,1为掉线
  */
uint8_t getMSGStatus(uint8_t cnMsgID)
{
    uint8_t enResult;
    if(msgList[cnMsgID][3] < 10u * msgList[cnMsgID][2])
    {
        enResult = 0u;
    }
    else
    {
        enResult = 1u;
    }
    return enResult;
}

/**
  *更改DTC状态
  *@param DTCNum DTC编号
  *@param DTCStatus DTC状态
  */
void ChangeDTCData(uint8_t DTCNum, uint8_t DTCStatus)
{
    uint32_t UDS_Vspeed;
    if(DTCTestIsOpen())
    {
        if((uint8_t)(DTCToDFlashInfo.DTC[DTCNum].DTCStatus & DTCNoTestLastClear) == DTCNoTestLastClear)
        {
            DTCToDFlashInfo.DTC[DTCNum].DTCStatus &= (uint8_t)(~DTCNoTestLastClear);
        }
        if((uint8_t)(DTCToDFlashInfo.DTC[DTCNum].DTCStatus & DTCNoTestThisCycle) == DTCNoTestThisCycle)
        {
            DTCToDFlashInfo.DTC[DTCNum].DTCStatus &= (uint8_t)(~DTCNoTestThisCycle);
        }
        if(DTCStatus == DTCError)
        {
            if((uint8_t)(DTCToDFlashInfo.DTC[DTCNum].DTCStatus & DTCError) != DTCError)
            {
                DTCToDFlashInfo.DTC[DTCNum].DTCStatus |= DTCError;
                if((uint8_t)(DTCToDFlashInfo.DTC[DTCNum].DTCStatus & DTCErrorThisCycle) != DTCErrorThisCycle)
                {
                    DTCToDFlashInfo.DTC[DTCNum].DTCStatus |= DTCErrorThisCycle;
                    DTCToDFlashInfo.DTC[DTCNum].DTCAgeing = 0u;
                    DTCToDFlashInfo.DTC[DTCNum].DTCPendingCount++;
                    if(DTCToDFlashInfo.DTC[DTCNum].DTCPendingCount >= MaxDTCPendingCount)
                    {
                        if((uint8_t)(DTCToDFlashInfo.DTC[DTCNum].DTCStatus & DTCConfirmed) != DTCConfirmed)
                        {
                            DTCToDFlashInfo.DTC[DTCNum].DTCStatus |= DTCConfirmed;

                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Second = (RTC_SECOND / 10) * 0x10 + (RTC_SECOND % 10);
                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Minute = (RTC_MINUTE / 10) * 0x10 + (RTC_MINUTE % 10);
                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Hour = (RTC_HOUR / 10) * 0x10 + (RTC_HOUR % 10);
                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Day = 0xFF;
                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Month = 0xFF;
                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Year = 0xFF;
                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Distance_H = (Mile_Get_Index_Value(MILE_INDEX_ODO) * 20) >> 24;
                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Distance_H_M = (Mile_Get_Index_Value(MILE_INDEX_ODO) * 20) >> 16;
                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Distance_L_M = (Mile_Get_Index_Value(MILE_INDEX_ODO) * 20) >> 8;
                            DTCToDFlashInfo.DTC[DTCNum].Extended.F_Distance_L = (Mile_Get_Index_Value(MILE_INDEX_ODO) * 20);
                            DTCToDFlashInfo.DTC[DTCNum].Snapshot.FirstOccurOdometer_H = (Mile_Get_Index_Value(MILE_INDEX_ODO) / 10) >> 24;
                            DTCToDFlashInfo.DTC[DTCNum].Snapshot.FirstOccurOdometer_H_M = (Mile_Get_Index_Value(MILE_INDEX_ODO) / 10) >> 16;
                            DTCToDFlashInfo.DTC[DTCNum].Snapshot.FirstOccurOdometer_L_M = (Mile_Get_Index_Value(MILE_INDEX_ODO) / 10) >> 8;
                            DTCToDFlashInfo.DTC[DTCNum].Snapshot.FirstOccurOdometer_L = (Mile_Get_Index_Value(MILE_INDEX_ODO) / 10);
                        
                        }
                    }
                }
                if((uint8_t)(DTCToDFlashInfo.DTC[DTCNum].DTCStatus & DTCPending) != DTCPending)
                {
                    DTCToDFlashInfo.DTC[DTCNum].DTCStatus |= DTCPending;
                }
                if((uint8_t)(DTCToDFlashInfo.DTC[DTCNum].DTCStatus & DTCErrorLastClear) != DTCErrorLastClear)
                {
                    DTCToDFlashInfo.DTC[DTCNum].DTCStatus |= DTCErrorLastClear;
                }

                if(DTCToDFlashInfo.DTC[DTCNum].Extended.F_OccurenceCounter < 0xFF)
                {
                    DTCToDFlashInfo.DTC[DTCNum].Extended.F_OccurenceCounter++;
                }
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Second = (RTC_SECOND / 10) * 0x10 + (RTC_SECOND % 10);
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Minute = (RTC_MINUTE / 10) * 0x10 + (RTC_MINUTE % 10);
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Hour = (RTC_HOUR / 10) * 0x10 + (RTC_HOUR % 10);
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Day = 0xFF;
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Month = 0xFF;
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Year = 0xFF;
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_SPNType = 0;
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Distance_H = (Mile_Get_Index_Value(MILE_INDEX_ODO) * 20) >> 24;
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Distance_H_M = (Mile_Get_Index_Value(MILE_INDEX_ODO) * 20) >> 16;
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Distance_L_M = (Mile_Get_Index_Value(MILE_INDEX_ODO) * 20) >> 8;
                DTCToDFlashInfo.DTC[DTCNum].Extended.L_Distance_L = (Mile_Get_Index_Value(MILE_INDEX_ODO) * 20);

                DTCToDFlashInfo.DTC[DTCNum].Snapshot.EngineSpeed_H = Get_DispEngineSpeed() * 8;
                DTCToDFlashInfo.DTC[DTCNum].Snapshot.EngineSpeed_L = (Get_DispEngineSpeed() * 8) >> 8;
                DTCToDFlashInfo.DTC[DTCNum].Snapshot.VehicleSpeed_H = getActVehicleSpeed() *  8 / 5;
                DTCToDFlashInfo.DTC[DTCNum].Snapshot.VehicleSpeed_L = (getActVehicleSpeed() *  8 / 5) >> 8;
                DTCToDFlashInfo.DTC[DTCNum].Snapshot.BatteryVoltage_H = getKL30Voltage() / 50;
                DTCToDFlashInfo.DTC[DTCNum].Snapshot.BatteryVoltage_L = (getKL30Voltage() / 50) >> 8;
                DTCToDFlashInfo.DTC[DTCNum].Snapshot.Odometer_H = (Mile_Get_Index_Value(MILE_INDEX_ODO) / 10) >> 24;
                DTCToDFlashInfo.DTC[DTCNum].Snapshot.Odometer_H_M = (Mile_Get_Index_Value(MILE_INDEX_ODO) / 10) >> 16;
                DTCToDFlashInfo.DTC[DTCNum].Snapshot.Odometer_L_M = (Mile_Get_Index_Value(MILE_INDEX_ODO) / 10) >> 8;
                DTCToDFlashInfo.DTC[DTCNum].Snapshot.Odometer_L = (Mile_Get_Index_Value(MILE_INDEX_ODO) / 10);

                isNeedSaveDTC = 1u;
            }
        }
        else
        {
            if((uint8_t)(DTCToDFlashInfo.DTC[DTCNum].DTCStatus & DTCError) == DTCError)
            {
                DTCToDFlashInfo.DTC[DTCNum].DTCStatus &= DTCNoError;
                isNeedSaveDTC = 1u;
            }
        }
    }
}

/**
  *保存DTC状态
  */
void SaveDTCData(void)
{
    WriteDFlashData_eel(WriteDTCAddr, (uint32_t *)&DTCToDFlashInfo.Flag, sizeof(DTCToDFlashInfo) , WriteEEL);
}
