/**
  ******************************************************************************
 *
 * @file        Sample_IR_Receive.c
 *
 * @brief       EXIC and TM10 decode IR receive data.
 *
 * @par         Project
 *              MG32
 * @version     V1.10
 * @date        2022/02/23
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 *
 ******************************************************************************
* @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "MG32_DRV.h"
#include "Sample_APB_IR_Receive.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/**
 * @var     dIR
 * @brief   APB IR receive variable strict definition
 */
///@{
Sample_APB_IRReceiveTypeDef dIR;
///@}
/* Private function prototypes -----------------------------------------------*/
void Sample_DRV_GPIO_Init(void);
void Sample_DRV_TM10_Init(void);
void Sample_DRV_EXIC0_Init(void);
void Sample_DRV_Clear_IR_STATE(void);
void Sample_DRV_IRDecoder(void);
void Sample_DRV_APB_IRReceiver(void);
uint8_t Sample_DRV_END_Code_Check(void);
void EXINT0_IRQ(void);

/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/



/**
 *******************************************************************************
 * @brief       TM10 Initial Count IR Data Width Function
 * @details     Check STOP time is exact
 * @return      None
 *******************************************************************************
 */
void Sample_DRV_TM10_Init(void)
{
    TM_TimeBaseInitTypeDef TM_TimeBase_InitStruct;

    // 1.initial TimeBase structure 
    TM_TimeBaseStruct_Init(&TM_TimeBase_InitStruct);

    // modify parameter
    TM_TimeBase_InitStruct.TM_Period = 0xFFFF; 
    TM_TimeBase_InitStruct.TM_Prescaler = 120-1;
    TM_TimeBase_InitStruct.TM_CounterMode = Cascade;

    TM_TimeBase_Init(TM10, &TM_TimeBase_InitStruct);

    // ----------------------------------------------------
    // 2.clear TOF flag
    TM_ClearFlag(TM10, TMx_TOF);

    // ----------------------------------------------------
    // 3.Timer Clock out
    TM_ClockOutSource_Select(TM10, (TM_CKOSrcDef) PrescalerCKO);
    TM_CKOOutputState_Init(TM10, CLR);
    TM_ClockOut_Cmd(TM10, ENABLE);

    // ----------------------------------------------------
    // 4.Interrupt Setting
    //		TM10->INT.MBIT.IEA = 1;
    //		TM10->INT.MBIT.TIE2 = 1;
        
    // ----------------------------------------------------
    //    // 5.Start TM10 
    TM_Timer_Cmd(TM10, ENABLE);
}

/**
 *******************************************************************************
 * @brief       PA0 EXIC Initialize
 * @details     Check STOP time is exact
 * @return      None
 *******************************************************************************
 */
void Sample_DRV_EXIC0_Init(void)
{
    EXIC->INT.MBIT.PA_IEA = 1;
    EXIC->CR0.MBIT.PA_AINV = 0;
    EXIC->PA_MSK.MBIT.PA0_AM = 1;
    EXIC->PA_TRGS.MBIT.PA0_TRGS = 3;
}

/**
 *******************************************************************************
 * @brief       IR Receive IO Initialize
 * @details     Check STOP time is exact
 * @return      None
 *******************************************************************************
 */
void Sample_DRV_GPIO_Init(void)
{
    PIN_InitTypeDef PINX_InitStruct;

    //Debug IO Init
    PINX_InitStruct.PINX_Mode				= PINX_Mode_PushPull_O;
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Disable;
    PINX_InitStruct.PINX_Speed              = PINX_Speed_Low;
    PINX_InitStruct.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    PINX_InitStruct.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    PINX_InitStruct.PINX_Inverse            = PINX_Inverse_Disable;
    PINX_InitStruct.PINX_Alternate_Function = 0;
    //Debug GPIO Setting
    GPIO_PinMode_Config(PINC(1),&PINX_InitStruct);
    GPIO_PinMode_Config(PINC(2),&PINX_InitStruct);
    GPIO_PinMode_Config(PINC(3),&PINX_InitStruct);

    //TM10 CKO IO Setting
    PINX_InitStruct.PINX_Alternate_Function = 4;
    GPIO_PinMode_Config(PINB(1),&PINX_InitStruct);

    //URT IO Setting
    PINX_InitStruct.PINX_Alternate_Function = 3;
    GPIO_PinMode_Config(PINB(8),&PINX_InitStruct);
    PINX_InitStruct.PINX_Mode				= PINX_Mode_Digital_I;
    GPIO_PinMode_Config(PINB(9),&PINX_InitStruct);

    //EXIC0 IO init(PA0)
    PINX_InitStruct.PINX_Alternate_Function = 0;
    GPIO_PinMode_Config(PINA(0),&PINX_InitStruct);
}

