EEPROM library, pointers, dynamic memory

A weirdly specific question: I want to make a universal library for all my projects to give a few variables to at init and then have it store/read them to/from EEPROM on command (using put()/get() - make it accept custom structures). I tried to pass it a pointer to the variable and its size (in bytes for EEPROM addressing) but then kame the problem of the variable changing its location in RAM - the pointer vas not up-to-date. Now I have another not-working version, where I pass it a function to give it the pointer right before it need to be used (in EEPROM.put()/get()).
Here is the github repo: EEpromSettings
And the code itself:

EEpromSettings.h
#ifndef LIB_H
#define LIB_H

#include "Arduino.h"

/*TODO:
 - EEPROM settings, pointer problems
 - CRC check?
*/

using ptr = void*;

struct settingPointer {
    ptr pointer;
    size_t size;
};

typedef settingPointer* (*PtrUpdater)();

class EEpromSettings {
    public:
        EEpromSettings(byte projID, PtrUpdater pointerUpdater, size_t settingsCount, bool overwrite = true);
        ~EEpromSettings();
        byte getEEpromProjID();
        void updatePointers(ptr settingsPointers[]);
        bool save();
        bool load();
    // private:
        byte _projID;
        settingPointer* _settingPointers;
        size_t _settingsCount;
        PtrUpdater _pointerUpdater;
};

#endif //LIB_H
EEpromSettings.cpp
#include "EEpromSettings.h"
#include <EEPROM.h>

EEpromSettings::EEpromSettings(byte projID, PtrUpdater pointerUpdater, size_t settingsCount, bool overwrite) : _projID(projID), _settingsCount(settingsCount) {
    _settingPointers = new settingPointer[settingsCount];
    _pointerUpdater = pointerUpdater;

    if(overwrite && EEPROM.read(0) != _projID) {
        EEPROM.update(0, _projID);
        save();
        Serial.println("Overwritten -> Saved defaults to EEPROM");
    }
};

EEpromSettings::~EEpromSettings() {
    delete[] _settingPointers;
};

byte EEpromSettings::getEEpromProjID() {
    return EEPROM.read(0);
}

bool EEpromSettings::save() {
    if (EEPROM.read(0) == _projID) {
        int adress = 1;
        size_t i = 0;
        _settingPointers = _pointerUpdater();
        while (i < _settingsCount) {
            EEPROM.put(adress, _settingPointers[i].pointer);
            adress += _settingPointers[i].size;
            i++;
        }
        Serial.println("Saved values to EEPROM");
        return true;
    }
    Serial.println("Failed to save values to EEPROM");
    return false;
};

bool EEpromSettings::load() {
    if (EEPROM.read(0) == _projID) {
        int adress = 1;
        size_t i = 0;
        while (i < _settingsCount) {
            _settingPointers = _pointerUpdater();
            // Serial.println((int)_settingPointers[i].pointer);
            EEPROM.get(adress, _settingPointers[i].pointer);
            Serial.println((int)_settingPointers[1].pointer);
            adress += _settingPointers[i].size;
            i++;
        }
        Serial.println("Loaded values from EEPROM");
        Serial.println((int)_settingPointers[1].pointer);
        return true;
    }
    Serial.println("Failed to load values from EEPROM");
    return false;
};
main.cpp (example and testing)
#include <Arduino.h>
#include <EEpromSettings.h>


struct myStruct {
    byte x;
    char y;
};

// char a[3] = "AB";
// int b = 1;
// myStruct c = { 5, 'f' };

char a[3] = "XX";
int b = 6;
myStruct c = { 0, 'x' };


#define SETTINGS_NUM 3
settingPointer settingPointers[SETTINGS_NUM];
settingPointer* settingsPtrUpdater() {
    settingPointers[0] = {&a, sizeof(a)};
    settingPointers[1] = {&b, sizeof(b)};
    settingPointers[2] = {&c, sizeof(c)};
    return settingPointers;
}

EEpromSettings eepromSettings(1, settingsPtrUpdater, SETTINGS_NUM, false);

