git-svn-id: https://svn.vbchaos.nl/svn/hsb/trunk@232 05563f52-14a8-4384-a975-3d1654cca0fa
339 lines
9.1 KiB
C
339 lines
9.1 KiB
C
// -----------------------------------------------------------------------------
|
|
/// @file Logger.c
|
|
/// @brief Description
|
|
// -----------------------------------------------------------------------------
|
|
// Micro-Key bv
|
|
// Industrieweg 28, 9804 TG Noordhorn
|
|
// Postbus 92, 9800 AB Zuidhorn
|
|
// The Netherlands
|
|
// Tel: +31 594 503020
|
|
// Fax: +31 594 505825
|
|
// Email: support@microkey.nl
|
|
// Web: www.microkey.nl
|
|
// -----------------------------------------------------------------------------
|
|
/// $Revision$
|
|
/// $Author$
|
|
/// $Date$
|
|
// (c) 2017 Micro-Key bv
|
|
// -----------------------------------------------------------------------------
|
|
|
|
/// @file main.c
|
|
/// @ingroup {group_name}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Include files
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
#include <FreeRTOSFixes.h>
|
|
#include "FreeRTOS.h"
|
|
#include "Logger.h"
|
|
#include "semphr.h"
|
|
#include "queue.h"
|
|
#include "task.h"
|
|
#include "misc.h"
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#include "uart.h"
|
|
// -----------------------------------------------------------------------------
|
|
// Constant and macro definitions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
#define LOGQUEUE_SIZE (24)
|
|
#define LOGGER_STACK_SIZE (512)
|
|
#define LOGGER_TASK_PRIORITY (2)
|
|
|
|
// Makefile compile options:
|
|
// ENABLE_SERIAL_LOGGING: Use the serial port for logging.
|
|
|
|
#if defined(ENABLE_SERIAL_LOGGING)
|
|
#define ENABLE_LOGGING
|
|
#else
|
|
#undef ENABLE_LOGGING
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Type definitions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// File-scope variables
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static struct IODevice* loggerDevice;
|
|
|
|
static xQueueHandle logQueue;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Function declarations
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static bool initialized = false;
|
|
static xTaskHandle loggerTaskHandle = NULL;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Function definitions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
static void composeLogQueueItem(struct LogQueueItem* logQueueItem, const char* fileName, const char* functionName,
|
|
int lineNumber, LogType logType, const char* context);
|
|
static void loggerTask(void* parameters);
|
|
|
|
|
|
/* ---------------------*
|
|
* Function definitions *
|
|
* ---------------------*
|
|
*/
|
|
|
|
ErrorStatus Logger_construct(struct IODevice* const device)
|
|
{
|
|
ErrorStatus returnValue = SUCCESS;
|
|
|
|
if(!initialized)
|
|
{
|
|
loggerDevice = device;
|
|
|
|
if(returnValue == SUCCESS)
|
|
{
|
|
logQueue = xQueueCreate(LOGQUEUE_SIZE, sizeof(struct LogQueueItem));
|
|
|
|
if(logQueue == 0)
|
|
{
|
|
returnValue = ERROR;
|
|
}
|
|
}
|
|
|
|
if(returnValue == SUCCESS)
|
|
{
|
|
if(xTaskCreate(loggerTask, (const char*)"loggerTask", LOGGER_STACK_SIZE, NULL, LOGGER_TASK_PRIORITY, &loggerTaskHandle) != pdPASS)
|
|
{
|
|
returnValue = ERROR;
|
|
}
|
|
}
|
|
|
|
if(returnValue == SUCCESS)
|
|
{
|
|
initialized = true;
|
|
LOGGER_INFO("Logger started");
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
returnValue = ERROR;
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
void Logger_terminate(void)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
ErrorStatus Logger_logModuleInfo(void)
|
|
{
|
|
ErrorStatus errorStatus = SUCCESS;
|
|
|
|
OS_logTaskInfo(loggerTaskHandle);
|
|
|
|
return errorStatus;
|
|
}
|
|
|
|
void Logger_log(const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* format, ...)
|
|
{
|
|
if(initialized)
|
|
{
|
|
static int nrLostMessages = 0;
|
|
static bool overflowRecovery = false;
|
|
int nrOfMessages;
|
|
struct LogQueueItem logQueueItem;
|
|
va_list ap;
|
|
|
|
nrOfMessages = uxQueueMessagesWaiting(&logQueue);
|
|
|
|
if((nrOfMessages == LOGQUEUE_SIZE - 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;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void Logger_logISR(const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* context)
|
|
{
|
|
#if defined(ENABLE_LOGGING)
|
|
if(initialized)
|
|
{
|
|
struct LogQueueItem logQueueItem;
|
|
portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
|
|
|
|
composeLogQueueItem(&logQueueItem, fileName, functionName, lineNumber, logType, context);
|
|
|
|
if(xQueueSendFromISR(logQueue, &logQueueItem, &higherPriorityTaskWoken) != pdTRUE)
|
|
{
|
|
// Queue failed
|
|
}
|
|
|
|
portEND_SWITCHING_ISR(higherPriorityTaskWoken);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
static void 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;
|
|
}
|
|
|
|
// All logtypes except LOGTYPE_PRINT need filename, functionname and linenumber.
|
|
strncpy(&(logQueueItem->fileName[0]), &fileName[fileNameIndex], fileNameSize);
|
|
strncpy(&(logQueueItem->functionName[0]), functionName, functionNameSize);
|
|
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';
|
|
}
|
|
}
|
|
|
|
static void loggerTask(void* parameters)
|
|
{
|
|
for(;;)
|
|
{
|
|
struct LogQueueItem logQueueItem;
|
|
|
|
xQueueReceive(logQueue, &logQueueItem, portMAX_DELAY);
|
|
|
|
if(logQueueItem.logType == LOGTYPE_PRINT)
|
|
{
|
|
// Raw print
|
|
#if defined(ENABLE_SERIAL_LOGGING)
|
|
IODevice_write(loggerDevice, logQueueItem.context, strlen(logQueueItem.context));
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
#if defined(ENABLE_SERIAL_LOGGING)
|
|
char str[256];
|
|
char* vt100Prefix = "";
|
|
const char* vt100Postfix = "\033[0m";
|
|
#endif
|
|
|
|
int hours;
|
|
int minutes;
|
|
int seconds;
|
|
|
|
#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
|
|
|
|
///TODO add RTC support
|
|
// RTC_getTime(&hours, &minutes, &seconds);
|
|
hours = 13;
|
|
minutes = 37;
|
|
seconds = 10;
|
|
|
|
#if defined(ENABLE_SERIAL_LOGGING)
|
|
// Formatted print
|
|
snprintf(str, sizeof(str) / sizeof(str[0]), "%s[%s] %02d:%02d:%02d %s, %s, %d: %s%s\n",
|
|
vt100Prefix,
|
|
(logQueueItem.logType == LOGTYPE_DEBUG) ? "DBG" :
|
|
(logQueueItem.logType == LOGTYPE_INFO) ? "INF" :
|
|
(logQueueItem.logType == LOGTYPE_WARNING) ? "WRN" : "ERR",
|
|
///TODO add RTC support
|
|
hours,
|
|
minutes,
|
|
seconds,
|
|
logQueueItem.fileName,
|
|
logQueueItem.functionName,
|
|
logQueueItem.lineNumber,
|
|
logQueueItem.context,
|
|
vt100Postfix);
|
|
#endif
|
|
|
|
#if defined(ENABLE_SERIAL_LOGGING)
|
|
IODevice_write(loggerDevice, str, strlen(str));
|
|
#endif
|
|
|
|
char buffer[5] = {0,};
|
|
size_t actualLength = 0;
|
|
IODevice_read(loggerDevice, buffer, 5, &actualLength);
|
|
|
|
snprintf(str, sizeof(str) / sizeof(str[0]), "%d - %x %x %x %x %x", actualLength, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
|
|
IODevice_write(loggerDevice, str, strlen(str));
|
|
}
|
|
}
|
|
}
|