/**
  * @brief  Receives an amount of data (Control Flow) in blocking mode.
  * @param  hspdif: pointer to a SPDIFRX_HandleTypeDef structure that contains
  *                 the configuration information for SPDIFRX module.
  * @param  pData: Pointer to data buffer
  * @param  Size: Amount of data to be received
  * @param  Timeout: Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPDIFRX_ReceiveControlFlow(SPDIFRX_HandleTypeDef *hspdif, uint32_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint32_t tickstart = 0U;

  if((pData == NULL ) || (Size == 0U))
  {
    return  HAL_ERROR;
  }

  if(hspdif->State == HAL_SPDIFRX_STATE_READY)
  {
    /* Process Locked */
    __HAL_LOCK(hspdif);

    hspdif->State = HAL_SPDIFRX_STATE_BUSY;

    /* Start synchronization */
    __HAL_SPDIFRX_SYNC(hspdif);

    /* Get tick */
    tickstart = HAL_GetTick();

    /* Wait until SYNCD flag is set */
    if(SPDIFRX_WaitOnFlagUntilTimeout(hspdif, SPDIFRX_FLAG_SYNCD, RESET, Timeout, tickstart) != HAL_OK)
    {
      return HAL_TIMEOUT;
    }

    /* Start reception */
    __HAL_SPDIFRX_RCV(hspdif);

    /* Receive control flow */
    while(Size > 0U)
    {
      /* Get tick */
      tickstart = HAL_GetTick();

      /* Wait until CSRNE flag is set */
      if(SPDIFRX_WaitOnFlagUntilTimeout(hspdif, SPDIFRX_FLAG_CSRNE, RESET, Timeout, tickstart) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }

      (*pData++) = hspdif->Instance->CSR;
      Size--;
    }

    /* SPDIFRX ready */
    hspdif->State = HAL_SPDIFRX_STATE_READY;

    /* Process Unlocked */
    __HAL_UNLOCK(hspdif);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}