void setup() {
    Serial.begin(115200);
    Serial.println();

    Serial.print("poiter to b = "); Serial.println((int)&b);

    Serial.print("ProjectID: 1, eepromProjectID: "); Serial.println(eepromSettings.getEEpromProjID());

    Serial.println("Default values:");
    Serial.print("a = "); Serial.println(a);
    Serial.print("b = "); Serial.println(b);
    Serial.print("c.x = "); Serial.println(c.x);
    Serial.print("c.y = "); Serial.println(c.y);

    // eepromSettings.save();

    if (eepromSettings.load()) {
        Serial.print("a = "); Serial.println(a);
        Serial.print("b = "); Serial.println(b);
        Serial.print("c.x = "); Serial.println(c.x);
        Serial.print("c.y = "); Serial.println(c.y);
    } else {
        Serial.println("Failed to load values from EEPROM - different project ID?");
    }

    Serial.println("b value from pointer from settingPointers:");
    Serial.println((int)settingPointers[1].pointer);
    Serial.println(*static_cast<int*>(settingPointers[1].pointer));

    Serial.println("b value from pointer from eepromSettings._settingPointers:");
    Serial.println((int)eepromSettings._settingPointers[1].pointer);
    Serial.println(*static_cast<int*>(eepromSettings._settingPointers[1].pointer));

    Serial.print("poiter to b = "); Serial.println((int)&b);

}

void loop() {
    //loop
}

So the questions:

  • Is there a library, that does something like this?
  • Is there a better way of doing it?
  • Could solved using the new[] operator because the address doesn't change over time? Is it a problem if I create a few (eg. up to ten) of these variables and then don't delete[] them for them to last the entire duration of the program - which is until a sudden power loss (like a global variable)? Will the get deleted because RAM is volatile or do I really need to use delete[]?
  • I also found something called smart pointers from C++ standard library. What's that? Could it maybe solve my problems?

Thanks for any kind of reply, I'm clueless
TheMoonlitWolf

Have you looked at the Arduino EEPROM Libary?

Yes, this is the library I'm using to do the read/write to the EEPROM itself. I'm using its put() and get() functions, so it should also support custom structures. Sorry for not being clear in the first post...

Why don't you just simply use put() to put the array of structs in EEPROM and get() to get it out? No fiddling with pointers needed.

It will be most of the time multiple variables, so I'd have to figure out the EEPROM addressing each time again, but yeah...
But I'd still like to know weather the new[] variables are deleted on power loss...

Yes, they are. If you don't change the sketch, after a power up (or reset) they should again be pointing to the same place in memory. If you change the sketch, all your bets are off.

Demo code

/*

b only
17:31:08.210 -> Hello
17:31:08.210 -> b points to 0x21c

c followed by b
17:33:02.428 -> Hello
17:33:02.428 -> c points to 0x22c
17:33:02.428 -> b points to 0x292

b followed by c
17:34:29.594 -> Hello
17:34:29.594 -> b points to 0x22c
17:34:29.594 -> c points to 0x292
*/

char buffer[64];
byte *b;
byte *c;


void setup()
{
  Serial.begin(115200);
  Serial.println("Hello");

  b = (byte *)malloc(100);
  sprintf(buffer, "b points to %p", b);
  Serial.println(buffer);

  c = (byte *)malloc(100);
  sprintf(buffer, "c points to %p", c);
  Serial.println(buffer);
}

void loop()
{
}

So malloc() is the same as new[]? Like (int)malloc(42) is the same as new int[42]?

But the value won't be there, because its RAM, right?

It's basically the same, dynamic memory allocation.

And yes, the data stored at that location will be gone after a reset / power cycle. But that is what you have EEPROM for :wink:

Ok, thank you very much, I'll try to incorporate it using dynamic memory allocation, and the result will be on GitHub. And if it doesn't work, I'll just use the EEPROM directly.

I made it work! If anyone is interested, I made it public on GitHub.
Thank you again for you help

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.