
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                                  Main                                     //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
// (c) 2021 Miroslav Nemecek, Panda38@seznam.cz, panda38.sweb.cz
// This source code may be used freely without restrictions for any purpose,
// including commercial.

#include "include.h"

#ifdef _MSC_VER
#define BATCH	10000	// batch size (number of generated samples)
#else
#define BATCH	1000	// batch size (number of generated samples)
#endif

#define ERRNUM	100		// number of generated errors per one sample
#define RNDMASK	0xff	// mask of random error bit (5 bits of sample index + 3 bits of bit index)
#define SAMPLEN	32		// length of sample (should be power of 2, be aware of RNDMASK)

u8 Sample[SAMPLEN]; // sample
u8 SampleOrig[SAMPLEN]; // original sample

u32 Samples = 0;	// number of tests

// start reference CRC
u32 Crc32;
u32 CrcPico;
u16 CrcIbm;
u16 CrcModbus;
u16 CrcKermit;
u16 CrcDnp;
u16 CrcXmodem;
u16 CrcCcitt;
u16 CrcCcittB;
u16 CrcSick;
u8 CrcDallas;
u8 CrcRDallas;
u8 Crc8Sum;
u16 Crc16Sum;
u32 Crc32Sum;
u8 CrcSht;
u16 CrcXor;
u8 CrcXor8;
u16 CrcXor0;
u16 CrcCcitt0;

// error counters
u32 Crc32Err = 0;
u32 CrcPicoErr = 0;
u32 CrcIbmErr = 0;
u32 CrcModbusErr = 0;
u32 CrcKermitErr = 0;
u32 CrcDnpErr = 0;
u32 CrcXmodemErr = 0;
u32 CrcCcittErr = 0;
u32 CrcCcittBErr = 0;
u32 CrcSickErr = 0;
u32 CrcDallasErr = 0;
u32 CrcRDallasErr = 0;
u32 Crc8SumErr = 0;
u32 Crc16SumErr = 0;
u32 Crc32SumErr = 0;
u32 CrcShtErr = 0;
u32 CrcXorErr = 0;
u32 CrcXor8Err = 0;
u32 CrcXor0Err = 0;
u32 CrcCcitt0Err = 0;

u8 crc_xor8(const void* buf, int len)
{
	u8 crc = CRCXOR_INIT;
	const u8* s = (const u8*)buf;
	for (; len > 0; len--)
	{
		crc ^= *s++;
		crc = rol8(crc, 1);
	}
	return crc;
}

u16 crc_xor0(const void* buf, int len)
{
	u16 crc = CRCXOR_INIT;
	const u8* s = (const u8*)buf;
	for (; len > 0; len--)
	{
		crc ^= *s++;
	}
	return crc;
}

u16 crc_ccitt0(const void* buf, int len)
{
	u16 crc = 12345;
	const u8* s = (const u8*)buf;

	for (; len > 0; len--)
	{
		crc = crc_ccitt_tab[(crc >> 8) ^ *s++] ^ (crc << 8);
	}
	return crc;
}

///////////////////////////////////////////////////////////////////////////////
// main function

#ifdef _MSC_VER