/**
 *******************************************************************************
 * @brief       APB IR Receive Software State Clear Function
 * @details     Check STOP time is exact
 * @return      None
 *******************************************************************************
 */
void Sample_DRV_Clear_IR_STATE(void)
{
    //Clear software flag
    dIR.RX_CNT = 0;
    dIR.IRRXF = 0;
    dIR.ircnt = 0;
    dIR.datacnt = 0;
    dIR.STARTF = 0;
}

/**
 *******************************************************************************
 * @brief       APB IR STOP Data Check
 * @details     Check STOP time is exact
 * @return      None
 *******************************************************************************
 */
uint8_t Sample_DRV_END_Code_Check(void)
{
    uint8_t state = 0x00;
    uint16_t TM10_VAL = 0x0000;
    
    TM10_VAL = TM_GetCounter(TM10);
    
    if(TM10_VAL>=10000)
    {
            //Time out flag
        if(dIR.STARTF)
        {
            state = 0xA1;
            Sample_DRV_Clear_IR_STATE();
        }
    }
    
    return state;
}

/**
 *******************************************************************************
 * @brief       APB IR Decoder
 * @details     Receive data decode function.
 * @return      None
 *******************************************************************************
 */
void Sample_DRV_IRDecoder(void)
{
    uint8_t data = 0;

    //Start code decode
    if(dIR.RXEF)
    {
        if(dIR.RXDATA[0]<APB_IR_LEAD_CW_MAX && dIR.RXDATA[0]>APB_IR_LEAD_CW_MIN)
        {
            /*!< Lead code decode */
            if(dIR.RXDATA[1]<APB_IR_LEAD_OW_MAX && dIR.RXDATA[1]>APB_IR_LEAD_OW_MIN)
            {
                dIR.RXSTAT = 1;
                dIR.STARTF = 1;
                
            }
            //Repead code decode
            if(dIR.RXDATA[1]<APB_IR_REPEAT_OW_MAX && dIR.RXDATA[1]>APB_IR_REPEAT_OW_MIN)
            {
                dIR.recnt++;
                if(dIR.IRDATA!=0)
                    dIR.REBUFF = dIR.IRDATA;                /*!< Copy the previous data */
            }
            else
                dIR.IRDATA = 0x00000000;                    /*!< Clear data buffer */
            
        }
    }

    //Address and code decode
    if(dIR.RXSTAT)
    {
        if(dIR.RXDATA[0]<APB_IR_CW_LOGIC_H_MAX && dIR.RXDATA[0]>APB_IR_CW_LOGIC_H_MIN)
        {
            if(dIR.RXDATA[1]<APB_IR_OW_LOGIC_L_MAX && dIR.RXDATA[1]>APB_IR_OW_LOGIC_L_MIN)
            {
                    data = 0;
            }

            if(dIR.RXDATA[1]<APB_IR_OW_LOGIC_H_MAX && dIR.RXDATA[1]>APB_IR_OW_LOGIC_H_MIN)
            {
                    data = 1;
            }
            
            if(data)
                dIR.IRDATA |= (0x01<<dIR.datacnt);
            
            else
                dIR.IRDATA &= ~(0x01<<dIR.datacnt);
            
            dIR.datacnt++;
        }
        
    }
    dIR.RXEF = 0;
}

/**
 *******************************************************************************
 * @brief       APB IR Receiver 
 * @details     Print IR decoder result when IR date transmit.
 * @return      None
 *******************************************************************************
 */
