/**
 * @file hv_pm51_app_IR.C
 * @brief Infrared remote control function module
 * @details Using timer and GPIO to parse IR key values
 * @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 <reg51.h>
#include "hv_pm51_Base.h"
#include "hv_pm51_driver_Timer.h"
#include "hv_pm51_driver_GPIO.h"
#include "hv_pm51_driver_Reg.h"
#include "hv_pm51_driver_UART.h"
#include "hv_pm51_app_IR.h"
#include "hv_pm51_app_Mailbox.h"
#include "hv_pm51_app_Sys.h"
#include "hv_pm51_app_PM.h"

#if IR_ENABLE

#define IR_DEBUG_EN                   0
#define IR_SYS_CODE_HIGH              ((HV_PROJECT_CONFIG_PM51_IR_SYSCODE0 >> 8) & 0xff)
#define IR_SYS_CODE_LOW               (HV_PROJECT_CONFIG_PM51_IR_SYSCODE0 & 0xff)
#define IR_FACTORY_SYS_CODE_HIGH      ((HV_PROJECT_CONFIG_PM51_IR_SYSCODE1 >> 8) & 0xff)
#define IR_FACTORY_SYS_CODE_LOW       (HV_PROJECT_CONFIG_PM51_IR_SYSCODE1 & 0xff)
#define IR_DATA_POWER_KEY             HV_PROJECT_CONFIG_PM51_IR_POWERCODE

static xdata IRStatusType s_enIRStatus = E_IR_IDLE;
static xUCHAR8 s_aucIRData[4] = {0x0};
static xUCHAR8 s_aucCurIRData[4] = {0x0};
static iUCHAR8 s_ucHandleIR = HV_FALSE;
static iUCHAR8 s_ucHandleIRRepeat = HV_FALSE;
static xUCHAR8 s_ucIRCnt = 0;
#if IR_DEBUG_EN
static xULONG32 s_ulIRData = 0;
static xULONG32 s_aulIRRawData[4];
static xUCHAR8 s_ucIRErrorCnt = 0;
static xUCHAR8 s_ucIRRepeatCnt = 0;
static xULONG32 s_ucIRErrorCnt1 = 0;
#endif

extern xULONG32 g_ulTimer0Cnt;

void Hv_PM51_IR_Init(void)
{
    Hv_PM51_Gpio_Init();
    Hv_PM51_Gpio_SetIODirection(HV_PROJECT_CONFIG_PM51_IR_USE_GPIO, GPIO_INPUT);
    Hv_PM51_Gpio_EnableInt(HV_PROJECT_CONFIG_PM51_IR_USE_GPIO,GPIO_INTR_EDGE_N); /* fall edge */
    Hv_PM51_Reg_Write(HS_Standby__standby_peri_reg__reg_gp0_filter_num_ADDR+4*HV_PROJECT_CONFIG_PM51_IR_USE_GPIO, 0x2500);
    
    Hv_PM51_Sys_SetKeyState(HV_TRUE);
    Hv_PM51_Timer_Init(INNERTIMER0, E_16BIT);
}

void Hv_PM51_IR_Reset(void)
{
    s_aucIRData[0] = 0x0;
    s_aucIRData[1] = 0x0;
    s_aucIRData[2] = 0x0;
    s_aucIRData[3] = 0x0;
    s_ucIRCnt = 0;
    s_ucHandleIR = HV_FALSE;
    s_ucHandleIRRepeat = HV_FALSE;
    s_enIRStatus = E_IR_IDLE;
    g_ulTimer0Cnt = 0;
}

