Efficient Embedded Development: Design and Implementation of a Lightweight Error Handling Module

In embedded development, an elegant and efficient error handling mechanism is key to ensuring system stability. Today, we share a lightweight error handling module that helps developers quickly locate issues and enhance code robustness!

✨ Module Features

  • Lightweight Design: Requires minimal memory, suitable for resource-constrained embedded environments

  • Error Leveling: Supports error priority management, capturing the most severe errors

  • Precise Location: Records filename, function name, and line number for quick issue identification

  • Easy Integration: Simple API design for easy incorporation into existing projects

🎯 Core Functions

// Error structure design
typedef struct {
    int32_t grade;    // Error level
    const char *name; // Error type
    const char *file; // Filename
    const char *func; // Function name
    uint32_t line;    // Line number
} userError_t;

🚀 Usage Instructions

1. Initialize the error object

userError_t err;
userError_Init(&err);

2. Capture error information

if (operation_failed) {
    userError_Capture(&err, ERR_UNKNOWN, ERR_POSITION);
}

3. Read error information

printf("Error Type: %s\n", err.name);
printf("Location: %s::%s@%d\n", err.file, err.func, err.line);

4. Clean up error records

userError_Clean(&err);

📝 Practical Application Example

int main() {
    userError_t err;
    userError_Init(&err);
    // Simulate operation failure
    int32_t ret = -1;
    if (ret < 0) {
        userError_Capture(&err, ERR_UNKNOWN_REPEAT(1), ERR_POSITION);
    }
    // Output error information
    printf("Error Level: %d\n", err.grade);
    printf("Error Type: %s\n", err.name);
    printf("Location: %s::%s@%d\n", err.file, err.func, err.line);
    userError_Clean(&err);
    return 0;
}

💡 Design Philosophy

This module follows the “minimum priority capture” principle: error information is only updated when the level of the new error is higher (numerically lower) than the recorded error. This ensures that developers always receive the most severe error information.

Conclusion

This lightweight error handling module provides simple yet powerful error tracking capabilities for embedded development. With precise error location and level management, it significantly reduces debugging time and enhances system reliability.

Try integrating it into your next project and experience the joy of efficient error handling!

Example code:

#ifndef _ERROR_CLASS_H__
#define _ERROR_CLASS_H__
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <limits.h>
// Macro to get error location
#define ERR_POSITION __FILE__, __func__, __LINE__
// Error type definitions
#define ERR_UNKNOWN 0, "unknown"               // Unknown error
#define ERR_UNKNOWN_REPEAT(i) 0, "unknown_" #i // Repeated unknown error (with number)
// Error structure
typedef struct {
    int32_t grade;    // Error level, lower value indicates higher level
    const char *name; // Error type name
    const char *file; // Filename where the error occurred
    const char *func; // Function name where the error occurred
    uint32_t line;    // Line number where the error occurred
} userError_t;
/**
 * @description: Initialize error information
 * @param userError_t *err: Pointer to error structure
 * @return: Always returns 0 indicating success
 */
int32_t userError_Init(userError_t *err);
/**
 * @description: Capture exception
 * @param userError_t *err: Pointer to error structure
 * @param int32_t grade: Error level
 * @param const char *name: Error name
 * @param const char *file: Filename
 * @param const char *func: Function name
 * @param uint32_t line: Line number
 * @return: Always returns 0 indicating success
 */
int32_t userError_Capture(userError_t *err, int32_t grade, const char *name,
                          const char *file, const char *func, uint32_t line);
/**
 * @description: Clean up error information
 * @param userError_t *err: Pointer to error structure
 * @return: Always returns 0 indicating success
 */
int32_t userError_Clean(userError_t *err);
#endif /* _ERROR_CLASS_H__ */
#include "error_class.h"
/**
 * @description: Initialize error information
 * @param userError_t *err: Pointer to error structure
 * @return: Always returns 0 indicating success
 */
int32_t userError_Init(userError_t *err) {
    if (err == NULL) {
        return -1;
    }
    err->grade = INT32_MAX;  // Initialize to maximum possible value, indicating no error
    err->name = NULL;
    err->file = NULL;
    err->func = NULL;
    err->line = 0;
    return 0;
}
/**
 * @description: Capture exception
 * @param userError_t *err: Pointer to error structure
 * @param int32_t grade: Error level
 * @param const char *name: Error name
 * @param const char *file: Filename
 * @param const char *func: Function name
 * @param uint32_t line: Line number
 * @return: Always returns 0 indicating success
 */
int32_t userError_Capture(userError_t *err, int32_t grade, const char *name,
                          const char *file, const char *func, uint32_t line) {
    if (err == NULL) {
        return -1;
    }
    // Only update error information if the current error level is lower or no error information exists
    // Lower value indicates higher error level
    if ((err->name == NULL) || (err->grade > grade)) {
        err->grade = grade;
        err->name = name;
        err->file = file;
        err->func = func;
        err->line = line;
    }
    // Logging can be added here
    // LOG_I("ERR:%s file:%s func:%s line:%d\n", name, file, func, line);
    return 0;
}
/**
 * @description: Clean up error information
 * @param userError_t *err: Pointer to error structure
 * @return: Always returns 0 indicating success
 */
int32_t userError_Clean(userError_t *err) {
    if (err == NULL) {
        return -1;
    }
    err->grade = INT32_MAX;  // Reset to maximum possible value, indicating no error
    err->name = NULL;
    err->file = NULL;
    err->func = NULL;
    err->line = 0;
    return 0;
}
#include <stdio.h>
#include "error_class.h"
int main(int argc, char const *argv[]) {
    int32_t ret = -1;
    userError_t err;
    userError_Init(&err); // Initialize error structure
    printf("**************** ERR_UNKNOWN ****************\n");
    if (ret < 0) { // Simulate error occurrence
        userError_Capture(&err, ERR_UNKNOWN, ERR_POSITION);
    }
    printf("err grade: %d\n", err.grade);
    printf("err name: %s\n", err.name);
    printf("err file: %s\n", err.file);
    printf("err func: %s\n", err.func);
    printf("err line: %d\n", err.line);
    userError_Clean(&err); // Clean up error information
    printf("\n**************** ERR_UNKNOWN_REPEAT ****************\n");
    if (ret < 0) { // Simulate error occurrence
        userError_Capture(&err, ERR_UNKNOWN_REPEAT(1), ERR_POSITION);
    }
    printf("err grade: %d\n", err.grade);
    printf("err name: %s\n", err.name);
    printf("err file: %s\n", err.file);
    printf("err func: %s\n", err.func);
    printf("err line: %d\n", err.line);
    userError_Clean(&err); // Clean up error information
    return 0;
}

Writing is not easy; if you find this useful, please give a 【follow】 and 【recommend】. Your likes are my motivation to keep writing, thank you!

Leave a Comment