/**
  * @brief  DMA IRDA receive process complete callback.
  * @param  hdma: DMA handle
  * @retval None
  */
static void IRDA_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
  IRDA_HandleTypeDef* hirda = ( IRDA_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
  /* DMA Normal mode */
  if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U)
  {
    hirda->RxXferCount = 0U;

    /* Disable the DMA transfer for the receiver request by setting the DMAR bit
       in the IRDA CR3 register */
    hirda->Instance->CR3 &= (uint16_t)~((uint16_t)USART_CR3_DMAR);

	/* At end of Rx process, restore hirda->RxState to Ready */
    hirda->RxState = HAL_IRDA_STATE_READY;
  }

  HAL_IRDA_RxCpltCallback(hirda);
}
/**
  * @brief DMA IRDA Rx Transfer completed callback 
  * @param hdma: DMA handle
  * @retval None
  */
static void IRDA_DMAReceiveCplt(DMA_HandleTypeDef *hdma)  
{
  IRDA_HandleTypeDef* hirda = ( IRDA_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
  hirda->RxXferCount = 0;
  
  /* Disable the DMA transfer for the receiver request by setting the DMAR bit 
     in the IRDA CR3 register */
  hirda->Instance->CR3 &= (uint16_t)~((uint16_t)USART_CR3_DMAR);
  
  if(hirda->State == HAL_IRDA_STATE_BUSY_TX_RX) 
  {
    hirda->State = HAL_IRDA_STATE_BUSY_TX;
  }
  else
  {
    hirda->State = HAL_IRDA_STATE_READY;
  }

  HAL_IRDA_RxCpltCallback(hirda);
}
/**
  * @brief  DMA IRDA receive process complete callback. 
  * @param  hdma: Pointer to a DMA_HandleTypeDef structure that contains
  *               the configuration information for the specified DMA module.
  * @retval None
  */
static void IRDA_DMAReceiveCplt(DMA_HandleTypeDef *hdma)   
{
  IRDA_HandleTypeDef* hirda = ( IRDA_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
  /* DMA Normal mode */
  if ( HAL_IS_BIT_CLR(hdma->Instance->CCR, DMA_CCR_CIRC) )
  {
    hirda->RxXferCount = 0;

    /* Disable the DMA transfer for the receiver request by setting the DMAR bit 
       in the IRDA CR3 register */
    CLEAR_BIT(hirda->Instance->CR3, USART_CR3_DMAR);

    if(hirda->State == HAL_IRDA_STATE_BUSY_TX_RX) 
    {
      hirda->State = HAL_IRDA_STATE_BUSY_TX;
    }
    else
    {
      hirda->State = HAL_IRDA_STATE_READY;
    }
  }

  HAL_IRDA_RxCpltCallback(hirda);
}
/**
  * @brief  Receive an amount of data in non-blocking mode. 
  * @param  hirda: Pointer to a IRDA_HandleTypeDef structure that contains
  *                the configuration information for the specified IRDA module.
  * @retval HAL status
  */
static HAL_StatusTypeDef IRDA_Receive_IT(IRDA_HandleTypeDef *hirda)
{
  uint16_t* tmp = 0;
  uint32_t tmp_state = 0;

  tmp_state = hirda->State;  
  if((tmp_state == HAL_IRDA_STATE_BUSY_RX) || (tmp_state == HAL_IRDA_STATE_BUSY_TX_RX))
  {
    if(hirda->Init.WordLength == IRDA_WORDLENGTH_9B)
    {
      tmp = (uint16_t*) hirda->pRxBuffPtr;
      if(hirda->Init.Parity == IRDA_PARITY_NONE)
      {
        *tmp = (uint16_t)(hirda->Instance->DR & IRDA_DR_MASK_U16_9DATABITS);
        hirda->pRxBuffPtr += 2;
      }
      else
      {
        *tmp = (uint16_t)(hirda->Instance->DR & IRDA_DR_MASK_U16_8DATABITS);
        hirda->pRxBuffPtr += 1;
      }
    } 
    else
    {
      if(hirda->Init.Parity == IRDA_PARITY_NONE)
      {
        *hirda->pRxBuffPtr++ = (uint8_t)(hirda->Instance->DR & IRDA_DR_MASK_U8_8DATABITS);
      }
      else
      {
        *hirda->pRxBuffPtr++ = (uint8_t)(hirda->Instance->DR & IRDA_DR_MASK_U8_7DATABITS);
      }
    }

    if(--hirda->RxXferCount == 0)
    {

      __HAL_IRDA_DISABLE_IT(hirda, IRDA_IT_RXNE);
      
      if(hirda->State == HAL_IRDA_STATE_BUSY_TX_RX) 
      {
        hirda->State = HAL_IRDA_STATE_BUSY_TX;
      }
      else
      {
        /* Disable the IRDA Parity Error Interrupt */
        __HAL_IRDA_DISABLE_IT(hirda, IRDA_IT_PE);

        /* Disable the IRDA Error Interrupt: (Frame error, noise error, overrun error) */
        __HAL_IRDA_DISABLE_IT(hirda, IRDA_IT_ERR);

        hirda->State = HAL_IRDA_STATE_READY;
      }
      HAL_IRDA_RxCpltCallback(hirda);

      return HAL_OK;
    }
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
}
/**
 * @brief  Receives an amount of data in non blocking mode. 
 * @param  hirda: IRDA handle
 * @retval HAL status
 */
static HAL_StatusTypeDef IRDA_Receive_IT(IRDA_HandleTypeDef *hirda)
{
	uint16_t* tmp;
	uint32_t tmp1 = 0;

	tmp1 = hirda->State;
	if((tmp1 == HAL_IRDA_STATE_BUSY_RX) || (tmp1 == HAL_IRDA_STATE_BUSY_TX_RX))
	{
		/* Process Locked */
		__HAL_LOCK(hirda);

		if(hirda->Init.WordLength == IRDA_WORDLENGTH_9B)
		{
			tmp = (uint16_t*) hirda->pRxBuffPtr;
			if(hirda->Init.Parity == IRDA_PARITY_NONE)
			{
				*tmp = (uint16_t)(hirda->Instance->DR & (uint16_t)0x01FF);
				hirda->pRxBuffPtr += 2;
			}
			else
			{
				*tmp = (uint16_t)(hirda->Instance->DR & (uint16_t)0x00FF);
				hirda->pRxBuffPtr += 1;
			}
		}
		else
		{
			if(hirda->Init.Parity == IRDA_PARITY_NONE)
			{
				*hirda->pRxBuffPtr++ = (uint8_t)(hirda->Instance->DR & (uint8_t)0x00FF);
			}
			else
			{
				*hirda->pRxBuffPtr++ = (uint8_t)(hirda->Instance->DR & (uint8_t)0x007F);
			}
		}

		if(--hirda->RxXferCount == 0)
		{
			while(HAL_IS_BIT_SET(hirda->Instance->SR, IRDA_FLAG_RXNE))
			{
			}
			__HAL_IRDA_DISABLE_IT(hirda, IRDA_IT_RXNE);

			if(hirda->State == HAL_IRDA_STATE_BUSY_TX_RX)
			{
				hirda->State = HAL_IRDA_STATE_BUSY_TX;
			}
			else
			{
				/* Disable the IRDA Parity Error Interrupt */
				__HAL_IRDA_DISABLE_IT(hirda, IRDA_IT_PE);

				/* Disable the IRDA Error Interrupt: (Frame error, noise error, overrun error) */
				__HAL_IRDA_DISABLE_IT(hirda, IRDA_IT_ERR);

				hirda->State = HAL_IRDA_STATE_READY;
			}
			/* Call the Process Unlocked before calling the Rx call back API to give the possibiity to
			 start again the receiption under the Rx call back API */
			__HAL_UNLOCK(hirda);

			HAL_IRDA_RxCpltCallback(hirda);

			return HAL_OK;
		}

		/* Process Unlocked */
		__HAL_UNLOCK(hirda);

		return HAL_OK;
	}
	else
	{
		return HAL_BUSY;
	}
}