#include "Backlight.h"
#include "Components.h"

#define BACK_LIGHT_Val_1 100
#define BACK_LIGHT_Val_2 300
#define BACK_LIGHT_Val_3 500
#define BACK_LIGHT_Val_4 700
#define BACK_LIGHT_Val_5 900

typedef struct
{
    Light_uint16_t Temperature; /* 温度 */
    Light_uint16_t Resistance;  /* 阻值 */
} _st_Backlight;

typedef struct
{
    Light_uint16_t BacklightLevel; /* 背光等级 */
    Light_uint16_t BacklightDuty;  /* 背光占空比 */
} _st_BacklightLevel;

#define Backlight_Max 10
#define BacklightLevel_Max 10
_st_Backlight BacklightTable[Backlight_Max] =
    {
        /*温度   阻值 */
        {550, 2708},
        {600, 2602},
        {650, 2500},
        {700, 2043},
        {750, 2310},
        {800, 2221},
        {850, 2136},
        {900, 2055},
        {950, 1977},
        {1000, 1902},
};
_st_BacklightLevel BacklightLevelTable[BacklightLevel_Max] =
    {
        /*背光等级   背光占空比 */
        {1, 100},
        {2, 200},
        {3, 300},
        {4, 400},
        {5, 500},


};



Light_uint16_t GetBacklightDutyByLevel(Light_uint16_t level)
{
    for (Light_uint8_t i = 0; i < BacklightLevel_Max; ++i)
    {
        if (BacklightLevelTable[i].BacklightLevel == level)
        {
            return BacklightLevelTable[i].BacklightDuty;
        }
    }
    return 0;
}

typedef void (*SetPwm)(Light_uint16_t Pwm);
typedef Light_uint8_t (*SetPwmEnable)(void);
typedef Light_uint8_t (*SetPwmLevel)(void);
typedef Light_uint16_t (*NtcRes)(void);

typedef struct
{
    SetPwm SetPwmCbk;           /* 设置PWM回调函数 */
    SetPwmEnable SetPwmEnCbk;   /* 设置PWM使能回调函数 */
    SetPwmLevel SetPwmLevelCbk; /* 背光等级回调函数 */
    NtcRes NtcResCbk;           /* 获取电阻值回调函数 */
} BackLightExtPara;

typedef struct
{
    SetPwm SetPwmCbk;           /* 设置PWM回调函数 */
    SetPwmEnable SetPwmEnCbk;   /* 设置PWM使能回调函数 */
    SetPwmLevel SetPwmLevelCbk; /* 背光等级回调函数 */
    NtcRes NtcResCbk;
    Light_uint8_t BacklightEn;     /* 背光使能 */
    Light_uint16_t BacklightPwm;   /* 背光PWM */
    Light_uint16_t BacklightLevel; /* 背光等级 */
} _Backlight_Op;

_Backlight_Op Backlight_Operate;


/* 设置PWM回调函数 */
void Backlight_SetPwm(Light_uint16_t Pwm)
{
    TimerM_PWM_set_duty(TIMERM_COUNTER1, TIMERM_CHB, Pwm);
}

/* 设置PWM使能回调函数 */
Light_uint8_t Backlight_SetPwmEn(void)
{
    
    return 1;
}

/* 背光等级回调函数 */
Light_uint8_t Backlight_SetPwmLevel(void)
{

    return 1;
}

/* 获取电阻值回调函数 */
Light_uint8_t Backlight_NtcRes(void)
{

    return 1;
}

void Backlight_Init(BackLightExtPara *backlightInit)
{
    Backlight_Operate.SetPwmCbk = backlightInit->SetPwmCbk;
    Backlight_Operate.SetPwmEnCbk = backlightInit->SetPwmEnCbk;
    Backlight_Operate.SetPwmLevelCbk = backlightInit->SetPwmLevelCbk;
    Backlight_Operate.NtcResCbk = backlightInit->NtcResCbk;
}

void Backlight_KL30_Wakeup_Init(void)
{
    BackLightExtPara pFunc;

    pFunc.SetPwmCbk        = Backlight_SetPwm;
    pFunc.SetPwmEnCbk      = Backlight_SetPwmEn;
    pFunc.SetPwmLevelCbk   = Backlight_SetPwmLevel;
    pFunc.NtcResCbk        = Backlight_NtcRes;

    Backlight_Init(&pFunc);
}



/**
 * 根据给定的背光表和输入电阻值，获取对应的温度值。
 * 这个函数通过线性插值方法在背光表中查找与输入电阻最接近的温度值。
 * @param backlightTable 背光表，包含电阻和对应温度的数组。
 * @param size 背光表的大小，即数组的元素个数。
 * @param input 输入的电阻值。
 * @return 返回对应的温度值。
 */
