Link to home
Start Free TrialLog in
Avatar of stevebeech
stevebeech

asked on

CRC creation problem.

Here's my situation:

I have a string in Hex format:

C8005106FA0603041609150000000000050000000000050000000000000030303030303100000500082602000000000000000000000000000200000001000000000100000000000000000000000000000000520103

and I need to calculate a CRC for it, which I know should be 8DDE.

However, my code gives the result as: CD51

Can anyone spot where I've gone wrong? (I'm using the CCITT version of CRC 16bit generation I think) Here's my class (called like "java CRC16 C800510.......")

public class CRC16 {

      /**  generator polynomial */
      private final static int poly = 0x1021;
      /*
          x16 + x12 + x5 + 1 generator polynomial
        */
      /*
          0x8408 used in European X.25
        */
      /**  scrambler lookup table for fast computation. */
      private static int[] crcTable = new int[256];
      static {
            // initialise scrambler table
            for (int i = 0; i < 256; i++) {
                  int fcs = 0;
                  int d = i << 8;
                  for (int k = 0; k < 8; k++) {
                        if (((fcs ^ d) & 0x8000) != 0) {
                              fcs = (fcs << 1) ^ poly;
                        } else {
                              fcs = (fcs << 1);
                        }
                        d <<= 1;
                        fcs &= 0xffff;
                  }
                  crcTable[i] = fcs;
            }
      }



      /**
       *  Calc CRC with CCITT method.
       *
       *@param  b  byte array to compute CRC on
       *@return    16-bit CRC, unsigned
       */
      public static short crc16(byte[] b) {
            // loop, calculating CRC for each byte of the string
            int work = 0xffff;
            for (int i = 0; i < b.length; i++) {
                  // xor the next data byte with the high byte of what we have so far to
                  // look up the scrambler.
                  // xor that with the low byte of what we have so far.
                  // Mask back to 16 bits.
                  work = (crcTable[(b[i] ^ (work >>> 8)) & 0xff] ^ (work << 8)) &
                              0xffff;
            }
            return (short) work;
      }


      /**
       *  Convert a byte[] array to readable string format. This makes the "hex"
       *  readable!
       *
       *@param  in  byte[] buffer to convert to string format
       *@return     result String buffer in String format
       */

      public static String byteArrayToHexString(byte in[]) {

            byte ch = 0x00;

            int i = 0;

            if (in == null || in.length <= 0) {

                  return null;
            }

            String pseudo[] = {"0", "1", "2",
                        "3", "4", "5", "6", "7", "8",
                        "9", "A", "B", "C", "D", "E",
                        "F"};

            StringBuffer out = new StringBuffer(in.length * 2);

            while (i < in.length) {

                  ch = (byte) (in[i] & 0xF0);
                  // Strip off high nibble

                  ch = (byte) (ch >>> 4);
                  // shift the bits down

                  ch = (byte) (ch & 0x0F);
                  // must do this is high order bit is on!

                  out.append(pseudo[(int) ch]);
                  // convert the nibble to a String Character

                  ch = (byte) (in[i] & 0x0F);
                  // Strip off low nibble

                  out.append(pseudo[(int) ch]);
                  // convert the nibble to a String Character

                  i++;

            }

            String rslt = new String(out);

            return rslt;
      }


      /**
       *  Description of the Method
       *
       *@param  hexStr  Description of the Parameter
       *@return         Description of the Return Value
       */
      public static byte[] toBinArray(String hexStr) {
            byte bArray[] = new byte[hexStr.length() / 2];
            for (int i = 0; i < (hexStr.length() / 2); i++) {
                  byte firstNibble = Byte.parseByte(hexStr.substring(2 * i, 2 * i + 1), 16);
                  // [x,y)
                  byte secondNibble = Byte.parseByte(hexStr.substring(2 * i + 1, 2 * i + 2), 16);
                  int finalByte = (secondNibble) | (firstNibble << 4);
                  // bit-operations only with numbers, not bytes.
                  bArray[i] = (byte) finalByte;
            }
            return bArray;
      }


      /**
       *  Description of the Method
       *
       *@param  a  Description of the Parameter
       *@return    Description of the Return Value
       */
      public static String ShortToHex(long a) {

            String hex = "0123456789ABCDEF";

            char[] digits = new char[4];

            for (int k = (3); k >= 0; k--) {
                  digits[k] = hex.charAt((int) (a & 15));
                  a = a >>> 4;
            }

            return new String(digits);
      }


      /**
       *  Description of the Method
       *
       *@param  args  Description of the Parameter
       */
      public static void main(String args[]) {

            if (args.length != 1) {
                  System.out.println("Usage: java CRC16 parameter - where parameter is a Hex string (e.g. AF34BD");
                  System.exit(-1);
            }

            String hexstring = args[0];
            System.out.println("Original Hex String: " + hexstring);

            byte[] ba = toBinArray(hexstring);
            System.out.println("Converted to Byte array");

            System.out.println("Reconversion gives: " + byteArrayToHexString(ba));
            System.out.println("Now calculating CRC....");

            short x = crc16(ba);
            String str = Integer.toBinaryString(x);
            System.out.println("Binary representation of CRC: " + str);
            System.out.println("Now converting to a two byte array");
            byte[] byte_array = str.getBytes();
            String q = byteArrayToHexString(byte_array);
            System.out.println("Hex value of 2 byte array (short): " + q);

            System.out.println("Hex Val of Short: " + ShortToHex(x));
      }
}
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Here's the way Sun does it. Maybe you can compare:

http://mindprod.com/jgloss/crc.html
Avatar of Giant2
Giant2

See here to calculate a checksum.
http://javaalmanac.com/egs/java.util.zip/CalculateChecksum.html

Bye, Giant.
And here:
http://www.java2s.com/Code/Java/Security/CRC.htm

Hope these links could help you.
Bye, Giant.
does anybody know whats the deference between CRC and CRC32 ?
Incidentally, taking those bytes as big-endian, with sun.misc.CRC16, i get

d0e3

Taking it as little-endian, i get

c1ea
i have already calculated the CRC32 of the givven hex string and that was 59a817f9
the asker said it should be 8DDE, so he can not produce that checksum with java.util.zip.crc32 either
he needs a 16 checksum instead
>>> 16 bit
Hi stevebeech,

I just tested your string into my hex editor with CRC calculation :
    init value=FFFF  xor=0  key=1021  highbit first   -> crc-16 = CD51 (the value you get)
    init value=0000  xor=0  key=8408  lowbit first    -> crc-16 = 8DDE (the value you want)
ASKER CERTIFIED SOLUTION
Avatar of Webstorm
Webstorm

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

And your static initialisation can be simplified :

     static {
          // initialise scrambler table
          for (int i = 0; i < 256; i++) {
               int fcs = i;
               for (int k = 0; k < 8; k++) {
                    if ((fcs & 0x0001) != 0) {
                         fcs = (fcs >>> 1) ^ poly;
                    } else {
                         fcs = (fcs >>> 1);
                    }
                    fcs &= 0xffff;
               }
               crcTable[i] = fcs;
          }
     }
Avatar of stevebeech

ASKER

You don't know how happy you've made me, Webstorm.

I'd figured that I'd got the wrong initializer, thought that the poly needed to be reflected, but hadn't figured the bit ordering was wrong.

Just one error in your code:

 work = (crcTable[(b[i] ^ work)) & 0xff] ^ (work >>> 8)) & 0xffff;

should be:

 work = (crcTable[(b[i] ^ work) & 0xff] ^ (work >>> 8)) & 0xffff;

Apart from that it works like a dream - you get all the points!

Cheers,

Steve