0% found this document useful (0 votes)
5 views6 pages

Error Handler C

The document implements a thread-safe error handling system in C, featuring a circular buffer for error records, error statistics, and a callback mechanism for error notifications. It includes functions for initializing the error handler, logging errors, retrieving the latest error, and managing error statistics. The system uses a mutex for thread safety and provides functionality to clear error records and check for critical errors.

Uploaded by

Jose Maca
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views6 pages

Error Handler C

The document implements a thread-safe error handling system in C, featuring a circular buffer for error records, error statistics, and a callback mechanism for error notifications. It includes functions for initializing the error handler, logging errors, retrieving the latest error, and managing error statistics. The system uses a mutex for thread safety and provides functionality to clear error records and check for critical errors.

Uploaded by

Jose Maca
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 6

/**

* @file error_handler.c
* @brief Implementation of the thread-safe error handling system
*/

#include "error_handler.h"
#include <string.h>
#include <stdio.h>
#include "task.h"

/**
* @brief Internal structure for error handling system state
*/
typedef struct {
ErrorRecord_t records[ERROR_MAX_RECORDS]; /**< Circular buffer of error
records */
uint32_t write_index; /**< Current write position in
buffer */
ErrorStats_t stats; /**< Error statistics */
ErrorCallback_t callback; /**< Error notification callback */
SemaphoreHandle_t mutex; /**< Mutex for thread safety */
StaticSemaphore_t mutex_buffer; /**< Static buffer for mutex */
bool initialized; /**< Initialization flag */
} ErrorHandler_t;

/* Static instance of error handler */


static ErrorHandler_t error_handler;

/* Private function prototypes */


static void ErrorHandler_TruncateFilename(const char* src, char* dst, size_t
max_len);
static void ErrorHandler_UpdateStats(ErrorSeverity_t severity, ErrorCategory_t
category);
static bool ErrorHandler_AcquireMutex(void);
static void ErrorHandler_ReleaseMutex(void);

BaseType_t ErrorHandler_Init(void) {
/* Prevent multiple initialization */
if (error_handler.initialized) {
return pdFAIL;
}

/* Clear all data */


memset(&error_handler, 0, sizeof(ErrorHandler_t));

/* Create mutex using static buffer */


error_handler.mutex = xSemaphoreCreateMutexStatic(&error_handler.mutex_buffer);
if (error_handler.mutex == NULL) {
return pdFAIL;
}

error_handler.initialized = true;
return pdPASS;
}

bool ErrorHandler_Log(
ErrorSeverity_t severity,
ErrorCategory_t category,
uint32_t error_code,
const char* file,
uint32_t line,
const char* message,
uint32_t data
) {
if (!error_handler.initialized || !file || !message) {
return false;
}

/* Validate parameters */
if (severity > ERROR_SEVERITY_CRITICAL ||
category >= ERROR_CAT_COUNT) {
return false;
}

if (!ErrorHandler_AcquireMutex()) {
error_handler.stats.mutex_timeouts++;
return false;
}

/* Get pointer to current record */


ErrorRecord_t* record = &error_handler.records[error_handler.write_index];

/* Fill record */
record->timestamp = xTaskGetTickCount();
record->severity = severity;
record->category = category;
record->error_code = error_code;
record->line = line;
record->data = data;

/* Safely copy strings */


ErrorHandler_TruncateFilename(file, record->file, ERROR_FILE_NAME_LEN);
strncpy(record->message, message, ERROR_MAX_MSG_LEN - 1);
record->message[ERROR_MAX_MSG_LEN - 1] = '\0';

/* Update indices and statistics */


error_handler.write_index = (error_handler.write_index + 1) %
ERROR_MAX_RECORDS;
ErrorHandler_UpdateStats(severity, category);

/* Notify callback if registered and error is severe enough */


if (error_handler.callback && severity >= ERROR_SEVERITY_ERROR) {
error_handler.callback(record);
}

ErrorHandler_ReleaseMutex();
return true;
}

bool ErrorHandler_RegisterCallback(ErrorCallback_t callback) {


if (!error_handler.initialized) {
return false;
}

if (!ErrorHandler_AcquireMutex()) {
return false;
}
bool has_critical = false;
for (uint32_t i = 0; i < ERROR_MAX_RECORDS; i++) {
if (error_handler.records[i].severity == ERROR_SEVERITY_CRITICAL) {
has_critical = true;
break;
}
}

ErrorHandler_ReleaseMutex();
return has_critical;
}