Light_uint16_t Get_Ntc_Temp(_st_Backlight *backlightTable, Light_uint8_t size, Light_uint16_t input)
{
    Light_uint16_t result = 0;
    Light_uint32_t temp = 0;
    Light_uint8_t i = 0;

    if (input >= backlightTable[0].Resistance)
    {
        result = backlightTable[0].Temperature;
    }
    else if (input <= backlightTable[size - 1].Resistance)
    {
        result = backlightTable[size - 1].Temperature;
    }
    else
    {
        for (i = 0; i < size - 1; i++)
        {
            if ((input < backlightTable[i].Resistance) && (input >= backlightTable[i + 1].Resistance))
            {
                temp = backlightTable[i + 1].Temperature - backlightTable[i].Temperature;
                temp *= (backlightTable[i].Resistance - input);
                temp /= (backlightTable[i].Resistance - backlightTable[i + 1].Resistance);
                temp += backlightTable[i].Temperature;
                result = (Light_uint16_t)temp;
                break;
            }
        }
    }

    return result;
}

Light_uint16_t Get_Pwm_Factor_Optimized(Light_uint16_t CurrentTemp)
{
    if (CurrentTemp >= 900)
    {
        return 10;
    }
    if (CurrentTemp >= 880 && CurrentTemp <= 890)
    {
        return 20;
    }
    if (CurrentTemp >= 850 && CurrentTemp <= 860)
    {
        return 70;
    }
    if (CurrentTemp >= 800 && CurrentTemp <= 830)
    {
        return 75;
    }
    if (CurrentTemp >= 750 && CurrentTemp <= 780)
    {
        return 80;
    }
    if (CurrentTemp >= 700 && CurrentTemp <= 730)
    {
        return 85;
    }
    if (CurrentTemp >= 650 && CurrentTemp <= 680)
    {
        return 90;
    }
    if (CurrentTemp >= 600 && CurrentTemp <= 630)
    {
        return 95;
    }
    if (CurrentTemp < 580)
    {
        return 100;
    }

    return 100;
}

typedef struct
{
    Light_uint8_t destFactor;
    Light_uint8_t curFactor;
    Light_uint16_t NtcDelayTimer;
    Light_uint16_t u16DialcurDuty;
    Light_uint16_t u16DialdestDuty;
    Light_uint16_t u16DialDampingTimer;
} _st_BacklightFactor_Ctrl;

_st_BacklightFactor_Ctrl BacklightFactorCtrl;

/**
 * @brief 实现数据的渐变效果
 * 该函数用于更新当前值，使其逐渐接近目标值，渐变的步长由step参数控制。同时，通过timer参数来实现一定的延迟效果，
 * 仅当计时器达到或超过预设的timedelay时，才会进行一次渐变操作。这有助于平滑数据的变化，避免突变。
 * @param cur 当前值的指针，函数将更新这个值
 * @param dest 目标值，当前值将逐渐变化到这个值
 * @param step 每次变化的步长
 * @param timer 计时器的指针，用于实现变化的延迟
 * @param timedelay 延迟的时间阈值，当计时器达到或超过这个值时，才会进行变化
 */
void U16_Data_Gradient(Light_uint16_t *cur, Light_uint16_t dest, Light_uint16_t step, Light_uint16_t *timer, const Light_uint16_t timedelay)
{
    if (*cur > dest)
    {
        if ((*cur - dest) > step)
        {
            if (*timer >= timedelay)
            {
                (*cur) -= step;
                (*timer) = 0;
            }
            else
            {
                (*timer)++;
            }
        }
        else
        {
            *cur = dest;
            *timer = 0;
        }
    }
    else
    {
        if ((dest - *cur) > step)
        {
            if (*timer >= timedelay)
            {
                (*cur) += step;
                (*timer) = 0;
            }
            else
            {
                (*timer)++;
            }
        }
        else
        {
            *cur = dest;
            *timer = 0;
        }
    }
}

