This commit is contained in:
2026-01-19 16:19:41 +01:00
commit edd3e96591
301 changed files with 36763 additions and 0 deletions

View File

@@ -0,0 +1,366 @@
/**
* @file logger.cpp
* @brief ASF Logger - Implementation of ESP-IDF logging wrapper
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*/
#include "logger.hpp"
#include <cstdio>
#include <cstring>
#include <ctime>
#include <sys/time.h>
namespace asf {
namespace logger {
// Static configuration
static LoggerConfig s_config = {
.minLevel = LogLevel::INFO,
.enableTimestamp = true,
.enableColor = true,
.enableId = true,
.maxMessageLength = 256,
.filePath = nullptr
};
// Color codes for different log levels
static const char* COLOR_RESET = "\033[0m";
static const char* COLOR_VERBOSE = "\033[37m"; // White
static const char* COLOR_DEBUG = "\033[36m"; // Cyan
static const char* COLOR_INFO = "\033[32m"; // Green
static const char* COLOR_WARNING = "\033[33m"; // Yellow
static const char* COLOR_ERROR = "\033[31m"; // Red
void initialize(const LoggerConfig& config)
{
s_config = config;
// Set ESP-IDF log level based on our minimum level
esp_log_level_t espLevel = ESP_LOG_NONE;
switch (config.minLevel) {
case LogLevel::VERBOSE:
espLevel = ESP_LOG_VERBOSE;
break;
case LogLevel::DEBUG:
espLevel = ESP_LOG_DEBUG;
break;
case LogLevel::INFO:
espLevel = ESP_LOG_INFO;
break;
case LogLevel::WARNING:
espLevel = ESP_LOG_WARN;
break;
case LogLevel::ERROR:
espLevel = ESP_LOG_ERROR;
break;
case LogLevel::NONE:
espLevel = ESP_LOG_NONE;
break;
}
esp_log_level_set("*", espLevel);
}
void setLogLevel(LogLevel level)
{
s_config.minLevel = level;
// Update ESP-IDF log level
LoggerConfig tempConfig = s_config;
tempConfig.minLevel = level;
initialize(tempConfig);
}
LogLevel getLogLevel()
{
return s_config.minLevel;
}
void enableTimestamp(bool enable)
{
s_config.enableTimestamp = enable;
}
void enableColor(bool enable)
{
s_config.enableColor = enable;
}
void enableId(bool enable)
{
s_config.enableId = enable;
}
void enableFileLogging(const char* filePath)
{
s_config.filePath = filePath;
}
const char* getIsoTimestamp(char* buffer, size_t bufferSize)
{
if (buffer == nullptr || bufferSize < 24) {
return "";
}
// Get current time with microseconds
struct timeval tv;
gettimeofday(&tv, nullptr);
struct tm* timeinfo = localtime(&tv.tv_sec);
// Format: YYYY-MM-DDTHH:MM:SS.sssZ
snprintf(buffer, bufferSize, "%04d-%02d-%02dT%02d:%02d:%02d.%03ldZ",
timeinfo->tm_year + 1900,
timeinfo->tm_mon + 1,
timeinfo->tm_mday,
timeinfo->tm_hour,
timeinfo->tm_min,
timeinfo->tm_sec,
tv.tv_usec / 1000);
return buffer;
}
void log(const char* tag, uint32_t id, LogLevel level, Criticality criticality, const char* format, ...)
{
// Check if we should log this level
if (level < s_config.minLevel) {
return;
}
if (tag == nullptr || format == nullptr) {
return;
}
// Prepare message buffer
char messageBuffer[s_config.maxMessageLength];
// Format the user message
va_list args;
va_start(args, format);
vsnprintf(messageBuffer, sizeof(messageBuffer), format, args);
va_end(args);
// Prepare final output buffer
char outputBuffer[s_config.maxMessageLength + 128]; // Extra space for timestamp, tag, etc.
char timestampBuffer[32];
// Build the formatted log message
const char* colorStart = s_config.enableColor ? logLevelToColor(level) : "";
const char* colorEnd = s_config.enableColor ? COLOR_RESET : "";
const char* timestamp = s_config.enableTimestamp ? getIsoTimestamp(timestampBuffer, sizeof(timestampBuffer)) : "";
const char* levelStr = logLevelToString(level);
const char* critStr = criticalityToString(criticality);
if (s_config.enableTimestamp && s_config.enableId) {
snprintf(outputBuffer, sizeof(outputBuffer), "%s%s : %s[%s][%s] : %lu : %s%s",
colorStart, timestamp, tag, levelStr, critStr, id, messageBuffer, colorEnd);
} else if (s_config.enableTimestamp && !s_config.enableId) {
snprintf(outputBuffer, sizeof(outputBuffer), "%s%s : %s[%s][%s] : %s%s",
colorStart, timestamp, tag, levelStr, critStr, messageBuffer, colorEnd);
} else if (!s_config.enableTimestamp && s_config.enableId) {
snprintf(outputBuffer, sizeof(outputBuffer), "%s%s[%s][%s] : %lu : %s%s",
colorStart, tag, levelStr, critStr, id, messageBuffer, colorEnd);
} else {
snprintf(outputBuffer, sizeof(outputBuffer), "%s%s[%s][%s] : %s%s",
colorStart, tag, levelStr, critStr, messageBuffer, colorEnd);
}
// Output using ESP-IDF logging system
switch (level) {
case LogLevel::VERBOSE:
ESP_LOGV("ASF", "%s", outputBuffer);
break;
case LogLevel::DEBUG:
ESP_LOGD("ASF", "%s", outputBuffer);
break;
case LogLevel::INFO:
ESP_LOGI("ASF", "%s", outputBuffer);
break;
case LogLevel::WARNING:
ESP_LOGW("ASF", "%s", outputBuffer);
break;
case LogLevel::ERROR:
ESP_LOGE("ASF", "%s", outputBuffer);
break;
case LogLevel::NONE:
break;
}
// Write to file if enabled
if (s_config.filePath != nullptr) {
FILE* f = fopen(s_config.filePath, "a");
if (f != nullptr) {
// Re-format without color codes for file output
char fileBuffer[s_config.maxMessageLength + 128];
if (s_config.enableTimestamp && s_config.enableId) {
snprintf(fileBuffer, sizeof(fileBuffer), "%s : %s[%s][%s] : %lu : %s\n",
timestamp, tag, levelStr, critStr, id, messageBuffer);
} else if (s_config.enableTimestamp && !s_config.enableId) {
snprintf(fileBuffer, sizeof(fileBuffer), "%s : %s[%s][%s] : %s\n",
timestamp, tag, levelStr, critStr, messageBuffer);
} else if (!s_config.enableTimestamp && s_config.enableId) {
snprintf(fileBuffer, sizeof(fileBuffer), "%s[%s][%s] : %lu : %s\n",
tag, levelStr, critStr, id, messageBuffer);
} else {
snprintf(fileBuffer, sizeof(fileBuffer), "%s[%s][%s] : %s\n",
tag, levelStr, critStr, messageBuffer);
}
fprintf(f, "%s", fileBuffer);
fclose(f);
}
}
}
void logVerbose(const char* tag, uint32_t id, Criticality criticality, const char* format, ...)
{
if (LogLevel::VERBOSE < s_config.minLevel) {
return;
}
va_list args;
va_start(args, format);
char messageBuffer[s_config.maxMessageLength];
vsnprintf(messageBuffer, sizeof(messageBuffer), format, args);
va_end(args);
log(tag, id, LogLevel::VERBOSE, criticality, "%s", messageBuffer);
}
void logDebug(const char* tag, uint32_t id, Criticality criticality, const char* format, ...)
{
if (LogLevel::DEBUG < s_config.minLevel) {
return;
}
va_list args;
va_start(args, format);
char messageBuffer[s_config.maxMessageLength];
vsnprintf(messageBuffer, sizeof(messageBuffer), format, args);
va_end(args);
log(tag, id, LogLevel::DEBUG, criticality, "%s", messageBuffer);
}
void logInfo(const char* tag, uint32_t id, Criticality criticality, const char* format, ...)
{
if (LogLevel::INFO < s_config.minLevel) {
return;
}
va_list args;
va_start(args, format);
char messageBuffer[s_config.maxMessageLength];
vsnprintf(messageBuffer, sizeof(messageBuffer), format, args);
va_end(args);
log(tag, id, LogLevel::INFO, criticality, "%s", messageBuffer);
}
void logWarning(const char* tag, uint32_t id, Criticality criticality, const char* format, ...)
{
if (LogLevel::WARNING < s_config.minLevel) {
return;
}
va_list args;
va_start(args, format);
char messageBuffer[s_config.maxMessageLength];
vsnprintf(messageBuffer, sizeof(messageBuffer), format, args);
va_end(args);
log(tag, id, LogLevel::WARNING, criticality, "%s", messageBuffer);
}
void logError(const char* tag, uint32_t id, Criticality criticality, const char* format, ...)
{
if (LogLevel::ERROR < s_config.minLevel) {
return;
}
va_list args;
va_start(args, format);
char messageBuffer[s_config.maxMessageLength];
vsnprintf(messageBuffer, sizeof(messageBuffer), format, args);
va_end(args);
log(tag, id, LogLevel::ERROR, criticality, "%s", messageBuffer);
}
LoggerConfig getDefaultConfig()
{
LoggerConfig config = {};
config.minLevel = LogLevel::INFO;
config.enableTimestamp = true;
config.enableColor = true;
config.enableId = true;
config.maxMessageLength = 256;
config.filePath = nullptr;
return config;
}
const char* logLevelToString(LogLevel level)
{
switch (level) {
case LogLevel::VERBOSE:
return "VERBOSE";
case LogLevel::DEBUG:
return "DEBUG";
case LogLevel::INFO:
return "INFO";
case LogLevel::WARNING:
return "WARNING";
case LogLevel::ERROR:
return "ERROR";
case LogLevel::NONE:
return "NONE";
default:
return "UNKNOWN";
}
}
const char* logLevelToColor(LogLevel level)
{
switch (level) {
case LogLevel::VERBOSE:
return COLOR_VERBOSE;
case LogLevel::DEBUG:
return COLOR_DEBUG;
case LogLevel::INFO:
return COLOR_INFO;
case LogLevel::WARNING:
return COLOR_WARNING;
case LogLevel::ERROR:
return COLOR_ERROR;
case LogLevel::NONE:
return COLOR_RESET;
default:
return COLOR_RESET;
}
}
const char* criticalityToString(Criticality criticality)
{
switch (criticality) {
case Criticality::LOW:
return "LOW";
case Criticality::MEDIUM:
return "MEDIUM";
case Criticality::HIGH:
return "HIGH";
case Criticality::VERY_HIGH:
return "VERY_HIGH";
default:
return "UNKNOWN";
}
}
} // namespace logger
} // namespace asf

View File

@@ -0,0 +1,226 @@
/**
* @file logger.hpp
* @brief ASF Logger - Wrapper for ESP-IDF logging functionality
* @author Mahmoud Elmohtady
* @company Nabd solutions - ASF
* @copyright Copyright (c) 2025
*
* @details
* Abstract logger class for the application and device driver layers
* - Does not depend directly on the low-level logging mechanism provided by platform
* - Supports logging levels (info, warn, debug, error, verbose)
* - Formats messages with ISO timestamp, TAG, level, and unique ID
* - Low overhead design for minimal performance impact
* - Easily included in all modules without compile/linking errors
* - Efficient in compilation time and flash space
*
* Design: Namespace with free functions for simplicity and zero overhead
*/
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include <cstdint>
#include <cstdarg>
#include "esp_log.h"
#include "esp_timer.h"
/**
* @brief Logger namespace containing all logging functionality
*/
namespace asf {
namespace logger {
/**
* @brief Log level enumeration
*/
enum class LogLevel : uint8_t
{
VERBOSE = 0, ///< Verbose level (most detailed)
DEBUG = 1, ///< Debug level
INFO = 2, ///< Information level
WARNING = 3, ///< Warning level
ERROR = 4, ///< Error level
NONE = 5 ///< No logging
};
/**
* @brief Log criticality enumeration
*/
enum class Criticality : uint8_t
{
LOW, ///< Low criticality
MEDIUM, ///< Medium criticality
HIGH, ///< High criticality
VERY_HIGH ///< Very high criticality
};
/**
* @brief Logger configuration structure
*/
struct LoggerConfig
{
LogLevel minLevel; ///< Minimum log level to display
bool enableTimestamp; ///< Enable ISO timestamp in output
bool enableColor; ///< Enable color output
bool enableId; ///< Enable unique ID in output
uint32_t maxMessageLength; ///< Maximum message length
const char* filePath; ///< Path to log file (nullptr to disable file logging)
};
/**
* @brief Initialize the logger with configuration
* @param config Logger configuration
*/
void initialize(const LoggerConfig& config);
/**
* @brief Set minimum log level
* @param level Minimum log level to display
*/
void setLogLevel(LogLevel level);
/**
* @brief Get current minimum log level
* @return Current minimum log level
*/
LogLevel getLogLevel();
/**
* @brief Enable or disable timestamp in log output
* @param enable True to enable, false to disable
*/
void enableTimestamp(bool enable);
/**
* @brief Enable or disable color in log output
* @param enable True to enable, false to disable
*/
void enableColor(bool enable);
/**
* @brief Enable or disable ID in log output
* @param enable True to enable, false to disable
*/
void enableId(bool enable);
/**
* @brief Enable file logging
* @param filePath Path to the log file (e.g., "/ESP/log.txt")
*/
void enableFileLogging(const char* filePath);
/**
* @brief Get ISO 8601 formatted timestamp
* @param buffer Buffer to store timestamp
* @param bufferSize Size of buffer
* @return Pointer to buffer
*/
const char* getIsoTimestamp(char* buffer, size_t bufferSize);
/**
* @brief Main logging function
* @param tag Log tag (module name)
* @param id Unique message ID
* @param level Log level
* @param criticality Message criticality
* @param format Printf-style format string
* @param ... Variable arguments
*/
void log(const char* tag, uint32_t id, LogLevel level, Criticality criticality, const char* format, ...);
/**
* @brief Log verbose message
* @param tag Log tag (module name)
* @param id Unique message ID
* @param criticality Message criticality
* @param format Printf-style format string
* @param ... Variable arguments
*/
void logVerbose(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);
/**
* @brief Log debug message
* @param tag Log tag (module name)
* @param id Unique message ID
* @param criticality Message criticality
* @param format Printf-style format string
* @param ... Variable arguments
*/
void logDebug(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);
/**
* @brief Log info message
* @param tag Log tag (module name)
* @param id Unique message ID
* @param criticality Message criticality
* @param format Printf-style format string
* @param ... Variable arguments
*/
void logInfo(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);
/**
* @brief Log warning message
* @param tag Log tag (module name)
* @param id Unique message ID
* @param criticality Message criticality
* @param format Printf-style format string
* @param ... Variable arguments
*/
void logWarning(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);
/**
* @brief Log error message
* @param tag Log tag (module name)
* @param id Unique message ID
* @param criticality Message criticality
* @param format Printf-style format string
* @param ... Variable arguments
*/
void logError(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);
/**
* @brief Get default logger configuration
* @return Default logger configuration
*/
LoggerConfig getDefaultConfig();
/**
* @brief Convert log level to string
* @param level Log level
* @return String representation of log level
*/
const char* logLevelToString(LogLevel level);
/**
* @brief Convert log level to color code
* @param level Log level
* @return ANSI color code string
*/
const char* logLevelToColor(LogLevel level);
/**
* @brief Convert criticality to string
* @param criticality Message criticality
* @return String representation of criticality
*/
const char* criticalityToString(Criticality criticality);
} // namespace logger
} // namespace asf
// Convenience macros for easier usage
#define ASF_LOG_VERBOSE(tag, id, crit, format, ...) asf::logger::logVerbose(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOG_DEBUG(tag, id, crit, format, ...) asf::logger::logDebug(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOG_INFO(tag, id, crit, format, ...) asf::logger::logInfo(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOG_WARNING(tag, id, crit, format, ...) asf::logger::logWarning(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOG_ERROR(tag, id, crit, format, ...) asf::logger::logError(tag, id, crit, format, ##__VA_ARGS__)
// Short form macros
#define ASF_LOGV(tag, id, crit, format, ...) ASF_LOG_VERBOSE(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOGD(tag, id, crit, format, ...) ASF_LOG_DEBUG(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOGI(tag, id, crit, format, ...) ASF_LOG_INFO(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOGW(tag, id, crit, format, ...) ASF_LOG_WARNING(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOGE(tag, id, crit, format, ...) ASF_LOG_ERROR(tag, id, crit, format, ##__VA_ARGS__)
#endif // LOGGER_HPP