I have 2 instances of a struct. One has def values stored and second stores values read from a file on SPIFFS
.
I'm trying to use a for loop over all struct's variables - if file was read OK and key was found, store its value in final_par
else get value from def_par
.
For that, I've created keys
array - but I can't find a way to iterate, in a for loop
as final_par.keys[i] = def_par.keys[i]
- but this is not possible.
How can it be done ?
struct parameters
{
bool ext_inputs;
bool auto_relay_off;
bool useSerial;
bool useWDT;
bool useOTA;
bool useResetKeeper;
bool useFailNTP;
bool useDebugLog;
char deviceTopic[20];
char groupTopic[20];
char prefixTopic[20];
int inputUpPin;
int inputDownPin;
int outputUpPin;
int outputDownPin;
int inputUpExtPin;
int inputDownExtPin;
int auto_relay_off_timeout;
};
char *keys[] = {"ext_inputs", "auto_relay_off", "useSerial", "useWDT", "useOTA", "useResetKeeper",
"useFailNTP", "useDebugLog", "deviceTopic", "groupTopic", "prefixTopic", "inputUpPin",
"inputDownPin", "outputUpPin", "outputDownPin", "inputUpExtPin", "inputDownExtPin",
"auto_relay_off_timeout"};
parameters def_par{false, false, false, true, true, false, true, "devTopic", "noGroup", "myHome", 2, 1, 14, 12, 0, 2, 60};
parameters final_par;
2 Answers 2
You can create a 'hardcoded' copy function:
void CopyParameter(int parameterIndex)
{
switch (parameterIndex)
{
case 0: final_par.ext_inputs = def_par.ext_inputs; break;
case 1: final_par.auto_relay_off = def_par.auto_relay_off; break;
...
default: // Error
}
}
Of course you can also pass final_par
and/or def_par
as arguments.
If you don't want to use an index, create an enum
with the index values for each parameter, like:
enum EParameters
{
ExtInputs,
AutoRelayOff
...
};
void CopyParameter(EParameter parameter)
{
switch (parameter)
{
case ExtInputs : final_par.ext_inputs = def_par.ext_inputs ; break;
case AutoRelayOff: final_par.auto_relay_off = def_par.auto_relay_off; break;
...
default: // Error
}
}
The disadvantage is that you have to keep the structure and the copy function manually synchronized.
The advantage is that you can do a shallow, deep copy or even add more logic depending on each struct member.
You can do it but it can be awkward. You'll need an array of structs, each member of which describes one member of your 'struct parameters' - essentially, an expansion of your present 'keys[]'.
Then you can consult this array randomly or in order to find the name, data-type, and memory offset of a given parameter (indexed by parameter order), or search it, to access the same information by parameter name.
Here's your parameter struct with some (incomplete but runnable) code to list the descriptor array, and incidentally, show how to build and use the array. Note that the code compiles but with a warning that a member of your 'parameters' was not initialized. I chose not to fix that; it isn't used here and doesn't prevent compilation.
struct parameters
{
bool ext_inputs;
bool auto_relay_off;
bool useSerial;
bool useWDT;
bool useOTA;
bool useResetKeeper;
bool useFailNTP;
bool useDebugLog;
char deviceTopic[20];
char groupTopic[20];
char prefixTopic[20];
int inputUpPin;
int inputDownPin;
int outputUpPin;
int outputDownPin;
int inputUpExtPin;
int inputDownExtPin;
int auto_relay_off_timeout;
};
//char *keys[] = {"ext_inputs", "auto_relay_off", "useSerial", "useWDT", "useOTA", "useResetKeeper",
// "useFailNTP", "useDebugLog", "deviceTopic", "groupTopic", "prefixTopic", "inputUpPin",
// "inputDownPin", "outputUpPin", "outputDownPin", "inputUpExtPin", "inputDownExtPin",
// "auto_relay_off_timeout"};
parameters def_par{false, false, false, true, true, false, true, "devTopic", "noGroup", "myHome", 2, 1, 14, 12, 0, 2, 60};
parameters final_par;
// A couple of functions to extract data from an array or struct:
#define countof(a) (sizeof(a)/sizeof(a[0])) // ret # of array elements (not bytes)
#define offsetof(struc, member) ((int)(&(((struc*)(0))->member))) // ret byte-offset from start of struct to the given member
// Enumerate possible parameter types
typedef enum {
t_bool,
t_char,
t_int
} parType;
// Descriptor table - contains name, type, and offset of each parameter
// Could go in flash to save a bunch of RAM
struct descriptor {
const char *name;
parType pType;
uint8_t offset;
} Descriptors[] = {
{ "ext_inputs", t_bool, offsetof(parameters, ext_inputs) },
{ "auto_relay_off", t_bool, offsetof(parameters, auto_relay_off) },
// ...
{ "inputUpPin", t_int, offsetof(parameters, inputUpPin) },
// ...
{ "auto_relay_off_timeout", t_int, offsetof(parameters, auto_relay_off_timeout) }
};
void setup() {
Serial.begin(115200);
Serial.println("parameter type offset\n");
// List the parameters' names, types, and offsets within 'struct parameters'
for( uint8_t i = 0; i < countof(Descriptors); ++i ){
Serial.print(Descriptors[i].name); Serial.print(", ");
Serial.print(Descriptors[i].pType); Serial.print(", ");
Serial.println(Descriptors[i].offset);
}
}
void loop(){
;
}
memcpy(&final_par, &def_par, sizeof(parameters));