From 0dfa8fad2b5c94a5fa74450cfe726c46943e805e Mon Sep 17 00:00:00 2001 From: Matthias Mitscherlich Date: Mon, 16 Jan 2023 15:58:24 +0100 Subject: [PATCH] Added logger - functional --- code/.project | 5 + code/main/CMakeLists.txt | 1 + code/main/inc/logger.h | 182 ++++++++++++++++++++++++++++ code/main/main.cpp | 36 +++++- code/main/src/logger.cpp | 249 +++++++++++++++++++++++++++++++++++++++ code/sdkconfig | 14 +-- code/sdkconfig.old | 16 ++- 7 files changed, 482 insertions(+), 21 deletions(-) create mode 100644 code/main/inc/logger.h create mode 100644 code/main/src/logger.cpp diff --git a/code/.project b/code/.project index 06fb76d..1514a30 100644 --- a/code/.project +++ b/code/.project @@ -968,6 +968,11 @@ 1 /home/matthias/esp/esp-idf/components/vfs/vfs_uart.c + + build/ide/esp_idf_components/vfs/vfs_usb_serial_jtag.c + 1 + /home/matthias/esp/esp-idf/components/vfs/vfs_usb_serial_jtag.c + build/ide/esp_idf_components/wear_levelling/Partition.cpp 1 diff --git a/code/main/CMakeLists.txt b/code/main/CMakeLists.txt index f869fc7..eeaffee 100644 --- a/code/main/CMakeLists.txt +++ b/code/main/CMakeLists.txt @@ -6,6 +6,7 @@ idf_component_register( "main.cpp" "src/gpio.cpp" "src/wifi.cpp" + "src/logger.cpp" INCLUDE_DIRS # optional, add here public include directories "inc" PRIV_INCLUDE_DIRS # optional, add here private include directories diff --git a/code/main/inc/logger.h b/code/main/inc/logger.h new file mode 100644 index 0000000..5429571 --- /dev/null +++ b/code/main/inc/logger.h @@ -0,0 +1,182 @@ +// -------------------------------------------------------------------------------------------------------------------- +/// \file logger.h +/// \brief File description +// -------------------------------------------------------------------------------------------------------------------- +// +// vbchaos software design +// +// -------------------------------------------------------------------------------------------------------------------- +/// $Revision: $ +/// $Author: $ +/// $Date: $ +// (c) 2023 vbchaos +// -------------------------------------------------------------------------------------------------------------------- + + +#ifndef MAIN_INC_LOGGER_H_ +#define MAIN_INC_LOGGER_H_ + +/** + * Logger implementation + * \defgroup Logger + * \brief Implementation of a non-blocking logger for debug purpose + * \ingroup Platform + * + * A non-blocking logger that implements its own task with very low (unimportant) + * priority + * @{ + */ + + +// -------------------------------------------------------------------------------------------------------------------- +// Include files +// -------------------------------------------------------------------------------------------------------------------- + +// CompilerIncludes +// All include files that are provided by the compiler directly +#include +#include + + +// ProjectIncludes +// All include files that are provided by the project +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +#include "driver/uart_select.h" + +// -------------------------------------------------------------------------------------------------------------------- +// Constant and macro definitions +// -------------------------------------------------------------------------------------------------------------------- + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_ERROR(...) \ + Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__) + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_WARNING(...) \ + Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_WARNING, ##__VA_ARGS__) + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_INFO(...) \ + Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_INFO, ##__VA_ARGS__) + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_DEBUG(...) \ + Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_DEBUG, ##__VA_ARGS__) + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_PRINT(...) \ + Logger_log("", "", 0, LOGTYPE_PRINT, ##__VA_ARGS__) + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_ERROR_ISR(...) \ + Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__) + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_WARNING_ISR(...) \ + Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_WARNING, ##__VA_ARGS__) + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_INFO_ISR(...) \ + Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_INFO, ##__VA_ARGS__) + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_DEBUG_ISR(a, ...) \ + Logger_logISR(a, __FILE__, __func__, __LINE__, LOGTYPE_DEBUG, ##__VA_ARGS__) + +/** + * Logs an error + * \memberof Logger + */ +#define LOGGER_PRINT_ISR(a, ...) \ + Logger_logISR(a, "", "", 0, LOGTYPE_PRINT, ##__VA_ARGS__) + +// -------------------------------------------------------------------------------------------------------------------- +// Type definitions. +// -------------------------------------------------------------------------------------------------------------------- + +typedef enum +{ + LOGTYPE_PRINT, /**< Raw print */ + LOGTYPE_DEBUG, /**< Debug information only; will not be stored on SD-card */ + LOGTYPE_INFO, /**< Informational messages of important events */ + LOGTYPE_WARNING, /**< Recoverable fault */ + LOGTYPE_SUCCESS, /**< A specific success message */ + LOGTYPE_ERROR /**< Unrecoverable fault */ +} LogType; + + +struct LogQueueItem +{ + char fileName[32]; + char functionName[32]; + char context[128]; + int lineNumber; + LogType logType; +}; + +// -------------------------------------------------------------------------------------------------------------------- +// Function declarations +// -------------------------------------------------------------------------------------------------------------------- + + +class Logger +{ + public: + static uart_port_t uartPort; + static int queuesize; + static QueueHandle_t logQueue; + + Logger(int queuesize, uart_port_t uartPort); + + static void Logger_log(const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* format, ...); + + static void Logger_logISR(struct Logger* self, const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* context); + + private: + static TaskHandle_t logTaskHandle; + + static void loggerTask(void* parameters); + + static void composeLogQueueItem(struct LogQueueItem* logQueueItem, const char* fileName, const char* functionName, + int lineNumber, LogType logType, const char* context); +}; + + + + + + +/** @} */ + +#endif /* MAIN_INC_LOGGER_H_ */ diff --git a/code/main/main.cpp b/code/main/main.cpp index cf78a06..2deb336 100644 --- a/code/main/main.cpp +++ b/code/main/main.cpp @@ -10,23 +10,23 @@ #include "driver/gpio.h" #include "inc/gpio.h" +#include "driver/uart_select.h" #include "inc/wifi.h" +#include "inc/logger.h" + +static const uart_port_t uartPort = UART_NUM_0; static TaskHandle_t devTaskHandle = NULL; static void devTask(void* parameters); static GPIO gpio0(4, GPIO_DIRECTION_OUTPUT); static GPIO gpio1(18, GPIO_DIRECTION_OUTPUT); static time_t currentTime; -// -//static void wifi_init(void); -static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); -void wifi_init_sta(void); + extern "C" void app_main(void) { esp_log_level_set("*", ESP_LOG_WARN); - esp_err_t ret = nvs_flash_init(); if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) @@ -35,6 +35,30 @@ extern "C" void app_main(void) ret = nvs_flash_init(); } + //-------------------------------------------- + // UART + // + const uart_config_t uartConfig = + { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 0, + .source_clk = UART_SCLK_DEFAULT + }; + ESP_ERROR_CHECK(uart_param_config(uartPort, &uartConfig)); + ESP_ERROR_CHECK(uart_set_pin(uartPort, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + ESP_ERROR_CHECK(uart_driver_install(uartPort, 1024, 1024, 0, NULL, 0)); + + uart_write_bytes(uartPort, "helloWorld", sizeof("helloworld")); + + Logger logger(10, uartPort); + logger.Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_DEBUG, "Hello World from the Logger himself"); + + LOGGER_DEBUG("YEAHAAA"); + // Create the development task if(xTaskCreate(devTask, "DevTask", 2048, NULL, 3, &devTaskHandle) != pdPASS) { @@ -60,7 +84,7 @@ extern "C" void app_main(void) printf("%lld\n\r", currentTime); printf("%i:%i:%i\n\r", tm.tm_hour, tm.tm_min, tm.tm_sec); - vTaskDelay(1000); + vTaskDelay(1000); } } diff --git a/code/main/src/logger.cpp b/code/main/src/logger.cpp new file mode 100644 index 0000000..72626c9 --- /dev/null +++ b/code/main/src/logger.cpp @@ -0,0 +1,249 @@ +// -------------------------------------------------------------------------------------------------------------------- +/// \file logger.cpp +/// \brief Description +// -------------------------------------------------------------------------------------------------------------------- +// +// vbchaos software design +// +// -------------------------------------------------------------------------------------------------------------------- +/// $Revision: $ +/// $Author: $ +/// $Date: $ +// (c) 2023 vbchaos +// -------------------------------------------------------------------------------------------------------------------- + + + +// -------------------------------------------------------------------------------------------------------------------- +// Include files +// -------------------------------------------------------------------------------------------------------------------- + +#include +#include + +#include "logger.h" + +// -------------------------------------------------------------------------------------------------------------------- +// Constant and macro definitions +// -------------------------------------------------------------------------------------------------------------------- + +#define ENABLE_SERIAL_LOGGING +//#undef ENABLE_SERIAL_LOGGING + + +// -------------------------------------------------------------------------------------------------------------------- +// Type definitions +// -------------------------------------------------------------------------------------------------------------------- + + + +// -------------------------------------------------------------------------------------------------------------------- +// File-scope variables +// -------------------------------------------------------------------------------------------------------------------- + + + +// -------------------------------------------------------------------------------------------------------------------- +// Function declarations +// -------------------------------------------------------------------------------------------------------------------- + + + +// -------------------------------------------------------------------------------------------------------------------- +// Function definitions +// -------------------------------------------------------------------------------------------------------------------- + +TaskHandle_t Logger::logTaskHandle = NULL; +uart_port_t Logger::uartPort = 0; +QueueHandle_t Logger::logQueue = NULL; +int Logger::queuesize = 0; + +Logger::Logger(int queuesize, uart_port_t uartPort) +{ + Logger::uartPort = uartPort; + Logger::queuesize = queuesize; + logQueue = xQueueCreate(queuesize, sizeof(struct LogQueueItem)); + + xTaskCreate(loggerTask, (const char*)"loggerTask", 3072, NULL, 3, &logTaskHandle); + +} + +void Logger::Logger_log(const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* format, ...) +{ +#if defined(ENABLE_SERIAL_LOGGING) + static int nrLostMessages = 0; + static bool overflowRecovery = false; + int nrOfMessages; + struct LogQueueItem logQueueItem; + va_list ap; + + nrOfMessages = uxQueueMessagesWaiting(Logger::logQueue); + + if((nrOfMessages == queuesize - 1) && !overflowRecovery) + { + // Queue almost full, only one entry left. Log a warning instead + composeLogQueueItem(&logQueueItem, __FILE__, __func__, __LINE__, LOGTYPE_WARNING, "Log queue overflow"); + (void)xQueueSend(logQueue, &logQueueItem, 0); + + overflowRecovery = true; + nrLostMessages = 1; + } + else if((nrOfMessages == 0) && overflowRecovery) + { + // Queue empty again after an overflow + char str[128]; + snprintf(str, sizeof(str) / sizeof(str[0]), "%d messages lost", nrLostMessages); + composeLogQueueItem(&logQueueItem, __FILE__, __func__, __LINE__, LOGTYPE_WARNING, str); + (void)xQueueSend(logQueue, &logQueueItem, 0); + + overflowRecovery = false; + } + else if(!overflowRecovery) + { + // Normal behaviour, queue not full + char str[128]; + va_start(ap, format); + vsnprintf(str, sizeof(str) / sizeof(str[0]), format, ap); + va_end(ap); + + composeLogQueueItem(&logQueueItem, fileName, functionName, lineNumber, logType, str); + (void)xQueueSend(logQueue, &logQueueItem, 0); + } + else + { + // Count number of lost messages + ++nrLostMessages; + } +#endif +} + +void Logger_logISR(struct Logger* self, const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* context) +{ +#if defined(ENABLE_LOGGING) + if (self->initialized) + { + struct LogQueueItem logQueueItem; + portBASE_TYPE higherPriorityTaskWoken = pdFALSE; + + composeLogQueueItem(&logQueueItem, fileName, functionName, lineNumber, logType, context); + + if(xQueueSendFromISR(self->logQueue, &logQueueItem, &higherPriorityTaskWoken) != pdTRUE) + { + // Queue failed + } + + portEND_SWITCHING_ISR(higherPriorityTaskWoken); + } +#endif +} + + +#if defined(ENABLE_SERIAL_LOGGING) +void Logger::composeLogQueueItem(struct LogQueueItem* logQueueItem, const char* fileName, const char* functionName, + int lineNumber, LogType logType, const char* context) +{ + const size_t fileNameSize = sizeof(logQueueItem->fileName) / sizeof(logQueueItem->fileName[0]); + const size_t functionNameSize = sizeof(logQueueItem->functionName) / sizeof(logQueueItem->functionName[0]); + const size_t contextSize = sizeof(logQueueItem->context) / sizeof(logQueueItem->context[0]); + + logQueueItem->logType = logType; + strncpy(&(logQueueItem->context[0]), context, contextSize); + logQueueItem->context[contextSize - 1] = '\0'; + + if(logType != LOGTYPE_PRINT) + { + int fileNameIndex = 0; + + // If filename starts with "src/", strip this part + if((fileName[0] == 's') && + (fileName[1] == 'r') && + (fileName[2] == 'c') && + (fileName[3] == '/')) + { + fileNameIndex = 4; + } + +// It is known that the strncpy use can potentially truncate the source string, meaning +// that the target string size is smaller then the original string +// This is not a problem in this particular case, so the compiler warning is disabled +// for this situation +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-truncation" + // All logtypes except LOGTYPE_PRINT need filename, functionname and linenumber. + strncpy(&(logQueueItem->fileName[0]), &fileName[fileNameIndex], fileNameSize); + strncpy(&(logQueueItem->functionName[0]), functionName, functionNameSize); +#pragma GCC diagnostic pop + logQueueItem->lineNumber = lineNumber; + + // Fix terminating null byte in strncpy in case string to be copied is too long + logQueueItem->fileName[fileNameSize - 1] = '\0'; + logQueueItem->functionName[functionNameSize - 1] = '\0'; + } +} +#endif + +void Logger::loggerTask(void* parameters) +{ + while(true) + { + struct LogQueueItem logQueueItem; + + xQueueReceive(logQueue, &logQueueItem, portMAX_DELAY); + + if(logQueueItem.logType == LOGTYPE_PRINT) + { + // Raw print + #if defined(ENABLE_SERIAL_LOGGING) + uart_write_bytes(uartPort, logQueueItem.context, strlen(logQueueItem.context)); + #endif + + } + else + { + #if defined(ENABLE_SERIAL_LOGGING) + char str[256]; + char* vt100Prefix = ""; + const char* vt100Postfix = "\033[0m"; + #endif + + #if defined(ENABLE_SERIAL_LOGGING) + if(logQueueItem.logType == LOGTYPE_INFO) + { + vt100Prefix = "\033[33m"; + } + else if(logQueueItem.logType == LOGTYPE_WARNING) + { + vt100Prefix = "\033[35m"; + } + else if(logQueueItem.logType == LOGTYPE_ERROR) + { + vt100Prefix = "\033[31m"; + } + #endif + + unsigned int seconds = 0; + + #if defined(ENABLE_SERIAL_LOGGING) + // Formatted print + snprintf(str, sizeof(str) / sizeof(str[0]), "%s[%s] %09d %s, %s, %d: %s%s\n\r", + vt100Prefix, + (logQueueItem.logType == LOGTYPE_DEBUG) ? "DBG" : + (logQueueItem.logType == LOGTYPE_INFO) ? "INF" : + (logQueueItem.logType == LOGTYPE_WARNING) ? "WRN" : "ERR", + seconds, + logQueueItem.fileName, + logQueueItem.functionName, + logQueueItem.lineNumber, + logQueueItem.context, + vt100Postfix); + #endif + + #if defined(ENABLE_SERIAL_LOGGING) + uart_write_bytes(uartPort, str, strlen(str)); + #endif + + } + } + + vTaskDelete(NULL); +} diff --git a/code/sdkconfig b/code/sdkconfig index e0bbafd..97a81f8 100644 --- a/code/sdkconfig +++ b/code/sdkconfig @@ -760,15 +760,13 @@ CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y # CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 -CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_UART_DEFAULT is not set # CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set # CONFIG_ESP_CONSOLE_UART_CUSTOM is not set -# CONFIG_ESP_CONSOLE_NONE is not set +CONFIG_ESP_CONSOLE_NONE=y CONFIG_ESP_CONSOLE_SECONDARY_NONE=y # CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG is not set -CONFIG_ESP_CONSOLE_UART=y CONFIG_ESP_CONSOLE_UART_NUM=0 -CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 CONFIG_ESP_INT_WDT=y CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 CONFIG_ESP_TASK_WDT_EN=y @@ -1536,13 +1534,11 @@ CONFIG_ESP32C3_MEMPROT_FEATURE_LOCK=y CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 CONFIG_MAIN_TASK_STACK_SIZE=3584 -CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_DEFAULT is not set # CONFIG_CONSOLE_UART_CUSTOM is not set -# CONFIG_CONSOLE_UART_NONE is not set -# CONFIG_ESP_CONSOLE_UART_NONE is not set -CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NONE=y +CONFIG_ESP_CONSOLE_UART_NONE=y CONFIG_CONSOLE_UART_NUM=0 -CONFIG_CONSOLE_UART_BAUDRATE=115200 CONFIG_INT_WDT=y CONFIG_INT_WDT_TIMEOUT_MS=300 CONFIG_ESP_TASK_WDT=y diff --git a/code/sdkconfig.old b/code/sdkconfig.old index 4a42b22..423b4e2 100644 --- a/code/sdkconfig.old +++ b/code/sdkconfig.old @@ -365,8 +365,8 @@ CONFIG_PARTITION_TABLE_MD5=y # # Example Configuration # -CONFIG_ESP_WIFI_SSID="myssid" -CONFIG_ESP_WIFI_PASSWORD="mypassword" +CONFIG_ESP_WIFI_SSID="vbchaos" +CONFIG_ESP_WIFI_PASSWORD="mijninternet" # end of Example Configuration # @@ -760,14 +760,16 @@ CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y # CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 -CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_UART_DEFAULT is not set # CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set -# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +CONFIG_ESP_CONSOLE_UART_CUSTOM=y # CONFIG_ESP_CONSOLE_NONE is not set CONFIG_ESP_CONSOLE_SECONDARY_NONE=y # CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG is not set CONFIG_ESP_CONSOLE_UART=y CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_TX_GPIO=0 +CONFIG_ESP_CONSOLE_UART_RX_GPIO=1 CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 CONFIG_ESP_INT_WDT=y CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 @@ -1536,12 +1538,14 @@ CONFIG_ESP32C3_MEMPROT_FEATURE_LOCK=y CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 CONFIG_MAIN_TASK_STACK_SIZE=3584 -CONFIG_CONSOLE_UART_DEFAULT=y -# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_DEFAULT is not set +CONFIG_CONSOLE_UART_CUSTOM=y # CONFIG_CONSOLE_UART_NONE is not set # CONFIG_ESP_CONSOLE_UART_NONE is not set CONFIG_CONSOLE_UART=y CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_TX_GPIO=0 +CONFIG_CONSOLE_UART_RX_GPIO=1 CONFIG_CONSOLE_UART_BAUDRATE=115200 CONFIG_INT_WDT=y CONFIG_INT_WDT_TIMEOUT_MS=300