void Sample_DRV_APB_IRReceiver(void)
{
    uint8_t irdata = 0x00,irdata_bar = 0x00,addr_data = 0x00,addr_data_bar = 0x00;
    uint8_t IRCON = 0x00;

    
    // make sure :
    
    //===Set CSC init====
    //MG32_CSC_Init.h(Configuration Wizard)
    
    //===Set GPIO init====
    //Set GPIOA 0 to input mode and enable GPIOA 0 interrupt.
    //Sample_DRV_GPIO_Init();
    
    //===Set TM10 init====
    //TM10 100kHz initialize for count IR data time base.
    //Sample_DRV_TM10_Init();
    
    //===Set IRQ init====
    //Enable TM10 and EXINT0_NVIC IRQ handler in "Manage Run Time Environment"
    //EXIC->INT.MBIT.PA_IEA = 1;
    //EXIC->CR0.MBIT.PA_AINV = 0;
    //EXIC->PA_MSK.MBIT.PA0_AM = 1;
    //EXIC->PA_TRGS.MBIT.PA0_TRGS = 3;
    //Sample_DRV_EXIC0_Init();
    
    // ------------------------------------------------------------------------
    // 1. GPIO Initial
    // 2. GPIOA 0 Interrupt Enable
    // 3. TM10 100kHz Counter Initialize and Interrupt Enable
    // ------------------------------------------------------------------------
    
    Sample_DRV_GPIO_Init();
    Sample_DRV_TM10_Init();
    Sample_DRV_EXIC0_Init();
    
//    while(1)
//    {
        if(dIR.IRRXF==0x10)
        {
            if(dIR.RXEF)
                Sample_DRV_IRDecoder();
            
            //End code check and clear state
            IRCON = Sample_DRV_END_Code_Check();
        }
        if(IRCON==0xA1)
        {
            addr_data = (uint8_t)dIR.IRDATA;
            addr_data_bar = (uint8_t)(dIR.IRDATA>>8);
            irdata = (uint8_t)(dIR.IRDATA>>16);
            irdata_bar = (dIR.IRDATA>>24);
            printf("ADDR = %x , ADDR_BAR = %x , DATA = %x , DATA_BAR = %x\n",(uint8_t)addr_data,(uint8_t)addr_data_bar,(uint8_t)irdata,(uint8_t)irdata_bar);
            IRCON = 0xA0;
        }
        if(dIR.recnt!=0)
        {
            addr_data = (uint8_t)(dIR.REBUFF);
            addr_data_bar = (uint8_t)(dIR.REBUFF>>8);
            irdata = (uint8_t)(dIR.REBUFF>>16);
            irdata_bar = (dIR.REBUFF>>24);
            printf("READDR = %x , READDR_BAR = %x , REDATA = %x , REDATA_BAR = %x\n",(uint8_t)addr_data,(uint8_t)addr_data_bar,(uint8_t)irdata,(uint8_t)irdata_bar);
            if(dIR.recnt>0)
                dIR.recnt--;
        }
//    }
}

/**
 *******************************************************************************
 * @brief       EXIC interrupt function.
 * @details     
 * @return      
 * @exception   No
 * @note
 * @par         Example
 * @code
 * @endcode
 *******************************************************************************
 */
void EXINT0_IRQ(void)
{
    
    if(EXIC_GetPxTriggerAndITFlagStatus(EXIC_PA_ITF)==DRV_Happened)
    {
        //Record TM10 count value
        dIR.RXDATA[dIR.ircnt] = TM_GetCounter(TM10);
        TM_Counter_Config(TM10,0,65535);
        /*!< Clear the TM10 count value, when receive the start code */
        if(dIR.RX_CNT==0)
                dIR.RXDATA[dIR.ircnt] = 0;
        /*!< Input data count. */
        if(dIR.RX_CNT!=0)
        {
                dIR.ircnt++;
        }
        /*!< IR data receive count, if over will cover the old data. */
        if(dIR.ircnt>1)
        {
                dIR.RXEF = 1;
                dIR.ircnt = 0;
        }
        dIR.IRRXF = 0x10;
        dIR.RX_CNT++;
        EXIC_ClearPxTriggerITFlag(EXIC_PA_ITF,EXIC_PX_AF);          /*!< Clear PXAF */
    }
    
    // Clear EXIC0 OR Flag
    if(EXIC_GetPxTriggerOrITFlagStatus(EXIC_PA_ITF)==DRV_Happened)
    {
        EXIC_ClearPxTriggerEventFlag(EXIC_PA, EXIC_PX_AllPIN );
        EXIC_ClearPxTriggerITFlag(EXIC_PA_ITF,EXIC_PX_OF);
    }
}



