Started with a blank main file
- Added GPIO handling - Added a logger class with additional static debug log handling Tested, functional
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
/// \file logger.cpp
|
||||
/// \brief Description
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// vbchaos software design
|
||||
//
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
/// $Revision: $
|
||||
/// $Author: $
|
||||
/// $Date: $
|
||||
// (c) 2023 vbchaos
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Include files
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include <logger.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Constant and macro definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// File-scope variables
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Function declarations
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Function definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
logger::logger(uint32_t queuesize, ISerialBus<uint8_t>& serialPort) : port {serialPort}, queuesize {queuesize}
|
||||
{
|
||||
numberOfLostMessages = 0;
|
||||
// Compose the debug type level list
|
||||
composeTypeParameterList();
|
||||
}
|
||||
|
||||
|
||||
FunctionStatus logger::log(const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* format, ...)
|
||||
{
|
||||
FunctionStatus returnValue = FUNCTION_STATUS_OK;
|
||||
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
bool overflowRecovery = false;
|
||||
int nrOfMessages;
|
||||
struct LogQueueItem logQueueItem;
|
||||
va_list ap;
|
||||
|
||||
nrOfMessages = queue.size();
|
||||
|
||||
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");
|
||||
queue.push_back(logQueueItem);
|
||||
|
||||
overflowRecovery = true;
|
||||
numberOfLostMessages = 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", (unsigned int)numberOfLostMessages);
|
||||
composeLogQueueItem(&logQueueItem, __FILE__, __func__, __LINE__, LOGTYPE_WARNING, str);
|
||||
queue.push_back(logQueueItem);
|
||||
|
||||
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);
|
||||
queue.push_back(logQueueItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Count number of lost messages
|
||||
++numberOfLostMessages;
|
||||
}
|
||||
#endif
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
void logger::composeTypeParameterList(void)
|
||||
{
|
||||
typeParameterList.clear();
|
||||
// Add Debug information
|
||||
typeParameterList.push_back({LOGTYPE_DEBUG, "\033[33m", "DBG", "\033[0m"});
|
||||
// Add Warning information
|
||||
typeParameterList.push_back({LOGTYPE_WARNING, "\033[35m", "WRN", "\033[0m"});
|
||||
// Add Error information
|
||||
typeParameterList.push_back({LOGTYPE_ERROR, "\033[31m", "ERR", "\033[0m"});
|
||||
// Add Success information
|
||||
typeParameterList.push_back({LOGTYPE_SUCCESS, "\033[32m", "SCS", "\033[0m"});
|
||||
// Add Information information
|
||||
typeParameterList.push_back({LOGTYPE_INFO, "\033[33m", "INF", "\033[0m"});
|
||||
// Add Print information
|
||||
typeParameterList.push_back({LOGTYPE_PRINT, "", "DBG", "\033[0m"});
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
void logger::composeLogQueueItem(struct LogQueueItem* logQueueItem, std::string fileName, std::string functionName,
|
||||
int lineNumber, LogType logType, std::string context)
|
||||
{
|
||||
|
||||
logQueueItem->logType = logType;
|
||||
logQueueItem->context = context;
|
||||
// strncpy((char*)&(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.
|
||||
logQueueItem->fileName = fileName;
|
||||
logQueueItem->functionName = functionName;
|
||||
// strncpy((char*)&(logQueueItem->fileName[0]), &fileName[fileNameIndex], fileNameSize);
|
||||
// strncpy((char*)&(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::task()
|
||||
{
|
||||
struct LogQueueItem logQueueItem;
|
||||
|
||||
// Check if there is anything in the queue
|
||||
// If queue is empty, return to scheduler
|
||||
if (queue.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Get the first log item from queue
|
||||
logQueueItem = queue.front();
|
||||
// Remove the item from the queue
|
||||
this->queue.pop_front();
|
||||
|
||||
|
||||
if(logQueueItem.logType == LOGTYPE_PRINT)
|
||||
{
|
||||
// Raw print
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
|
||||
port.write((uint8_t*)logQueueItem.context.c_str(), logQueueItem.context.length() + 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int seconds = 0;
|
||||
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
// Formatted print
|
||||
|
||||
// Find the correct Log level type
|
||||
auto it = std::find_if(typeParameterList.begin(), typeParameterList.end(), [&logQueueItem](const struct typeParameters& obj) {return obj.logType == logQueueItem.logType;});
|
||||
|
||||
std::string outputString = it->vt100Prefix + " "
|
||||
+ it->vt100Prefix + " "
|
||||
+ std::to_string(seconds) + " "
|
||||
+ logQueueItem.fileName + " "
|
||||
+ logQueueItem.functionName + " "
|
||||
+ "(line " + std::to_string(logQueueItem.lineNumber) + "): "
|
||||
+ logQueueItem.context + " "
|
||||
+ it->vt100Postfix;
|
||||
|
||||
port.write((uint8_t*)outputString.c_str(), outputString.length() + 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user