/**
  ******************************************************************************
  * @file    ys32md211_crc.c
  * @author  YSPRING Application Team
  * @version V1.0.1
  * @date    2023.6.12
  * @brief   This file provides firmware functions to manage the following 
  *          functionalities of CRC computation unit peripheral:
  *            + Configuration of the CRC computation unit
  *            + CRC computation of one/many 32-bit data
  *
  *  @verbatim
 ===============================================================================
                     ##### How to use this driver #####
 ===============================================================================
    [..]
    
         (+) Enable CRC AHB clock using RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE)
             function
         (+) use CRC_CalcCRC() function to compute the CRC of a 32-bit data
             or use CRC_CalcBlockCRC() function to compute the CRC if a 32-bit 
             data buffer
         (+) use CRC_CalcBlockCRC16bits() or CRC_CalcBlockCRC8bits() function to compute 
		     the CRC if a 16-bit or 8-bit data buffer			 
            (@) To compute the CRC of a new data use CRC_ResetCRCCalculationUnit() to reset
                 the CRC computation unit before starting the computation
                 otherwise you can get wrong CRC values.
         (+) use CRC_CalibCRC() function to achieve CRC Calibration mode      
     @endverbatim
  *  
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "ys32md211_crc.h"

/** @addtogroup YS32MD211_StdPeriph_Driver
  * @{
  */

/** @defgroup CRC 
  * @brief CRC driver modules
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup CRC_Private_Functions
  * @{
  */

/** @defgroup CRC_Group1 Configuration of the CRC computation unit functions
 *  @brief   Configuration of the CRC computation unit functions 
 *
@verbatim
 ===============================================================================
                     ##### CRC configuration functions #####
 ===============================================================================

@endverbatim
  * @{
  */
 
 /**
  * @brief  Deinitializes CRC peripheral registers to their default reset values.
  * @param  None
  * @retval None
  */
void CRC_DeInit(void)
{
  /* Set DATA register to reset value */
  CRC->DATA = 0xFFFFFFFF;
  
  /* Reset the CRC calculation unit */
  CRC->RESULT = 0xFFFFFFFF;  
}
 
  /**
  * @brief  Resets the CRC calculation unit..
  * @param  None
  * @retval None
  */
void CRC_ResetCRCCalculationUnit(void)
{
  /* Reset CRC generator */
  CRC->RESULT = CRC_Result_Reset;
}

/**
  * @}
  */



/** @defgroup CRC_Group2 CRC computation of one/many 32-bit data functions
 *  @brief   CRC computation of one/many 32-bit data functions
 *
@verbatim
 ===============================================================================
                     ##### CRC computation functions #####
 ===============================================================================

@endverbatim
  * @{
  */

/**
  * @brief  Calibrates the 32-bit CRC value.
  * @param  CRC_Data: the expected CRC value
  * @retval None
  */
void CRC_CalibCRC(uint32_t CRC_Data)
{
  CRC->DATA = CRC_Data;
}



/**
  * @brief  Computes the 32-bit CRC of a given data word(32-bit).
  * @param  CRC_Data: data word(32-bit) to compute its CRC
  * @retval 32-bit CRC
  */
uint32_t CRC_CalcCRC(uint32_t CRC_Data)
{
  CRC->DATA = CRC_Data;
  
  return (CRC->DATA);
}


/**
  * @brief  Computes the 32-bit CRC of a given buffer of data word(32-bit).
  * @param  InData Data Array 32 bit value to be provided to CRC calculator between between Min_Data=0 and Max_Data=0xFFFFFFFF
  * @param  DataSize: length of the buffer to be computed
  * @retval result: 32-bit CRC check result
  */
uint32_t CRC_CalcBlockCRC(uint32_t *InData, uint32_t DataSize)
{
  uint32_t i = 0;
  
  for(i = 0; i < DataSize; i++)
  {
    CRC->DATA = *(InData + i);
  }
  return (CRC->RESULT);
}

/**
  * @brief  Write given 16-bit data to the CRC calculator
  * @param  InData Data Array 16 bit value to be provided to CRC calculator between between Min_Data=0 and Max_Data=0xFFFF
  * @param  BufferLength the size of Input Data array. It can only be a multiple of 2, and if not, the Initial Data will be supplemented by 0
  * @note   A CRC Result is calculated only when the DATA register receives 32bit data
  * @retval None
  */
uint32_t CRC_CalcBlockCRC16bits(uint16_t *InData, uint32_t BufferLength)
{
  volatile uint16_t *p;
  uint32_t i;
  uint32_t pos;
    
  p = (uint16_t *)(&(CRC->DATA));
  for(i = 0; i < BufferLength; i++)
  {
    *(p + (i % 2)) = *(InData + i);
  }
  
  if(BufferLength % 2 != 0)
  {
      pos = (i % 4);
      for(i = 0; i < (2 - BufferLength % 2); i++, pos++)
      {
          *(p + pos) = 0x0000;
      }
  }
  return (CRC->RESULT);
}

/**
  * @brief  Write given 8-bit data to the CRC calculator
  * @param  InData Data Array 8 bit value to be provided to CRC calculator between between Min_Data=0 and Max_Data=0xFF
  * @param  BufferLength the size of Input Data array. It can only be a multiple of 4, and if not, the Initial Data will be supplemented by 0
  * @note   A CRC Result is calculated only when the DATA register receives 32bit data
  * @retval None
  */
uint32_t CRC_CalcBlockCRC8bits(uint8_t *InData, uint32_t BufferLength)
{
  volatile uint8_t *p;
  uint32_t i;
  uint32_t pos;
    
  p = (uint8_t *)(&(CRC->DATA));
  for(i = 0; i < BufferLength; i++)
  {
    *(p + (i % 4)) = *(InData + i);
  }
  
  if(BufferLength % 4 != 0)
  {
      pos = (i % 4);
      for(i = 0; i < (4 - BufferLength % 4); i++, pos++)
      {
          *(p + pos) = 0x00;
      }
  }
  return (CRC->RESULT);
}

/**
  * @brief  Returns the current CRC value.
  * @param  None
  * @retval 32-bit CRC
  */
uint32_t CRC_GetCRC(void)
{
  return (CRC->RESULT);
}

/**
  * @brief  Checks the CRC calibrate result flag
  * @param  FLAG: CRC check result flag
  *            @arg CRC_FLAG: CRC calibrate result flag
  * @retval state: The CRC_FLAG state(SET or RESET).
  */
FlagStatus CRC_GetFlagStatus(uint16_t FLAG)
{
    FlagStatus bitstatus = RESET; 

    assert_param(IS_CRC_FLAG(FLAG));

    if (CRC->SR & FLAG)
    {
        bitstatus = SET;
    }
    else
    {
        bitstatus = RESET;
    }
    
    return bitstatus;
}

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */
  

