Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

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.

 

// 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);
}

RandImage.txt

"Beer is proof that God loves us and wants us to be happy."

-Benjamin Franklin

Posted

Finally here is the correct algorithm

 

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


"Beer is proof that God loves us and wants us to be happy."

-Benjamin Franklin

  • Administrators
Posted

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.

Posting Guidelines FAQ Post Formatting

 

Intellectuals solve problems; geniuses prevent them.

-- Albert Einstein

Posted

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

"Beer is proof that God loves us and wants us to be happy."

-Benjamin Franklin

  • Administrators
Posted

You could replace the core routine with something like

           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.

Posting Guidelines FAQ Post Formatting

 

Intellectuals solve problems; geniuses prevent them.

-- Albert Einstein

Posted

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

"Beer is proof that God loves us and wants us to be happy."

-Benjamin Franklin

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...