Thread: Calculating CheckSum

  1. #1
    Registered User
    Join Date
    Nov 2009
    Posts
    53

    Calculating CheckSum

    Hello,

    I'm trying to calculate the checksum of a string by adding all characters and then using ones complement on the addition result, this is what I've done so far.

    Code:
    int main(short argc, char **argv)
    {
    
       unsigned char serNum [] = "DS0008D-0111A";
       unsigned short checksum;
    
       checksum = CalcChksum(serNum, 13);
       
    cout << hex << checksum << "\n" << "\n"; //Here I get only the first byte 2B on the output, should be FD 2B;
    }
    
    unsigned short CalcChksum(unsigned char *start_addr, int bytecnt)
    {
       int i;
       unsigned short chksum;
    
       chksum = 0;
       // Calculate 1's complement chksum
       for(i=0; i<bytecnt; i++)
          chksum+= (unsigned short)*(start_addr+i);
       chksum = (char)~chksum;
       return(chksum);
    
    }
    If there is an easier method or better way of doing this I would appreciate any help

  2. #2
    Registered User
    Join Date
    Dec 2010
    Posts
    15
    You're using type conversions incorrectly:
    Code:
    chksum+= (unsigned short)*(start_addr+i);
    (unsigned short) is not needed here.
    Code:
    chksum = (char)~chksum;
    (char) truncates your checksum from 2 bytes to 1. If you remove it, you'll get FD 2B.

    Also the checksum finding method doesn't use symbol positions in calculation. It can be not reliable enough, but it depends on the purpose.

  3. #3
    Registered User
    Join Date
    Nov 2009
    Posts
    53
    Thanks, that really helped, specially the
    Code:
    chksum = (char)~chksum;
    line, can't believe I missed that.

    I don't really get what you mean with
    Code:
    chksum+= (unsigned short)*(start_addr+i);
    should I just add the bytes with no conversion?

    what do you mean by symbol positions in calculation, I want to make this as reliable as I can as it may be used on a DLL file.

  4. #4
    Registered User
    Join Date
    Dec 2010
    Posts
    15
    You should use conversion only when target type can contain smaller amount of data (assignment of "short" to "char" for example).

    By position I mean that "DS0008D-0111A", "DS0080D-0111A" will give the same sum.
    To get something more reliable, CRC-16 could be used.

  5. #5
    Registered User
    Join Date
    Nov 2009
    Posts
    53
    Ok, I understand now. This was the requirement I was given, just sum and do the 1's complement. We use CRC-16 for other stuff, but I'm just sticking with what I was given for now.

    Thanks for your help!

  6. #6
    Registered User
    Join Date
    Nov 2009
    Posts
    53
    Ok so now that I can calculate the checksum I'm trying to send it to the end of a string so I can write the data to an EEPROM. The only problem is that when I do it the checksum bytes are inverted for some reason.

    Code:
    int main(short argc, char **argv)
    {
       int i;
     
       unsigned char serNum [9] = "DS0008D-";
       unsigned char serNum1 [6] = "0111A";
       unsigned char ckSum_data [13];
       unsigned short checksum[3]={0x00,0x00,0x00};
    
       		for (i = 0; i < 5; i++)
    		{
    			ckSum_data [i + 8] = serNum1[i];
    	}
    		for (i = 0; i < 8; i++)
    	{
    			ckSum_data [i] = serNum[i];
    	}
    
    //ckSum_data[] should hold the entire serial number (DS0008D-0111A)
    
       checksum[0] = CalcChksum(ckSum_data, 13);
       		memcpy(&ckSum_data[14],&checksum[0],3);
    		cout << "\n" << checksum[0]; // Checksum output on console is FD 2B
    
    }
    So basically the last two bytes (15,16) should contain the checksum FD 2B.

    15 >> FD
    16 >> 2B

    But the freaking thing is putting them reversed.

  7. #7
    Registered User
    Join Date
    Dec 2010
    Posts
    31
    Looks like you're bumping into an endian issue.
    Look at Endianness - Wikipedia, the free encyclopedia

  8. #8
    Registered User
    Join Date
    Nov 2009
    Posts
    53
    That makes sense and I think the memcpy is causing this issues, how can I fix this?

  9. #9
    Registered User
    Join Date
    Nov 2009
    Posts
    53
    This is what I did. It places the checksum in the place I want the bytes to be.

    Code:
    		low = checksum&0x00FF;			//lower byte of checksum
    		high = (checksum>>8)&0x00FF;	//higher byte of checksum
    		memcpy(&ckSum_data[14],&high,1);
    		memcpy(&ckSum_data[15],&low,1);
    If there is any other way that this could be done please let me know. Thanks

  10. #10
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by drkidd22 View Post
    This is what I did. It places the checksum in the place I want the bytes to be.

    Code:
    		low = checksum&0x00FF;			//lower byte of checksum
    		high = (checksum>>8)&0x00FF;	//higher byte of checksum
    		memcpy(&ckSum_data[14],&high,1);
    		memcpy(&ckSum_data[15],&low,1);
    If there is any other way that this could be done please let me know. Thanks
    I trust you adjusted the size of your ckSum_data array... if you're still using the original definition from above 14 and 15 are out of bounds and may cause problems known as "undefined behaviour"... i.e. screwups.

  11. #11
    Registered User
    Join Date
    Dec 2010
    Posts
    31
    Quote Originally Posted by drkidd22 View Post
    This is what I did. It places the checksum in the place I want the bytes to be.

    Code:
    		low = checksum&0x00FF;			//lower byte of checksum
    		high = (checksum>>8)&0x00FF;	//higher byte of checksum
    		memcpy(&ckSum_data[14],&high,1);
    		memcpy(&ckSum_data[15],&low,1);
    If there is any other way that this could be done please let me know. Thanks
    I would not be swapping the bytes. This assumes you know something about
    the system architecture. It would not work if you wrote the data on a system
    with one Endian and read it back on a system with the opposite Endian.

    Not knowing your requirements it's hard to say how you should proceed.

    If you can afford to waste a byte of PROM space then you should pad the
    data when count is not a multiple of 2. Then you could stuff the checksum
    at the end of the data with *(unsigned short *)&ckSum_date[14] = checksum;
    And extract it the same way.

    If you can't afford to waste a byte of PROM space then maybe an
    8 bit checksum could be used, since your char arrays are small.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Runtime problem
    By SantoshN in forum C Programming
    Replies: 2
    Last Post: 10-12-2010, 02:42 PM
  2. checksum sender vs reciever?
    By silhoutte75 in forum C Programming
    Replies: 1
    Last Post: 04-13-2008, 01:27 PM
  3. weird checksum function
    By sagitt13 in forum C Programming
    Replies: 7
    Last Post: 10-31-2006, 01:25 AM
  4. Recursion
    By Lionmane in forum C Programming
    Replies: 11
    Last Post: 06-04-2005, 12:00 AM