Параметрический доступ к переменной структуры на ESP8266

У меня есть 2 экземпляра структуры. В одном хранятся значения def, а во втором хранятся значения, считанные из файла на SPIFFS.

Я пытаюсь использовать цикл for для всех переменных структуры - если файл был прочитан нормально и найден ключ, сохранить его значение в final_par, иначе получить значение из def_par.

Для этого я создал массив keys, но не могу найти способ выполнить итерацию в цикле for

как final_par.keys[i] = def_par.keys[i] - но это невозможно.

Как это можно сделать?

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

Обсуждение

Если вы хотите скопировать каждое значение, используйте memcpy(&final_par, &def_par, sizeof(parameters));, @Johnny Mopp

невозможно получить доступ к полю по имени. как это сделать зависит от того, что вы хотите с ним делать., @Juraj

Имена существуют только в исходном коде. После компиляции программа не знает *никаких* имен., @Majenko

для динамических пар имя-значение с базовыми типами данных можно использовать ArduinoJson. особенно если он должен храниться в FS, @Juraj


2 ответа


Лучший ответ:

1

Вы можете создать "жестко закодированную" функцию копирования:

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: // Ошибка
    }
}

Конечно, вы также можете передать final_par и/или def_par в качестве аргументов.

Если вы не хотите использовать индекс, создайте enum со значениями индекса для каждого параметра, например:

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: // Ошибка
    }
}

Недостаток заключается в том, что вам придется вручную синхронизировать структуру и функцию копирования.

Преимущество заключается в том, что вы можете сделать поверхностное, глубокое копирование или даже добавить больше логики в зависимости от каждого члена структуры.

,

1

Вы можете это сделать, но это может быть неудобно. Вам понадобится массив структур, каждый член которого описывает один член ваших «структурных параметров» — по сути, расширение ваших нынешних «ключей []».

Затем вы можете обратиться к этому массиву случайным образом или для того, чтобы найти имя, тип данных и смещение в памяти заданного параметра (индексированного по порядку параметров), или выполнить поиск, чтобы получить доступ к той же информации по имени параметра.< /p>

Вот ваша структура параметров с некоторым (незавершенным, но работоспособным) кодом для перечисления массива дескрипторов и, кстати, демонстрации того, как создавать и использовать массив. Обратите внимание, что код компилируется, но с предупреждением о том, что член ваших «параметров» не был инициализирован. Я решил не исправлять это; здесь он не используется и не препятствует компиляции.

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;

// Пара функций для извлечения данных из массива или структуры:
#define countof(a) (sizeof(a)/sizeof(a[0]))                             // ret # элементов массива (не байтов)
#define offsetof(struc, member) ((int)(&(((struc*)(0))->member)))   // возвращаем смещение в байтах от начала структуры до заданного члена

// Перечислить возможные типы параметров
typedef enum {
   t_bool, 
   t_char,
   t_int
} parType;

// Таблица дескрипторов - содержит имя, тип и смещение каждого параметра
// Можно было бы перейти во флэш-память, чтобы сэкономить кучу ОЗУ
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");
    // Список имен, типов и смещений параметров в «параметрах структуры»
    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(){
    ;
}
,