Представляю Вашему вниманию еще одну маленькую библиотечку. Для чего она нужна?
Пожалуй самый популярный способ “отладки” программ для Arduino – добавление в код скетча текстовых отладочных сообщений, а затем их отслеживание через подключение по COM-порту. Что-то вроде этого:
HTTPClient https; if (https.begin(wifiClient, httpRequest)) { int httpCode = https.GET(); if (httpCode > 0) { if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { result = true; Serial.printf("TLG :: Send \"%s\": OK (%d)\n", message.c_str(), httpCode); } else { Serial.printf("TLG :: Send \"%s\": FAILED (%d) %s\n", message.c_str(), httpCode, https.errorToString(httpCode).c_str()); }; } else { Serial.println(F("TLG :: Send FAILED: Unable to connect!")); }; https.end(); } else { Serial.println(F("TLG :: Send FAILED: Unable to create HTTPS client!")); };
Приведенный выше код содержит множество отладочных Serial.println(…), позволяющих через COM-порт определить, на каком этапе что пошло не так. Все это просто и хорошо, но ровно до того момента, когда устройство оказывается полностью отлажено и собрано, то есть готово “в продакшен”. В “боевой” обстановке устройство обычно работает вдали от компьютера и вывод в serial только мешает – занимает и процессорные ресурсы, и память. Хорошо бы иметь возможность отключать вывод отладочных сообщений, а при возможных доработках проекта – включать.
Именно такой принцип заложен в библиотеку, которая “встроена” в Framework Arduino для ESP32: “esp32-hal-log.h” (в фреймворке ESP-IDF есть более “навороченная” версия – “esp_log.h”). Причем отключать “отладку” можно “частями” – чем ниже заданный уровень – тем меньше сообщений Вы увидите. Например: ничего, только ошибки, ошибки + предупреждения, ошибки + предупреждения + сообщения и т.д. Большая часть построена на макросах, а это означает, что сообщения выше заданного уровня будут полностью исключены из кода. Очень удобно. И достаточно просто.
Так зачем же еще изобретать велосипед? Есть несколько “но”:
- Во-первых, включив уровень “DEBUG” в настройках проекта, Вы увидите не только “свои” сообщения, но и кучу отладочных сообщений из всех подключенных библиотек фреймворка. Хотелось бы как-то разделить все-таки. То есть подавить “системные” сообщения, оставив только нужные.
- Во-вторых, эти библиотеки не будут работать на ESP8266, и уж тем более на AVR. А из-за этого код какой-нибудь “своей” библиотеки перестает работать на другом контроллере только из-за отладки. Конечно, можно нагородить леса типа с помощью макросов #if … #endif, но это сильно загромождает код и усложняет написание программы. Хотелось бы какого-то однообразия.
- Ну и наконец – Вы не сможете изменить настройки sdkconfig.h, если используется только “framework-arduinoespressif32”, он поставляется уже сконфигурированным. То есть Вы не сможете самостоятельно изменить уровень отладки.
Исходя из этого мне ничего не оставалось, кроме как самым наглейшим образом передрать код “esp32-hal-log.h”, портировать его на ESP8266 и AVR, и сделать отдельные настройки для всего этого. Вот так и получилась эта библиотека. Использовать ее можно на ESP8266, ESP32, AVR и других контроллерах, в Arduino IDE и PlatformIO, в том числе в фреймворке ESP-IDF.
Библиотека бесплатная, Open source, скачать ее можно с GitHub с помощью кнопки ниже.
Как использовать
Есть несколько уровней отладочных сообщений:
- RLOG_LEVEL_NONE – Сообщения не выводятся
- RLOG_LEVEL_ERROR – Критические ошибки, программный модуль не может восстановиться самостоятельно
- RLOG_LEVEL_WARN – Состояния ошибки, из которых были приняты меры по устранению
- RLOG_LEVEL_INFO – Информационные сообщения, описывающие нормальный ход событий
- RLOG_LEVEL_DEBUG – Дополнительная информация, которая не требуется для нормального использования (значения, указатели, размеры и т.д.).
- RLOG_LEVEL_VERBOSE – Большие фрагменты отладочной информации или частые сообщения, которые потенциально могут переполнить вывод.
Им соответствуют несколько функций для вывода этих сообщений:
- rlog_e(tag, format, …) – Сообщения уровня RLOG_LEVEL_ERROR
- rlog_w(tag, format, …) – Сообщения уровня RLOG_LEVEL_WARN
- rlog_i(tag, format, …) – Сообщения уровня RLOG_LEVEL_INFO
- rlog_d(tag, format, …) – Сообщения уровня RLOG_LEVEL_DEBUG
- rlog_v(tag, format, …) – Сообщения уровня RLOG_LEVEL_VERBOSE
где: tag – идентификатор, с помощью которого удобно обозначать модуль, откуда пришло сообщение (например “mqtt” или “telegram”) format – собственно сообщение с символами форматирования (или без них) … – переменные, передаваемые в строку форматирования (например “Value = %d\n”, 10). Их может и не быть вовсе.
Соответственно, чем выше уровень отладки в Вашем проекте, тем больше сообщений Вы увидите.
Уровень отладки задается с помощью определения #define CONFIG_RLOG_PROJECT_LEVEL RLOG_LEVEL_XXXX, где RLOG_LEVEL_XXXX – этот самый уровень и есть. Кроме этого, есть возможность включить вывод системного времени и цветных ASCII-кодов в сообщения. Эти опции также включаются с помощью макросов.
Например при CONFIG_RLOG_PROJECT_LEVEL == RLOG_LEVEL_INFO в код попадут только макросы-функции rlog_e, rlog_w, rlog_i, а остальные будут игнорированы.
Для CONFIG_RLOG_PROJECT_LEVEL == RLOG_LEVEL_DEBUG будут отображаться ещё и rlog_d.
А при CONFIG_RLOG_PROJECT_LEVEL == RLOG_LEVEL_NONE все отладочные сообщения будет исключены.
Настройка уровня вывода
Осталось придумать, как определить этот самый CONFIG_RLOG_PROJECT_LEVEL
Если весь Ваш код содержится в одном файле – то с этим не будет никаких проблем. Просто добавьте воды #define CONFIG_RLOG_PROJECT_LEVEL RLOG_LEVEL_INFO в начале файла и проблема будет решена.
Сложнее, если Вы будете дробить код по разным файлам. В этом случае целесообразно вынести определения макросов в отдельный файл, например “project_config.h”. Если все файлы проекта находятся в одной папке, то проблем не возникнет.
Проблема будет, если Вы будете подключать какие-то библиотеки, которые находятся в каталогах, отличных от каталога проекта (общие библиотеки, которые используется в нескольких проектах одновременно). В этом случае компилятор при сборке не найдет Ваш “project_config.h”. Нужно ему подсказать, где искать. В PlatformIO это можно сделать с помощью опции -Iкаталог, например так:
[env] build_flags = -Isrc
Вуаля. При компиляции библиотек компилятор обязательно заглянет в каталог src, найдет Ваш файл “project_config.h” и подключит его к коду.
А вот в Arduino IDE я не нашел другого выхода, кроме как свалить все в одну кучу и хорошенько перемешать, то есть скопировать все библиотеки в каталог проекта. Впрочем, я не сильно и старался.
Примеры
Примеры для различных платформ и фреймворков Вы можете найти в архиве с исходниками (см. ссылку в конце статьи) в каталоге examples.
#include "Arduino.h" #include "project_config.h" #include "rLog.h" void setup() { // put your setup code here, to run once: Serial.begin(19200); Serial.println(); rlog_v("DEMO", "Test message, level: %s", "VERBOSE"); rlog_d("DEMO", "Test message, level: %s", "DEBUG"); rlog_i("DEMO", "Test message, level: %s", "INFORMATION"); rlog_w("DEMO", "Test message, level: %s", "WARNING"); rlog_e("DEMO", "Test message, level: %s", "ERROR"); } void loop() { // put your main code here, to run repeatedly: // nothing }
Результаты компиляции для различных платформ:
Arduino Nano + Framework Arduino

