// ----------------------------------------------------------------------------- /// @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 #include "FreeRTOS.h" #include "Logger.h" #include "semphr.h" #include "queue.h" #include "task.h" #include "misc.h" #include #include #include #include #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)); } } }