text: /**
    ******************************************************************************
    * @file    bl602_ir.c
    * @version V1.0
    * @date
    * @brief   This file is the standard driver c file
    ******************************************************************************
    * @attention
    *
    * <h2><center>&copy; COPYRIGHT(c) 2020 Bouffalo Lab</center></h2>
    *
    * Redistribution and use in source and binary forms, with or without modification,
    * are permitted provided that the following conditions are met:
    *   1. Redistributions of source code must retain the above copyright notice,
    *      this list of conditions and the following disclaimer.
    *   2. Redistributions in binary form must reproduce the above copyright notice,
    *      this list of conditions and the following disclaimer in the documentation
    *      and/or other materials provided with the distribution.
    *   3. Neither the name of Bouffalo Lab nor the names of its contributors
    *      may be used to endorse or promote products derived from this software
    *      without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    ******************************************************************************
    */
  
  #include "bl602_ir.h"
  #include "bl602_glb.h"
  
  /** @addtogroup  BL602_Peripheral_Driver
   *  @{
   */
  
  /** @addtogroup  IR
   *  @{
   */
  
  /** @defgroup  IR_Private_Macros
   *  @{
   */
  #define NEC_HEAD_H_MIN          17000
  #define NEC_HEAD_H_MAX          19000
  #define NEC_HEAD_L_MIN           8400
  #define NEC_HEAD_L_MAX           9600
  #define NEC_BIT0_H_MIN            525
  #define NEC_BIT0_H_MAX           1725
  #define RC5_ONE_PLUSE_MIN        1175
  #define RC5_ONE_PLUSE_MAX        2375
  #define RC5_TWO_PLUSE_MIN        2955
  #define RC5_TWO_PLUSE_MAX        4155
  #define IR_TX_INT_TIMEOUT_COUNT          (100*160*1000)
  #define IR_RX_INT_TIMEOUT_COUNT          (100*160*1000)
  
  /*@} end of group IR_Private_Macros */
  
  /** @defgroup  IR_Private_Types
   *  @{
   */
  
  /*@} end of group IR_Private_Types */
  
  /** @defgroup  IR_Private_Variables
   *  @{
   */
  static intCallback_Type * irIntCbfArra[IR_INT_ALL]= {NULL,NULL};
  
  
  /*@} end of group IR_Private_Variables */
  
  /** @defgroup  IR_Global_Variables
   *  @{
   */
  
  /*@} end of group IR_Global_Variables */
  
  /** @defgroup  IR_Private_Fun_Declaration
   *  @{
   */
  
  /*@} end of group IR_Private_Fun_Declaration */
  
  /** @defgroup  IR_Private_Functions
   *  @{
   */
  
  /*@} end of group IR_Private_Functions */
  
  /** @defgroup  IR_Public_Functions
   *  @{
   */
  
  /****************************************************************************//**
   * @brief  IR RX IRQ handler function
   *
   * @param  None
   *
   * @return None
   *
  *******************************************************************************/
  #ifndef BL602_USE_HAL_DRIVER
  void IRRX_IRQHandler(void)
  {
      uint32_t tmpVal;
      
      tmpVal = BL_RD_REG(IR_BASE,IRRX_INT_STS);
      if(BL_IS_REG_BIT_SET(tmpVal,IRRX_END_INT) && !BL_IS_REG_BIT_SET(tmpVal,IR_CR_IRRX_END_MASK)){
          BL_WR_REG(IR_BASE,IRRX_INT_STS,BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_END_CLR));
          if(irIntCbfArra[IR_INT_RX] != NULL){
              irIntCbfArra[IR_INT_RX]();
          }
      }
  }
  #endif
  
  /****************************************************************************//**
   * @brief  IR TX IRQ handler function
   *
   * @param  None
   *
   * @return None
   *
  *******************************************************************************/
  #ifndef BL602_USE_HAL_DRIVER
  void IRTX_IRQHandler(void)
  {
      uint32_t tmpVal;
      
      tmpVal = BL_RD_REG(IR_BASE,IRTX_INT_STS);
      if(BL_IS_REG_BIT_SET(tmpVal,IRTX_END_INT) && !BL_IS_REG_BIT_SET(tmpVal,IR_CR_IRTX_END_MASK)){
          BL_WR_REG(IR_BASE,IRTX_INT_STS,BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_END_CLR));
          if(irIntCbfArra[IR_INT_TX] != NULL){
              irIntCbfArra[IR_INT_TX]();
          }
      }
  }
  #endif
  
  /****************************************************************************//**
   * @brief  IR tx initialization function
   *
   * @param  irTxCfg: IR tx configuration structure pointer
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_TxInit(IR_TxCfg_Type *irTxCfg)
  {
      uint32_t tmpVal;
      
      tmpVal = BL_RD_REG(IR_BASE,IRTX_CONFIG);
      /* Set data bit */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_DATA_NUM,irTxCfg->dataBits-1);
      /* Set tail pulse */
      ENABLE == irTxCfg->tailPulseInverse ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_TAIL_HL_INV)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_TAIL_HL_INV));
      ENABLE == irTxCfg->tailPulse ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_TAIL_EN)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_TAIL_EN));
      /* Set head pulse */
      ENABLE == irTxCfg->headPulseInverse ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_HEAD_HL_INV)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_HEAD_HL_INV));
      ENABLE == irTxCfg->headPulse ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_HEAD_EN)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_HEAD_EN));
      /* Enable or disable logic 1 and 0 pulse inverse */
      ENABLE == irTxCfg->logic1PulseInverse ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_LOGIC1_HL_INV)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_LOGIC1_HL_INV));
      ENABLE == irTxCfg->logic0PulseInverse ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_LOGIC0_HL_INV)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_LOGIC0_HL_INV));
      /* Enable or disable data pulse */
      ENABLE == irTxCfg->dataPulse ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_DATA_EN)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_DATA_EN));
      /* Enable or disable output modulation */
      ENABLE == irTxCfg->outputModulation ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_MOD_EN)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_MOD_EN));
      /* Enable or disable output inverse */
      ENABLE == irTxCfg->outputInverse ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_OUT_INV)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_OUT_INV));
      
      /* Write back */
      BL_WR_REG(IR_BASE,IRTX_CONFIG,tmpVal);
  
  #ifndef BFLB_USE_HAL_DRIVER
      //Interrupt_Handler_Register(IRTX_IRQn,IRTX_IRQHandler);
  #endif
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR tx pulse width configure function
   *
   * @param  irTxPulseWidthCfg: IR tx pulse width configuration structure pointer
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_TxPulseWidthConfig(IR_TxPulseWidthCfg_Type *irTxPulseWidthCfg)
  {
      uint32_t tmpVal;
      
      tmpVal = BL_RD_REG(IR_BASE,IRTX_PW);
      /* Set logic 0 pulse phase 0 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_LOGIC0_PH0_W,irTxPulseWidthCfg->logic0PulseWidth_0-1);
      /* Set logic 0 pulse phase 1 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_LOGIC0_PH1_W,irTxPulseWidthCfg->logic0PulseWidth_1-1);
      /* Set logic 1 pulse phase 0 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_LOGIC1_PH0_W,irTxPulseWidthCfg->logic1PulseWidth_0-1);
      /* Set logic 1 pulse phase 1 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_LOGIC1_PH1_W,irTxPulseWidthCfg->logic1PulseWidth_1-1);
      /* Set head pulse phase 0 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_HEAD_PH0_W,irTxPulseWidthCfg->headPulseWidth_0-1);
      /* Set head pulse phase 1 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_HEAD_PH1_W,irTxPulseWidthCfg->headPulseWidth_1-1);
      /* Set tail pulse phase 0 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_TAIL_PH0_W,irTxPulseWidthCfg->tailPulseWidth_0-1);
      /* Set tail pulse phase 1 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_TAIL_PH1_W,irTxPulseWidthCfg->tailPulseWidth_1-1);
      BL_WR_REG(IR_BASE,IRTX_PW,tmpVal);
      
      tmpVal = BL_RD_REG(IR_BASE,IRTX_PULSE_WIDTH);
      /* Set modulation phase 0 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_MOD_PH0_W,irTxPulseWidthCfg->moduWidth_0-1);
      /* Set modulation phase 1 width */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_MOD_PH1_W,irTxPulseWidthCfg->moduWidth_1-1);
      /* Set pulse width unit */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_PW_UNIT,irTxPulseWidthCfg->pulseWidthUnit-1);
      BL_WR_REG(IR_BASE,IRTX_PULSE_WIDTH,tmpVal);
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR tx software mode pulse width(multiples of pulse width unit) configure function
   *
   * @param  irTxSWMPulseWidthCfg: IR tx software mode pulse width configuration structure pointer
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_TxSWMPulseWidthConfig(IR_TxSWMPulseWidthCfg_Type *irTxSWMPulseWidthCfg)
  {
      /* Set swm pulse width,multiples of pulse width unit */
      BL_WR_REG(IR_BASE,IRTX_SWM_PW_0,irTxSWMPulseWidthCfg->swmData0);
      BL_WR_REG(IR_BASE,IRTX_SWM_PW_1,irTxSWMPulseWidthCfg->swmData1);
      BL_WR_REG(IR_BASE,IRTX_SWM_PW_2,irTxSWMPulseWidthCfg->swmData2);
      BL_WR_REG(IR_BASE,IRTX_SWM_PW_3,irTxSWMPulseWidthCfg->swmData3);
      BL_WR_REG(IR_BASE,IRTX_SWM_PW_4,irTxSWMPulseWidthCfg->swmData4);
      BL_WR_REG(IR_BASE,IRTX_SWM_PW_5,irTxSWMPulseWidthCfg->swmData5);
      BL_WR_REG(IR_BASE,IRTX_SWM_PW_6,irTxSWMPulseWidthCfg->swmData6);
      BL_WR_REG(IR_BASE,IRTX_SWM_PW_7,irTxSWMPulseWidthCfg->swmData7);
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR rx initialization function
   *
   * @param  irRxCfg: IR rx configuration structure pointer
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_RxInit(IR_RxCfg_Type *irRxCfg)
  {
      uint32_t tmpVal;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_RXMODE_TYPE(irRxCfg->rxMode));
      
      tmpVal = BL_RD_REG(IR_BASE,IRRX_CONFIG);
      /* Set rx mode */
      switch(irRxCfg->rxMode)
      {
          case IR_RX_NEC:
              tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_MODE,0x0);
              break;
          case IR_RX_RC5:
              tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_MODE,0x1);
              break;
          case IR_RX_SWM:
              tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_MODE,0x2);
              break;
          default:
              break;
      }
      /* Enable or disable input inverse */
      ENABLE == irRxCfg->inputInverse ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_IN_INV)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRRX_IN_INV));
      /* Enable or disable rx input de-glitch function */
      ENABLE == irRxCfg->rxDeglitch ? (tmpVal=BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_DEG_EN)):(tmpVal=BL_CLR_REG_BIT(tmpVal,IR_CR_IRRX_DEG_EN));
      /* Set de-glitch function cycle count */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_DEG_CNT,irRxCfg->DeglitchCnt);
      /* Write back */
      BL_WR_REG(IR_BASE,IRRX_CONFIG,tmpVal);
      
      tmpVal = BL_RD_REG(IR_BASE,IRRX_PW_CONFIG);
      /* Set pulse width threshold to trigger end condition */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_END_TH,irRxCfg->endThreshold-1);
      /* Set pulse width threshold for logic0/1 detection */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_DATA_TH,irRxCfg->dataThreshold-1);
      /* Write back */
      BL_WR_REG(IR_BASE,IRRX_PW_CONFIG,tmpVal);
  
  #ifndef BFLB_USE_HAL_DRIVER
      //Interrupt_Handler_Register(IRRX_IRQn,IRRX_IRQHandler);
  #endif
  
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR set default value of all registers function
   *
   * @param  None
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_DeInit(void)
  {
      GLB_AHB_Slave1_Reset(BL_AHB_SLAVE1_IRR);
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR enable function
   *
   * @param  direct: IR direction type
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_Enable(IR_Direction_Type direct)
  {
      uint32_t tmpVal;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_DIRECTION_TYPE(direct));
      
      if(direct == IR_TX || direct == IR_TXRX){
          /* Enable ir tx unit */
          tmpVal = BL_RD_REG(IR_BASE,IRTX_CONFIG);
          BL_WR_REG(IR_BASE,IRTX_CONFIG,BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_EN));
      }
  
      if(direct == IR_RX || direct == IR_TXRX){
          /* Enable ir rx unit */
          tmpVal = BL_RD_REG(IR_BASE,IRRX_CONFIG);
          BL_WR_REG(IR_BASE,IRRX_CONFIG,BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_EN));
      }
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR disable function
   *
   * @param  direct: IR direction type
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_Disable(IR_Direction_Type direct)
  {
      uint32_t tmpVal;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_DIRECTION_TYPE(direct));
      
      if(direct == IR_TX || direct == IR_TXRX){
          /* Disable ir tx unit */
          tmpVal = BL_RD_REG(IR_BASE,IRTX_CONFIG);
          BL_WR_REG(IR_BASE,IRTX_CONFIG,BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_EN));
      }
  
      if(direct == IR_RX || direct == IR_TXRX){
          /* Disable ir rx unit */
          tmpVal = BL_RD_REG(IR_BASE,IRRX_CONFIG);
          BL_WR_REG(IR_BASE,IRRX_CONFIG,BL_CLR_REG_BIT(tmpVal,IR_CR_IRRX_EN));
      }
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR tx software mode enable or disable function
   *
   * @param  txSWM: Enable or disable
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_TxSWM(BL_Fun_Type txSWM)
  {
      uint32_t tmpVal;
      
      /* Enable or disable tx swm */
      tmpVal = BL_RD_REG(IR_BASE,IRTX_CONFIG);
      if(ENABLE == txSWM){
          BL_WR_REG(IR_BASE,IRTX_CONFIG,BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_SWM_EN));
      }else{
          BL_WR_REG(IR_BASE,IRTX_CONFIG,BL_CLR_REG_BIT(tmpVal,IR_CR_IRTX_SWM_EN));
      }
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR clear rx fifo function
   *
   * @param  None
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_RxFIFOClear(void)
  {
      uint32_t tmpVal;
      
      /* Clear rx fifo */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_SWM_FIFO_CONFIG_0);
      BL_WR_REG(IR_BASE,IRRX_SWM_FIFO_CONFIG_0,BL_SET_REG_BIT(tmpVal,IR_RX_FIFO_CLR));
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR send data function
   *
   * @param  irWord: IR tx data word 0 or 1
   * @param  data: data to send
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_SendData(IR_Word_Type irWord,uint32_t data)
  {
      /* Check the parameters */
      CHECK_PARAM(IS_IR_WORD_TYPE(irWord));
      
      /* Write word 0 or word 1 */
      if(IR_WORD_0 == irWord){
          BL_WR_REG(IR_BASE,IRTX_DATA_WORD0,data);
      }
      else{
          BL_WR_REG(IR_BASE,IRTX_DATA_WORD1,data);
      }
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR software mode send pulse width data function
   *
   * @param  data: data to send
   * @param  length: Length of send buffer
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_SWMSendData(uint16_t *data,uint8_t length)
  {
      uint8_t i = 0,j = 0;
      uint16_t minData = data[0];
      uint32_t tmpVal;
      uint32_t pwVal = 0;
      uint32_t count = (length+7)/8;
      
      /* Search for min value */
      for(i=1;i<length;i++){
          if(minData>data[i] && data[i]!=0){
              minData = data[i];
          }
      }
      
      /* Set pulse width unit */
      tmpVal = BL_RD_REG(IR_BASE,IRTX_PULSE_WIDTH);
      BL_WR_REG(IR_BASE,IRTX_PULSE_WIDTH,BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_PW_UNIT,minData));
      
      /* Set tx SWM pulse width data as multiples of pulse width unit */
      for(i=0;i<count;i++){
          pwVal = 0;
          if(i<count-1){
              for(j=0;j<8;j++){
                  tmpVal = ((2*data[j+i*8]+minData)/(2*minData)-1)&0xf;
                  pwVal |= tmpVal<<(4*j);
              }
              *(volatile uint32_t*)(IR_BASE+IRTX_SWM_PW_0_OFFSET+i*4) = pwVal;
          }else{
              for(j=0;j<length%8;j++){
                  tmpVal = ((2*data[j+i*8]+minData)/(2*minData)-1)&0xf;
                  pwVal |= tmpVal<<(4*j);
              }
              *(volatile uint32_t*)(IR_BASE+IRTX_SWM_PW_0_OFFSET+i*4) = pwVal;
          }
      }
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR send command function
   *
   * @param  word1: IR send data word 1
   * @param  word0: IR send data word 0
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_SendCommand(uint32_t word1,uint32_t word0)
  {
      uint32_t timeoutCnt = IR_TX_INT_TIMEOUT_COUNT;
      
      /* Write data */
      IR_SendData(IR_WORD_1,word1);
      IR_SendData(IR_WORD_0,word0);
      
      /* Mask tx interrupt */
      IR_IntMask(IR_INT_TX,MASK);
      
      /* Clear tx interrupt */
      IR_ClrIntStatus(IR_INT_TX);
      
      /* Enable ir tx */
      IR_Enable(IR_TX);
      
      /* Wait for tx interrupt */
      while(SET != IR_GetIntStatus(IR_INT_TX)){
          timeoutCnt--;
          if(timeoutCnt == 0){
              IR_Disable(IR_TX);
              
              return TIMEOUT;
          }
      }
      
      /* Disable ir tx */
      IR_Disable(IR_TX);
      
      /* Clear tx interrupt */
      IR_ClrIntStatus(IR_INT_TX);
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR send command in software mode function
   *
   * @param  data: IR fifo data to send
   * @param  length: Length of data
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_SWMSendCommand(uint16_t* data,uint8_t length)
  {
      uint32_t timeoutCnt = IR_TX_INT_TIMEOUT_COUNT;
      
      /* Write fifo */
      IR_SWMSendData(data,length);
      
      /* Mask tx interrupt */
      IR_IntMask(IR_INT_TX,MASK);
      
      /* Clear tx interrupt */
      IR_ClrIntStatus(IR_INT_TX);
      
      /* Enable ir tx */
      IR_Enable(IR_TX);
      
      /* Wait for tx interrupt */
      while(SET != IR_GetIntStatus(IR_INT_TX)){
          timeoutCnt--;
          if(timeoutCnt == 0){
              IR_Disable(IR_TX);
              
              return TIMEOUT;
          }
      }
      
      /* Disable ir tx */
      IR_Disable(IR_TX);
      
      /* Clear tx interrupt */
      IR_ClrIntStatus(IR_INT_TX);
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR send in NEC protocol
   *
   * @param  address: Address
   * @param  command: Command
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_SendNEC(uint8_t address,uint8_t command)
  {
      uint32_t tmpVal = ((~command&0xff)<<24)+(command<<16)+((~address&0xff)<<8)+address;
      
      IR_SendCommand(0,tmpVal);
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR interrupt mask or unmask function
   *
   * @param  intType: IR interrupt type
   * @param  intMask: Mask or unmask
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_IntMask(IR_INT_Type intType,BL_Mask_Type intMask)
  {
      uint32_t tmpVal;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_INT_TYPE(intType));
      
      if(intType == IR_INT_TX || intType == IR_INT_ALL){
          /* Mask or unmask tx interrupt */
          tmpVal = BL_RD_REG(IR_BASE,IRTX_INT_STS);
          BL_WR_REG(IR_BASE,IRTX_INT_STS,BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_END_MASK,intMask));
      }
  
      if(intType == IR_INT_RX || intType == IR_INT_ALL){
          /* Mask or unmask rx interrupt */
          tmpVal = BL_RD_REG(IR_BASE,IRRX_INT_STS);
          BL_WR_REG(IR_BASE,IRRX_INT_STS,BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_END_MASK,intMask));
      }
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  Clear ir interrupt function
   *
   * @param  intType: IR interrupt type
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_ClrIntStatus(IR_INT_Type intType)
  {
      uint32_t tmpVal;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_INT_TYPE(intType));
      
      if(intType == IR_INT_TX || intType == IR_INT_ALL){
          /* Clear tx interrupt */
          tmpVal = BL_RD_REG(IR_BASE,IRTX_INT_STS);
          BL_WR_REG(IR_BASE,IRTX_INT_STS,BL_SET_REG_BIT(tmpVal,IR_CR_IRTX_END_CLR));
      }
  
      if(intType == IR_INT_RX || intType == IR_INT_ALL){
          /* Clear rx interrupt */
          tmpVal = BL_RD_REG(IR_BASE,IRRX_INT_STS);
          BL_WR_REG(IR_BASE,IRRX_INT_STS,BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_END_CLR));
      }
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR install interrupt callback function
   *
   * @param  intType: IR interrupt type
   * @param  cbFun: Pointer to interrupt callback function. The type should be void (*fn)(void)
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_Int_Callback_Install(IR_INT_Type intType,intCallback_Type *cbFun)
  {
      /* Check the parameters */
      CHECK_PARAM(IS_IR_INT_TYPE(intType));
      
      irIntCbfArra[intType] = cbFun;
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR get interrupt status function
   *
   * @param  intType: IR int type
   *
   * @return IR tx or rx interrupt status
   *
  *******************************************************************************/
  BL_Sts_Type IR_GetIntStatus(IR_INT_Type intType)
  {
      uint32_t tmpVal = 0;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_INT_TYPE(intType));
      
      /* Read tx or rx interrupt status */
      if(IR_INT_TX == intType){
          tmpVal = BL_RD_REG(IR_BASE,IRTX_INT_STS);
          tmpVal = BL_GET_REG_BITS_VAL(tmpVal,IRTX_END_INT);
      }
      else if(IR_INT_RX == intType){
          tmpVal = BL_RD_REG(IR_BASE,IRRX_INT_STS);
          tmpVal = BL_GET_REG_BITS_VAL(tmpVal,IRRX_END_INT);
      }
      
      if(tmpVal)
      {
          return SET;
      }else{
          return RESET;
      }
  }
  
  /****************************************************************************//**
   * @brief  IR get rx fifo underflow or overflow status function
   *
   * @param  fifoSts: IR fifo status type
   *
   * @return IR rx fifo status
   *
  *******************************************************************************/
  BL_Sts_Type IR_GetRxFIFOStatus(IR_FifoStatus_Type fifoSts)
  {
      uint32_t tmpVal;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_FIFOSTATUS_TYPE(fifoSts));
      
      /* Read rx fifo status */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_SWM_FIFO_CONFIG_0);
      if(fifoSts == IR_RX_FIFO_UNDERFLOW){
          tmpVal = BL_GET_REG_BITS_VAL(tmpVal,IR_RX_FIFO_UNDERFLOW);
      }else{
          tmpVal = BL_GET_REG_BITS_VAL(tmpVal,IR_RX_FIFO_OVERFLOW);
      }
      
      if(tmpVal){
          return SET;
      }else{
          return RESET;
      }
  }
  
  /****************************************************************************//**
   * @brief  IR receive data function
   *
   * @param  irWord: IR rx data word 0 or 1
   *
   * @return Data received
   *
  *******************************************************************************/
  uint32_t IR_ReceiveData(IR_Word_Type irWord)
  {
      uint32_t tmpVal;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_WORD_TYPE(irWord));
      
      /* Read word 0 or word 1 */
      if(IR_WORD_0 == irWord){
          tmpVal = BL_RD_REG(IR_BASE,IRRX_DATA_WORD0);
      }
      else{
          tmpVal = BL_RD_REG(IR_BASE,IRRX_DATA_WORD1);
      }
      return tmpVal;
  }
  
  /****************************************************************************//**
   * @brief  IR software mode receive pulse width data function
   *
   * @param  data: Data received
   * @param  length: Max length of receive buffer
   *
   * @return Length of datas received
   *
  *******************************************************************************/
  uint8_t IR_SWMReceiveData(uint16_t* data,uint8_t length)
  {
      uint8_t rxLen = 0;
      
      while(rxLen<length && IR_GetRxFIFOCount()>0){
          /* Read data */
          data[rxLen++] = BL_RD_REG(IR_BASE,IRRX_SWM_FIFO_RDATA)&0xffff;
      }
      return rxLen;
  }
  
  /****************************************************************************//**
   * @brief  IR receive in NEC protocol
   *
   * @param  address: Address
   * @param  command: Command
   *
   * @return SUCCESS or ERROR
   *
  *******************************************************************************/
  BL_Err_Type IR_ReceiveNEC(uint8_t* address,uint8_t* command)
  {
      uint32_t tmpVal = IR_ReceiveData(IR_WORD_0);
      
      *address = tmpVal&0xff;
      *command = (tmpVal>>16)&0xff;
      
      if((~(*address)&0xff) != ((tmpVal>>8)&0xff) || (~(*command)&0xff) != ((tmpVal>>24)&0xff)){
          return ERROR;
      }
      
      return SUCCESS;
  }
  
  /****************************************************************************//**
   * @brief  IR get rx data bit count function
   *
   * @param  None
   *
   * @return IR rx data bit count
   *
  *******************************************************************************/
  uint8_t IR_GetRxDataBitCount(void)
  {
      uint32_t tmpVal;
      
      /* Read rx data bit count */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_DATA_COUNT);
      tmpVal = BL_GET_REG_BITS_VAL(tmpVal,IR_STS_IRRX_DATA_CNT);
      
      return tmpVal;
  }
  
  /****************************************************************************//**
   * @brief  IR get rx fifo count function
   *
   * @param  None
   *
   * @return IR rx fifo available count
   *
  *******************************************************************************/
  uint8_t IR_GetRxFIFOCount(void)
  {
      uint32_t tmpVal;
      
      /* Read rx fifo count */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_SWM_FIFO_CONFIG_0);
      tmpVal = BL_GET_REG_BITS_VAL(tmpVal,IR_RX_FIFO_CNT);
      
      return tmpVal;
  }
  
  /****************************************************************************//**
   * @brief  IR learning to set rx and tx mode function
   *
   * @param  data: Buffer to save data
   * @param  length: Length of data
   *
   * @return Protocol type
   *
  *******************************************************************************/
  IR_RxMode_Type IR_LearnToInit(uint32_t* data,uint8_t* length)
  {
      uint32_t tmpVal;
      uint32_t timeoutCnt = IR_RX_INT_TIMEOUT_COUNT;
      
      /* Disable rx,set rx in software mode and enable rx input inverse */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_CONFIG);
      tmpVal = BL_CLR_REG_BIT(tmpVal,IR_CR_IRRX_EN);
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_MODE,0x2);
      tmpVal = BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_IN_INV);
      BL_WR_REG(IR_BASE,IRRX_CONFIG,tmpVal);
      /* Set pulse width threshold to trigger end condition */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_PW_CONFIG);
      BL_WR_REG(IR_BASE,IRRX_PW_CONFIG,BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_END_TH,19999));
      
      /* Clear and mask rx interrupt */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_INT_STS);
      tmpVal = BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_END_MASK);
      BL_WR_REG(IR_BASE,IRRX_INT_STS,BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_END_CLR));
      
      /* Enable rx */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_CONFIG);
      BL_WR_REG(IR_BASE,IRRX_CONFIG,BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_EN));
      
      /* Wait for rx interrupt */
      while(SET != IR_GetIntStatus(IR_INT_RX)){
          timeoutCnt--;
          if(timeoutCnt == 0){
              IR_Disable(IR_RX);
              
              return IR_RX_SWM;
          }
      }
      
      /* Disable rx */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_CONFIG);
      BL_WR_REG(IR_BASE,IRRX_CONFIG,BL_CLR_REG_BIT(tmpVal,IR_CR_IRRX_EN));
      
      /* Clear rx interrupt */
      tmpVal = BL_RD_REG(IR_BASE,IRRX_INT_STS);
      BL_WR_REG(IR_BASE,IRRX_INT_STS,BL_SET_REG_BIT(tmpVal,IR_CR_IRRX_END_CLR));
      
      /*Receive data */
      *length = IR_GetRxFIFOCount();
      *length = IR_SWMReceiveData((uint16_t*)data,*length);
      
      /* Judge protocol type */
      if(NEC_HEAD_H_MIN<(data[0]&0xffff)&&(data[0]&0xffff)<NEC_HEAD_H_MAX&&NEC_HEAD_L_MIN<(data[0]>>16)&&(data[0]>>16)<NEC_HEAD_L_MAX&&NEC_BIT0_H_MIN<(data[1]&0xffff)&&(data[1]&0xffff)<NEC_BIT0_H_MAX){
          /* Set rx in NEC mode */
          tmpVal = BL_RD_REG(IR_BASE,IRRX_CONFIG);
          BL_WR_REG(IR_BASE,IRRX_CONFIG,BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_MODE,0x0));
          /* Set pulse width threshold to trigger end condition and pulse width threshold for logic0/1 detection */
          BL_WR_REG(IR_BASE,IRRX_PW_CONFIG,0x23270d47);
          /* Set tx in NEC mode */
          /* Tx configure */
          BL_WR_REG(IR_BASE,IRTX_CONFIG,0x1f514);
          /* Set logic 0,logic 1,head and tail pulse width */
          BL_WR_REG(IR_BASE,IRTX_PW,0x7f2000);
          /* Set modulation phase width and pulse width unit */
          BL_WR_REG(IR_BASE,IRTX_PULSE_WIDTH,0x22110464);
          
          return IR_RX_NEC;
      }
      else if(RC5_ONE_PLUSE_MIN<(data[0]&0xffff)&&(data[0]&0xffff)<RC5_ONE_PLUSE_MAX&&((RC5_ONE_PLUSE_MIN<(data[0]>>16)&&(data[0]>>16)<RC5_ONE_PLUSE_MAX)||(RC5_TWO_PLUSE_MIN<(data[0]>>16)&&(data[0]>>16)<RC5_TWO_PLUSE_MAX))&& \
              ((RC5_ONE_PLUSE_MIN<(data[1]&0xffff)&&(data[1]&0xffff)<RC5_ONE_PLUSE_MAX)||(RC5_TWO_PLUSE_MIN<(data[1]&0xffff)&&(data[1]&0xffff)<RC5_TWO_PLUSE_MAX))){
          /* Set rx in RC-5 mode */
          tmpVal = BL_RD_REG(IR_BASE,IRRX_CONFIG);
          BL_WR_REG(IR_BASE,IRRX_CONFIG,BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_MODE,0x1));
          /* Set pulse width threshold to trigger end condition and pulse width threshold for logic0/1 detection */
          BL_WR_REG(IR_BASE,IRRX_PW_CONFIG,0x13870a6a);
          /* Set tx in RC-5 mode */
          /* Tx configure */
          BL_WR_REG(IR_BASE,IRTX_CONFIG,0xc134);
          /* Set logic 0,logic 1,head and tail pulse width */
          BL_WR_REG(IR_BASE,IRTX_PW,0);
          /* Set modulation phase width and pulse width unit */
          BL_WR_REG(IR_BASE,IRTX_PULSE_WIDTH,0x221106f1);
          
          return IR_RX_RC5;
      }else if((data[0]>>16) != 0){
          /* Set tx in software mode */
          /* Tx configure */
          BL_WR_REG(IR_BASE,IRTX_CONFIG,*length<<12 | 0xc);
          /* Set modulation phase width */
          BL_WR_REG(IR_BASE,IRTX_PULSE_WIDTH,0x22110000);
          
          return IR_RX_SWM;
      }else{
          tmpVal = BL_RD_REG(IR_BASE,IRRX_CONFIG);
          tmpVal = BL_GET_REG_BITS_VAL(tmpVal,IR_CR_IRRX_MODE);
          if(tmpVal == 0){
              return IR_RX_NEC;
          }else if(tmpVal == 1){
              return IR_RX_RC5;
          }else{
              return IR_RX_SWM;
          }
      }
  }
  
  /****************************************************************************//**
   * @brief  IR receive data according to mode which is learned function
   *
   * @param  mode: Protocol type
   * @param  data: Buffer to save data
   *
   * @return Length of data
   *
  *******************************************************************************/
  uint8_t IR_LearnToReceive(IR_RxMode_Type mode,uint32_t* data)
  {
      uint8_t length = 0;
      uint32_t timeoutCnt = IR_RX_INT_TIMEOUT_COUNT;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_RXMODE_TYPE(mode));
      
      /* Disable ir rx */
      IR_Disable(IR_RX);
      
      /* Clear and mask rx interrupt */
      IR_ClrIntStatus(IR_INT_RX);
      IR_IntMask(IR_INT_RX,MASK);
      
      /* Enable ir rx */
      IR_Enable(IR_RX);
      
      /* Wait for rx interrupt */
      while(SET != IR_GetIntStatus(IR_INT_RX)){
          timeoutCnt--;
          if(timeoutCnt == 0){
              IR_Disable(IR_RX);
              
              return TIMEOUT;
          }
      }
      
      /* Disable ir rx */
      IR_Disable(IR_RX);
      
      /* Clear rx interrupt */
      IR_ClrIntStatus(IR_INT_RX);
      
      /* Receive data according to mode */
      if(mode == IR_RX_NEC || mode == IR_RX_RC5){
          /* Get data bit count */
          length = IR_GetRxDataBitCount();
          data[0] = IR_ReceiveData(IR_WORD_0);
      }else{
          /* Get fifo count */
          length = IR_GetRxFIFOCount();
          length = IR_SWMReceiveData((uint16_t*)data,length);
      }
      
      return length;
  }
  
  
  /****************************************************************************//**
   * @brief  IR send data according to mode which is learned function
   *
   * @param  mode: Protocol type
   * @param  data: Buffer of data to send
   * @param  length: Length of data
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_LearnToSend(IR_RxMode_Type mode,uint32_t* data,uint8_t length)
  {
      uint32_t tmpVal;
      
      /* Check the parameters */
      CHECK_PARAM(IS_IR_RXMODE_TYPE(mode));
      
      /* Set send length */
      tmpVal = BL_RD_REG(IR_BASE,IRTX_CONFIG);
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal,IR_CR_IRTX_DATA_NUM,length-1);
      BL_WR_REG(IR_BASE,IRTX_CONFIG,tmpVal);
      
      if(mode == IR_RX_NEC || mode == IR_RX_RC5){
          IR_SendCommand(0,data[0]);
      }else{
          IR_SWMSendCommand((uint16_t*)data,length);
      }
      
      return SUCCESS;
  }
  
  
  /****************************************************************************//**
   * @brief  IR init to control led function
   *
   * @param  clk: Clock source
   * @param  div: Clock division(1~64)
   * @param  unit: Pulse width unit(multiples of clock pulse width, 1~4096)
   * @param  code0H: code 0 high level time(multiples of pulse width unit, 1~16)
   * @param  code0L: code 0 low level time(multiples of pulse width unit, 1~16)
   * @param  code1H: code 1 high level time(multiples of pulse width unit, 1~16)
   * @param  code1L: code 1 low level time(multiples of pulse width unit, 1~16)
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_LEDInit(HBN_XCLK_CLK_Type clk,uint8_t div,uint8_t unit,uint8_t code0H,uint8_t code0L,uint8_t code1H,uint8_t code1L)
  {
      IR_TxCfg_Type txCfg = {
          24,                                                  /* 24-bit data */
          DISABLE,                                             /* Disable signal of tail pulse inverse */
          DISABLE,                                             /* Disable signal of tail pulse */
          DISABLE,                                             /* Disable signal of head pulse inverse */
          DISABLE,                                             /* Disable signal of head pulse */
          DISABLE,                                             /* Disable signal of logic 1 pulse inverse */
          DISABLE,                                             /* Disable signal of logic 0 pulse inverse */
          ENABLE,                                              /* Enable signal of data pulse */
          DISABLE,                                             /* Disable signal of output modulation */
          ENABLE                                               /* Enable signal of output inverse */
      };
      
      IR_TxPulseWidthCfg_Type txPWCfg = {
          code0L,                                              /* Pulse width of logic 0 pulse phase 1 */
          code0H,                                              /* Pulse width of logic 0 pulse phase 0 */
          code1L,                                              /* Pulse width of logic 1 pulse phase 1 */
          code1H,                                              /* Pulse width of logic 1 pulse phase 0 */
          1,                                                   /* Pulse width of head pulse phase 1 */
          1,                                                   /* Pulse width of head pulse phase 0 */
          1,                                                   /* Pulse width of tail pulse phase 1 */
          1,                                                   /* Pulse width of tail pulse phase 0 */
          1,                                                   /* Modulation phase 1 width */
          1,                                                   /* Modulation phase 0 width */
          unit                                                 /* Pulse width unit */
      };
      
      HBN_Set_XCLK_CLK_Sel(clk);
      GLB_Set_IR_CLK(ENABLE,GLB_IR_CLK_SRC_XCLK,div-1);
      
      /* Disable ir before config */
      IR_Disable(IR_TXRX);
  
      /* IR tx init */
      IR_TxInit(&txCfg);
      IR_TxPulseWidthConfig(&txPWCfg);
      
      return SUCCESS;
  }
  
  
  /****************************************************************************//**
   * @brief  IR send 24-bit data to control led function
   *
   * @param  data: Data to send(24-bit)
   *
   * @return SUCCESS
   *
  *******************************************************************************/
  BL_Err_Type IR_LEDSend(uint32_t data)
  {
      /* Change MSB_first to LSB_first */
      data = ((data>>1)&0x55555555)|((data<<1)&0xaaaaaaaa);
      data = ((data>>2)&0x33333333)|((data<<2)&0xcccccccc);
      data = ((data>>4)&0x0f0f0f0f)|((data<<4)&0xf0f0f0f0);
      data = ((data>>16)&0xff)|(data&0xff00)|((data<<16)&0xff0000);
      IR_SendCommand(0,data);
      
      return SUCCESS;
  }
  
  
  /*@} end of group IR_Public_Functions */
  
  /*@} end of group IR */
  
  /*@} end of group BL602_Peripheral_Driver */
  