/**
 * @file hv_pm51_app_Key.c
 * @brief
 * @details
 * @author HiView SoC Software Team
 * @version 0.0.1
 * @date 20230301
 * @copyright Copyright(c),2023-3, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>author                     <th>date           <th>description
 * <tr><td>HiView SoC Software Team   <td>20230301       <td>Create and first Version.
 * </table>
**/

#include "hv_pm51_Setting.h"
#include "hv_pm51_driver_Reg.h"
#include "hv_pm51_driver_GPIO.h"
#include "hv_pm51_driver_UART.h"
#include "hv_pm51_driver_Timer.h"
#include "hv_pm51_app_Mailbox.h"
#include "hv_pm51_app_Key.h"
#include "hv_pm51_app_Sys.h"
#include "Keyboard.h"
#include "KeyboardConfig.h"
#include "hv_pm51_driver_PWM.h"

#if ADC_KEY_ENABLE

#define ADC_KEY_DEBUG_EN    0

extern xUSHORT16 g_asAdcDataMap[ADC_KEY_NUMS][ADCDATAMAPMAX];
#if ADC_COMBO_KEY_NUMS
extern AdcComboKeyMap g_stAdcComboKeyMap[ADC_COMBO_KEY_NUMS];
#endif
extern xdata BOOL s_bIsKeyWork;

static xdata KeyStatus s_aenKeyStatus[2] = {E_KEY_IDEL, E_KEY_IDEL};
static xdata AdcKeyVal s_aenKeyVal[2] = {E_ADC_KEY_VAL_MAX, E_ADC_KEY_VAL_MAX};
#ifdef ADC_KEY_RETRY
#define ADC_MAX_RETRY 20
static xdata KeyPressRetry = 0;
static xdata KeyReleaseRetry = 0;
static xdata MaxRetry = 0;
AdcKeyVal ulTempKeyVal;
#endif

void Hv_PM51_Key_Init(void)
{
#if ADC0_KEY_ENABLE
    Hv_PM51_Adc_Init(E_ADC0, HV_TRUE);
    Hv_PM51_Adc_SetFilterNum(E_ADC0, 0x10000);
#else
    Hv_PM51_Adc_Init(E_ADC0, HV_FALSE);
#endif

#if ADC1_KEY_ENABLE
    Hv_PM51_Adc_Init(E_ADC1, HV_TRUE);
    Hv_PM51_Adc_SetFilterNum(E_ADC1, 0x10000);
#else
    Hv_PM51_Adc_Init(E_ADC1, HV_FALSE);
#endif

    Hv_PM51_Adc_SetTheshold(E_ADC0, ADC_Theshold_MIN, ADC_Theshold_MAX);
    Hv_PM51_Adc_Enable(E_ADC0);

    Hv_PM51_Adc_SetTheshold(E_ADC1, ADC_Theshold_MIN, ADC_Theshold_MAX);
    Hv_PM51_Adc_Enable(E_ADC1);

#if (ADC0_KEY_ENABLE || ADC1_KEY_ENABLE)
    Hv_PM51_Timer_Init(EXTIMER0, E_TIMER_MODE_NULL);
#endif
}