void Hv_PM51_IR_RecvHandler(void)
{
    xULONG32 ulIREdge = 0;   /* time between fall edge */
    //xUCHAR8 u8EventIntEn = 0;

    TCON &= ~(BIT_4);    /* Hv_PM51_Timer_Clear(INNERTIMER0) */

    switch(s_enIRStatus)
    {
        case E_IR_IDLE:
            s_enIRStatus = E_IR_HEAD;
            g_ulTimer0Cnt = 0;
            Hv_PM51_Timer_Set(INNERTIMER0, 0x0);
            break;
        case E_IR_HEAD:
            Hv_PM51_Timer_Get(INNERTIMER0, &ulIREdge);

            if((ulIREdge > (IR_HEADER - (IR_HEADER/10)))&&(ulIREdge < (IR_HEADER + (IR_HEADER/10))))
            {
                g_ulTimer0Cnt = 0;
                Hv_PM51_Timer_Set(INNERTIMER0, 0x0);
                s_aucIRData[0] = 0x0;
                s_aucIRData[1] = 0x0;
                s_aucIRData[2] = 0x0;
                s_aucIRData[3] = 0x0;
                s_enIRStatus = E_IR_DATA;
                s_ucIRCnt = 0;
            }
            else if((ulIREdge > (IR_REPEAT - (IR_REPEAT/10)))&&(ulIREdge < (IR_REPEAT + (IR_REPEAT/10))))
            {
#if IR_DEBUG_EN
                Hv_PM51_Reg_Write(0x11011904, ++s_ucIRRepeatCnt);
#endif
                s_ucHandleIRRepeat = HV_TRUE;
                s_enIRStatus = E_IR_IDLE;
                s_aucCurIRData[0] = s_aucIRData[0];
                s_aucCurIRData[1] = s_aucIRData[1];
                s_aucCurIRData[2] = s_aucIRData[2];
                s_aucCurIRData[3] = s_aucIRData[3];
            }
            else
            {
                TCON &= ~(BIT_4);
                s_aucIRData[0] = 0x0;
                s_aucIRData[1] = 0x0;
                s_aucIRData[2] = 0x0;
                s_aucIRData[3] = 0x0;
                s_ucIRCnt = 0;
                s_ucHandleIR = HV_FALSE;
                s_ucHandleIRRepeat = HV_FALSE;
                s_enIRStatus = E_IR_HEAD;
                g_ulTimer0Cnt = 0;
                Hv_PM51_Timer_Set(INNERTIMER0, 0x0);
#if IR_DEBUG_EN
                Hv_PM51_Reg_Write(0x11011908, ulIREdge);
                Hv_PM51_Reg_Write(0x11011910, ++s_ucIRErrorCnt1);
#endif
            }
            break;

        case E_IR_DATA:
            Hv_PM51_Timer_Get(INNERTIMER0, &ulIREdge);
#if IR_DEBUG_EN
            Hv_PM51_Reg_Write(0x11011930+s_ucIRCnt*4, ulIREdge);
#endif
            if((ulIREdge > (IR_BIT_ONE - 5000)) && (ulIREdge < (IR_BIT_ONE + 3000)))
            {
                if(s_ucIRCnt < 8)
                {
                    s_aucIRData[0] |= (BIT_0 << s_ucIRCnt);
                }
                else if((s_ucIRCnt >= 8) && (s_ucIRCnt < 16))
                {
                    s_aucIRData[1] |= (BIT_0 << (s_ucIRCnt-8));
                }
                else if((s_ucIRCnt >= 16) && (s_ucIRCnt < 24))
                {
                    s_aucIRData[2] |= (BIT_0 << (s_ucIRCnt-16));
                }
                else
                {
                    s_aucIRData[3] |= (BIT_0 << (s_ucIRCnt-24));
                }
            }
            else if((ulIREdge > (IR_BIT_ZERO - 5000)) && (ulIREdge < (IR_BIT_ZERO + 3000)))
            {
                /* do nothing */
            }
            else
            {
                TCON &= ~(BIT_4);
                s_aucIRData[0] = 0x0;
                s_aucIRData[1] = 0x0;
                s_aucIRData[2] = 0x0;
                s_aucIRData[3] = 0x0;
                s_ucIRCnt = 0;
                s_ucHandleIR = HV_FALSE;
                s_ucHandleIRRepeat = HV_FALSE;
                s_enIRStatus = E_IR_HEAD;
                g_ulTimer0Cnt = 0;
                Hv_PM51_Timer_Set(INNERTIMER0, 0x0);
#if IR_DEBUG_EN
                Hv_PM51_Reg_Write(0x11011900, ++s_ucIRErrorCnt);
#endif
                return;
            }

            s_ucIRCnt++;
            if(s_ucIRCnt < IR_DATA_BIT_LEN)
            {
                g_ulTimer0Cnt = 0;
                Hv_PM51_Timer_Set(INNERTIMER0, 0x0);
            }
            else
            {
                s_ucIRCnt = 0;
                s_ucHandleIR = HV_TRUE;
                s_enIRStatus = E_IR_IDLE;
                s_aucCurIRData[0] = s_aucIRData[0];
                s_aucCurIRData[1] = s_aucIRData[1];
                s_aucCurIRData[2] = s_aucIRData[2];
                s_aucCurIRData[3] = s_aucIRData[3];
#if 0
#if IR_INPUT_USE_GP0
                u8EventIntEn = Hv_PM51_Reg_ReadByte(HS_Standby__standby_mcu_reg__reg_event_int_en_ADDR+2);
                u8EventIntEn = (u8EventIntEn & 0xFE);
                Hv_PM51_Reg_WriteByte((HS_Standby__standby_mcu_reg__reg_event_int_en_ADDR+2), u8EventIntEn);
#else
                u8EventIntEn = Hv_PM51_Reg_ReadByte(HS_Standby__standby_mcu_reg__reg_event_int_en_ADDR+2);
                u8EventIntEn = (u8EventIntEn & 0xBF);
                Hv_PM51_Reg_WriteByte((HS_Standby__standby_mcu_reg__reg_event_int_en_ADDR+2), u8EventIntEn);
#endif
#endif
#if IR_DEBUG_EN
                s_aulIRRawData[0] = s_aucIRData[0];
                s_aulIRRawData[1] = s_aucIRData[1];
                s_aulIRRawData[2] = s_aucIRData[2];
                s_aulIRRawData[3] = s_aucIRData[3];
                s_ulIRData = s_aulIRRawData[0] | (s_aulIRRawData[1] << 8) | (s_aulIRRawData[2] << 16) | (s_aulIRRawData[3] << 24);
                Hv_PM51_Reg_Write(0x1101190C, s_ulIRData);
#endif
            }
            break;
        default:
            break;
    }
}

