Instead of reflecting the data coming in, and the CRC coming in, and the CRC going out, you simply reflect the polynomial and the operations. You only need to do that once, when you're writing the code. The reflected polynomial is 0x8408
.
typedef unsigned char uint8_t;
typedef unsigned short crc;
crc crcTable[256];
#define POLYNOMIAL 0x8408
void Init()
{
crc remainder;
for (int dividend = 0; dividend < 256; ++dividend)
{
remainder = dividend;
for (uint8_t bit = 8; bit > 0; --bit)
{
if (remainder & 1)
remainder = (remainder >> 1) ^ POLYNOMIAL;
else
remainder = (remainder >> 1);
}
crcTable[dividend] = remainder;
}
}
crc Calculate(const uint8_t *message, int nBytes, crc wOldCRC)
{
uint8_t data;
crc remainder = wOldCRC;
for (int byte = 0; byte < nBytes; ++byte)
{
data = message[byte] ^ remainder;
remainder = crcTable[data] ^ (remainder >> 8);
}
return remainder;
}
int main()
{
crc expected = 0x6f91;
uint8_t pattern[] = "123456789";
Init();
crc result = Calculate(pattern, 9, 0xFFFF);
if (result != expected)
{
// this output is not relevant to the question, despite C++ tag
printf("CRC 0x%04x wrong, expected 0x%04x
", result, expected);
}
}
For the general case, if the input data is reflected, then you reflect the polynomial as shown in this answer, feed the byte at the bottom, check the low bit for exclusive-oring the polynomial, and shift up. If the input data is not reflected, then you do it as in the code in your question, leaving the polynomial as is, feeding the byte at the top, check the high bit, and shift down.
In nearly all cases, the reflection of the output is the same as the reflection of the input. For all of those, there is no need for a bit reverse function. You leave the result from the shift register as is if both input and output are not reflected, or if both input and output are reflected. In only one of the 72 CRCs catalogued at the RevEng site is the reflect out different from the reflect in (CRC-12/3GPP). In that one case, you need to bit reverse the output since the input is not reflected, but the output is.
The initial CRC is simply the initial contents of the shift register. You set that once when starting the CRC. The final exclusive-or is applied to the shift register contents at the end. If you have a function that computes a CRC a piece at a time, you need to apply the final exclusive-or when entering the function as well, and also apply that final exclusive-or to the initial value that the user sees, so that the actual initial value is what ends up in the shift register.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…