AdcKeyVal PM51_Key_GetAdcKeyVal(AdcNum enAdcNum, USHORT16 usAdcKeyData)
{
    xUCHAR8 ucKeyMapIndex;
    xUSHORT16  usMinAdcData;
    xUSHORT16  usMaxAdcData;

    for (ucKeyMapIndex = 0; ucKeyMapIndex < ADC_KEY_NUMS; ucKeyMapIndex++)
    {
        if (g_asAdcDataMap[ucKeyMapIndex][ADCDATAINDEX] > ADC_Theshold_MAX)
        {
            usMaxAdcData = ADC_Theshold_MAX;
        }
        else
        {
            usMaxAdcData = g_asAdcDataMap[ucKeyMapIndex][ADCDATAINDEX] + g_asAdcDataMap[ucKeyMapIndex][ADCDATAOFFSETINDEX];
            if (usMaxAdcData > ADC_Theshold_MAX)
            {
                usMaxAdcData = ADC_Theshold_MAX;
            }
        }
        if (g_asAdcDataMap[ucKeyMapIndex][ADCDATAINDEX] <= g_asAdcDataMap[ucKeyMapIndex][ADCDATAOFFSETINDEX])
        {
            usMinAdcData = ADC_Theshold_MIN;
        }
        else
        {
            usMinAdcData = g_asAdcDataMap[ucKeyMapIndex][ADCDATAINDEX] - g_asAdcDataMap[ucKeyMapIndex][ADCDATAOFFSETINDEX];
            if (usMinAdcData < ADC_Theshold_MIN)
            {
                usMinAdcData = ADC_Theshold_MIN;
            }
        }

        if (enAdcNum == E_ADC0)
        {
            if ((usAdcKeyData < usMaxAdcData)
                && (usAdcKeyData > usMinAdcData)
                && (g_asAdcDataMap[ucKeyMapIndex][ADCKEYVALUEINDEX] <=  E_ADC0_KEY_VAL_5))
            {
                return g_asAdcDataMap[ucKeyMapIndex][ADCKEYVALUEINDEX];
            }
        }
        else if (enAdcNum == E_ADC1)
        {
            if ((usAdcKeyData < usMaxAdcData)
                && (usAdcKeyData > usMinAdcData)
                && (g_asAdcDataMap[ucKeyMapIndex][ADCKEYVALUEINDEX] >=  E_ADC1_KEY_VAL_0))
            {
                return g_asAdcDataMap[ucKeyMapIndex][ADCKEYVALUEINDEX];
            }
        }
        else
        {
            return E_ADC_KEY_VAL_MAX;
        }
    }

    return E_ADC_KEY_VAL_MAX;
}

#if ADC_COMBO_KEY_NUMS
static AdcKeyVal PM51_Key_GetComboKeyVal(AdcKeyVal enAdc0KeyVal, AdcKeyVal enAdc1KeyVal)
{
    xUCHAR8 ucComboKeyMapIndex;

    for (ucComboKeyMapIndex = 0; ucComboKeyMapIndex < ADC_COMBO_KEY_NUMS; ucComboKeyMapIndex++)
    {
        if ((g_stAdcComboKeyMap[ucComboKeyMapIndex].enAdc0KeyVal == enAdc0KeyVal)
            && (g_stAdcComboKeyMap[ucComboKeyMapIndex].enAdc1KeyVal == enAdc1KeyVal))
        {
            return g_stAdcComboKeyMap[ucComboKeyMapIndex].enComboKeyVal;
        }
    }

    return E_ADC_KEY_VAL_MAX;
}
#endif
static xUCHAR8 PM51_Key_GetAdcKeyMapIndex(AdcKeyVal usAdcKeyVal)
{
    xUCHAR8 ucKeyMapIndex;

    for (ucKeyMapIndex = 0; ucKeyMapIndex < ADC_KEY_NUMS; ucKeyMapIndex++)
    {
        if (usAdcKeyVal == g_asAdcDataMap[ucKeyMapIndex][ADCKEYVALUEINDEX])
        {
            return ucKeyMapIndex;
        }
    }

    return ADC_KEY_NUMS;
}

void Hv_PM51_Key_Handler(AdcNum enAdcNum)
{
    xdata Msg stMsg;
    AdcKeyVal ulCurKeyVal;
    USHORT16 usCurKeyData;
#if ADC_COMBO_KEY_NUMS
    AdcKeyVal usCurComboKeyVal;
#endif

    if (s_aenKeyStatus[enAdcNum] == E_KEY_IDEL)
    {
        Hv_PM51_Sys_DelayMs(2);
        usCurKeyData = (USHORT16)Hv_PM51_Adc_ReadVal(enAdcNum);
        ulCurKeyVal = PM51_Key_GetAdcKeyVal(enAdcNum, usCurKeyData);
 #ifdef ADC_KEY_RETRY
        KeyPressRetry = 0;
        MaxRetry = 0;
        while (++MaxRetry)
        {
            Hv_PM51_Sys_DelayMs(2);
            usCurKeyData = (USHORT16)Hv_PM51_Adc_ReadVal(enAdcNum);
            ulTempKeyVal = PM51_Key_GetAdcKeyVal(enAdcNum, usCurKeyData);
            if (ulTempKeyVal == ulCurKeyVal)
            {
                KeyPressRetry++;
                if (ADC_KEY_RETRY == KeyPressRetry)
                {
                    break;
                }
            }
            else
            {
                KeyPressRetry = 0;
#if ADC_KEY_DEBUG_EN
                Hv_PM51_Uart_Print("key last new: ");
                Hv_PM51_Uart_PrintU32(ulCurKeyVal);
                Hv_PM51_Uart_PrintU32(ulTempKeyVal);
                Hv_PM51_Uart_Print("\r\n");
#endif
                ulCurKeyVal = ulTempKeyVal;
                if (MaxRetry>ADC_MAX_RETRY)
                {
                    return;
                }
            }
        }
#if ADC_KEY_DEBUG_EN
                Hv_PM51_Uart_Print("key final: ");
                Hv_PM51_Uart_PrintU32(ulCurKeyVal);
                Hv_PM51_Uart_PrintU32(usCurKeyData);
                Hv_PM51_Uart_Print("\r\n");
#endif
#endif
        if(ulCurKeyVal != E_ADC_KEY_VAL_MAX)
        {
            switch(s_aenKeyStatus[!(enAdcNum)])
            {
                case E_KEY_PUSHDONW:
                    {
#if ADC_COMBO_KEY_NUMS
                        s_aenKeyVal[enAdcNum] = ulCurKeyVal;
                        usCurComboKeyVal = PM51_Key_GetComboKeyVal(s_aenKeyVal[E_ADC0], s_aenKeyVal[E_ADC1]);

                        if (usCurComboKeyVal != E_ADC_KEY_VAL_MAX)
                        {
                            s_aenKeyVal[enAdcNum] = ulCurKeyVal;
                            s_aenKeyStatus[enAdcNum] = E_KEY_COMBO;
                            s_aenKeyStatus[!(enAdcNum)] = E_KEY_COMBO;
                            if (s_bIsKeyWork)
                            {
                                stMsg.u8Val[0] = usCurComboKeyVal;
                                stMsg.stMsgHeader.u8MsgType = E_MAILBOX_CMD_PM_TO_RISC_KEY_VAL;
                                stMsg.stMsgHeader.pu8MsgLen[0] = 1;
                                Hv_PM51_Mailbox_Send(&stMsg);
#if ADC_KEY_DEBUG_EN
                                Hv_PM51_Uart_Print("combo key: ");
                                Hv_PM51_Uart_PrintU32(usCurComboKeyVal);
                                Hv_PM51_Uart_Print("\r\n");
#endif
                            }
                            Hv_PM51_Timer_Set(EXTIMER0, 1000);  /* 10ms */
                        }
#endif
                        break;
                    }
                case E_KEY_IDEL:
                    {
                        s_aenKeyVal[enAdcNum] = ulCurKeyVal;
                        s_aenKeyStatus[enAdcNum] = E_KEY_PUSHDONW;

                        if (s_bIsKeyWork)
                        {
                            stMsg.u8Val[0] = ulCurKeyVal;
                            stMsg.stMsgHeader.u8MsgType = E_MAILBOX_CMD_PM_TO_RISC_KEY_VAL;
                            stMsg.stMsgHeader.pu8MsgLen[0] = 1;
                            Hv_PM51_Mailbox_Send(&stMsg);
#if ADC_KEY_DEBUG_EN
                            Hv_PM51_Uart_Print("key: ");
                            Hv_PM51_Uart_PrintU32(enAdcNum);
                            Hv_PM51_Uart_PrintU32(ulCurKeyVal);
                            Hv_PM51_Uart_PrintU32(usCurKeyData);
                            Hv_PM51_Uart_Print("\r\n");
#endif
#if PM51_DEBUG_DUMMY_REGS
                            if (enAdcNum == E_ADC0)
                            {
                                Hv_PM51_Reg_WriteByte(PM51_DEBUG_ADC0_KEY_ADDR, (ulCurKeyVal+1));
                            }
                            else
                            {
                                Hv_PM51_Reg_WriteByte(PM51_DEBUG_ADC1_KEY_ADDR, (ulCurKeyVal+1));
                            }
#endif
                        }
                        Hv_PM51_Timer_Set(EXTIMER0, 1000);  /* 10ms */

                        break;
                    }
                case E_KEY_COMBO:
                    {
                        s_aenKeyStatus[!(enAdcNum)] = E_KEY_IDEL;
                        break;
                    }
                default :
                    break;
            }
        }
        else
        {
            return;
        }
    }
}

