#include "Backlight.h"

#define BackLight_version 0X01

typedef struct __attribute__((aligned(4))) 
{
    SetPwm SetPwmCbk;           /* 设置PWM回调函数 */
    SetPwmEnable SetPwmEnCbk;   /* 设置PWM使能回调函数 */
    SetPwmLevel SetPwmLevelCbk; /* 背光等级回调函数 */
    GetNtcRes NtcResCbk;
    _st_Backlight_NtcTable *BacklightNTCTable;
    _st_BacklightLevel *BacklightLevelTable;
    Light_uint8_t BacklightEn;   /* 背光使能 */
    Light_uint16_t BacklightPwm; /* 背光PWM */
} _Backlight_Op;

typedef struct __attribute__((aligned(4))) 
{
    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;

static _Backlight_Op Backlight_Operate;
static _st_BacklightFactor_Ctrl BacklightFactorCtrl;
static Light_uint8_t Get_Pwm_Factor_Optimized(Light_uint16_t CurrentTemp);

/**
 * @brief 初始化背光模块
 * @param backlightInit 背光初始化配置结构体指针，包含所需的回调函数和数据表。
 */
void Backlight_KL30_WakeUp_Init(_st_BackLight_Init *backlightInit)
{
    Backlight_Operate.SetPwmCbk = backlightInit->SetPwmCbk;
    Backlight_Operate.SetPwmEnCbk = backlightInit->SetPwmEnCbk;
    Backlight_Operate.SetPwmLevelCbk = backlightInit->SetPwmLevelCbk;
    Backlight_Operate.NtcResCbk = backlightInit->NtcResCbk;
    Backlight_Operate.BacklightLevelTable = backlightInit->BacklightLevelTable;
    Backlight_Operate.BacklightNTCTable = backlightInit->BacklightNTCTable;
    Backlight_Operate.BacklightPwm = 0;
    Backlight_Operate.BacklightEn = 0;
    BacklightFactorCtrl.curFactor = 100;
    BacklightFactorCtrl.destFactor = 0;
    BacklightFactorCtrl.NtcDelayTimer = 0;
    BacklightFactorCtrl.u16DialcurDuty = 0;
    BacklightFactorCtrl.u16DialDampingTimer = 0;
    BacklightFactorCtrl.u16DialdestDuty = 0;
}

/**
 * @brief 初始化背光休眠设置
 * @note 调用该函数前，需确保相关硬件和寄存器已初始化。
 */
void BackLight_Sleep_Init(void)
{
    Backlight_Operate.BacklightPwm = 0;
    Backlight_Operate.BacklightEn = 0;
    BacklightFactorCtrl.curFactor = 100;
    BacklightFactorCtrl.destFactor = 0;
    BacklightFactorCtrl.NtcDelayTimer = 0;
    BacklightFactorCtrl.u16DialcurDuty = 0;
    BacklightFactorCtrl.u16DialDampingTimer = 0;
    BacklightFactorCtrl.u16DialdestDuty = 0;
}

/**
 * 根据背光等级获取对应的背光占空比。
 *
 * @param level 背光等级。
 * @return 对应背光等级的占空比，如果找不到对应等级则返回0。
 *
 * 该函数通过遍历背光等级表格，查找与输入等级匹配的背光占空比。
 * 如果找到匹配的等级，則返回该等级对应的占空比；如果未找到匹配的等级，
 * 则返回0。这允许应用程序根据背光等级动态调整背光的亮度。
 */
Light_uint16_t GetBacklightDutyByLevel(Light_uint16_t level)
{
    for (Light_uint8_t i = 0; i < BacklightLevel_Max; ++i)
    {
        if (Backlight_Operate.BacklightLevelTable[i].BacklightLevel == level)
        {
            return Backlight_Operate.BacklightLevelTable[i].BacklightDuty;
        }
    }
    /* 找不到匹配的等级，返回默认值50 */
    return 50;
}

/**
 * 根据给定的背光表和输入电阻值，获取对应的温度值。
 * 这个函数通过线性插值方法在背光表中查找与输入电阻最接近的温度值。
 * @param backlightTable 背光表，包含电阻和对应温度的数组。
 * @param size 背光表的大小，即数组的元素个数。
 * @param input 输入的电阻值。
 * @return 返回对应的温度值。
 */
Light_uint16_t Get_Ntc_Temp(_st_Backlight_NtcTable *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;
}

/**
 * @brief 根据当前温度，获取当前百分比
 * @param CurrentTemp 当前温度，单位为摄氏度
 * @return 当前百分比，取值范围为10到100
 * 注意：如果当前温度不在预定义的范围内，则默认返回100。
 */
static Light_uint8_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;
}

/**
 * @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;

    if (Backlight_Operate.NtcResCbk != ((void *)0))
    {
        CurrentTemp = Get_Ntc_Temp(Backlight_Operate.BacklightNTCTable, Backlight_NTC_Max, Backlight_Operate.NtcResCbk());
    }
    else
    {
        CurrentTemp = 0XFFFF; /* 无效不执行NTC策略 */
    }

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

    if (Backlight_Operate.SetPwmEnCbk != ((void *)0))
    {
        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 <= Backlight_Operate.BacklightNTCTable[0].Temperature))
            {
                if (BacklightFactorCtrl.NtcDelayTimer <= BackLight_Up_Timer)
                    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 <= BackLight_Down_Timer)
                    BacklightFactorCtrl.NtcDelayTimer++;
                else
                {
                    BacklightFactorCtrl.NtcDelayTimer = 0;
                    BacklightFactorCtrl.curFactor--;
                }

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

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

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

            if (CurrentTemp <= Backlight_Operate.BacklightNTCTable[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);
    }
}