Результаты компиляции для Arduini Nano + Framework Arduino

Тестовый вывод для Arduini Nano + Framework Arduino
ESP8266 + Framework Arduino

Результаты компиляции для ESP8266 + Framework Arduino

Тестовый вывод для ESP8266 + Framework Arduino
ESP32 + Framework Arduino

Результаты компиляции для ESP32 + Framework Arduino

Тестовый вывод для ESP32 + Framework Arduino
ESP32 + Framework ESP-IDF

Результаты компиляции для ESP32 + Framework ESP-IDF

Тестовый вывод для ESP32 + Framework ESP-IDF
Скачать библиотеку:
Библиотека бесплатная, Open source, скачать ее можно с GitHub с помощью кнопки ниже. В архиве Вы также найдете примеры скетча для Arduino IDE и PlatformIO – загляните в папку examples.
✳️ Другие мои библиотеки для PlatformIO и ArduinoIDE
Благодарю за внимание.
Спасибо! Очень помогает эта библиотека.
Отличная библиотека, взял на вооружение.
Но как напечатать ip адрес, маску, mac – адрес?
Добрый день. Зависит от того, откуда вы берете данные.
Например можно так:
esp_netif_ip_info_t local_ip = wifiLocalIP();
if (local_ip.ip.addr != 0) {
uint8_t * loc_ip = (uint8_t*)&(local_ip.ip);
rlog_d(logTAG, “%d.%d.%d.%d”, loc_ip[0], loc_ip[1], loc_ip[2], loc_ip[3]);
}