void Hv_PM51_Key_TimerHandler(void)
{
    xdata Msg stMsg;
    xUCHAR8 ucAdc0KeyMapIndex = PM51_Key_GetAdcKeyMapIndex(s_aenKeyVal[E_ADC0]);
    xUCHAR8 ucAdc1KeyMapIndex = PM51_Key_GetAdcKeyMapIndex(s_aenKeyVal[E_ADC1]);
    USHORT16 usCurKeyData;
    BOOL bScanKey = HV_FALSE;
    xUSHORT16  usMinAdcData;
    xUSHORT16  usMaxAdcData;
#if ADC_COMBO_KEY_NUMS
    AdcKeyVal usCurComboKeyVal;
#endif

    if ((s_aenKeyStatus[E_ADC0] != E_KEY_IDEL) && (ucAdc0KeyMapIndex != ADC_KEY_NUMS))
    {
        if (g_asAdcDataMap[ucAdc0KeyMapIndex][ADCDATAINDEX] > ADC_Theshold_MAX)
        {
            usMaxAdcData = ADC_Theshold_MAX;
        }
        else
        {
            usMaxAdcData = g_asAdcDataMap[ucAdc0KeyMapIndex][ADCDATAINDEX] + g_asAdcDataMap[ucAdc0KeyMapIndex][ADCDATAOFFSETINDEX];
            if (usMaxAdcData > ADC_Theshold_MAX)
            {
                usMaxAdcData = ADC_Theshold_MAX;
            }
        }
        if (g_asAdcDataMap[ucAdc0KeyMapIndex][ADCDATAINDEX] <= g_asAdcDataMap[ucAdc0KeyMapIndex][ADCDATAOFFSETINDEX])
        {
            usMinAdcData = ADC_Theshold_MIN;
        }
        else
        {
            usMinAdcData = g_asAdcDataMap[ucAdc0KeyMapIndex][ADCDATAINDEX] - g_asAdcDataMap[ucAdc0KeyMapIndex][ADCDATAOFFSETINDEX];
            if (usMinAdcData < ADC_Theshold_MIN)
            {
                usMinAdcData = ADC_Theshold_MIN;
            }
        }

        usCurKeyData = Hv_PM51_Adc_ReadVal(E_ADC0);
#ifdef ADC_KEY_RETRY
        KeyReleaseRetry = 0;
        while (1)
        {
            if((usCurKeyData < usMaxAdcData)
                && (usCurKeyData > usMinAdcData))
            {
                bScanKey = HV_TRUE;
                break;
            }
            else
            {
                KeyReleaseRetry++;
            }
            if (ADC_KEY_RETRY == KeyReleaseRetry)
            {
                break;
            }
            Hv_PM51_Sys_DelayMs(2);
            usCurKeyData = (USHORT16)Hv_PM51_Adc_ReadVal(E_ADC0);
        }
#endif
        if((usCurKeyData < usMaxAdcData)
            && (usCurKeyData > usMinAdcData))

        {
            bScanKey = HV_TRUE;
        }
        else
        {
            if (s_bIsKeyWork)
            {
                stMsg.stMsgHeader.u8MsgType = E_MAILBOX_CMD_PM_TO_RISC_KEY_UPSPRING;
                stMsg.stMsgHeader.pu8MsgLen[0] = 1;
#if ADC_COMBO_KEY_NUMS
                if ((s_aenKeyStatus[E_ADC0] == E_KEY_COMBO) && (s_aenKeyStatus[E_ADC1] == E_KEY_COMBO))
                {
                    usCurComboKeyVal = PM51_Key_GetComboKeyVal(s_aenKeyVal[E_ADC0], s_aenKeyVal[E_ADC1]);
                    if (usCurComboKeyVal != E_ADC_KEY_VAL_MAX)
                    {
                        stMsg.u8Val[0] = usCurComboKeyVal;
                    }
                    else
                    {
                        stMsg.u8Val[0] = s_aenKeyVal[E_ADC0];
                    }
                }
                else
#endif
                {
                    stMsg.u8Val[0] = s_aenKeyVal[E_ADC0];
                }
                Hv_PM51_Mailbox_Send(&stMsg);
#if ADC_KEY_DEBUG_EN
                Hv_PM51_Uart_Print("release adc0 key: ");
                Hv_PM51_Uart_PrintU32(s_aenKeyVal[E_ADC0]);
                Hv_PM51_Uart_PrintU32(usCurKeyData);
                Hv_PM51_Uart_PrintU32(usMinAdcData);
                Hv_PM51_Uart_PrintU32(usMaxAdcData);
                Hv_PM51_Uart_Print("\r\n");
#endif
#if PM51_DEBUG_DUMMY_REGS
                Hv_PM51_Reg_WriteByte(PM51_DEBUG_ADC0_KEY_ADDR, 0);
#endif
            }

            s_aenKeyStatus[E_ADC0] = E_KEY_IDEL;
            if (s_aenKeyStatus[E_ADC1] == E_KEY_COMBO)
            {
                s_aenKeyStatus[E_ADC1] = E_KEY_PUSHDONW;
            }
        }
    }

    if ((s_aenKeyStatus[E_ADC1] != E_KEY_IDEL) && (ucAdc1KeyMapIndex != ADC_KEY_NUMS))
    {
        if (g_asAdcDataMap[ucAdc1KeyMapIndex][ADCDATAINDEX] > ADC_Theshold_MAX)
        {
            usMaxAdcData = ADC_Theshold_MAX;
        }
        else
        {
            usMaxAdcData = g_asAdcDataMap[ucAdc1KeyMapIndex][ADCDATAINDEX] + g_asAdcDataMap[ucAdc1KeyMapIndex][ADCDATAOFFSETINDEX];
            if (usMaxAdcData > ADC_Theshold_MAX)
            {
                usMaxAdcData = ADC_Theshold_MAX;
            }
        }
        if (g_asAdcDataMap[ucAdc1KeyMapIndex][ADCDATAINDEX] <= g_asAdcDataMap[ucAdc1KeyMapIndex][ADCDATAOFFSETINDEX])
        {
            usMinAdcData = ADC_Theshold_MIN;
        }
        else
        {
            usMinAdcData = g_asAdcDataMap[ucAdc1KeyMapIndex][ADCDATAINDEX] - g_asAdcDataMap[ucAdc1KeyMapIndex][ADCDATAOFFSETINDEX];
            if (usMinAdcData < ADC_Theshold_MIN)
            {
                usMinAdcData = ADC_Theshold_MIN;
            }
        }

        usCurKeyData = Hv_PM51_Adc_ReadVal(E_ADC1);
#ifdef ADC_KEY_RETRY
        KeyReleaseRetry = 0;
        while (1)
        {
            if((usCurKeyData < usMaxAdcData)
                && (usCurKeyData > usMinAdcData))
            {
                bScanKey = HV_TRUE;
                break;
            }
            else
            {
                KeyReleaseRetry++;
            }
            if (ADC_KEY_RETRY == KeyReleaseRetry)
            {
                break;
            }
            Hv_PM51_Sys_DelayMs(2);
            usCurKeyData = (USHORT16)Hv_PM51_Adc_ReadVal(E_ADC1);
        }
#endif
        if((usCurKeyData < usMaxAdcData)
            && (usCurKeyData > usMinAdcData))

        {
            bScanKey = HV_TRUE;
        }
        else
        {
            if (s_bIsKeyWork)
            {
                stMsg.stMsgHeader.u8MsgType = E_MAILBOX_CMD_PM_TO_RISC_KEY_UPSPRING;
                stMsg.stMsgHeader.pu8MsgLen[0] = 1;
#if ADC_COMBO_KEY_NUMS
                if ((s_aenKeyStatus[E_ADC0] == E_KEY_COMBO) && (s_aenKeyStatus[E_ADC1] == E_KEY_COMBO))
                {
                    usCurComboKeyVal = PM51_Key_GetComboKeyVal(s_aenKeyVal[E_ADC0], s_aenKeyVal[E_ADC1]);
                    if (usCurComboKeyVal != E_ADC_KEY_VAL_MAX)
                    {
                        stMsg.u8Val[0] = usCurComboKeyVal;
                    }
                    else
                    {
                        stMsg.u8Val[0] = s_aenKeyVal[E_ADC1];
                    }
                }
                else
#endif
                {
                    stMsg.u8Val[0] = s_aenKeyVal[E_ADC1];
                }
                Hv_PM51_Mailbox_Send(&stMsg);
#if ADC_KEY_DEBUG_EN
                Hv_PM51_Uart_Print("release adc1 key: ");
                Hv_PM51_Uart_PrintU32(s_aenKeyVal[E_ADC1]);
                Hv_PM51_Uart_PrintU32(usCurKeyData);
                Hv_PM51_Uart_PrintU32(usMinAdcData);
                Hv_PM51_Uart_PrintU32(usMaxAdcData);
                Hv_PM51_Uart_Print("\r\n");
#endif
#if PM51_DEBUG_DUMMY_REGS
                Hv_PM51_Reg_WriteByte(PM51_DEBUG_ADC1_KEY_ADDR, 0);
#endif
            }

            s_aenKeyStatus[E_ADC1] = E_KEY_IDEL;
            if (s_aenKeyStatus[E_ADC0] == E_KEY_COMBO)
            {
                s_aenKeyStatus[E_ADC0] = E_KEY_PUSHDONW;
            }
        }
    }

    if (bScanKey)
    {
        Hv_PM51_Timer_Set(EXTIMER0, 2000);  /* 20ms */
    }
}

