Добрый день, уважаемый читатель!
В прошлых статьях мы обсуждали, как настроить проект PlatformIO и ESP-IDF (если вы не знакомы с этими разделами, но статьи почему-либо пропустили, рекомендую ознакомиться). Но в реальном проекте нам дополнительно может понадобиться довольно большое количество “прикладных” параметров, которые не входят в “стандартные” файлы конфигурации ESP-IDF. Например:
- номера выводов GPIO, задействованные в проекте
- имя WiFi сети и пароль доступа
- адрес MQTT сервера, логин и пароль доступа
- токен доступа к Telegram-боту
- размеры стеков прикладных задач
и многое-многое другое…
Для чего нужен “свой” файл конфигурации проекта?
Как я уже писал в статье, посвященной конфигурированию ESP-IDF, в принципе, всё это и многое другое можно запихнуть в тот же sdkconfig.h. В этом случаем мы получим универсальный инструмент конфигурации, в котором будут собраны и “стандартные” и “прикладные” параметры, и который к тому же будет автоматически доступен из всех ваших файлов прикладных задач и библиотек (через include "sdkconfig.h"
). В принципе, этот вариант вполне имеет право на существование, и как бы автоматически предполагается разработчиками из Espressif. Если бы не одно “но”….
Время! Войти в меню SDK Config занимает определенное время (обычно 20…60 секунд), затем после каждого изменения конфигурации PlatformIO начнет заново компилировать все ESP-IDF библиотеки, что занимает дополнительное время. А иногда требуется подобрать тот или иной параметр (например размер стека) и это превращается в муку.
В итоге я не придумал ничего лучше, чем создать для “прикладных” задач обычный текстовый файл, который я назвал project_config.h (вы можете назвать его по другому – не суть), и в котором собраны все мои (ну почти все, на самом деле сейчас у меня их несколько) параметры проекта, не включенные в sdkconfig.h. Выглядит это просто как набор макросов препроцессора (ну в принципе как и sdkconfig.h) с комментариями:
Поменять строчку в текстовом файле прямо из редактора кода – дело пары секунд, поэтому на практике этот способ конфигурации гораздо быстрее. Но и ошибку сделать гораздо легче.
Содержимое файла конфигурации для программ на базе “моей” прошивки частью зависит от конкретной задачи, а частью это “стандартные” макросы, использующиеся во многих проектах одновременно. С примером такого файла вы можете ознакомиться по ссылке, а описание его можно найти здесь.
Почему именно #define (а не static const int к примеру)?
Почему я использую макросы препроцессора для объявления констант вместо явного объявления глобальных статических констант (надеюсь вы в курсе, что это такое)? Например в примере выше я использовал конструкцию:
#define CONFIG_SENSORS_TASK_CYCLE 15000
Эта строчка управляет временным циклом чтения данных с сенсоров в миллисекундах. Но можно так же это же самое записать и так:
static const uint32_t CONFIG_SENSORS_TASK_CYCLE = 15000;
Примечание: я специально не стал менять написание константы для наглядности, хотя это и не принято
На сайтах для начинающих программистов Arduino, вы наверняка видели настоятельные рекомендации использовать именно второй вариант. И они правы в данном случае! Препроцессор “ничего не знает” о типах переменных и констант, поэтому в случае использования # define легко сделать ошибку, которую будет потом нелегко найти, например так:
#define CONFIG_SENSORS_TASK_CYCLE "15000"
Так зачем же я всё-таки применяю исключительно #define?
Давайте взглянем на следующую строчку:
#define CONFIG_SENSORS_STATIC_ALLOCATION 1
Этот параметр определяет, как будет создана прикладная задача – в статической области памяти BSS или в куче (подробнее об этом читайте в другой статье). Так вот, здесь записать эту строку как константу уже не выйдет!
static const uint8_t CONFIG_SENSORS_STATIC_ALLOCATION = 1;
Дело в том, что это объявление далее используется в конструкции вида:
#if (CONFIG_SENSORS_STATIC_ALLOCATION == 1) .. статическое создание задачи #else .. динамическое создание задачи #endif // CONFIG_SENSORS_STATIC_ALLOCATION
и здесь static const чего-то там уже не может быть использована.
Вот и приходится использовать макросы препроцессора. Но не мешать же в одном и том же файле “классические” константы с макросами…
По этой же самой причине, я полагаю, в sdkconfig.h используются только макросы препроцессора.
Проблема номер раз
Хорошо, зачем нужен файл – разобрались. Но при попытке применить свой файл project_config.h в общих библиотеках “вне” каталога проекта, мы очень быстро наткнемся на проблему – внешние подключенные библиотеки (то есть библиотеки, находящиеся вне поля зрения проекта и использующиеся в нескольких проектах сразу) “ничего не знают” об этом файле и мы не сможем правильно скомпилировать проект.
Решение мне подсказали на форуме PlatformIO, когда я ещё только-только начинал создавать свои библиотеки для ESP-IDF. Справедливости ради нужно сказать, что это не решение, а костыль. Нужно указать компилятору, где искать этот самый файл при компиляции любых файлов проекта, в том числе любых сторонних библиотек и даже ESP-IDF. Делается это с помощью директивы -i
(include
) компилятора. Добавить эту директиву можно в файл platformio.ini проекта:
В моем случае я помещаю этот файл в подкаталог ./include проекта, поэтому и указываю на него в этом параметре. Вуаля – всё работает как часы. Только не забываем в нужным местах #include ”project_config.h” добавлять, разумеется.
Проблема номер два
Когда проектов станет больше двух-трех, вы наверняка столкнетесь с необходимостью как-то “синхронизировать” некоторые из настроек между проектами. То есть, некоторые параметры желательно оставить только для текущего проекта, а некоторые – сделать так, чтобы изменение в одном месте привело к изменениям сразу во всех проектах, иначе дублирование “общих” настроек может занимать значительное время и сильно утомительно.
Выход из этой ситуации напрашивается сам собой. В общих библиотеках создаем один или несколько файлов, в которых размещаем необходимые настройки, по аналогии с project_config.h выше. Например у меня это выглядит так:
В этом случае дополнительно подключать эти файлы к проекту в platformio.ini не требуется (кроме, собственно, подключения общих библиотек).
Как видите, решить этот вопрос ещё проще.
На этом пока всё, до встречи на сайте и на dzen-канале!
💠 Полный архив статей вы найдете здесь
Пожалуйста, оцените статью: