Arduino esp32: storing array of struct EEPROM - arduino

I'm facing a problem can't be able to resolve to store an array of struct in nvs.
I have this structure composed of variable length String:
typedef struct
{
String Name;
String Surname;
String Status;
String Expiry;
} EpromTags;
EpromTags arraytag[50];
void setup()
{
//should load arraytag from EEPROM here
}
In other routines I have this data coming from a remote server, so I'm saving it to me arraytag
for (int i=0, i<50,i++)
{
arraytag[i].Name = valuename[i];
arraytag[i].Surname = valuesurname[i];
arraytag[i].Status = valuestatus[i];
arraytag[i].Expiry = valueexp[i];
}
//should save to arraytag to EEPROM here
The idea is to load the value of the structure to men on arrive and load back on setup.
I have been able to write single elements to EEPROM but I'm finding difficulties in saving this array of struct.
can someone drive me in the right directions or have suggestions?

The String class handles a char array buffer allocated in heap memory. The object of class String only has a pointer to this buffer. If you store a String object to EEPROM, you don't store the buffer and after retrieving the object the pointer is not valid.
Use C strings (zero terminated character arrays) of predefined size to store a struct with string in EEPROM.
typedef struct
{
char name[NAME_MAX_LENGTH];
char surname[SURENAME_MAX_LENGTH];
char status[STATUS_LENGTH];
char expiry[EXP_LENGTH];
} EpromTags;
To save any data type you can use EEPROM.put(). To read it back you use EEPROM.get(). So you can use a straight forward EEPROM.put(arraytag) to store all 50 items of the array and EEPROM.get(arraytag) to read it back.
The size of the struct is sizeof(EpromTags). The size of the array is count of items multiplied by the size of the item.
Note that the ESP32 EEPROM library emulates the EEPROM in flash memory and requires to call EEPROM.begin() and EEPROM.commit(). See the examples of the ESP32 EEPROM library on how to use it.

Related

Can I assign a #define value to Char*?