xUCHAR8 PM51_Key_JudgeMenuSts(void)
{
#if (PM51_CONFIG_MENU_KEY_WITH_ADC_INDEX == MENU_KEY_WITH_ADC0)
    if (s_aenKeyStatus[0] != E_KEY_IDEL)
    {
        Hv_PM51_Uart_Print("PM51_Key_JudgeMenuSts s_aenKeyVal: ");
        Hv_PM51_Uart_PrintU32(s_aenKeyVal[0]);
        Hv_PM51_Uart_Print("\r\n");
        /* Menu is pressed */
        if (s_aenKeyVal[0] == E_ADC0_KEY_VAL_0)
        {
            return HV_TRUE;
        }
    }
#else
    if (s_aenKeyStatus[1] != E_KEY_IDEL)
    {
        Hv_PM51_Uart_Print("PM51_Key_JudgeMenuSts s_aenKeyVal: ");
        Hv_PM51_Uart_PrintU32(s_aenKeyVal[1]);
        Hv_PM51_Uart_Print("\r\n");
        /* Menu is pressed */
        if (s_aenKeyVal[1] == E_ADC1_KEY_VAL_0)
        {
            return HV_TRUE;
        }
    }
#endif
    return HV_FALSE;
}

xUCHAR8 PM51_Key_FactoryModeJudgeMenuSts(void)
{
    xUCHAR8 ucKeyVal = PM51_CONFIG_FACTORY_MODE_KEY_VAL;

    if (ucKeyVal == E_ADC_KEY_VAL_MAX)
    {
        return HV_FALSE;
    }

    if ((s_aenKeyStatus[0] != E_KEY_IDEL) || (s_aenKeyStatus[1] != E_KEY_IDEL))
    {
        /* Factory mode key is pressed */
        if ((s_aenKeyVal[0] == ucKeyVal)
            || (s_aenKeyVal[1] == ucKeyVal))
        {
            return HV_TRUE;
        }
    }

    return HV_FALSE;
}

