/**
  ******************************************************************************
  * @file    lcm32f06x_crc.c
  * @author  System R&D Team
  * @version V2.0.2
  * @date    10-April-2025
  * @brief   This file provides all the crc firmware functions.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) Hangzhou Lingxin Microelectronics Co.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "lcm32f06x_crc.h"

/**
  * @name   Crc_initial_config_8
  * @brief  EN: CRC-8 polynomial 0x07 initialization configuration.
  *         CN: CRC-8 多项式 0x07 初始化配置。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @param  CrcMode: 
  *         EN: CRC-8 polynomial 0x07 mode.
  *         CN: CRC-8 多项式 0x07 模式。
  *             @arg CRC_8
  *             @arg CRC_8_ITU
  *             @arg CRC_8_ROHC
  * @retval None
  */
void Crc_initial_config_8(CRC_TypeDef *CRCx, CRC_8_MODE_TypeDef CrcMode)
{
  if (CrcMode == CRC_8_ITU)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC8 | CRC_SWAP_00 | CRC_INVEN_LSB | CRC_LM_MSB | CRC_BYTE_1 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
  else if (CrcMode == CRC_8_ROHC)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC8 | CRC_SWAP_00 | CRC_INVEN_MSB | CRC_LM_LSB | CRC_BYTE_1 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
  else
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC8 | CRC_SWAP_00 | CRC_INVEN_LSB | CRC_LM_MSB | CRC_BYTE_1 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
}

/**
  * @name   Crc_initial_config_16a
  * @brief  EN: CRC-16 polynomial 0x8005 initialization configuration.
  *         CN: CRC-16 多项式 0x8005 初始化配置。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @param  CrcMode: 
  *         EN: CRC-16 polynomial 0x8005 mode.
  *         CN: CRC-16 多项式0x8005 模式。
  *             @arg CRC_16A_IBM
  *             @arg CRC_16A_MAXIM
  *             @arg CRC_16A_USB
  *             @arg CRC_16A_MODBUS
  * @retval None
  */
void Crc_initial_config_16a(CRC_TypeDef *CRCx, CRC_16A_MODE_TypeDef CrcMode)
{
  if (CrcMode == CRC_16A_IBM)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC16a | CRC_SWAP_00 | CRC_INVEN_MSB | CRC_LM_LSB | CRC_BYTE_2 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
  else if (CrcMode == CRC_16A_MAXIM)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC16a | CRC_SWAP_00 | CRC_INVEN_MSB | CRC_LM_LSB | CRC_BYTE_2 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
  else if (CrcMode == CRC_16A_USB)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC16a | CRC_SWAP_00 | CRC_INVEN_MSB | CRC_LM_LSB | CRC_BYTE_2 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
  else if (CrcMode == CRC_16A_MODBUS)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC16a | CRC_SWAP_00 | CRC_INVEN_MSB | CRC_LM_LSB | CRC_BYTE_2 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
}

/**
  * @name   Crc_initial_config_16b
  * @brief  EN: CRC-16 polynomial 0x1021 initialization configuration.
  *         CN: CRC-16 多项式 0x1021 初始化配置。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @param  CrcMode: 
  *         EN: CRC-16 polynomial 0x1021 mode.
  *         CN: CRC-16 0x1021 模式。
  *             @arg CRC_16B_CCITT
  *             @arg CRC_16B_CCITT_FALSE
  *             @arg CRC_16B_X25
  *             @arg CRC_16B_XMODEM
  * @retval None
  */
void Crc_initial_config_16b(CRC_TypeDef *CRCx, CRC_16B_MODE_TypeDef CrcMode)
{
  if (CrcMode == CRC_16B_CCITT)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC16b | CRC_SWAP_00 | CRC_INVEN_MSB | CRC_LM_LSB | CRC_BYTE_2 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
  else if (CrcMode == CRC_16B_CCITT_FALSE)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC16b | CRC_SWAP_00 | CRC_INVEN_LSB | CRC_LM_MSB | CRC_BYTE_2 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
  else if (CrcMode == CRC_16B_X25)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC16b | CRC_SWAP_00 | CRC_INVEN_MSB | CRC_LM_LSB | CRC_BYTE_2 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
  else if (CrcMode == CRC_16B_XMODEM)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC16b | CRC_SWAP_00 | CRC_INVEN_LSB | CRC_LM_MSB | CRC_BYTE_2 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
}

/**
  * @name   Crc_initial_config_32
  * @brief  EN: CRC-32 polynomial 0x0411DB7 initialization configuration.
  *         CN: CRC-32 多项式 0x0411DB7 初始化配置。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @param  CrcMode: 
  *         EN: CRC-32 polynomial 0x0411DB7 mode.
  *         CN: CRC-32 0x0411DB7 模式。
  *             @arg CRC_32
  *             @arg CRC_32_MPEG_2
  * @retval None
  */
