?
Solved

CRC creation problem.

Posted on 2006-04-04
13
Medium Priority
?
2,083 Views
Last Modified: 2012-05-05
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));
      }
}
0
Comment
Question by:stevebeech
  • 4
  • 3
  • 3
  • +2
13 Comments
 
LVL 86

Expert Comment

by:CEHJ
ID: 16370875
Here's the way Sun does it. Maybe you can compare:

http://mindprod.com/jgloss/crc.html
0
 
LVL 12

Expert Comment

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

Bye, Giant.
0
 
LVL 12

Expert Comment

by:Giant2
ID: 16370897
And here:
http://www.java2s.com/Code/Java/Security/CRC.htm

Hope these links could help you.
Bye, Giant.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 14

Expert Comment

by:hoomanv
ID: 16370940
does anybody know whats the deference between CRC and CRC32 ?
0
 
LVL 12

Expert Comment

by:Giant2
ID: 16370973
Maybe here there is an expanation:
http://en.wikipedia.org/wiki/Cyclic_redundancy_check
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 16371033
Incidentally, taking those bytes as big-endian, with sun.misc.CRC16, i get

d0e3

Taking it as little-endian, i get

c1ea
0
 
LVL 14

Expert Comment

by:hoomanv
ID: 16371042
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
0
 
LVL 14

Expert Comment

by:hoomanv
ID: 16371048
>>> 16 bit
0
 
LVL 13

Expert Comment

by:Webstorm
ID: 16372122
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)
0
 
LVL 13

Accepted Solution

by:
Webstorm earned 1200 total points
ID: 16372177

->
     private final static int poly = 0x8408;

     private static int[] crcTable = new int[256];
     static {
          // initialise scrambler table
          for (int i = 0; i < 256; i++) {
               int fcs = 0;
               int d = i ;
               for (int k = 0; k < 8; k++) {
                    if (((fcs ^ d) & 0x0001) != 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 = 0;
          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)) & 0xff] ^ (work >>> 8)) &
                         0xffff;
          }
          return (short) work;
     }

0
 
LVL 13

Expert Comment

by:Webstorm
ID: 16372250

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;
          }
     }
0
 

Author Comment

by:stevebeech
ID: 16374206
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
0
 
LVL 13

Expert Comment

by:Webstorm
ID: 16374334
:-)
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

By the end of 1980s, object oriented programming using languages like C++, Simula69 and ObjectPascal gained momentum. It looked like programmers finally found the perfect language. C++ successfully combined the object oriented principles of Simula w…
In this post we will learn different types of Android Layout and some basics of an Android App.
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
Suggested Courses
Course of the Month15 days, 4 hours left to enroll

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question