I have been writing a C - programm. Where I have a structure with char* members.
#define SS_Value_1 "Value for SS1"
#define SS_Value_1 "Value for SS2"
struct aSamplestruct {
char* s1;
char* s2;
}aSample;
aSample ss;
fun1( &aSample );
I am sending the structure point to a function and I know the best practice is to allocate memory to S1 and copy the string what ever we want and free the allocated memory after usage, As shown below
ss->s1 = (char*) MEM_alloc(sizeof(char) * (strlen(SS_Value_1) + 1);
strcpy(ss->s1, SS_Value_1);
use the variable ss.s1 in a report and do mem free.
MEM_free(ss.s1);
Its working fine no worries. but I have to write the same piece of code for some 10 char* members in 36 different conditions.
The other way is that, without allocating any memory I am able to directly assign the #define values to my structure members as below.
ss->s1 = SS_Value_1;
use this variable in a report and no need to free any memory.
this way also fine, no problems in a sample execution.
what I would like to know is
whether this will cause any memory leaks ?
will it stop executing for large data ?
Thanks in advance
Regards,
Sudhir
This is similar to
char *str;
str = "abc";
That is, you are declaring a char pointer, creating a string literal and assigning its address to the pointer. should work for any amount of data.

Memory allocation for Pointer

In which section memory is allocated if I write something like
1. int *ptr;
*ptr = 22;
2. int *ptr = new int(22);
What I Understand is when we use keyword new then memory is get reserved into Heap and that reserved memory address is get returned .
But what happened in case we didn't use keyword new ?? Where memory is get allocated ??
is Both Syntax is Same ?? If No, what is Exact difference between these two statement ??
You code examples can be rephrased as follows:
1st:
int * ptr;
*ptr = 22;
2nd:
int * ptr;
ptr = new int; //the only difference
*ptr = 22;
What happens in the second one:
int * ptr; means create variable capable of storing address of int variable. For now variable isn't initialized, so it stores garbage. If you interpret garbage as pointer, it can points anywhere (it can be 0, or 0xabcdef11, or 0x31323334, or literally ANYTHING which is left on non-cleared memory form previous usage)
ptr = new int; means "allocate memory area capable of holding int and store its address in ptr variable". Since this line, ptr points to specific memory
*ptr = 22; means put value 22 to memory pointed by ptr.
In the first example you create variable, but don't initialize it. ptr contains garbage, but you ask to interpret it as address and store 22 to this address. What can happen:
address is invalid (e.g. 0, or out of address range, or points to protected memory) => program crashes
address is valid and writable, but memory area is used by another part of the program: you'll write 22, but it will corrupt someone's data, result totally unpredictable.
address is valid and writable, memory area isn't in use. You'll write 22, but you aren't guaranteed to read it back. Memory can become used for different purpose and 22 will be overwritten.
anything else. All this is actually an undefined behavior, everything is possible.
That's why it's always recommended to initialize pointer immediately:
int * ptr = NULL; //or better "nullptr" starting from C++11
Attempt to store value *ptr = 22; will at least explicitly crash the program.

reading an array in a function

I am trying using the arduino IDE to write a sketch. I have data in progmem and want to move the data with a function to a memory address allocated using malloc. My code is below:
const uint8_t Data_6 [256] PROGMEM = { 0x11, 0x39......};
void setup() {
Serial.begin(57600);
oddBallData (Data_6, 0x00, 256);
}
void main() {
}
void oddBallData(const uint8_t *data, uint8_t mem, uint16_t bytes) {
uint8_t *buff1 = (uint8_t*)malloc(sizeof(bytes));
if (buff1 = 0) {
Serial.println(F("FATAL ERROR - NO MEMORY"));
}
else {
for (uint16_t x = 0; x < 6; x++ ) {
buff1[x] = data[x]; //edited from data[0] to [x] made a mistake in post
Serial.println(buff1[x],HEX);
}
}
buff1[0] = data[0];
Serial.println(buff1[0],HEX);
free(buff1);
}
I have some data saved in progmem and want to write that data to a second device using i2c protocol. I have multiple constant arrays of data saved to my progmem, with different sizes. So I have used malloc to reserve some memory from the heap, inside of the function.
I have not been able to write the data from the progmem so I have stripped things back to so that I am just trying to point to the progmem data using malloc and then print it.
This is where I found a the problem. If I print a single array entry from the data constant. It prints the correct value. If I use a loop I get mixed results, the loop works as long as the condition check value is below 3 or sometimes below 6!!!...?
If above this value the entire print is just garbage. Can anyone explain what I am seeing?
The culprit is probably
uint8_t *buff1 = (uint8_t*)malloc(sizeof(bytes));
sizeof(bytes) returns the size of the variable (which is probably 2 bytes) so you are just allocating 2 bytes of memory. You should use the value directly, eg:
uint8_t* buff1 = malloc(bytes);
Mind that the cast is not required in C since a void* is convertible to any other pointer type directly.
Again - AVR PROGMEM is not directly accessible from memory space, it needs different instruction than access into the RAM. If you are using it like this, you'll get RAM content on passed address, not the FLASH one. You have to use special functions for this. For example memcpy_P(ram_buff,flash_ptr); makes a copy from flash into the ram. Or you can read one byte by pgm_read_byte(flash_ptr + offset)
BTW: If you are using Data_6[0] and it's working, it's just because compiler sees it as a constant and constant can be replaced by its value compile time.
I Guess you just forgot to flush()
try to do Serial.flushI() after Serial.println(buff1[x],HEX);
you can also check flush documentation

C functions returning an array

Sorry for the post. I have researched this but..... still no joy in getting this to work. There are two parts to the question too. Please ignore the code TWI Reg code as its application specific I need help on nuts and bolts C problem.
So... to reduce memory usage for a project I have started to write my own TWI (wire.h lib) for ATMEL328p. Its not been put into a lib yet as '1' I have no idea how to do that yet... will get to that later and '2'its a work in progress which keeps getting added to.
The problem I'm having is with reading multiple bytes.
Problem 1
I have a function that I need to return an Array
byte *i2cBuff1[16];
void setup () {
i2cBuff1 = i2cReadBytes(mpuAdd, 0x6F, 16);
}
/////////////////////READ BYTES////////////////////
byte* i2cReadBytes(byte i2cAdd, byte i2cReg, byte i2cNumBytes) {
static byte result[i2cNumBytes];
for (byte i = 0; i < i2cNumBytes; i ++) {
result[i] += i2cAdd + i2cReg;
}
return result;
}
What I understand :o ) is I have declared a Static byte array in the function which I point to as the return argument of the function.
The function call requests the return of a pointer value for a byte array which is supplied.
Well .... it doesn't work .... I have checked multiple sites and I think this should work. The error message I get is:
MPU6050_I2C_rev1:232: error: incompatible types in assignment of 'byte* {aka unsigned char*}' to 'byte* [16] {aka unsigned char* [16]}'
i2cBuff1 = i2cReadBytes(mpuAdd, 0x6F, 16);
Problem 2
Ok say IF the code sample above worked. I am trying to reduce the amount of memory that I use in my sketch. By using any memory in the function even though the memory (need) is released after the function call, the function must need to reserve an amount of 'space' in some way, for when the function is called. Ideally I would like to avoid the use of static variables within the function that are duplicated within the main program.
Does anyone know the trade off with repeated function call.... i.e looping a function call with a bit shift operator, as apposed to calling a function once to complete a process and return ... an Array? Or was this this the whole point that C does not really support Array return in the first place.
Hope this made sense, just want to get the best from the little I got.
BR
Danny
This line:
byte *i2cBuff1[16];
declares i2cBuff1 as an array of 16 byte* pointers. But i2cReadBytes doesn't return an array of pointers, it returns an array of bytes. The declaration should be:
byte *i2cBuff1;
Another problem is that a static array can't have a dynamic size. A variable-length array has to be an automatic array, so that its size can change each time the function is called. You should use dynamic allocation with malloc() (I used calloc() instead because it automatically zeroes the memory).
byte* i2cReadBytes(byte i2cAdd, byte i2cReg, byte i2cNumBytes) {
byte *result = calloc(i2cNumBytes, sizeof(byte));
for (byte i = 0; i < i2cNumBytes; i ++) {
result[i] += i2cAdd + i2cReg;
}
return result;
}

