GRBL-Advanced/Libraries/CRC/CRC.c

339 wiersze
7.8 KiB
C

/*
CRC.c - Simple library to calculate 8-, 16-, and 32-Bit CRC
Copyright (c) 2018 Patrick F.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "CRC.h"
//---- Prototypes ----//
static void CRC_CalculateCRC8Table(void);
static void CRC_CalculateCRC16Table(void);
static void CRC_CalculateCRC32Table(void);
static uint8_t CRC_ReverseBitOrder8(uint8_t value);
static uint32_t CRC_ReverseBitOrder32(uint32_t value);
#if (CRC_8_MODE == TABLE)
static uint8_t CRC8Table[256u];
#endif
#if (CRC_16_MODE == TABLE)
static uint16_t CRC16Table[256u];
#endif
#if (CRC_32_MODE == TABLE)
static uint32_t CRC32Table[256u];
#endif
void CRC_Init(void)
{
CRC_CalculateCRC8Table();
CRC_CalculateCRC16Table();
CRC_CalculateCRC32Table();
}
uint8_t CRC_CalculateCRC8(const uint8_t *Buffer, uint16_t Length)
{
uint8_t retVal = 0u;
uint16_t byteIndex = 0u;
if(Buffer != NULL)
{
#if (CRC_8_MODE == RUNTTIME)
uint8_t bitIndex = 0u;
retVal = CRC_8_INIT_VALUE;
/* Do calculation procedure for each byte */
for(byteIndex = 0u; byteIndex < Length; byteIndex++)
{
/* XOR new byte with temp result */
retVal ^= (Buffer[byteIndex] << (CRC_8_RESULT_WIDTH - 8u));
/* Do calculation for current data */
for(bitIndex = 0u; bitIndex < 8u; bitIndex++)
{
if(retVal & (1u << (CRC_8_RESULT_WIDTH - 1u)))
{
retVal = (retVal << 1u) ^ CRC_8_POLYNOMIAL;
}
else
{
retVal = (retVal << 1u);
}
}
}
/* XOR result with specified value */
retVal ^= CRC_8_XOR_VALUE;
#elif (CRC_8_MODE == TABLE)
retVal = CRC_8_INIT_VALUE;
for(byteIndex = 0u; byteIndex < Length; byteIndex++)
{
retVal = CRC8Table[(retVal) ^ Buffer[byteIndex]];
}
/* XOR result with specified value */
retVal ^= CRC_8_XOR_VALUE;
#else
/* Mode not implemented */
retVal = 0x00u;
#endif
}
return retVal;
}
uint16_t CRC_CalculateCRC16(const uint8_t *Buffer, uint16_t Length)
{
uint16_t retVal = 0u;
uint16_t byteIndex = 0u;
if(Buffer != NULL)
{
#if (CRC_16_MODE==RUNTTIME)
retVal = CRC_16_INIT_VALUE;
/* Do calculation procedure for each byte */
for(byteIndex = 0u; byteIndex < Length; byteIndex++)
{
/* XOR new byte with temp result */
retVal ^= (Buffer[byteIndex] << (CRC_16_RESULT_WIDTH - 8u));
uint8_t bitIndex = 0u;
/* Do calculation for current data */
for(bitIndex = 0u; bitIndex < 8u; bitIndex++)
{
if(retVal & (1u << (CRC_16_RESULT_WIDTH - 1u)))
{
retVal = (retVal << 1u) ^ CRC_16_POLYNOMIAL;
}
else
{
retVal = (retVal << 1u);
}
}
}
/* XOR result with specified value */
retVal ^= CRC_16_XOR_VALUE;
#elif (CRC_16_MODE==TABLE)
retVal = CRC_16_INIT_VALUE;
/* Update the CRC using the data */
for(byteIndex = 0u; byteIndex < Length; byteIndex++)
{
retVal = (retVal << 8u) ^ CRC16Table[(retVal >> 8u) ^ Buffer[byteIndex]];
}
/* XOR result with specified value */
retVal ^= CRC_16_XOR_VALUE;
#else
/* Mode not implemented */
retVal = 0x0000u;
#endif
}
return retVal;
}
uint32_t CRC_CalculateCRC32(const uint8_t *Buffer, uint16_t Length)
{
uint32_t retVal = 0u;
uint16_t byteIndex = 0u;
if(Buffer != NULL)
{
#if (CRC_32_MODE==RUNTTIME)
retVal = CRC_32_INIT_VALUE;
/* Do calculation procedure for each byte */
for(byteIndex = 0u; byteIndex < Length; byteIndex++)
{
/* XOR new byte with temp result */
retVal ^= (CRC_ReverseBitOrder8(Buffer[byteIndex]) << (CRC_32_RESULT_WIDTH - 8u));
uint8_t bitIndex = 0u;
/* Do calculation for current data */
for(bitIndex = 0u; bitIndex < 8u; bitIndex++)
{
if(retVal & (1u << (CRC_32_RESULT_WIDTH - 1u)))
{
retVal = (retVal << 1u) ^ CRC_32_POLYNOMIAL;
}
else
{
retVal = (retVal << 1u);
}
}
}
/* XOR result with specified value */
retVal ^= CRC_32_XOR_VALUE;
#elif (CRC_32_MODE==TABLE)
uint8_t data = 0u;
retVal = CRC_32_INIT_VALUE;
for(byteIndex = 0u; byteIndex < Length; ++byteIndex)
{
data = CRC_ReverseBitOrder8(Buffer[byteIndex]) ^ (retVal >> (CRC_32_RESULT_WIDTH - 8u));
retVal = CRC32Table[data] ^ (retVal << 8u);
}
/* XOR result with specified value */
retVal ^= CRC_32_XOR_VALUE;
#else
/* Mode not implemented */
retVal = 0x00000000u;
#endif
}
/* Reflect result */
retVal = CRC_ReverseBitOrder32(retVal);
return retVal;
}
static void CRC_CalculateCRC8Table(void)
{
#if (CRC_8_MODE==TABLE)
uint16_t i = 0u, j = 0u;
for(i = 0u; i < 256u; ++i)
{
uint8_t curr = i;
for(j = 0u; j < 8u; ++j)
{
if((curr & 0x80u) != 0u)
{
curr = (curr << 1u) ^ CRC_8_POLYNOMIAL;
}
else
{
curr <<= 1u;
}
}
CRC8Table[i] = curr;
}
#endif
}
static void CRC_CalculateCRC16Table(void)
{
#if (CRC_16_MODE==TABLE)
uint16_t i = 0u, j = 0u;
uint16_t result = 0u;
uint16_t xor_flag = 0u;
for(i = 0u; i < 256u; i++)
{
result = i << 8u;
for(j = 0u; j < 8u; j++)
{
/* Flag for XOR if leftmost bit is set */
xor_flag = result & 0x8000u;
/* Shift CRC */
result <<= 1u;
/* Perform the XOR */
if(xor_flag != 0u)
result ^= CRC_16_POLYNOMIAL;
}
CRC16Table[i] = result;
}
#endif
}
static void CRC_CalculateCRC32Table(void)
{
#if (CRC_32_MODE==TABLE)
uint32_t remainder = 0u;
for(uint32_t dividend = 0u; dividend < 256u; ++dividend)
{
remainder = dividend << (CRC_32_RESULT_WIDTH - 8u);
for(uint8_t bit = 8u; bit > 0u; --bit)
{
if(remainder & (1u << (CRC_32_RESULT_WIDTH - 1u)))
{
remainder = (remainder << 1u) ^ CRC_32_POLYNOMIAL;
}
else
{
remainder = (remainder << 1u);
}
}
CRC32Table[dividend] = remainder;
}
#endif
}
static uint8_t CRC_ReverseBitOrder8(uint8_t value)
{
value = (value & 0xF0) >> 4u | (value & 0x0F) << 4u;
value = (value & 0xCC) >> 2u | (value & 0x33) << 2u;
value = (value & 0xAA) >> 1u | (value & 0x55) << 1u;
return value;
}
static uint32_t CRC_ReverseBitOrder32(uint32_t value)
{
uint32_t reversed = 0u;
for(uint8_t i = 31u; value; )
{
reversed |= (value & 1u) << i;
value >>= 1u;
--i;
}
return reversed;
}