This is not a normal CRC. The initial CRC is cycled left 16 times, then the first short is XOR'ed to the lower 16 bits of the CRC, which is then cycled again 16 times, and the next short is XOR'ed to the lower 16 bits of the CRC. If the data is just 2 shorts, it's the same as cycling the initial CRC 32 times, then XOR'ing the 2 shorts to the cycled CRC. To get the CRC==0, just set the 2 shorts to the initial CRC cycled 32 times. Example code below.
How to calculate data buffer to zero checksum value with as little data as possible
Just need 2 shorts to do this. Set the 2 shorts = 0, calculate CRC, then set the 2 shorts to the calculated CRC. This will result in a CRC of 0 for any initial CRC.
I switched to a table driven version of the checksum function, but the code below also includes a "cleaned up" version of the questions example CRC function.
This code compares the CRC outputs from the questions code, an alternate version, and a table driven version:
#include <iostream>
#include <iomanip>
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
uint32_t crctbl[65536];
void gentbl()
{
uint32_t crc;
int i, j;
for(j = 0; j < 0x10000; j++){
crc = j<<16;
for(i = 0; i < 16; i++)
// assumes twos complement
crc = (crc<<1)^((0-(crc>>31))&0x400007u);
crctbl[j] = crc;
}
}
int calcCrcPartial(unsigned short* lpdwBlockData, unsigned short dwBlockSizeInBytes, int iInitialCrc)
{
unsigned short dwBlocksSizeInWords;
int bIsSigned;
signed int j;
signed int i;
unsigned short dwDataItem;
bool bIsNegative;
// number of WORD blocks
dwBlocksSizeInWords = dwBlockSizeInBytes >> 1;
for (i = 0; ; ++i)
{
if (dwBlocksSizeInWords <= i)
{
break;
}
dwDataItem = lpdwBlockData[i];
// bInvalidCrc not delcared and not used
// if (dwDataItem != 0)
// {
// bInvalidCrc = false;
// }
for (j = 0; j <= 15; ++j)
{
bIsSigned = (dwDataItem & 0x8000u) != 0;
dwDataItem <<= 1;
bIsNegative = iInitialCrc < 0;
iInitialCrc <<= 1;
iInitialCrc += bIsSigned;
if (bIsNegative)
{
iInitialCrc ^= 0x400007u;
}
}
}
return iInitialCrc;
}
// alternate version of calcCrcPartial
uint32_t calcCrcPartiala(uint16_t* lpwBlockData, uint16_t wBlockSizeInBytes, uint32_t iInitialCrc)
{
int sz = wBlockSizeInBytes >> 1;
int i;
while(sz--){
for(i = 0; i < 16; i++)
// assumes twos complement
iInitialCrc = (iInitialCrc<<1)^((0-(iInitialCrc>>31))&0x400007u);
iInitialCrc ^= *lpwBlockData++;
}
return iInitialCrc;
}
// table version of calcCrcPartial
uint32_t calcCrcPartialt(uint16_t* lpwBlockData, uint16_t wBlockSizeInBytes, uint32_t iInitialCrc)
{
int sz = wBlockSizeInBytes >> 1;
while(sz--)
iInitialCrc = (iInitialCrc<<16)^crctbl[iInitialCrc>>16]^*lpwBlockData++;
return iInitialCrc;
}
int main()
{
uint16_t data[] = {0x0000, 0x0000};
uint32_t iCrc, oCrc, oCra, oCrt;
gentbl();
iCrc = 0x00000000u;
do{
oCrc = calcCrcPartial (data, sizeof(data), iCrc);
oCra = calcCrcPartiala(data, sizeof(data), iCrc);
oCrt = calcCrcPartiala(data, sizeof(data), iCrc);
if(oCrc != oCra || oCrc != oCrt){
std::cout << "mismatch" << std::endl;
break;}
if ((iCrc & 0x0ffffffu) == 0)
std::cout << std::hex << iCrc << std::endl;
}while(++iCrc != 0x10000000u);
return 0;
}
This code tests all 4 billion possible initial CRCs.
#include <iostream>
#include <iomanip>
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
uint32_t crctbl[65536];
void gentbl()
{
uint32_t crc;
int i, j;
for(j = 0; j < 0x10000; j++){
crc = j<<16;
for(i = 0; i < 16; i++)
// assumes twos complement
crc = (crc<<1)^((0-(crc>>31))&0x400007u);
crctbl[j] = crc;
}
}
uint32_t calcCrcPartial(uint16_t* lpwBlockData, uint16_t wBlockSizeInBytes, uint32_t iInitialCrc)
{
int sz = wBlockSizeInBytes >> 1;
while(sz--)
iInitialCrc = (iInitialCrc<<16)^crctbl[iInitialCrc>>16]^*lpwBlockData++;
return iInitialCrc;
}
// alternate version of questions code
uint32_t calcCrcPartialx(uint16_t* lpwBlockData, uint16_t wBlockSizeInBytes, uint32_t iInitialCrc)
{
int sz = wBlockSizeInBytes >> 1;
int i;
while(sz--){
for(i = 0; i < 16; i++)
// assumes twos complement
iInitialCrc = (iInitialCrc<<1)^((0-(iInitialCrc>>31))&0x400007u);
iInitialCrc ^= *lpwBlockData++;
}
return iInitialCrc;
}
int main()
{
uint16_t data[] = {0x0000, 0x0000};
uint32_t iCrc, oCrc;
gentbl();
iCrc = 0x00000000u;
do{
// oCrc = iCrc cycled 32 times
data[0] = 0x0000;
data[1] = 0x0000;
oCrc = calcCrcPartial(data, 4, iCrc);
// store oCrc and verify new crc == 0
data[0] = (oCrc>>16);
data[1] = (oCrc>> 0);
oCrc = calcCrcPartial(data, 4, iCrc);
if (oCrc != 0) {
std::cout << "error" << std::endl;
break;
}
if ((iCrc & 0xfffffffu) == 0)
std::cout << std::hex << iCrc << std::endl;
}while(++iCrc != 0x00000000u);
return 0;
}
How to calculate data buffer to zero checksum value with as little data as possible
If this means the minimum number of error bits, then in a buffer of 34 shorts, all zero, and initial CRC = 0, 6 bits in specific locations (based on poly and initial CRC) need to be toggled to also produce a CRC = 0:
0x8000, 0x0000, 0x0000, 0x0000, 0x0000,0x0000,0x0000,0x0000,
0x0000, 0x0000, 0x8000, 0x0000, 0x0000,0x0000,0x0000,0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,0x0000,0x0000,0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,0x0000,0x0020,0x8003,
0x0000, 0x0000
or simple still use the CRC polynomial which only has 5 bits = 1, only 5 words needed:
0x0100, 0x4000, 0x0700, 0x0000, 0x0000
This is how this version of CRC could be used for 512 bytes of data and 4 bytes of CRC:
#include <stdlib.h> // for rand()
// # of shorts in data, not including CRC
#define COUNT 256
int main()
{
uint16_t data[COUNT+2];
uint32_t iCrc, oCrc;
int i;
gentbl();
// fill data with psuedo random values
for(i = 0; i < COUNT; i++)
data[i] = ((rand()>>4)&0xff)|((rand()<<4)&0xff00);
iCrc = 0x00000000u;
do{
// generate crc
data[COUNT+0] = 0x0000u;
data[COUNT+1] = 0x0000u;
oCrc = calcCrcPartial(data, sizeof(data), iCrc);
// append crc to data
data[COUNT+0] = (oCrc>>16);
data[COUNT+1] = (oCrc>> 0);
// check crc
oCrc = calcCrcPartial(data, sizeof(data), iCrc);
if (oCrc != 0) {
std::cout << "error" << std::endl;
break;
}
if ((iCrc & 0xfffffu) == 0)
std::cout << std::hex << iCrc << std::endl;
}while(++iCrc != 0x01000000u);
return 0;
}