why do strings have pointers as there return type?

I know what pointers are but when it comes to strings/arrays I get really confused. If someone has an answer or a website that explains it that would be great. For example:
char * strncopy (char*dest, char * source, size_t);
Why the pointer? what is it pointing to? Does it a pointer usually store an address?
It is sayed in my textbook that each string building function is of type pointer char*.
Also I was trying to see if I could write a program that would clear things up, but it didn't work. Can someone tell me how to fix it, or what I'm doing wrong.
#include <stdio.h>
#include <string.h>
char * getname ()
{
char name [10];
scanf ("%s", name);
return (name);
}
int main (void)
{
char name[10];
printf ("Enter your name\n");
name[] = getname();
printf ("Hi %s", name);
return (0);
}
Inside of your getname function, when you return a pointer to the name array because it's allocated on the stack it gets destroyed leaving you with an invalid pointer. Dereferencing such a pointer causes many, many problems.
You should allocate the name array inside of getname on the heap, with malloc/calloc so that when you return the pointer the data won't be destroyed.
With regards to functions like strncpy, they tend to return a pointer to the resulting string; e.g.: strncpy returns a pointer to the destination.
Pointer itself represents an address, e.g. if you have a pointer typed char *pstr, you can always check the underlying address with printf("address of my pointer %p\n", pstr);
In C programming language, a string is an array of char. If you have a good knowledge of array and its memory layout, it's not too hard for you to understand c-styled string. Generally speaking, an array in C is a continuous chunk of memory with name of array represent address of the first element in the array. So is string who is a chunk of memory with name of the char array address of the first character. In addition, c-styled string terminates with character \0, so if you want to manage memory for string yourself, remember one extra byte for the tailing \0.
As to your second problem, your name in function getname is a local variable whose life time ends when function returns. However, you still want to access name outside the function which is inappropriate. You can solve this be dynamically allocated memory like in dasblinkenlight's and others' post.
Good luck.

Resources