/**
* @brief Truncate filename to remove path
*
* @param src Source filename with path
* @param dst Destination buffer
* @param max_len Maximum length of destination buffer
*/
static void ErrorHandler_TruncateFilename(const char* src, char* dst, size_t
max_len) {
size_t len = strlen(src);
const char* start = src;

/* Find last slash or backslash */


for (const char* p = src + len - 1; p >= src; p--) {
if (*p == '/' || *p == '\\') {
start = p + 1;
break;
}
}

strncpy(dst, start, max_len - 1);


dst[max_len - 1] = '\0';
}

/**
* @brief Update error statistics
*
* @param severity Error severity level
* @param category Error category
*/
static void ErrorHandler_UpdateStats(ErrorSeverity_t severity, ErrorCategory_t
category) {
error_handler.stats.total_errors++;
error_handler.stats.errors_by_severity[severity]++;
error_handler.stats.errors_by_category[category]++;

/* Check for buffer overrun */


if (error_handler.stats.total_errors > ERROR_MAX_RECORDS) {
error_handler.stats.buffer_overruns++;
}
}

/**
* @brief Acquire the error handler mutex with timeout
*
* @return true if mutex was acquired, false if timeout
*/
static bool ErrorHandler_AcquireMutex(void) {
if (xSemaphoreTake(error_handler.mutex,
pdMS_TO_TICKS(ERROR_MUTEX_TIMEOUT_MS)) != pdTRUE) {
return false;
}
return true;
}

/**
* @brief Release the error handler mutex
*/
static void ErrorHandler_ReleaseMutex(void) {
xSemaphoreGive(error_handler.mutex);
}
return false;
}

if (!ErrorHandler_AcquireMutex()) {
return false;
}

error_handler.callback = callback;
ErrorHandler_ReleaseMutex();

return true;
}

const ErrorRecord_t* ErrorHandler_GetLatest(void) {


if (!error_handler.initialized || error_handler.stats.total_errors == 0) {
return NULL;
}

if (!ErrorHandler_AcquireMutex()) {
return NULL;
}

uint32_t latest_index = (error_handler.write_index - 1) % ERROR_MAX_RECORDS;


const ErrorRecord_t* latest = &error_handler.records[latest_index];

ErrorHandler_ReleaseMutex();
return latest;
}

bool ErrorHandler_GetStats(ErrorStats_t* stats) {


if (!error_handler.initialized || !stats) {
return false;
}

if (!ErrorHandler_AcquireMutex()) {
return false;
}

*stats = error_handler.stats;
ErrorHandler_ReleaseMutex();

return true;
}

uint32_t ErrorHandler_GetLogString(char* buffer, uint32_t max_len, uint32_t


num_errors) {
if (!error_handler.initialized || !buffer || max_len == 0) {
return 0;
}

uint32_t written = 0;
uint32_t available = max_len;

/* Header */
written += snprintf(buffer + written, available,
"Error Log (Last %lu of %lu errors):\r\n",
num_errors, error_handler.stats.total_errors);
available = max_len - written;

if (!ErrorHandler_AcquireMutex()) {
return written;
}

/* Calculate start index */


uint32_t count = 0;
uint32_t index = error_handler.write_index;

while (count < num_errors &&


count < error_handler.stats.total_errors &&
available > 0) {
if (index == 0) {
index = ERROR_MAX_RECORDS - 1;
} else {
index--;
}

const ErrorRecord_t* record = &error_handler.records[index];

/* Format timestamp as seconds.milliseconds */


uint32_t ms_per_tick = portTICK_PERIOD_MS;
uint32_t timestamp_s = (record->timestamp * ms_per_tick) / 1000;
uint32_t timestamp_ms = (record->timestamp * ms_per_tick) % 1000;

written += snprintf(buffer + written, available,


"%lu.%03lu - [%s:%lu] %s: %s (0x%lX)\r\n",
timestamp_s, timestamp_ms,
record->file, record->line,
record->severity == ERROR_SEVERITY_CRITICAL ? "CRIT" :
record->severity == ERROR_SEVERITY_ERROR ? "ERROR" :
record->severity == ERROR_SEVERITY_WARNING ? "WARN" : "INFO",
record->message,
record->data);

available = max_len - written;


count++;
}

ErrorHandler_ReleaseMutex();
return written;
}

bool ErrorHandler_Clear(void) {
if (!error_handler.initialized) {
return false;
}

if (!ErrorHandler_AcquireMutex()) {
return false;
}

memset(error_handler.records, 0, sizeof(error_handler.records));
memset(&error_handler.stats, 0, sizeof(error_handler.stats));
error_handler.write_index = 0;

ErrorHandler_ReleaseMutex();
return true;
}

bool ErrorHandler_HasCritical(void) {
if (!error_handler.initialized) {

You might also like