void PM51_Key_SetLed(KeyLedStatus enKeyLedSts)
{
    PwmParam stParam;

    stParam.enPol           = E_PWM_POL_LOW;
    stParam.enCntMode       = E_PWM_CNT_MODE_UP;
    stParam.ucPrescaler     = 4;
    stParam.ucCntTopVal     = PWM_COUNTS_PER_SEC_DEFAULT*2 -1;
    stParam.usCmpStartVal   = PWM_COUNTS_PER_SEC_DEFAULT;
    stParam.usCmpEndVal     = PWM_COUNTS_PER_SEC_DEFAULT;
    stParam.usCmpStepVal    = 0x0;

#if (PM51_CONFIG_LED_ON_WITH_PWM_POL == PWM_POL_HIGH)
    stParam.enPol = E_PWM_POL_HIGH;
#endif

    if (enKeyLedSts == E_KEY_LED_ON)
    {
        Hv_PM51_Pwm_Init(&stParam);
        Hv_PM51_Pwm_Stop();
        Hv_PM51_Uart_Print("E_KEY_LED_ON \r\n");
    }
    else if (enKeyLedSts == E_KEY_LED_BREATH)
    {
        stParam.ucPrescaler = 11; /* Default 26.6M/2048 = 12988(1s) */
#ifdef PM51_CONFIG_LED_BREATH_TIME
        #if (PM51_CONFIG_LED_BREATH_TIME == 2)
        stParam.ucPrescaler = 12;
        #elif (PM51_CONFIG_LED_BREATH_TIME == 3)
        stParam.ucPrescaler = 12;
        stParam.ucCntTopVal     = PWM_COUNTS_PER_SEC_DEFAULT*3 - 1;
        stParam.usCmpStartVal   = PWM_COUNTS_PER_SEC_DEFAULT/2*3;
        stParam.usCmpEndVal     = PWM_COUNTS_PER_SEC_DEFAULT/2*3;
        #else
        stParam.ucPrescaler = 11;
        #endif
#endif
        Hv_PM51_Pwm_SetPrescaler(4);
        Hv_PM51_Pwm_Stop();
        Hv_PM51_Sys_DelayMs(15);
        Hv_PM51_Pwm_Init(&stParam);
        Hv_PM51_Pwm_Start();
        Hv_PM51_Uart_Print("E_KEY_LED_BREATH \r\n");
    }
    else if (enKeyLedSts == E_KEY_LED_ON1)
    {
#if (PM51_CONFIG_LED_ON_WITH_PWM_POL == PWM_POL_HIGH)
        stParam.usCmpStartVal   = PWM_COUNTS_PER_SEC_DEFAULT/2*3;
        stParam.usCmpEndVal     = PWM_COUNTS_PER_SEC_DEFAULT/2*3;
#else
        stParam.usCmpStartVal   = PWM_COUNTS_PER_SEC_DEFAULT/2;
        stParam.usCmpEndVal     = PWM_COUNTS_PER_SEC_DEFAULT/2;
#endif
        Hv_PM51_Pwm_SetOutputDisable();
        Hv_PM51_Pwm_Stop();
        Hv_PM51_Sys_DelayMs(10);
        Hv_PM51_Pwm_Init(&stParam);
        Hv_PM51_Sys_DelayMs(10);
        Hv_PM51_Pwm_Start();
        Hv_PM51_Uart_Print("E_KEY_LED_ON1 \r\n");

    }
    else if (enKeyLedSts == E_KEY_LED_ON2)
    {
        stParam.usCmpStartVal   = PWM_COUNTS_PER_SEC_DEFAULT;
        stParam.usCmpEndVal     = PWM_COUNTS_PER_SEC_DEFAULT;
        Hv_PM51_Pwm_Init(&stParam);
        Hv_PM51_Pwm_Stop();
        Hv_PM51_Sys_DelayMs(15);
        Hv_PM51_Pwm_Start();
        Hv_PM51_Uart_Print("E_KEY_LED_ON2 \r\n");
    }
    else if (enKeyLedSts == E_KEY_LED_ON3)
    {
#if (PM51_CONFIG_LED_ON_WITH_PWM_POL == PWM_POL_HIGH)
        stParam.usCmpStartVal   = PWM_COUNTS_PER_SEC_DEFAULT/2;
        stParam.usCmpEndVal     = PWM_COUNTS_PER_SEC_DEFAULT/2;
#else
        stParam.usCmpStartVal   = PWM_COUNTS_PER_SEC_DEFAULT/2*3;
        stParam.usCmpEndVal     = PWM_COUNTS_PER_SEC_DEFAULT/2*3;
#endif
        Hv_PM51_Pwm_Init(&stParam);
        Hv_PM51_Pwm_Stop();
        Hv_PM51_Sys_DelayMs(15);
        Hv_PM51_Pwm_Start();
        Hv_PM51_Uart_Print("E_KEY_LED_ON3 \r\n");
    }
    else
    {
        #if (PM51_CONFIG_LED_ON_WITH_PWM_POL == PWM_POL_HIGH)
        stParam.enPol = E_PWM_POL_LOW;
        #else
        stParam.enPol = E_PWM_POL_HIGH;
        #endif
        Hv_PM51_Pwm_Init(&stParam);
        Hv_PM51_Pwm_Stop();
        Hv_PM51_Uart_Print("E_KEY_LED_OFF \r\n");
    }

#if PM51_DEBUG_DUMMY_REGS
        Hv_PM51_Reg_WriteByte(PM51_DEBUG_LED_STATUS_ADDR, enKeyLedSts);
#endif
    return;
}

