How find at a struct parameter has been change?

Go To Last Post
24 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi.

I have a struct who has a lot of parameter. Parameter can be setup from GSM or Modbus via UART.

I need to have an count to register how much time parameter has been change. 

Struct is over 800 value , will not make a copy and compare.

I want to "count all bit or make a crc" and compare if  crc change. 

I can not found how to do that? 

Thank you for help.

This topic has a solution.

Thierry Pottier

Last Edited: Sun. Mar 25, 2018 - 12:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well a struct is just a sequential sequences of bytes so you can just access each byte in turn and add them up to make a checksum. But this won't identify which of the 800 values changed. You could break it down into sections but that would only identify the section(s) in which there were changes. The only way to find the exact change is really to keep a copy and diff  them. Another way might be to keep a "journal" of the updates if they are only sparse.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you're talking about C struct objects, note that you probably don't want to include padding bytes. Sometimes structures will be arranged with space between some members. Probably not common on AVR, but if you're getting things from something else, it could happen. The empty space isn't usually considered part of the value.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well 

I am not a prof in C.

//eeprom struct eeprom_test {

   struct eeprom_test {

             char stid[LENGTH_STID]; // ID name 32 ascii char

             int  add;      // Slave modbus address

             int  rif;      // Slave modbus address

             int powi; // Power config, if battery supply or fast power

             int prot; // Protocol

             char sip[LENGTH_SIP]; // IP address

             int prpo; // Port protocol

             int funk; // function of unit, normal, us ++++

             int lock; // config source avaible: Config IF serial, sms, IP

             int comf;      // com function // config reading +++

             int coms[LENGTH_COMS]; // baud rate /100, partity 0 no-1 even -2 odd, stop 1 - 2

             int comdg; // delay for end of transmition for GSM

             int comdm; // delay for end of transmition for MODBUS

             int msw; // config magnet switch activity

             int maxr; // max report per day, 0 no limit

             /*

             int cor; //Control report for power

             int coa1; // state for analog1 out

             int coa2; // state for analog2 out

             int pou1;

             int pou2;

             int pout1;

             int pout2;

             */

             int batdis[3]; // battery level for display

             char apn[LENGTH_APN]; // APN name

             char apnc[LENGTH_APNC]; // message when connected

             char apnu[LENGTH_APNU]; //  APN user name

             char apnp[LENGTH_APNP]; //

             int coct; // connection time limit , ping serveur & reboot if no answer +++

             int cip[LENGTH_COIP]; // connection IP

             //int APN_notused[3];

 

             int lrep; // live report condition 0:off, 01 SMS,

             int lrepi; // live report interval, time i min, 0 no report interval

             int lrept; // live report time MSB timer, LSB day of week 1 = Monday

             int lrepip[LENGTH_LREPIP]; // live report IP

             int lreppo; // live report port

             int lreptlf;

             //int lrepnotused[5];

 

             int digin; // Not used

             int dig1; // not used but set if input is pull up, low Zm High Z

             int dig2; // not used but set if input is pull up, low Zm High Z

             int dig3; // not used but set if input is pull up, low Zm High Z

             int dig4; // not used but set if input is pull up, low Zm High Z

             int dig5; // not used but set if input is pull up, low Zm High Z

             int dig6; // not used but set if input is pull up, low Zm High Z

             //int digNotUsed[10];// not used

 

             int ais1; // Analog 1 , 0:off, 1:4-20mA, 2 0-10V

             int aij1[5]; // sign teller, divider, sign offset

             int ais2; // Analog 2 , 0:off, 1:4-20mA, 2 0-10V

             int aij2[5]; // sign teller, divider, sign offset

             int tif1; // Temperatur 1 , 0:off, 1:4-PT1000, 2 PT100

             int tij1[5]; // teller, divider, offset

             int tif2; // Temperatur 2 , 0:off, 1:4-PT1000, 2 PT100

             int tij2[5]; // teller, divider, offset

             int dis1; // Seting for distance measure with US

             int disj1[5]; // teller, divider, offset

             int pows; // power seting 00 fast power 01 bat, 02 extern bat,

             int batt; // type of battery chimical

             int battj[5]; // teller, divider, offset

             //int batNotUsed[3];

 

             char di1ton[LENGTH_OUT]; // (txt 16 char not case sens, 1ch. only)

             char di1toff[LENGTH_OUT];

             char di2ton[LENGTH_OUT];

             char di2toff[LENGTH_OUT];

             int dims; // seting for interval or data

             int dint; // time in minutt

             int ltim; //

             int aim1; // seting for Analog1 measure

             int aint1; // time in minutt

             int atim1; // clock seting

             int aim2; // seting for Analog2  measure

             int aint2; // time in minutt

             int atim2; // clock seting

             int tim1; // seting rapport temperature 1

             int tim2; // seting rapport temperature 2

             int tint;

             int ttim;

             int dis; // measure distance

             int disnt;

             int dstim;

             //int d_NotUsed[30];

             //alix,altx,alvx,alhx,alux,alsx1,alsx2,alnx

             // alarm1  setting ref 1100h

             int ali1; //  Trigger inngang 0:off +++ :alarm def for more info

             int alt1; // condition test if al > alva1 :alarm def for more info

             int alv1; // condition test if al > alva1 :alarm def for more info

             int alh1;

             int alu1;

             char als11[LENGTH_ALS];

             char als12[LENGTH_ALS];

             int aln1;

             //int al_NotUsed1[9];

             // alarm2  setting ref 1130h

             int ali2; //  Trigger inngang 0:off +++ :alarm def for more info

             int alt2; // condition test if al > alva1 :alarm def for more info

             int alv2; // condition test if al > alva1 :alarm def for more info

             int alh2;

             int alu2; //

             char als21[LENGTH_ALS];

             char als22[LENGTH_ALS];

             int aln2;

             //int al_NotUsed2[9];

             // alarm3  setting ref 1130h

             int ali3; //  Trigger inngang 0:off +++ :alarm def for more info

             int alt3; // condition test if al > alva1 :alarm def for more info

             int alv3; // condition test if al > alva1 :alarm def for more info

             int alh3;

             int alu3;

             char als31[LENGTH_ALS];

             char als32[LENGTH_ALS];

             int aln3;

             //int al_NotUsed3[9];

// alarm4  setting ref 1130h

             int ali4; //  Trigger inngang 0:off +++ :alarm def for more info

             int alt4; // condition test if al > alva1 :alarm def for more info

             int alv4; // condition test if al > alva1 :alarm def for more info

             int alh4;

             int alu4;

             char als41[LENGTH_ALS];

             char als42[LENGTH_ALS];

             int aln4;

             //int al_NotUsed4[8];

             char tlf1[LENGTH_TEL];

             char conf1;

             char tlf2[LENGTH_TEL];

             char conf2;

             char tlf3[LENGTH_TEL];

             char conf3;

             char tlf4[LENGTH_TEL];

             char conf4;

             char tlf5[LENGTH_TEL];

char conf5;

             char tlf6[LENGTH_TEL];

             char conf6;

             char tlf7[LENGTH_TEL];

             char conf7;

             char tlf8[LENGTH_TEL];

             char conf8;

             char tlf9[LENGTH_TEL];

             char conf9;

               } ;