void Crc_initial_config_32(CRC_TypeDef *CRCx, CRC_32_MODE_TypeDef CrcMode)
{
  if (CrcMode == CRC_32)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC32 | CRC_SWAP_00 | CRC_INVEN_MSB | CRC_LM_LSB | CRC_BYTE_4 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
  else if (CrcMode == CRC_32_MPEG_2)
  {
    CRCx->CRC_CTRL = CRC_GPS_CRC32 | CRC_SWAP_00 | CRC_INVEN_LSB | CRC_LM_MSB | CRC_BYTE_4 | CRC_RESET_RESULT_EN | CRC_RESET_OFF;
  }
}

/**
  * @name   CRC_CalcBlockCRC8
  * @brief  EN: CRC-8 verification data processing.
  *         CN: CRC-8 校验数据处理。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @param  CrcMode: 
  *         EN: CRC-8 mode.
  *         CN: CRC-8 模式。
  *             @arg CRC_8
  *             @arg CRC_8_ITU
  *             @arg CRC_8_ROHC
  * @param  pBuffer[]: 
  *         EN: The data to be verified.
  *         CN: 待校验的数据。
  * @param  BufferLength: 
  *         EN: The length of the data to be verified.
  *         CN: 待校验数据长度。
  * @retval uint8_t
  */
uint8_t CRC_CalcBlockCRC8(CRC_TypeDef *CRCx, CRC_8_MODE_TypeDef CrcMode, uint8_t pBuffer[], uint8_t BufferLength)
{
  uint8_t index = 0;
  uint8_t temp;
  if (CrcMode == CRC_8_ROHC)
  {
    CRCx->CRC_RESULT = 0xFF;  //初始值
  }
  else
  {
    CRCx->CRC_RESULT = 0x00;  //初始值
  }

  for (index = 0; index < BufferLength; index++)
  {
    CRCx->CRC_DATA = pBuffer[index];
    while (CRCx->CRC_CTRL & CRC_CTRL_CRC_VALID_Msk)
    {
        __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    };
  }

  if (CrcMode == CRC_8_ITU)
  {
    temp = Crc_read_result(CRCx) ^ 0x55;  //结果异或值
  }
  else
  {
    temp = Crc_read_result(CRCx);        //结果异或值
  }

  CRCx->CRC_CTRL_b.CRC_SRST = 1;      //复位结果
  CRCx->CRC_CTRL_b.CRC_SRSTALL = 1;   //复位CRC
  return temp;
}

/**
  * @name   CRC_CalcBlockCRC16a
  * @brief  EN: CRC-16 polynomial 0x8005 verification data processing.
  *         CN: CRC-16 多项式 0x8005 校验数据处理。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @param  CrcMode:
  *         EN: CRC-16 polynomial 0x8005 mode.
  *         CN: CRC-16 多项式 0x8005 模式。
  *             @arg CRC_16A_IBM
  *             @arg CRC_16A_MAXIM
  *             @arg CRC_16A_USB
  *             @arg CRC_16A_MODBUS
  * @param  pBuffer[]: 
  *         EN: The data to be verified.
  *         CN: 待校验的数据。
  * @param  BufferLength: 
  *         EN: The length of the data to be verified.
  *         CN: 待校验数据长度。
  * @retval uint16_t
  */
uint16_t CRC_CalcBlockCRC16a(CRC_TypeDef *CRCx, CRC_16A_MODE_TypeDef CrcMode, uint8_t pBuffer[], uint8_t BufferLength)
{
  uint8_t index = 0;
  uint16_t temp;

  if ((CrcMode == CRC_16A_USB) || (CrcMode == CRC_16A_MODBUS))
  {
    CRCx->CRC_RESULT = 0xFFFF;  //初始值
  }
  else
  {
    CRCx->CRC_RESULT = 0x0000;  //初始值
  }

  for (index = 0; index < BufferLength; index += 2)
  {
    CRCx->CRC_DATA = pBuffer[index] | (pBuffer[index + 1] << 8);
    while (CRCx->CRC_CTRL & CRC_CTRL_CRC_VALID_Msk)
    {
        __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    };
  }

  if ((CrcMode == CRC_16A_MAXIM) || (CrcMode == CRC_16A_USB))
  {
    temp = Crc_read_result(CRCx) ^ 0xFFFF;  //结果异或值
  }
  else
  {
    temp = Crc_read_result(CRCx);        //结果异或值
  }

  CRCx->CRC_CTRL_b.CRC_SRST = 1;      //复位结果
  CRCx->CRC_CTRL_b.CRC_SRSTALL = 1;   //复位CRC
  return temp;
}

/**
  * @name   CRC_CalcBlockCRC16b
  * @brief  EN: CRC-16 polynomial 0x1021 verification data processing.
  *         CN: CRC-16 多项式 0x1021 校验数据处理。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @param  CrcMode:
  *         EN: CRC-16 polynomial 0x1021 mode.
  *         CN: CRC-16 多项式 0x1021 模式。
  *             @arg CRC_16B_CCITT
  *             @arg CRC_16B_CCITT_FALSE
  *             @arg CRC_16B_X25
  *             @arg CRC_16B_XMODEM
  * @param  pBuffer[]: 
  *         EN: The data to be verified.
  *         CN: 待校验的数据。
  * @param  BufferLength: 
  *         EN: The length of the data to be verified.
  *         CN: 待校验数据长度。
  * @retval uint16_t
  */