#elif GPIO_KEY_ENABLE

#define GPIO_KEY_NUMS     5

static xdata KeyStatus s_aenKeyStatus = E_KEY_IDEL;
static xdata GpioKeyMap s_stGpioKeyMap[GPIO_KEY_NUMS] =
    {
        {GPIO0, E_KEY_VAL_0},
        {GPIO1, E_KEY_VAL_1},
        {GPIO4, E_KEY_VAL_2},
        {GPIO5, E_KEY_VAL_3},
        {GPIO6, E_KEY_VAL_4},
    };

void Hv_PM51_Key_Init(void)
{
    xdata UCHAR8 ucIndex;

    Hv_PM51_Gpio_Init();

    for (ucIndex = 0; ucIndex < GPIO_KEY_NUMS; ucIndex++)
    {
        Hv_PM51_Gpio_InitPin(s_stGpioKeyMap[ucIndex].enGpio);
        Hv_PM51_Gpio_SetIODirection(s_stGpioKeyMap[ucIndex].enGpio, GPIO_INPUT);
        Hv_PM51_Gpio_EnableInt(s_stGpioKeyMap[ucIndex].enGpio, GPIO_INTR_EDGE_P);
        Hv_PM51_Gpio_EnableInt(s_stGpioKeyMap[ucIndex].enGpio, GPIO_INTR_EDGE_N);
    }
}

