Calculation of CCITT standard CRC with polynomial x^16 + x^12 + x^5 + 1 in Java

AdrianES picture AdrianES · Jul 11, 2014 · Viewed 24.3k times · Source

I need help with calculating of CCITT standard CRC with polynomial x^16 + x^12 + x^5 + 1 (0x1081) in Java. I have tried many examples on the internet but every one of them returns other values than the ones in the example.

For example for this array [0xFC] [05] [11] the result needs to be [27] [56].

Using this code:

public static void main(String[] args) {
        byte[] array = new byte[3];
        array[0] = (byte) 0xFC;
        array[1] = (byte) 0x05;
        array[2] = (byte) 0x11;
//        array[3] = (byte) 0x00;
//        array[4] = (byte) 0x00;

        System.out.println(Integer.toHexString(crc16(array)));
    }

    private static final int POLYNOMIAL = 0x1081;
    private static final int PRESET_VALUE = 0xFFFF;

    public static int crc16(byte[] data) {
        int current_crc_value = PRESET_VALUE;
        for (int i = 0; i < data.length; i++) {
            current_crc_value ^= data[i] & 0xFF;
            for (int j = 0; j < 8; j++) {
                if ((current_crc_value & 1) != 0) {
                    current_crc_value = (current_crc_value >>> 1) ^ POLYNOMIAL;
                } else {
                    current_crc_value = current_crc_value >>> 1;
                }
            }
        }
        current_crc_value = ~current_crc_value;

        return current_crc_value & 0xFFFF;
    } 

I get result FA DE not [27] [56]

Using this code:

public static void main(String[] args) { 
        int crc = 0x0000;         
        int polynomial = 0x1081;   

        // byte[] testBytes = "123456789".getBytes("ASCII");

//        byte[] array = args[0].getBytes();
        byte[] array = new byte[3];
        array[0] = (byte) 0xFC;
        array[1] = (byte) 0x05;
        array[2] = (byte) 0x11;

        for (byte b : array) {
            for (int i = 0; i < 8; i++) {
                boolean bit = ((b   >> (7-i) & 1) == 1);
                boolean c15 = ((crc >> 15    & 1) == 1);
                crc <<= 1;
                if (c15 ^ bit) crc ^= polynomial;
             }
        }

        crc &= 0xffff;
        System.out.println("CRC16-CCITT = " + Integer.toHexString(crc));
    }

I get this CRC16-CCITT = 8dca

Using this code:

private final int polynomial = 0x1081;

    private int[] table = new int[256];

    public int ComputeChecksum(int[] bytes) {
        int crc = 0xffff;
        for (int i = 0; i < bytes.length; ++i) {
            int index = (crc ^ bytes[i]) % 256;
            crc = (crc >> 8) ^ table[index];
        }
        return crc;
    }

    public CRC162() {
        int value;
        int temp;
        for (int i = 0; i < table.length; ++i) {
            value = 0;
            temp = i;
            for (byte j = 0; j < 8; ++j) {
                if (((value ^ temp) & 0x0001) != 0) {
                    value = (value >> 1) ^ polynomial;
                } else {
                    value >>= 1;
                }
                temp >>= 1;
            }
            table[i] = value;
        }
    }

    public static void main(String[] args) {
        CRC162 c = new CRC162();
        int[] arr = new int[]{0xFC, 0x05, 0x11};
        System.out.println(Integer.toHexString(c.ComputeChecksum(arr)));
    }

I get this 521

Hope someone can help me. I need this for communication with device using ID003 protocol.

EDIT: Using this online calculator at http://www.lammertbies.nl/comm/info/crc-calculation.html for input FC0511 i get 0x2756 right from CRC-CCITT (Kermit).

Answer

Mark Adler picture Mark Adler · Jul 11, 2014

x^16 + x^12 + x^5 + 1 is not 0x1081. It is 0x1021. x^5 is 20, not 80. (Note that the x^16 is dropped.)

Furthermore, the Kermit CRC that you need is reflected, so the polynomial is reversed giving 0x8408.

For this CRC, you initialize with zero and do not complement the result.

So modifying your first example accordingly, this computes what you want:

public static void main(String[] args) {
    byte[] array = new byte[3];
    array[0] = (byte) 0xFC;
    array[1] = (byte) 0x05;
    array[2] = (byte) 0x11;
    //        array[3] = (byte) 0x00;
    //        array[4] = (byte) 0x00;

    System.out.println(Integer.toHexString(crc16(array)));
}

private static final int POLYNOMIAL = 0x8408;
private static final int PRESET_VALUE = 0;

public static int crc16(byte[] data) {
    int current_crc_value = PRESET_VALUE;
    for (int i = 0; i < data.length; i++) {
        current_crc_value ^= data[i] & 0xFF;
        for (int j = 0; j < 8; j++) {
            if ((current_crc_value & 1) != 0) {
                current_crc_value = (current_crc_value >>> 1) ^ POLYNOMIAL;
            } else {
                current_crc_value = current_crc_value >>> 1;
            }
        }
    }

    return current_crc_value & 0xFFFF;
}