MTSkull Posted April 24, 2009 Posted April 24, 2009 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 Quote "Beer is proof that God loves us and wants us to be happy." -Benjamin Franklin
MTSkull Posted April 24, 2009 Author Posted April 24, 2009 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; } Quote "Beer is proof that God loves us and wants us to be happy." -Benjamin Franklin
Administrators PlausiblyDamp Posted April 24, 2009 Administrators Posted April 24, 2009 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. Quote Posting Guidelines FAQ Post Formatting Intellectuals solve problems; geniuses prevent them. -- Albert Einstein
MTSkull Posted April 24, 2009 Author Posted April 24, 2009 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 Quote "Beer is proof that God loves us and wants us to be happy." -Benjamin Franklin
Administrators PlausiblyDamp Posted April 25, 2009 Administrators Posted April 25, 2009 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. Quote Posting Guidelines FAQ Post Formatting Intellectuals solve problems; geniuses prevent them. -- Albert Einstein
MTSkull Posted April 27, 2009 Author Posted April 27, 2009 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 Quote "Beer is proof that God loves us and wants us to be happy." -Benjamin Franklin
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.