/**
  * @brief Receive an amount of data (Data Flow) mode with DMA 
  * @param hspdif: SPDIFRX handle
  * @param pData: a 32-bit pointer to the Receive data buffer.
  * @param Size: number of data sample to be received :
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPDIFRX_ReceiveDataFlow_DMA(SPDIFRX_HandleTypeDef *hspdif, uint32_t *pData, uint16_t Size)
{
  
  if((pData == NULL) || (Size == 0)) 
  {
    return  HAL_ERROR;                                    
  } 
  
  if((hspdif->State == HAL_SPDIFRX_STATE_READY) || (hspdif->State == HAL_SPDIFRX_STATE_BUSY_CX))
  {   
    hspdif->pRxBuffPtr = pData;
    hspdif->RxXferSize = Size;
    hspdif->RxXferCount = Size;

    /* Process Locked */
    __HAL_LOCK(hspdif);
    
    hspdif->ErrorCode = HAL_SPDIFRX_ERROR_NONE;
    hspdif->State = HAL_SPDIFRX_STATE_BUSY_RX;
    
    /* Set the SPDIFRX Rx DMA Half transfer complete callback */
    hspdif->hdmaDrRx->XferHalfCpltCallback = SPDIFRX_DMARxHalfCplt;
    
    /* Set the SPDIFRX Rx DMA transfer complete callback */
    hspdif->hdmaDrRx->XferCpltCallback = SPDIFRX_DMARxCplt;
    
    /* Set the DMA error callback */
    hspdif->hdmaDrRx->XferErrorCallback = SPDIFRX_DMAError;
       
    /* Enable the DMA request */
    HAL_DMA_Start_IT(hspdif->hdmaDrRx, (uint32_t)&hspdif->Instance->DR, (uint32_t)hspdif->pRxBuffPtr, Size);

    /* Enable RXDMAEN bit in SPDIFRX CR register for data flow reception*/
     hspdif->Instance->CR |= SPDIFRX_CR_RXDMAEN;
             
        if ((SPDIFRX->CR & SPDIFRX_CR_SPDIFEN) != SPDIFRX_STATE_SYNC || (SPDIFRX->CR & SPDIFRX_CR_SPDIFEN) != 0x00) 
        {
        /* Start synchronization */
        __HAL_SPDIFRX_SYNC(hspdif);
        
        /* Wait until SYNCD flag is set */
      if(SPDIFRX_WaitOnFlagUntilTimeout(hspdif, SPDIFRX_FLAG_SYNCD, RESET, SPDIFRX_TIMEOUT_VALUE) != HAL_OK)
      { 
        return HAL_TIMEOUT;
      }  
            
        /* Start reception */    
      __HAL_SPDIFRX_RCV(hspdif);
        }
    
    /* Process Unlocked */
    __HAL_UNLOCK(hspdif);
     
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
}
/**
  * @brief Receive an amount of data (Control Flow) with Interrupt
  * @param hspdif: SPDIFRX handle
  * @param pData: a 32-bit pointer to the Receive data buffer.
  * @param Size: number of data sample (Control Flow) to be received :
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPDIFRX_ReceiveControlFlow_IT(SPDIFRX_HandleTypeDef *hspdif, uint32_t *pData, uint16_t Size)
{
 if((hspdif->State == HAL_SPDIFRX_STATE_READY) || (hspdif->State == HAL_SPDIFRX_STATE_BUSY_RX))
  {
    if((pData == NULL ) || (Size == 0)) 
    {
      return HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(hspdif);

    hspdif->pCsBuffPtr = pData;
    hspdif->CsXferSize = Size;
    hspdif->CsXferCount = Size;

    hspdif->ErrorCode = HAL_SPDIFRX_ERROR_NONE;
    
    /* Check if a receive process is ongoing or not */
     hspdif->State = HAL_SPDIFRX_STATE_BUSY_CX;


    /* Enable the SPDIFRX PE Error Interrupt */
     __HAL_SPDIFRX_ENABLE_IT(hspdif, SPDIFRX_IT_PERRIE);

    /* Enable the SPDIFRX OVR Error Interrupt */
     __HAL_SPDIFRX_ENABLE_IT(hspdif, SPDIFRX_IT_OVRIE);

    /* Process Unlocked */
    __HAL_UNLOCK(hspdif);

    /* Enable the SPDIFRX CSRNE interrupt */
    __HAL_SPDIFRX_ENABLE_IT(hspdif, SPDIFRX_IT_CSRNE);
        
        if ((SPDIFRX->CR & SPDIFRX_CR_SPDIFEN) != SPDIFRX_STATE_SYNC || (SPDIFRX->CR & SPDIFRX_CR_SPDIFEN) != 0x00) 
        {
        /* Start synchronization */
        __HAL_SPDIFRX_SYNC(hspdif);
        
        /* Wait until SYNCD flag is set */
      if(SPDIFRX_WaitOnFlagUntilTimeout(hspdif, SPDIFRX_FLAG_SYNCD, RESET, SPDIFRX_TIMEOUT_VALUE) != HAL_OK)
      { 
        return HAL_TIMEOUT;
      }  
                        
        /* Start reception */    
      __HAL_SPDIFRX_RCV(hspdif);
      }
        
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
}
/**
  * @brief Receive an amount of data (Control Flow) with DMA
  * @param hspdif SPDIFRX handle
  * @param pData a 32-bit pointer to the Receive data buffer.
  * @param Size number of data (Control Flow) sample to be received :
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPDIFRX_ReceiveControlFlow_DMA(SPDIFRX_HandleTypeDef *hspdif, uint32_t *pData, uint16_t Size)
{
  __IO uint32_t count = SPDIFRX_TIMEOUT_VALUE * (SystemCoreClock / 24U / 1000U);

  if((pData == NULL) || (Size == 0))
  {
    return  HAL_ERROR;
  }

  if((hspdif->State == HAL_SPDIFRX_STATE_READY) || (hspdif->State == HAL_SPDIFRX_STATE_BUSY_RX))
  {
    hspdif->pCsBuffPtr = pData;
    hspdif->CsXferSize = Size;
    hspdif->CsXferCount = Size;

    /* Process Locked */
    __HAL_LOCK(hspdif);

    hspdif->ErrorCode = HAL_SPDIFRX_ERROR_NONE;
    hspdif->State = HAL_SPDIFRX_STATE_BUSY_CX;

    /* Set the SPDIFRX Rx DMA Half transfer complete callback */
    hspdif->hdmaCsRx->XferHalfCpltCallback = SPDIFRX_DMACxHalfCplt;

    /* Set the SPDIFRX Rx DMA transfer complete callback */
    hspdif->hdmaCsRx->XferCpltCallback = SPDIFRX_DMACxCplt;

    /* Set the DMA error callback */
    hspdif->hdmaCsRx->XferErrorCallback = SPDIFRX_DMAError;

    /* Enable the DMA request */
    HAL_DMA_Start_IT(hspdif->hdmaCsRx, (uint32_t)&hspdif->Instance->CSR, (uint32_t)hspdif->pCsBuffPtr, Size);

    /* Enable CBDMAEN bit in SPDIFRX CR register for control flow reception*/
    hspdif->Instance->CR |= SPDIFRX_CR_CBDMAEN;

    if ((SPDIFRX->CR & SPDIFRX_CR_SPDIFEN) != SPDIFRX_STATE_SYNC || (SPDIFRX->CR & SPDIFRX_CR_SPDIFEN) != 0x00U)
    {
      /* Start synchronization */
      __HAL_SPDIFRX_SYNC(hspdif);

      /* Wait until SYNCD flag is set */
      do
      {
        if (count-- == 0U)
        {
          /* Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts for the interrupt process */
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_RXNE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_CSRNE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_PERRIE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_OVRIE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_SBLKIE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_SYNCDIE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_IFEIE);

          hspdif->State= HAL_SPDIFRX_STATE_READY;

          /* Process Unlocked */
          __HAL_UNLOCK(hspdif);

          return HAL_TIMEOUT;
        }
      }
      while (__HAL_SPDIFRX_GET_FLAG(hspdif, SPDIFRX_FLAG_SYNCD) == RESET);

      /* Start reception */
      __HAL_SPDIFRX_RCV(hspdif);
    }

    /* Process Unlocked */
    __HAL_UNLOCK(hspdif);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}
