1

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;
  • 1
    If you want to copy every value use memcpy(&final_par, &def_par, sizeof(parameters)); – Johnny Mopp Aug 19 at 18:27
  • 3
    it is not possible to access a field by name. how to do it depends on what you want to do with it. – Juraj Aug 19 at 18:32
  • 2
    The names only exist in the source code. Once compiled the program has no knowledge of any names. – Majenko Aug 19 at 20:40
  • 1
    for dynamic name value pairs with basic data types ArduinoJson can be used. especially if it should be stored in FS – Juraj Aug 22 at 4:20
1

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.

| improve this answer | |
1

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(){
    ;
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.