void BackLight_Service(void)
{

    Light_uint16_t CurrentTemp = 0;
    Light_uint16_t Factor = 0;

    if (Backlight_Operate.NtcResCbk != Backlight_NULL)
    {
        CurrentTemp = Get_Ntc_Temp(BacklightTable, sizeof(BacklightTable) / sizeof(Light_uint16_t), Backlight_Operate.NtcResCbk());
    }
    else
    {
        CurrentTemp = 0XFFFF; /* 无效不执行NTC策略 */
    }

    /* 根据外部传入背光等级获取对应占空比 */
    if (Backlight_Operate.SetPwmLevelCbk != Backlight_NULL)
    {
        Backlight_Operate.BacklightPwm = GetBacklightDutyByLevel(Backlight_Operate.SetPwmLevelCbk());
    }

    if (Backlight_Operate.SetPwmEnCbk != Backlight_NULL)
    {
        Backlight_Operate.BacklightEn = Backlight_Operate.SetPwmEnCbk();
    }

    if (Backlight_Operate.BacklightEn == 1)
    {

        if (CurrentTemp != 0XFFFF)
        {

            BacklightFactorCtrl.destFactor = Get_Pwm_Factor_Optimized(CurrentTemp);

            if ((BacklightFactorCtrl.curFactor < BacklightFactorCtrl.destFactor) && (CurrentTemp <= BacklightTable[0].Temperature))
            {
                if (BacklightFactorCtrl.NtcDelayTimer <= 400)
                    BacklightFactorCtrl.NtcDelayTimer++;
                else
                {
                    BacklightFactorCtrl.NtcDelayTimer = 0;
                    BacklightFactorCtrl.curFactor++;
                }

                if (BacklightFactorCtrl.curFactor >= BacklightFactorCtrl.destFactor)
                    BacklightFactorCtrl.curFactor = BacklightFactorCtrl.destFactor;
            }
            else if (BacklightFactorCtrl.curFactor > BacklightFactorCtrl.destFactor)
            {
                if (BacklightFactorCtrl.NtcDelayTimer <= 200)
                    BacklightFactorCtrl.NtcDelayTimer++;
                else
                {
                    BacklightFactorCtrl.NtcDelayTimer = 0;
                    BacklightFactorCtrl.curFactor--;
                }

                if (BacklightFactorCtrl.curFactor <= BacklightFactorCtrl.destFactor)
                    BacklightFactorCtrl.curFactor = BacklightFactorCtrl.destFactor;
            }

            BacklightFactorCtrl.u16DialdestDuty = BacklightFactorCtrl.curFactor * BacklightFactorCtrl.curFactor / 100;

            if (BacklightFactorCtrl.u16DialdestDuty < 50)
            {
                BacklightFactorCtrl.u16DialdestDuty = 50;
            }

            if (CurrentTemp <= BacklightTable[0].Temperature)
            {
                BacklightFactorCtrl.u16DialcurDuty = BacklightFactorCtrl.u16DialdestDuty;
            }
            else
            {
                if (BacklightFactorCtrl.u16DialcurDuty < 100)
                {
                    BacklightFactorCtrl.u16DialcurDuty = BacklightFactorCtrl.u16DialdestDuty;
                }
                else
                {
                    U16_Data_Gradient((Light_uint16_t *)&BacklightFactorCtrl.u16DialcurDuty, BacklightFactorCtrl.u16DialdestDuty, 1u, (Light_uint16_t *)&BacklightFactorCtrl.u16DialDampingTimer, 1u);
                }
            }
            Backlight_Operate.BacklightPwm = BacklightFactorCtrl.u16DialcurDuty;

            Backlight_Operate.SetPwmCbk(Backlight_Operate.BacklightPwm);
        }
        else
        {
            /* 无NTC策略 直接根据当前背光等级调整PWM */
            Backlight_Operate.SetPwmCbk(Backlight_Operate.BacklightPwm);
        }
    }
    else
    {
        Backlight_Operate.SetPwmCbk(0);
    }
}

void BackLight_Process(void)
{
    if(Menu_Item_Select_Get(MENU_ITEM_BACKLIGHT_5) == 1)
    {
        TimerM_PWM_set_duty(TIMERM_COUNTER1, TIMERM_CHB, BACK_LIGHT_Val_5);
    }
    else if(Menu_Item_Select_Get(MENU_ITEM_BACKLIGHT_4) == 1)
    {
        TimerM_PWM_set_duty(TIMERM_COUNTER1, TIMERM_CHB, BACK_LIGHT_Val_4);
    }
    else if(Menu_Item_Select_Get(MENU_ITEM_BACKLIGHT_3) == 1)
    {
        TimerM_PWM_set_duty(TIMERM_COUNTER1, TIMERM_CHB, BACK_LIGHT_Val_3);
    }
    else if(Menu_Item_Select_Get(MENU_ITEM_BACKLIGHT_2) == 1)
    {
        TimerM_PWM_set_duty(TIMERM_COUNTER1, TIMERM_CHB, BACK_LIGHT_Val_2);
    }
    else if(Menu_Item_Select_Get(MENU_ITEM_BACKLIGHT_1) == 1)
    {
        TimerM_PWM_set_duty(TIMERM_COUNTER1, TIMERM_CHB, BACK_LIGHT_Val_1);
    }
    else
    {
        ;
    }
}