I want to calcul CRC ( add byte)

from value from the start of struct to the end.

I guess it must be possible with a pointer but all example I found seam to use " item navn of struct" not from first value...

Thank you for help.

 

Thierry Pottier

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found this: 

http://www.microchip.com/forums/...

but not understand realy how to use. but I try...

 

Thierry Pottier

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

800 bytes seems a lot of data for an AVR.

From how many of those 800 bytes do you actually want to track the changes?

 

Clawson's Journal idea might be a good solution. You can keep track of the last few changes in a circular buffer or a separate array during update of the structure.

With the journal approach you only have to store the old values, and where they come from, because the new "updated" values are of couse in your 800 byte structure.

If you want you can expand with timestamps or other miscellaneous info.

 

---------------------------------

If you want to implement a CRC, then a nice solution is to work with a union and "anonymous" structures.

The structure you have now, will become an "anonymous" structure, and you put that in an union together with an array of bytes.

The union will get the same name as the structure now has.

For the rest of the program it is the same, because of the "anonymous" structure you do not have to add an extra name to address you inner data, but you have added the array (which shares the same memory space as your structure). You can use one of the CRC routines from #include "util/crc.h" to calculate the CRC itself.

---------------------------------

A similar way of calculating the CRC is with working with void pointers or with casting the type of the pointer.

