#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define BYTE_WIDTH 8
#define TWO_UP_EIGHT 256

// Store the computed table values in a data file to be used in the Bytewise CRC calculation program.
#define OUTPUT_FILE "CRC-8.dat"

const unsigned char Poly = 213;
const unsigned char MSB = 128;
const unsigned char PowersOfTwo[BYTE_WIDTH] = { 1, 2, 4, 8, 16, 32, 64, 128 };

// Feed this function "TableIndex" and it will return the corresponding Lookup-Value for CRC-8.
unsigned char GenerateLookupTableValue(unsigned char TableIndex){
	unsigned int X;
	unsigned char TheRegister = TableIndex;
	// Shift a Byte worth of zeros into the register, and when a "1" is shifted out, perform the required "XOR" operation with "Poly".
	for ( X = BYTE_WIDTH; X; X-- ) {
		if ( MSB & TheRegister ) TheRegister = (TheRegister << 1) ^ Poly;
		else TheRegister <<= 1;
	}
	return TheRegister;
}

// Simply print out "ThisByte" using "1"s and "0"s.
void PrintByteInBinary(unsigned char ThisByte){
	unsigned int X;
	char HoldOut[BYTE_WIDTH + 1];
	for ( X = 0; X < BYTE_WIDTH; X++ ) HoldOut[X] = (ThisByte & PowersOfTwo[BYTE_WIDTH - 1 - X])? '1': '0';
	HoldOut[BYTE_WIDTH] = '\0';
	printf("%s", HoldOut);
}

int main(){
	int X;
	int Y;
	unsigned char CalculatedValues[TWO_UP_EIGHT];
	FILE* DataOut;
	DataOut = fopen(OUTPUT_FILE, "wb");
	for ( X = 0; X < TWO_UP_EIGHT; X++ ) {
		CalculatedValues[X] = GenerateLookupTableValue((unsigned char)X);
		printf("|%3u| - Value-|%2X| - Binary|", X, CalculatedValues[X]);
		PrintByteInBinary(CalculatedValues[X]);
		printf("|\n");
	}
	
	// Verify that each value in the lookup table is unique.
	// Each value can be the seen as the remainder when a 2-Byte message is divided by "Poly".
	// The second Byte is always "W" zeros, so only the first byte changes, making it impossible for two remainders to be the same.
	for ( X = 1; X < TWO_UP_EIGHT; X++ ) {
		for ( Y = (X - 1); Y >= 0; Y-- ) {
			if ( CalculatedValues[X] == CalculatedValues[Y] ) printf("Duplicate values found at |%d|, and |%d|\n", X, Y);
		}
	}
	printf("The search for duplicate values in the table is complete.\n");
	
	fwrite(CalculatedValues, sizeof(unsigned char), TWO_UP_EIGHT, DataOut);
	fclose(DataOut);
	return 0;
}

