Параметрический доступ к переменной структуры на 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;
@Guy . D, 👍1
Обсуждение2 ответа
Лучший ответ:
Вы можете создать "жестко закодированную" функцию копирования:
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: // Ошибка
}
}
Недостаток заключается в том, что вам придется вручную синхронизировать структуру и функцию копирования.
Преимущество заключается в том, что вы можете сделать поверхностное, глубокое копирование или даже добавить больше логики в зависимости от каждого члена структуры.
Вы можете это сделать, но это может быть неудобно. Вам понадобится массив структур, каждый член которого описывает один член ваших «структурных параметров» — по сути, расширение ваших нынешних «ключей []».
Затем вы можете обратиться к этому массиву случайным образом или для того, чтобы найти имя, тип данных и смещение в памяти заданного параметра (индексированного по порядку параметров), или выполнить поиск, чтобы получить доступ к той же информации по имени параметра.< /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(){
;
}
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Инициализация массива структур
- Отправить структуру через Serial
- Передавать данные структуры во внешнюю структуру через serial?
- Как получить размер (sizeof) массива структур
- Структура typedef не работает
- Собственное определение типа с использованием структуры не дает имени типу
- Одна и та же структура занимает разное пространство в памяти Uno и NodeMCU ESP8266, что приводит к повреждению данных при передаче через nRF24L01+
Если вы хотите скопировать каждое значение, используйте
memcpy(&final_par, &def_par, sizeof(parameters));
, @Johnny Moppневозможно получить доступ к полю по имени. как это сделать зависит от того, что вы хотите с ним делать., @Juraj
Имена существуют только в исходном коде. После компиляции программа не знает *никаких* имен., @Majenko
для динамических пар имя-значение с базовыми типами данных можно использовать ArduinoJson. особенно если он должен храниться в FS, @Juraj