I'm creating a framework to define a generic implementation of a Nextion display.
All Nextion components defined in their own library are taking a const char* as a constructor parameter, to define the name of the component, used when sending commands to the Nextion (Why not use Pid and Cid??).
The actual runtime objects are created and deleted dynamically when they are active on the display.
As my actual components have a fixed and predefined objectname I would really like to use PROGMEM to store the objectnames. So now I'm trying to define a class with a constructor that takes a PROGMEM char*.
So far I have managed to get to the result below, but that (of course) doesnt work because the original name member is private and const.
I would rather not change the library, but as a last resort, for obvious reasons.
How would you solve this problem?
class A // as defined in library
{
private:
const char *name;
public:
A(const char* aName) : name(aName) {}
String getName() {
return String(name);
}
};
class B:public A // my own extensions
{
public:
B(const char* PROGMEM aName) : A(" ") {
strcpy_P(name, aName); //ERROR because name is private and const in A
}
};
const char NAME_PROGMEM[] PROGMEM = "name in progmem";
void setup() {
Serial.begin(115200);
B b(NAME_PROGMEM);
Serial.println(b.getName());
}
void loop() {
}
Whandall:
There is no advantage in copying the PROGMEM stuff to a fixed (max) sized RAM buffer,
the compiler uses less memory for his RAM copy of strings.
Bear in mind that classes of type B are created and deleted dynamically (to preserve dynamic m emory), but the possible names are discreet and pre-defined.
Example: The display definition contains 2 pages, page one with 2 buttons ("OK", "CANCEL"), and page 1 with one button "APPLY".
When page 1 is active on the display, I want two instances of MyButton class (derived from NexButton) with the resp names "OK" and "CANCEL", and when page 2 is active the previous buttons are freed from memory and a new instance of MyButton with the name "APPLY" is created.
So I would like to define the names "OK", "CANCEL" and "APPLY" in PROGMEM
If I could, I would love to keep with those (being a Java/Delphi programmer during the day) but I don;t think it will do much good for the memory footprint of my sketch
class A // as defined in library
{
private:
protected:
const char *name;
public:
A(const char* aName) : name(aName) {}
String getName() {
return String(name);
}
};
class B:public A // my own extensions
{
public:
B(const char* PROGMEM aName) : A(" ") {
strcpy_P(name, aName); //ERROR because name is private and const in A
}
};
const char NAME_PROGMEM[] PROGMEM = "name in progmem";
const char NAME_PROGMEM1[] PROGMEM = "second name";
void setup() {
Serial.begin(115200);
B b(NAME_PROGMEM);
B c(NAME_PROGMEM1);
Serial.println(b.getName());
Serial.println(c.getName());
}
void loop() {
}
second name
second name
As you can see, ignoring the warning produces an overwrite.
Somewhere\PROGMEMStringClass\PROGMEMStringClass.ino: In constructor 'B::B(const char*)':
Somewhere\PROGMEMStringClass\PROGMEMStringClass.ino:20:25: warning: invalid conversion from 'const char*' to 'char*' [-fpermissive]
strcpy_P(name, aName); //ERROR because name is private and const in A
^
The names could only reside in PROGMEM, but that would need some changes to the library.
...but I don't think it will do much good for the memory footprint of my sketch
You're right. Requirements for garbage collection also limit what you can do on Arduino.
My latest C++ Arduino code used pointers, so I was just having a little fun above.