void Hv_PM51_IR_SendKeyVal(void)
{
    xUCHAR8 ucIRBitsCnt = 0;
    xUCHAR8 ucIRShift = 0;
    xdata Msg stMsg;

    if(s_ucHandleIR == HV_TRUE)
    {
        if(Hv_PM51_Sys_GetKeyState())
        {
            xULONG32 ulRData32;
            ulRData32 = Hv_PM51_Reg_ReadMask(HS_Standby__standby_mcu_reg__regr_power_on_ADDR,
                                   HS_Standby__standby_mcu_reg__regr_power_on_BITSTART,
                                   HS_Standby__standby_mcu_reg__regr_power_on_BITEND);
            if(ulRData32)
            {
                if(((s_aucCurIRData[0] == IR_SYS_CODE_HIGH) && (s_aucCurIRData[1] == IR_SYS_CODE_LOW))
                    || ((s_aucCurIRData[0] == IR_FACTORY_SYS_CODE_HIGH) && (s_aucCurIRData[1] == IR_FACTORY_SYS_CODE_LOW))
                    || (IR_SYS_CODE_LOW == 0xff)
                )
                {
                    stMsg.u8Val[0] = s_aucCurIRData[1];  /* syscode */
                    stMsg.u8Val[1] = s_aucCurIRData[2];  /* IR data */
                    stMsg.stMsgHeader.u8MsgType = E_MAILBOX_CMD_PM_TO_RISC_IR_VAL;
                    stMsg.stMsgHeader.pu8MsgLen[0] = 2;
                    Hv_PM51_Mailbox_Send(&stMsg);
                    Hv_PM51_Uart_Print("Send IR message to RISC.\r\n");
                }
            }
            else
            {
#if IR_WAKEUP_ENABLE
                if(((s_aucCurIRData[0] == IR_SYS_CODE_HIGH) && (s_aucCurIRData[1] == IR_SYS_CODE_LOW))
                    || ((s_aucCurIRData[0] == IR_FACTORY_SYS_CODE_HIGH) && (s_aucCurIRData[1] == IR_FACTORY_SYS_CODE_LOW))
                    || (IR_SYS_CODE_LOW == 0xff)
                )
                {
                    if(s_aucCurIRData[2] == IR_DATA_POWER_KEY) /* IR data: Power key */
                    {
                        //Hv_PM51_PM_BootUpSequense(E_WAKE_UP_TYPE_IR, s_aucCurIRData[2]);
#if WATCHDOG_ENABLE
                        Hv_PM51_Wdg_SetTimer(0x2);
                        Hv_PM51_Wdg_SetEnable(WDG_ENABLE);
#endif
                    }
                }
#endif
            }
        }
        s_ucHandleIR = HV_FALSE;
#if 0
#if IR_INPUT_USE_GP0
        Hv_PM51_Gpio_EnableInt(GPIO0, GPIO_INTR_EDGE_N);
#else
        Hv_PM51_Gpio_EnableInt(GPIO6, GPIO_INTR_EDGE_N);
#endif
#endif
    }

    if(s_ucHandleIRRepeat == HV_TRUE)
    {
        if(Hv_PM51_Sys_GetKeyState())
        {
            xULONG32 ulRData32;
            ulRData32 = Hv_PM51_Reg_ReadMask(HS_Standby__standby_mcu_reg__regr_power_on_ADDR,
                                   HS_Standby__standby_mcu_reg__regr_power_on_BITSTART,
                                   HS_Standby__standby_mcu_reg__regr_power_on_BITEND);
            if(ulRData32)
            {
                if(((s_aucCurIRData[0] == IR_SYS_CODE_HIGH) && (s_aucCurIRData[1] == IR_SYS_CODE_LOW))
                    || ((s_aucCurIRData[0] == IR_FACTORY_SYS_CODE_HIGH) && (s_aucCurIRData[1] == IR_FACTORY_SYS_CODE_LOW)))
                {
                    stMsg.u8Val[0] = s_aucCurIRData[1];  /* syscode */
                    stMsg.u8Val[1] = s_aucCurIRData[2];  /* IR data */
                    stMsg.stMsgHeader.u8MsgType = E_MAILBOX_CMD_PM_TO_RISC_IR_REPEAT;
                    stMsg.stMsgHeader.pu8MsgLen[0] = 2;
                    Hv_PM51_Mailbox_Send(&stMsg);
                }
            }
        }
        s_ucHandleIRRepeat = HV_FALSE;
    }
}

UCHAR8 Hv_PM51_IR_GetCurStatus(void)
{
    return (s_ucHandleIRRepeat || s_ucHandleIR);
}

#endif
