250 lines
8.5 KiB
C++
250 lines
8.5 KiB
C++
// --------------------------------------------------------------------------------------------------------------------
|
|
/// \file logger.cpp
|
|
/// \brief Description
|
|
// --------------------------------------------------------------------------------------------------------------------
|
|
//
|
|
// vbchaos software design
|
|
//
|
|
// --------------------------------------------------------------------------------------------------------------------
|
|
/// $Revision: $
|
|
/// $Author: $
|
|
/// $Date: $
|
|
// (c) 2023 vbchaos
|
|
// --------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------------------------------
|
|
// Include files
|
|
// --------------------------------------------------------------------------------------------------------------------
|
|
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
|
|
#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);
|
|
}
|