uint16_t CRC_CalcBlockCRC16b(CRC_TypeDef *CRCx, CRC_16B_MODE_TypeDef CrcMode, uint8_t pBuffer[], uint8_t BufferLength)
{
  uint8_t index = 0;
  uint16_t temp;

  if ((CrcMode == CRC_16B_CCITT_FALSE) || (CrcMode == CRC_16B_X25))
  {
    CRCx->CRC_RESULT = 0xFFFF;  //初始值
  }
  else
  {
    CRCx->CRC_RESULT = 0x0000;  //初始值
  }

  for (index = 0; index < BufferLength; index += 2)
  {
    CRCx->CRC_DATA = pBuffer[index] | (pBuffer[index + 1] << 8);
    while (CRCx->CRC_CTRL & CRC_CTRL_CRC_VALID_Msk)
    {
        __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    };
  }

  if (CrcMode == CRC_16B_X25)
  {
    temp = Crc_read_result(CRCx) ^ 0xFFFF;  //结果异或值
  }
  else
  {
    temp = Crc_read_result(CRCx);        //结果异或值
  }

  CRCx->CRC_CTRL_b.CRC_SRST = 1;      //复位结果
  CRCx->CRC_CTRL_b.CRC_SRSTALL = 1;   //复位CRC
  return temp;
}

/**
  * @name   CRC_CalcBlockCRC32
  * @brief  EN: CRC-32 polynomial 0x0411DB7 verification data processing.
  *         CN: CRC-32 多项式 0x0411DB7 校验数据处理。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @param  CrcMode:
  *         EN: CRC-32 polynomial 0x0411DB7 mode.
  *         CN: CRC-32 多项式 0x0411DB7 模式。
  *             @arg CRC_32
  *             @arg CRC_32_MPEG_2
  * @param  pBuffer[]: 
  *         EN: The data to be verified.
  *         CN: 待校验的数据。
  * @param  BufferLength: 
  *         EN: The length of the data to be verified.
  *         CN: 待校验数据长度。
  * @retval None
  */
uint32_t CRC_CalcBlockCRC32(CRC_TypeDef *CRCx, CRC_32_MODE_TypeDef CrcMode, uint8_t pBuffer[], uint8_t BufferLength)
{
  uint8_t index = 0;
  uint32_t temp;

  if ((CrcMode == CRC_32) || (CrcMode == CRC_32_MPEG_2))
  {
    CRCx->CRC_RESULT = 0xFFFFFFFF;  //初始值
  }
  else
  {
    CRCx->CRC_RESULT = 0x00000000;  //初始值
  }

  for (index = 0; index < BufferLength; index += 4)
  {
    CRCx->CRC_DATA = pBuffer[index] | (pBuffer[index + 1] << 8) | \
                    (pBuffer[index + 2] << 16) | (pBuffer[index + 3] << 24);
    while (CRCx->CRC_CTRL & CRC_CTRL_CRC_VALID_Msk)
    {
        __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    };
  }
  
  if (CrcMode == CRC_32)
  {
    temp = Crc_read_result(CRCx) ^ 0xFFFFFFFF;  //结果异或值
  }
  else
  {
    temp = Crc_read_result(CRCx);        //结果异或值
  }

  CRCx->CRC_CTRL_b.CRC_SRST = 1;      //复位结果
  CRCx->CRC_CTRL_b.CRC_SRSTALL = 1;   //复位CRC
  return temp;
}

/**
  * @name   Crc_write_crc_data
  * @brief  EN: CRC writes data.
  *         CN: CRC 写入数据。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @param  crc_data:
  *         EN: The data to be verified.
  *         CN: 待校验的数据。
  * @retval None
  */
void Crc_write_crc_data(CRC_TypeDef *CRCx, uint32_t crc_data)
{
  CRCx->CRC_DATA = crc_data;
}

/**
  * @name   Crc_read_result
  * @brief  EN: CRC reading result.
  *         CN: CRC 读取结果。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @retval EN: CRC verification results
  *         CN: CRC 校验结果
  */
uint32_t Crc_read_result(CRC_TypeDef *CRCx)
{
  uint32_t temp;
  temp = CRCx->CRC_RESULT;
  return temp;
}

/**
  * @name   Crc_write_result
  * @brief  EN: CRC writes the initial value.
  *         CN: CRC 写初始值。
  * @param  CRCx: 
  *         EN: There is only one CRCx: CRC0.
  *         CN: 仅有一个CRCx: CRC0 。
  * @retval None
  */
void Crc_write_result(CRC_TypeDef *CRCx, uint32_t Data)
{
  CRCx->CRC_RESULT = Data;
}