static GpioKeyVal PM51_Key_GetKeyVal(GpioEn enGpio)
{
    xdata UCHAR8 ucIndex;

    for (ucIndex = 0; ucIndex < GPIO_KEY_NUMS; ucIndex++)
    {
        if (s_stGpioKeyMap[ucIndex].enGpio == enGpio)
        {
            return s_stGpioKeyMap[ucIndex].enKeyVal;
        }
    }

    return E_KEY_VAL_MAX;
}

void Hv_PM51_Key_Handler(GpioEn enGpio)
{
    xdata Msg stMsg;
    xdata GpioKeyVal enKeyVal;

    if (s_aenKeyStatus == E_KEY_IDEL)
    {
        enKeyVal = PM51_Key_GetKeyVal(enGpio);

        if (enKeyVal < E_KEY_VAL_MAX)
        {
            stMsg.u8Val[0] = enKeyVal;
            Hv_PM51_Uart_Print("GPIO Key push down!\r\n");
            Hv_PM51_Uart_PrintU32(enKeyVal);
            Hv_PM51_Uart_Print("\r\n");
        }
        else
        {
            Hv_PM51_Uart_Print("Key val is invalid!\r\n");
            return;
        }

        stMsg.stMsgHeader.u8MsgType = E_MAILBOX_CMD_PM_TO_RISC_KEY_VAL;
        stMsg.stMsgHeader.pu8MsgLen[0] = 1;
        Hv_PM51_Mailbox_Send(&stMsg);

        s_aenKeyStatus = E_KEY_PUSHDONW;
    }
    else
    {
        stMsg.stMsgHeader.u8MsgType = E_MAILBOX_CMD_PM_TO_RISC_KEY_UPSPRING;
        Hv_PM51_Mailbox_Send(&stMsg);

        s_aenKeyStatus = E_KEY_IDEL;
    }
}

#endif
