Zebi
Zebi

Reputation: 8882

CRC 4 implementation for C#

Solved by this code -> https://gist.github.com/Sbreitzke/b26107798eee74e39ff85800abf71fb1


I searched the web for a CRC 4 implementation in C# because I have to calculate a checksum by

Changing the numbers of the barcode into Hex representation, then to bytes and then to bits and then calculate a CRC4 checksum on the bit stream.

I already found this question from 8 years ago without an answer CRC-4 implementation in C#.

I tried changing the CRC 8 and 16 implementations to CRC 4 but they don't quite get the result I require.

0130E0928270FFFFFFF should evaluate to 7.

I found two C implementation but was unable to convert them to C#. For example this one:

 short[] crc4_tab = {
 0x0, 0x7, 0xe, 0x9, 0xb, 0xc, 0x5, 0x2,
 0x1, 0x6, 0xf, 0x8, 0xa, 0xd, 0x4, 0x3,
};

/**
* crc4 - calculate the 4-bit crc of a value.
* @crc:  starting crc4
* @x:    value to checksum
* @bits: number of bits in @x to checksum
*
* Returns the crc4 value of @x, using polynomial 0b10111.
*
* The @x value is treated as left-aligned, and bits above @bits are ignored
* in the crc calculations.
*/
short crc4(uint8_t c, uint64_t x, int bits)
{
    int i;

    /* mask off anything above the top bit */
    x &= (1ull << bits) -1;

    /* Align to 4-bits */
    bits = (bits + 3) & ~0x3;

    /* Calculate crc4 over four-bit nibbles, starting at the MSbit */
    for (i = bits - 4; i >= 0; i -= 4)
    c = crc4_tab[c ^ ((x >> i) & 0xf)];

    return c;
}

My current generation code (unit test) looks like this:

[TestMethod]
public void x()
{
    var ordnungskennzeichen = 01;
    var kundennummer = 51251496;
    var einlieferungsbel = 9999;
    var sendungsnr = 16777215;

    var hex_ordnungskennzeichen = ordnungskennzeichen.ToString("x2");
    var hex_kundennummer = kundennummer.ToString("x2");
    var hex_einlieferungsbel = einlieferungsbel.ToString("x2");
    var hex_sendungsnr = sendungsnr.ToString("x2");

    var complete = hex_ordnungskennzeichen + hex_kundennummer + hex_einlieferungsbel + hex_sendungsnr;

    var bytes = Encoding.ASCII.GetBytes(complete);

    //var computeChecksum = crc4(???);
    //   Console.WriteLine(computeChecksum);

}

short[] crc4_tab = {
    0x0, 0x7, 0xe, 0x9, 0xb, 0xc, 0x5, 0x2,
    0x1, 0x6, 0xf, 0x8, 0xa, 0xd, 0x4, 0x3,
};

/**
* crc4 - calculate the 4-bit crc of a value.
* @crc:  starting crc4
* @x:    value to checksum
* @bits: number of bits in @x to checksum
*
* Returns the crc4 value of @x, using polynomial 0b10111.
*
* The @x value is treated as left-aligned, and bits above @bits are ignored
* in the crc calculations.
*/

short crc4(byte c, ulong x, int bits)
{
    int i;

    /* mask off anything above the top bit */
    x &= ((ulong)1 << bits) -1;

    /* Align to 4-bits */
    bits = (bits + 3) & ~0x3;

    /* Calculate crc4 over four-bit nibbles, starting at the MSbit */
    for (i = bits - 4; i >= 0; i -= 4)
        c = (byte) crc4_tab[c ^ ((x >> i) & 0xf)];

    return c;
}

Upvotes: 4

Views: 2535

Answers (3)

ub_coding
ub_coding

Reputation: 139

For the purpose of Deutsche Post as well, I'd like to contribute a rather less complex algorithm wich may more easily be translated into other languages as well:

       private string crc4(string sText) {
        int iCRC;
        int iPoly;
        int iByte;
        int iBit;
        byte[] bText;
        sText = sText.Replace(" ", "");
        iPoly = 0x13 << 3;
        iCRC = 0;
        bText = Encoding.Default.GetBytes(sText);
        for (iByte=0; iByte < bText.Length; iByte++){
            iCRC = iCRC ^ bText[iByte];
            for (iBit = 0; iBit < 8; iBit++){
                if ((iCRC & 0x80) != 0){
                    iCRC = iCRC ^ iPoly;
                }
                iCRC = iCRC << 1;
            }
        }
        iCRC = iCRC >> 4;

        return String.Format("{0:X}", iCRC);
    }

Fed with i.e. "A0 0101 002B 00 000C D10" the above code will calculate "F" as the correct check digit. (and tested with numerous other input values)

Upvotes: 2

Zebi
Zebi

Reputation: 8882

After further testing and communication with the Deutsche Post AG we made a correct implementation (for the purpose of Deutsche Post at least):

https://gist.github.com/Sbreitzke/b26107798eee74e39ff85800abf71fb1

Upvotes: 3

Evk
Evk

Reputation: 101443

Converting it to C# is not very hard. c is initial or previous nibble (4-bit number), x is 64bit number you want to calculate crc4 of, bits is number of bits in that 64bit number to actually use (the rest are ignored). Since you have array of bytes - you don't need to use 64bit number as x - use can just use byte. Then the first two lines are irrelevant for you, because all they do is throwing away irrelevant bits from 64bit number and ensuring bits is divisable by 4. So after removing irrelevant lines your implementation becomes:

static readonly byte[] crc4_tab = {
    0x0, 0x7, 0xe, 0x9, 0xb, 0xc, 0x5, 0x2,
    0x1, 0x6, 0xf, 0x8, 0xa, 0xd, 0x4, 0x3,
};

static byte crc4(byte c, byte x) {
    var low4Bits = x & 0x0F;
    var high4Bits = x >> 4;
    c = crc4_tab[c ^ high4Bits];
    c = crc4_tab[c ^ low4Bits];

    return c;
}

static byte crc4(byte[] array) {
    byte start = 0;
    foreach (var item in array) {
        start = crc4(start, item);
    }
    return start;
}

Upvotes: 3

Related Questions