This is an bit oldfashioned programming style, but it is perfectly valid C.

 

========================

The overall problem however is that we have an extremely limited view of what you want to do, and you have explicitly excluded the most logical "clean" solution.

Update: Most of your 800 byte data seems to never, or only very occasionally change. You can probably put a large chunk of it in Flash or EEprom.

 

TPE wrote:
Well I am not a prof in C.
This sounds like a lame excuse with your 12 year membership and 500+ posts. To me it looks like you should have gotten a good book or other resource for C and put in some concious effort to learn the language long ago. You can still do it now.

 

And CRC's have been done to death all over the internet, with hundreds of tutorials.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Why not just set a 'somethings has changed' flag in your GSM and Modbus routines?

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TPE wrote:
I need to have an count to register how much time parameter has been change.

Do you need a counter for each individual value or only one for the entire struct?

 

Either way, this seems like the best solution:

Brian Fairchild wrote:
Why not just set a 'somethings has changed' flag in your GSM and Modbus routines?

 

I would suggest to do it C++ style: Never write the struct directly, but use setter functions (methods in C++ terminology). This function would actually perform the change and update the counter. Make it inline to keep the stack small and preserve speed.

"Some people die at 25 and aren't buried until 75." -Benjamin Franklin

 

What is life's greatest illusion?"  "Innocence, my brother." -Skyrim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A CRC will tell you that the struct has changed, but it will not tell you which value (or values) actually changed.

 

If you need to do that, then I would make a union, overlaying an array over the struct. Then, at the time a new value is written to the struct, record, in a buffer, the array index of the value that was changed.

 

Jim

 

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

offsetof() could prove useful.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The struct can't magically change itself - so you must know when you change it!

 

As Brian said, keep a flag (or flags) to say what's changed.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for all comment.

I will continuous to find the solution. 

Yours comment are positive but not show a way out. 

 

Paulvdh wrote:
This sounds like a lame excuse with your 12 year membership and 500+ posts. To me it looks like you should have gotten a good book or other resource for C and put in some concious effort to learn the language long ago. You can still do it now.   And CRC's have been done to death all over the internet, with hundreds of tutorials.

Yes Paul. 

12 year in avrfreak and 1000000 of board with AVR but I will learn new think all the time and Google is a good way to find think. But I steel to said at I am not a prof in C.

but sometime help of people can give quicker and better solution. it is why AVRFREAK has so much people and post. if not need this , Google was the only one forum! 

 

 

Thierry Pottier

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TPE wrote:

Yours comment are positive but not show a way out. 

 

Can you explain why? That might help improve people's suggestions.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok 

thank you for all.

found a way to work out:

the base idea is:

I have already a crc for "char" 

than use like it, work nice.

 

temp =sizeof (SMS_IOG);

ptr = (eeprom unsigned int *)&SMS_IOG;

uchCRCHi = 0xFF ; /* high byte of CRC initialized */

uchCRCLo = 0xFF ; /* low byte of CRC initialized */

/

    while (temp--)

    {   x= (char)*ptr;

        uIndex = uchCRCLo ^ x ; /* calculate the CRC */

        uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex] ;

        uchCRCHi = auchCRCLo[uIndex] ;

         value+= (uchCRCHi << 8 | uchCRCLo);

        x= (char)(*ptr>>8);

        uIndex = uchCRCLo ^ x ; /* calculate the CRC */

        uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex] ;

        uchCRCHi = auchCRCLo[uIndex] ;

         value+= (uchCRCHi << 8 | uchCRCLo);

         *ptr++;

}