/**
  * @brief Receive an amount of data (Control Flow) with Interrupt
  * @param hspdif SPDIFRX handle
  * @param pData a 32-bit pointer to the Receive data buffer.
  * @param Size number of data sample (Control Flow) to be received :
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPDIFRX_ReceiveControlFlow_IT(SPDIFRX_HandleTypeDef *hspdif, uint32_t *pData, uint16_t Size)
{
  __IO uint32_t count = SPDIFRX_TIMEOUT_VALUE * (SystemCoreClock / 24U / 1000U);

  if((hspdif->State == HAL_SPDIFRX_STATE_READY) || (hspdif->State == HAL_SPDIFRX_STATE_BUSY_RX))
  {
    if((pData == NULL ) || (Size == 0))
    {
      return HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(hspdif);

    hspdif->pCsBuffPtr = pData;
    hspdif->CsXferSize = Size;
    hspdif->CsXferCount = Size;

    hspdif->ErrorCode = HAL_SPDIFRX_ERROR_NONE;

    /* Check if a receive process is ongoing or not */
    hspdif->State = HAL_SPDIFRX_STATE_BUSY_CX;

    /* Enable the SPDIFRX PE Error Interrupt */
    __HAL_SPDIFRX_ENABLE_IT(hspdif, SPDIFRX_IT_PERRIE);

    /* Enable the SPDIFRX OVR Error Interrupt */
    __HAL_SPDIFRX_ENABLE_IT(hspdif, SPDIFRX_IT_OVRIE);

    /* Process Unlocked */
    __HAL_UNLOCK(hspdif);

    /* Enable the SPDIFRX CSRNE interrupt */
    __HAL_SPDIFRX_ENABLE_IT(hspdif, SPDIFRX_IT_CSRNE);

    if ((SPDIFRX->CR & SPDIFRX_CR_SPDIFEN) != SPDIFRX_STATE_SYNC || (SPDIFRX->CR & SPDIFRX_CR_SPDIFEN) != 0x00U)
    {
      /* Start synchronization */
      __HAL_SPDIFRX_SYNC(hspdif);

      /* Wait until SYNCD flag is set */
      do
      {
        if (count-- == 0U)
        {
          /* Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts for the interrupt process */
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_RXNE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_CSRNE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_PERRIE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_OVRIE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_SBLKIE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_SYNCDIE);
          __HAL_SPDIFRX_DISABLE_IT(hspdif, SPDIFRX_IT_IFEIE);

          hspdif->State= HAL_SPDIFRX_STATE_READY;

          /* Process Unlocked */
          __HAL_UNLOCK(hspdif);

          return HAL_TIMEOUT;
        }
      }
      while (__HAL_SPDIFRX_GET_FLAG(hspdif, SPDIFRX_FLAG_SYNCD) == RESET);

      /* Start reception */
      __HAL_SPDIFRX_RCV(hspdif);
    }

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}