• AVR Freaks

Helpful ReplyHow to calculate checksum over struct using a byte sized pointer?

Author
BobAGI
Super Member
  • Total Posts : 1710
  • Reward points : 0
  • Joined: 2011/03/09 00:04:35
  • Location: Texas and Sweden
  • Status: offline
2012/04/26 01:48:18 (permalink)
0

How to calculate checksum over struct using a byte sized pointer?

I want to create a function that calculates a checksum across a struct holding configuration data.
So I tried as follows:

typedef struct      //This struct is used to hold the configuration data. Stored in EEPROM and RAM.
{
    unsigned int checksum; //Checksum over all items except checksum member
    unsigned int baud1;    //com port1..4 baudrates
    unsigned int baud2;
    unsigned int baud3;
    unsigned int baud4;
    unsigned char highcurrmode;
    unsigned int numnodes;
    unsigned int startaddr;
    unsigned long timer23count;
    long clockadjust;
    unsigned int curron2igbt;
    unsigned int curroff2igbt;
    char serialnumber[20];
} EEPROM;


UINT CheckSumConf(EEPROM *cnf)
{
    int i;
    UINT chk=0;
    unsigned char *data;

    data = (unsigned char)cnf;
    for (i=2; i < sizeof(EEPROM); i++) chk += *data++;
    return chk;
}

The EEPROM type is a struct which holds a number of configuration items for my board.
One member also holds the checksum, which I want to use in order to verify correct reading from the EEPROM before using the configuration items.
When I compile the above code I get warnings from C30 (version 3.30c):

source\eeprom.c|637|warning: cast from pointer to integer of different size
source\eeprom.c|637|warning: assignment makes pointer from integer without a cast


the line pointed to is:
data = (unsigned char)cnf;

So obviously I am doing something wrong here...
What I want to accomplish is to be able to loop the actual data bytes in memory and add them up to a 16 bit checksum (with roll-over if needed). So I need the data to be accessed as unsigned bytes.

What is the correct way to do this?


--
Bo B
Sweden & Texas
 
#1
mtaschl
Starting Member
  • Total Posts : 67
  • Reward points : 0
  • Joined: 2009/05/06 22:08:22
  • Location: Austria, Europe
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/26 02:59:51 (permalink)
0
     unsigned char *data; 
data = (unsigned char *) cnf;

or
     unsigned char data; 
data = *(unsigned char *) cnf;

post edited by mtaschl - 2012/04/26 06:09:00

/Martin
#2
BobAGI
Super Member
  • Total Posts : 1710
  • Reward points : 0
  • Joined: 2011/03/09 00:04:35
  • Location: Texas and Sweden
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/26 03:11:01 (permalink)
0
Thanks,
I see what you mean: I should typecast to the pointer type I want not to the data type...

Meanwhile:
If I change like this I don't get any warnings:

UINT CheckSumConf(void *cnf)
{
    int i;
    UINT chk=0;
    unsigned char *data;

    data = cnf;
    for (i=2; i < sizeof(EEPROM); i++) chk += *data++;
    return chk;
}

So specifying a void pointer in the argument makes it compatible to whatever is used in the body of the function, right?


--
Bo B
Sweden & Texas
 
#3
mtaschl
Starting Member
  • Total Posts : 67
  • Reward points : 0
  • Joined: 2009/05/06 22:08:22
  • Location: Austria, Europe
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/26 06:07:00 (permalink)
0
You are correct.

/Martin
#4
Ord
New Member
  • Total Posts : 16
  • Reward points : 0
  • Joined: 2011/03/16 19:37:51
  • Location: 0
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/26 06:09:53 (permalink) ☄ Helpful
0


Also, you would need data +=2 before the loop to skip over the checksum field, as is it will include the checksum in the calculation, but skip the last two characters of serial number
post edited by Ord - 2012/04/26 06:10:54
#5
BobAGI
Super Member
  • Total Posts : 1710
  • Reward points : 0
  • Joined: 2011/03/09 00:04:35
  • Location: Texas and Sweden
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 03:50:01 (permalink)
0
you would need data +=2 before the loop to skip over the checksum field