value show a state of struct, anychange in struct will change this value.

 

Thierry Pottier

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't know how often you make updates and how many between each CRC calc, but if you make many changes sooner or later you will

get CRC = ok when there have been made changes.

 

You have to tell what your problem is since you don't want to follow the suggestions!

 

is it speed or ?  

Last Edited: Sun. Mar 25, 2018 - 12:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sorry But I do not see some suggestions? 

the most post was question or another .. no solution.

but sometime not easy to explain what you need realy. 

My problem was to control if some value was change and if change increase a counter. 

this solution make my goal. 

 

Thierry Pottier

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But as I said at the start all a CRC will tell you that something has changed. Not which item. To achieve thatthat you would need a dcheck on every individual item and even then you have to kee and compare all the "before"/"after" cases.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have a struct, the only way it changes if you change it. So you don't need to detect changes. Normally.

 

But you seem to be expecting it to be changed by something other than your program, and your sample code says "eeprom unsigned int", so I'm wondering if you have an object in an eeprom. So something else can write to the eeprom, and you can check later to find out whether it got modified?

 

The reason no one is making coherent suggestions is that you have not actually described the problem! Please start from the beginning, and fully explain what is happening. Where is this object? How can it become modified? Can any code other than your code modify it? Is that code running on the AVR chip you wish to program, or are you sharing this eeprom with some other device?

 

 

Analogy: Imagine that you were in a forum full of medical techs, and you were asking about possible ways to test whether you have raised your arm, so you can test how often you raise your arm. One of the first questions will be "why not just make a note whenever you do that", and you respond by posting something about a blood test that could in theory indicate increased muscle activity levels, so if you just did blood draws from the arm every five seconds and did this test, maybe that would tell you whether you've raised your arm.

 

But you *know* whether you've raised your arm, because you're there when you do it.

 

If you have a thing in your code, you *know* whether you've changed it or not, because your code is the thing changing it.

 

 

It sounds like you're doing something more like "check the contents of an eeprom occasionally", or "receive incoming messages every so often, and you want to see whether the contents change between messages".

 

But you haven't actually told us what you're doing or why. I thought maybe the "SMS_IOG" name would help, but this thread is the only instance of that I can find anywhere.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TPE wrote:
Parameter can be setup from GSM or Modbus via UART.
I guess a key question is when this distant GSM/UART process sends an update does it just change one of the 800 values or does it send a complete set and you don't know which members it changed?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I guess a key question is when this distant GSM/UART process sends an update does it just change one of the 800 values or does it send a complete set and you don't know which members it changed?

 

well said clawson. 

it is the main idea of this. 

Thierry

Thierry Pottier

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If the GSM sends all 800 bytes with no indication of what has changed, a CRC would tell you IF there has been a change.
You would still have to compare with a previous struct to see WHICH fields have changed.
.
If you store the current state in EEPROM, you only need to compare each field as it arrives.
Make note of the altered field before updating the EEPROM field.
Unchanged fields do not require update.
.
Life is simpler if you download all 800 bytes into SRAM before updating the EEPROM.
Perhaps it is time to move to ARM. Most can reserve an area of Flash to emulate EEPROM. This does not have the endurance or convenience as AVR EEPROM but will be fine for most calibration data.
.
David.

Last Edited: Sun. Mar 25, 2018 - 02:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That was a question. I was asking which of those two it was. So are you saying it sends all 800 and you don't know which changed? If so then you have to "diff" the whole thing don't you? But if this is all about not wanting to write EEPROM for the ones that haven't changed then surely the standard EEPROM update routines already handle that?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was suggesting that Thierry compares the new with the old before calling eeprom_update().
You still get efficent code when updating Cliff_Lawsen to Cliff_Lawson.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But eeprom_update_byte() already avoids rewriting anything it does not need to so would only write the 'e' to an 'o' in that case anyway.