Checksum problem

MTSkull

Centurion
Joined
Mar 25, 2003
Messages
151
Location
Boulder, Colorado
Part 2 of an earlier post. Going in a different direction.

A vendor gave me some code to generate a checksum. I got the vendor code working and it does not even come close to returning the right value, so I suspect they did not understand what I was asking. It does generate a correct CRC 16 value but that is not what their program produces. If i can figure this out then I can automate one labor intensive process and eliminate a test further down the factory line.

I found this tutorial for generating checksums at http://www.netfor2.com/checksum.html I used this to base my new algorithm on because I downloaded “010 Editor” by Sweetscape. It calculates various checksums for bin files. Running this against my hex file I find that it’ generates a 16 bit Bigendian Checksum that equals the vendors correct checksum.

Against the attached Random Binary File I get. I had to change the extension to .txt, changing it back to .bin should yield the same data.

010Editor
Checksum, Ushort (16bit), Bigendian = 00000004 00162847

Vendor Value I am trying to Duplicate, generated by their manual software.
Data Sumcheck Unswapped=162847 (same as above without the carry)

My algorithm returns 16284B or 4 off the correct answer. Which, incidentally, is the same as the carry left over in the upper bytes from 010Editor.

Here is the algorithm I developed.

Code:
// following comments copied from http://www.netfor2.com/checksum.html  
//01 00 F2 03 F4 F5 F6 F7 00 00
//(00 00 is the checksum field)
//Form the 16-bit words
//0100 F203 F4F5 F6F7
//Calculate 2's complement sum
//0100 + F203 + F4F5 + F6F7 = 0002 DEEF (store the sum in a 32-bit word)
//Add the carries (0002) to get the 16-bit 1's complement sum
//DEEF + 002 = DEF1
//Calculate 1's complement of the 1's complement sum
//~DEF1 = 210E
//We send the packet including the checksum 21 0E
//01 00 F2 03 F4 F5 F6 F7 21 0E
UInt32 OnesCompCheckSum_WCarry(byte[] Bytes)
{ // developed based on above comments
      UInt64 CheckSum = 0; // bigger to capture overflow in upper bytes
      UInt32 tempOnes = 0;

      string temp = "";

      for (int x = 0; x < Bytes.GetUpperBound(0); x += 2)
      {
      	//swapped
            //temp = Bytes[x + 1].ToString("X").PadLeft(2, (char)48);
            //temp += Bytes[x].ToString("X").PadLeft(2, (char)48);

            //unswapped // very close to desired
            temp = Bytes[x].ToString("X").PadLeft(2, (char)48);
            temp += Bytes[x + 1].ToString("X").PadLeft(2, (char)48);
                
            tempOnes = UInt32.Parse(temp, NumberStyles.HexNumber);
            tempOnes = ~tempOnes;
            CheckSum += tempOnes;
      }

      //add the carry back in.
      temp = CheckSum.ToString("X").PadLeft(16, (char)48); // check sum to 16byte hex string
      UInt32 Carry = UInt32.Parse(temp.Substring(0,8),NumberStyles.HexNumber); // first 8 hex chars, to int
      tempOnes = UInt32.Parse(temp.Substring(8), NumberStyles.HexNumber); // last 8 hex chars, to int
      tempOnes += Carry;

      CheckSum = ~tempOnes; //so I can set a break point and see what I am returning
      temp = CheckSum.ToString("X").PadLeft(16, (char)48); 

      return ~(tempOnes);
}
 

Attachments

Finally here is the correct algorithm

Code:
        UInt64 Sixteen_Bit_Checksum(byte[] Bytes, bool BigEndian)
        {
            UInt32 workingByte = 0x0;
            UInt64 sum = 0x0;

            string msByte = ""; // most significant byte
            string lsByte = ""; // least significant byte

            for (Int32 x = 0; x < Bytes.GetUpperBound(0); x += 2)
            {
                if (BigEndian == true)
                { // big endian so swap bytes
                    msByte = Bytes[x + 1].ToString("X").PadLeft(2, (char)48);
                    lsByte = Bytes[x].ToString("X").PadLeft(2, (char)48);
                }
                else // little endian, no swap
                {
                    msByte = Bytes[x].ToString("X").PadLeft(2, (char)48);
                    lsByte = Bytes[x + 1].ToString("X").PadLeft(2, (char)48);
                }

                workingByte = UInt32.Parse(msByte + lsByte, NumberStyles.HexNumber);

                sum += (UInt64)workingByte;

            }

            return sum;
        }
 
You beat me to it... Testing your new routine though doesn't seem to give the same result as your original post, am I missing something?

Also if speed is an issue you should probably avoid string operations and use bitwise calculations - will be far more efficient code.
 
The least 8 bytes are used by the program. No Carries.

Interesting, It worked on several different files for me. Maybe I posted the wrong one, in the original post. One problem I had with the original was I forgot to seed the random array generator so I would get a different file every time, and a different checksum. I was ready for nervous break down till i figured that one out.

I just wanted it to work. Now that I know what I am doing I will look into optimizing it. On my machine with a one meg file there is a short but perceived lag.

This is part one. I need to generate two CRC32 values for other files as well. I think that may be a bit easier though. Although this should have been as well, just over thinking the problem.

Thanks
MTS
 
You could replace the core routine with something like
Code:
            UInt32 workingByte = 0x0;
            UInt64 sum = 0x0;

            for (Int32 x = 0; x < Bytes.GetUpperBound(0); x += 2)
            {
                if (BigEndian)
                     workingByte = ((uint)Bytes[x + 1] << 8) + Bytes[x];
                else // little endian, no swap
                    workingByte = ((uint)Bytes[x] << 8) + Bytes[x+1];
                
                sum += workingByte;
            }

            return sum;
note that you are returning a 64 bit value but only dealing with the bottom 32 bits so direct comparisons might fail - casting the result to a 32 bit value should sort that out though.
 
I keep forgetting how slow string manip really is. I dropped you code into the function and it now runs "Instantly" on a 1 meg byte array.

Thanks saved me from doing a bit more work.
MTS
 
Back
Top