Yikes! You are right!
I had meant to do an array summing using i as an index when I started, that is one reason I have the i variable.
But then I used the pointer instead and you are right, it sums in the checksum and leaves out the final part of the string.

I still have problems though (even after changing it the way you propose)...
It seems like the sizeof() function does not return the correct length of the struct. When I count up the variables contained in it, I get 47, but sizeof() returns 48!
So it looks like somehow I am getting a bogus byte added into my checksum and it throws off everything.
To try and fix this I changed member "Highcurrentmode" from unsigned char to unsigned int (8 bits to 16 bits). This did not change the size reported by sizeof(). Still size = 48.

When I store the struct in EEPROM I do it using a block write function that takes the address of the struct and the length (sizeof()). It should write the struct data including the checksum to EEPROM.

Then when I read back I use a similar block read function also using the address of the struct and sizeof() as length.

When I look at the actual data saved and retrieved they all look perfectly OK including the checksum value written to EEPROM.
But still the checksum read back from EEPROM does not compare to what I calculate (using the exact same function) across the read back data...

So I have good data as far as I can see but the checksum written into the struct at save time does not correspond to what I calculate at read time.
Must be some bug in the checksumming function, but it beats me what.
Currently it looks like this:

UINT CheckSumConf(void *cnf)
{
    int i;
    UINT chk=0;
    unsigned char *data;

    data = cnf;
    data += 2;    //To get pointer past checksum;

    for (i=2; i < sizeof(EEPROM); i++) chk += *data++;
    return chk;
}


--
Bo B
Sweden & Texas
 
#6
Mikael
New Member
  • Total Posts : 22
  • Reward points : 0
  • Joined: 2010/06/28 03:57:04
  • Location: Stockholm
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 04:19:56 (permalink)
0
word alinment in C30 ?
You have a ‘unsigned char’ in your struct, maybe the next element is aligned to the next word?
You should add __packed__ to the struct
typedef struct __attribute__((__packed__)) {
  unsigned char  data1;
  unsigned int   data2;
} test1;

typedef struct {
  unsigned char  data1;
  unsigned int   data2;
}  test2;

C32 -- sizeof(test1) == 5
C32 -- sizeof(test2) == 8

/Mikael
#7
Chris A
Super Member
  • Total Posts : 834
  • Reward points : 0
  • Joined: 2010/07/20 04:37:07
  • Location: 0
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 05:24:05 (permalink) ☄ Helpful
0
But if using __packed__, be aware that the compilier will generate more code to access the members that are not aligned.

It may be better to order stuff with care and ignore the wasted padding bytes.
#8
BobAGI
Super Member
  • Total Posts : 1710
  • Reward points : 0
  • Joined: 2011/03/09 00:04:35
  • Location: Texas and Sweden
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 05:35:54 (permalink)
0
I just combined all the advice I have gotten from this thread and the one about zeroing struct data.
Still when I examine the variables using my debugger I always get a mis-match.
But then I decided to run without breakpoints active and then it works!

So for some reason the fact that I am stepping through my code instead of letting it run free affects the checksum calculation. Strange.
I do have interrupts also enabled so maybe this affects things.....

Anyway my main objective to get the configuration saved and restored and guarded by a checksum seems now to be solved. grin

--
Bo B
Sweden & Texas
 
#9
Antipodean
Super Member
  • Total Posts : 1707
  • Reward points : 0
  • Joined: 2008/12/09 10:19:08
  • Location: Didcot, United Kingdom
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 07:04:43 (permalink)
0
Ord

Also, you would need data +=2 before the loop to skip over the checksum field, as is it will include the checksum in the calculation, but skip the last two characters of serial number


Do you want to skip over the checksum field?
 
One of the common ways of doing check sums is to load the check sum field with a value that when combined with the other data sums to 0 or all ones, either of which is easily checked.

Do not use my alias in your message body when replying, your message will disappear ...