int main(int argc, char* argv[])
{

#else

// Initialize Raspberry Pico
int main()
{
	stdio_init_all();

#endif

	// create or verify bit tables (returns FALSE on table error)
	if (!InitBitTab())
	{
		printf("Invalid bit tables!\n");
#ifdef _MSC_VER
		return 1;
#else
		while(True) {}
#endif
	}

	while (true)
	{
		// check CRC
		printf("--------------\n");
		printf("CRC check: ");
		int res = crc_check_all();
		if (res == 0)
			printf("OK\n");
		else
		{
			printf("ERROR %d!\n", res);
#ifdef _MSC_VER
			return 1;
#else
			while(True) {}
#endif
		}

		// loop through batch of random sample
		int i, j, k;
		for (i = BATCH; i > 0; i--)
		{
			// generate new sample
			for (j = 0; j < SAMPLEN; j++) Sample[j] = (u8)rand();
			memcpy(SampleOrig, Sample, SAMPLEN);

			// generate start checksums
			Crc32 = crc32(Sample, SAMPLEN);
			CrcPico = crc32_Pico(Sample, SAMPLEN);;
			CrcIbm = crc_ibm(Sample, SAMPLEN);
			CrcModbus = crc_modbus(Sample, SAMPLEN);
			CrcKermit = crc_kermit(Sample, SAMPLEN);
			CrcDnp = crc_dnp(Sample, SAMPLEN);
			CrcXmodem = crc_xmodem(Sample, SAMPLEN);
			CrcCcitt = crc_ccitt(Sample, SAMPLEN);
			CrcCcittB = crc_ccitt_b(Sample, SAMPLEN);
			CrcSick = crc_sick(Sample, SAMPLEN);
			CrcDallas = crc8_dallas(Sample, SAMPLEN);
			CrcRDallas = crc8_rdallas(Sample, SAMPLEN);
			Crc8Sum = crc8_sum(Sample, SAMPLEN);
			Crc16Sum = crc16_sum(Sample, SAMPLEN);
			Crc32Sum = crc32_sum(Sample, SAMPLEN);
			CrcSht = crc_sht(Sample, SAMPLEN);
			CrcXor = crc_xor(Sample, SAMPLEN);
			CrcXor8 = crc_xor8(Sample, SAMPLEN);
			CrcXor0 = crc_xor0(Sample, SAMPLEN);
			CrcCcitt0 = crc_ccitt0(Sample, SAMPLEN);

			// loop through errors
			for (j = ERRNUM; j > 0; j--)
			{
				// generate random bit (repeat if sample is equal to original sample)
				do {
					k = rand() & RNDMASK;
					Sample[k >> 3] ^= 1 << (k & 7);
				} while (memcmp(Sample, SampleOrig, SAMPLEN) == 0);

				Samples++;

				// check checksums
				if (Crc32 == crc32(Sample, SAMPLEN)) Crc32Err++;
				if (CrcPico == crc32_Pico(Sample, SAMPLEN)) CrcPicoErr++;
				if (CrcIbm == crc_ibm(Sample, SAMPLEN)) CrcIbmErr++;
				if (CrcModbus == crc_modbus(Sample, SAMPLEN)) CrcModbusErr++;
				if (CrcKermit == crc_kermit(Sample, SAMPLEN)) CrcKermitErr++;
				if (CrcDnp == crc_dnp(Sample, SAMPLEN)) CrcDnpErr++;
				if (CrcXmodem == crc_xmodem(Sample, SAMPLEN)) CrcXmodemErr++;
				if (CrcCcitt == crc_ccitt(Sample, SAMPLEN)) CrcCcittErr++;
				if (CrcCcittB == crc_ccitt_b(Sample, SAMPLEN)) CrcCcittBErr++;
				if (CrcSick == crc_sick(Sample, SAMPLEN)) CrcSickErr++;
				if (CrcDallas == crc8_dallas(Sample, SAMPLEN)) CrcDallasErr++;
				if (CrcRDallas == crc8_rdallas(Sample, SAMPLEN)) CrcRDallasErr++;
				if (Crc8Sum == crc8_sum(Sample, SAMPLEN)) Crc8SumErr++;
				if (Crc16Sum == crc16_sum(Sample, SAMPLEN)) Crc16SumErr++;
				if (Crc32Sum == crc32_sum(Sample, SAMPLEN)) Crc32SumErr++;
				if (CrcSht == crc_sht(Sample, SAMPLEN)) CrcShtErr++;
				if (CrcXor == crc_xor(Sample, SAMPLEN)) CrcXorErr++;
				if (CrcXor8 == crc_xor8(Sample, SAMPLEN)) CrcXor8Err++;
				if (CrcXor0 == crc_xor0(Sample, SAMPLEN)) CrcXor0Err++;
				if (CrcCcitt0 == crc_ccitt0(Sample, SAMPLEN)) CrcCcitt0Err++;
			}
		}

		// display result
		printf("\nChecked samples: %uK\n\n", Samples/1000);
		printf("CRC32 err=%u (%.5f%%)\n", Crc32Err, 100.0*Crc32Err/Samples);
		printf("Pico err=%u (%.5f%%)\n", CrcPicoErr, 100.0*CrcPicoErr/Samples);
		printf("IBM err=%u (%.5f%%)\n", CrcIbmErr, 100.0*CrcIbmErr/Samples);
		printf("Modbus err=%u (%.5f%%)\n", CrcModbusErr, 100.0*CrcModbusErr/Samples);
		printf("Kermit err=%u (%.5f%%)\n", CrcKermitErr, 100.0*CrcKermitErr/Samples);
		printf("DNP err=%u (%.5f%%)\n", CrcDnpErr, 100.0*CrcDnpErr/Samples);
		printf("XModem err=%u (%.5f%%)\n", CrcXmodemErr, 100.0*CrcXmodemErr/Samples);
		printf("CCITT err=%u (%.5f%%)\n", CrcCcittErr, 100.0*CrcCcittErr/Samples);
		printf("CCITTB err=%u (%.5f%%)\n", CrcCcittBErr, 100.0*CrcCcittBErr/Samples);
		printf("Sick err=%u (%.5f%%)\n", CrcSickErr, 100.0*CrcSickErr/Samples);
		printf("Dallas err=%u (%.5f%%)\n", CrcDallasErr, 100.0*CrcDallasErr/Samples);
		printf("RDallas err=%u (%.5f%%)\n", CrcRDallasErr, 100.0*CrcRDallasErr/Samples);
		printf("Sum8 err=%u (%.5f%%)\n", Crc8SumErr, 100.0*Crc8SumErr/Samples);
		printf("Sum16 err=%u (%.5f%%)\n", Crc16SumErr, 100.0*Crc16SumErr/Samples);
		printf("Sum32 err=%u (%.5f%%)\n", Crc32SumErr, 100.0*Crc32SumErr/Samples);
		printf("SHT err=%u (%.5f%%)\n", CrcShtErr, 100.0*CrcShtErr/Samples);
		printf("XOR err=%u (%.5f%%)\n", CrcXorErr, 100.0*CrcXorErr/Samples);
		printf("XOR8 err=%u (%.5f%%)\n", CrcXor8Err, 100.0*CrcXor8Err/Samples);
		printf("XOR0 err=%u (%.5f%%)\n", CrcXor0Err, 100.0*CrcXor0Err/Samples);
		printf("CCITT0 err=%u (%.5f%%)\n", CrcCcitt0Err, 100.0*CrcCcitt0Err/Samples);
	}

	return 0;
}
