#include <stdio.h>
// All wired for little endian memory with serial shift right,
// i.e.
//     Memory - Low byte High byte
//              MSB  LSB MSB   LSB
//     Serial -      MSB LSB

extern "C" unsigned int add2CRCESP(unsigned char  newData,
                                   unsigned int   oldCRC);
extern "C" unsigned int add2CRCESPa(unsigned char  newData,
                                    unsigned int   oldCRC);
extern "C" unsigned int add2CRC16(unsigned char  newData,
                                  unsigned int   oldCRC,
                                  unsigned int   genPoly);
extern "C" void         initCRCSmmt(unsigned int   genPoly);
extern "C" unsigned int add2CRCSmmt(unsigned char  newData,
                                    unsigned int  oldCRC);
extern "C" unsigned int add2CRCCITT(unsigned char  newData,
                                    unsigned int   oldCRC);
extern "C" unsigned int add2CRCCITTa(unsigned char  newData,
                                    unsigned int   oldCRC);
extern "C" void         initCRC4Bit(unsigned int   genPoly);
extern "C" unsigned int add2CRC4Bit(unsigned char  newData,
                                    unsigned int   oldCRC);


void
testCRC(unsigned char  *testString)
{
    unsigned char       *testData   = testString;
    unsigned int        crcAcc      = 0;

    unsigned int  genPoly    = 0x1021;
    unsigned int  polyGen    = 0x8408;
    unsigned int  crcAccInit = 0xFFFF;

    // Hard wired for ^16+^12+^5+1, "CITT CRC16" - HDLC, X.25
    printf("\nCRC CITT 'C'    (8408):");

    testData = testString;
    crcAcc   = crcAccInit;

    while ('\0' != *testData)
    {
        crcAcc = add2CRCCITT(*testData, crcAcc);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    // Hard wired for ^16+^12+^5+1, "CITT CRC16" - HDLC, X.25
    printf("\nCRC CITT 'TASM' (8408):");

    testData = testString;
    crcAcc   = crcAccInit;

    while ('\0' != *testData)
    {
        crcAcc = add2CRCCITTa(*testData, crcAcc);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    // CRC16
    printf("\nCRC16           (%04X):", polyGen);

    testData = testString;
    crcAcc   = crcAccInit;

    while ('\0' != *testData)
    {
        crcAcc = add2CRC16(*testData, crcAcc, polyGen);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    // Summit table CRC16
    printf("\nSummit          (%04X):", polyGen);

    testData = testString;
    crcAcc   = crcAccInit;

    initCRCSmmt(polyGen);

    while ('\0' != *testData)
    {
        crcAcc = add2CRCSmmt(*testData, crcAcc);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    // 4 bit table CRC16
    printf("\n4 bit           (%04X):", polyGen);

    testData = testString;
    crcAcc   = crcAccInit;

    initCRC4Bit(polyGen);

    while ('\0' != *testData)
    {
        crcAcc = add2CRC4Bit(*testData, crcAcc);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    printf("\n");

    genPoly    = 0x8005;
    polyGen    = 0xA001;
    crcAccInit = 0;

    // Hard wired for ^16+^15+^2+1, "CRC-16" */
    printf("\nGEM ESP 'C'     (A001):");

    testData = testString;
    crcAcc   = crcAccInit;

    while ('\0' != *testData)
    {
        crcAcc = add2CRCESP(*testData, crcAcc);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    // Hard wired for ^16+^15+^2+1, "CRC-16" */
    printf("\nGEM ESP 'TASM'  (A001):");

    testData = testString;
    crcAcc   = crcAccInit;

    while ('\0' != *testData)
    {
        crcAcc = add2CRCESPa(*testData, crcAcc);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    // CRC16
    printf("\nCRC16           (%04X):", polyGen);

    testData = testString;
    crcAcc   = crcAccInit;

    while ('\0' != *testData)
    {
        crcAcc = add2CRC16(*testData, crcAcc, polyGen);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    // Summit table CRC16
    printf("\nSummit          (%04X):", polyGen);

    testData = testString;
    crcAcc   = crcAccInit;

    initCRCSmmt(polyGen);

    while ('\0' != *testData)
    {
        crcAcc = add2CRCSmmt(*testData, crcAcc);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    // 4 bit table CRC16
    printf("\n4 bit           (%04X):", polyGen);

    testData = testString;
    crcAcc   = crcAccInit;

    initCRC4Bit(polyGen);

    while ('\0' != *testData)
    {
        crcAcc = add2CRC4Bit(*testData, crcAcc);
        testData++;

        //printf(" %04X", crcAcc);
    }
    printf(" %04X", crcAcc);

    printf("\n");
}


int
main(int, char**)
{
    testCRC((unsigned char*)"0123456789ABCDEF");
    testCRC((unsigned char*)"Hello");

    return  0;
}