Alan
#10
aschen0866
Super Member
  • Total Posts : 4459
  • Reward points : 0
  • Joined: 2006/01/08 22:18:32
  • Location: San Diego
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 07:13:33 (permalink)
0
BobAGI

you would need data +=2 before the loop to skip over the checksum field


 
UINT CheckSumConf(void *cnf)
{

   unsigned char *data;
   ...
   data = cnf;
   data += 2;    //To get pointer past checksum;
   ...
}


Would that be easier if you just write:

   data = (unsigned char *)&cnf.baud1;

The problem with using "data += 2" to get pointer to pass the checksum field is that if you ever have to port this code to a different processor/compiler tool, where "unsigned int" is 32-bit wide, your code will fail.

#11
Chris A
Super Member
  • Total Posts : 834
  • Reward points : 0
  • Joined: 2010/07/20 04:37:07
  • Location: 0
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 08:41:32 (permalink)
0
Ah but Bob is parsing a void pointer now, not the struct.  Also allows him to use the same function on other setting structs if he parses the size as an extra parameter.

But these would be better than += 2
    data += sizeof(unsigned int);
or even
    data += offsetof(EEPROM,baud1);


post edited by Chris A - 2012/04/27 08:47:45
#12
Ord
New Member
  • Total Posts : 16
  • Reward points : 0
  • Joined: 2011/03/16 19:37:51
  • Location: 0
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 09:07:31 (permalink)
0
I don't see anything right away wrong with that.

I just finished debugging a routing for checksum on program memory in flash, one thing that helped was making the calculation simple enough that I could check it manually. In your case, if you set all elements in your struct to zero, you should get a checksum of zero. Then you can set a value to one of the baud rates, and make sure it comes with the right result.
#13
aschen0866
Super Member
  • Total Posts : 4459
  • Reward points : 0
  • Joined: 2006/01/08 22:18:32
  • Location: San Diego
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 09:17:44 (permalink)
0
Chris A

Ah but Bob is parsing a void pointer now, not the struct. ...

You are right. Not sure what'd hack I was looking... I guess somehow I got the impression the function was defined as

UINT CheckSumConf(EEPROM *cnf)
{
...
}

It is almost pointless to pass in a void pointer and only have the size of the object decided by sizeof(EEPROM) inside the call.

If the goal is to have a generic checksum calculation function, then it should have, as you suggested, a void pointer along with the size of the object, for instance:

UINT GetChecksum(void *p, size_t size)
{
}




#14
BobAGI
Super Member
  • Total Posts : 1710
  • Reward points : 0
  • Joined: 2011/03/09 00:04:35
  • Location: Texas and Sweden
  • Status: offline
Re:How to calculate checksum over struct using a byte sized pointer? 2012/04/27 15:34:27 (permalink)
0
Hi again!
Meanwhile I have changed the approach and made my checksumming functions generic rather than knowing about the struct etc:

UINT CheckSum(void *block, UINT len)
{
    unsigned char * data;
    UINT chk=0;
    data = block;
    while(len--) chk += *data++;
    return chk;
}

Then in the EEPROM write function I call a checksum updater as follows:

void UpdateChecksum(EEPROM * data)
{
    data->checksum = 0;  //Remove previous checksum so addition can be done over all bytes
    data->checksum = CheckSum(data, sizeof(EEPROM));
}

BOOL WriteConfiguration(EEPROM *conf)
{
    EEPROM confcpy;
    confcpy = *conf;  //In order to safeguard against interrupts changing the original while writing to EEPROM
    UpdateChecksum(&confcpy);   //Set checksum member to sum of all other bytes
    return (WriteEEEPROMBlock(0, sizeof(EEPROM), &confcpy)) == 0;
}


I tried following some advice about putting the checksum into the struct such that it would sum up to zero, but realized that it would not work because I am summing on bytes but I keep the result as a 16 bit integer. There is no way two byte values could offset a large enough 16 bit result....
So I am keeping my original scheme to use a 16 bit checksum and comparing the calculated value against the stored one for equality.



--
Bo B
Sweden & Texas
 
#15
Jump to:
© 2019 APG vNext Commercial Version 4.5