API Design Guidelines

This comprehensive guide covers API design principles, patterns, and best practices for the Nexus Embedded Platform.

Overview

Well-designed APIs are crucial for a successful embedded platform. This guide provides detailed guidelines for:

  • API design principles

  • Naming conventions

  • Function signatures

  • Error handling

  • Memory management

  • Thread safety

  • Documentation requirements

  • Versioning and compatibility

Good API design makes the platform:

  • Easy to use: Intuitive and consistent

  • Hard to misuse: Type-safe and well-documented

  • Maintainable: Clear and well-structured

  • Extensible: Easy to add new features

  • Portable: Works across platforms

Design Principles

Fundamental Principles

1. Consistency

Maintain consistency across all APIs:

  • Naming conventions

  • Parameter ordering

  • Return value conventions

  • Error handling patterns

  • Documentation style

Example - Consistent Naming:

/* Good: Consistent naming pattern */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);
hal_status_t hal_uart_init(hal_uart_id_t id, const hal_uart_config_t* config);
hal_status_t hal_spi_init(hal_spi_id_t id, const hal_spi_config_t* config);

/* Bad: Inconsistent naming */
hal_status_t gpio_initialize(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);
hal_status_t InitUART(hal_uart_id_t id, const hal_uart_config_t* config);
hal_status_t spi_setup(hal_spi_id_t id, const hal_spi_config_t* config);

2. Simplicity

Keep APIs simple and focused:

  • One function, one purpose

  • Minimal parameters

  • Clear semantics

  • No hidden behavior

Example - Simple vs Complex:

/* Good: Simple, focused function */
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t level);

/* Bad: Too many responsibilities */
hal_status_t hal_gpio_write_with_delay_and_toggle(
    hal_gpio_port_t port,
    uint8_t pin,
    hal_gpio_level_t level,
    uint32_t delay_ms,
    bool toggle_after,
    uint32_t toggle_count
);

3. Orthogonality

Functions should be independent:

  • No unexpected side effects

  • No hidden dependencies

  • Composable operations

  • Predictable behavior

Example - Orthogonal Design:

/* Good: Independent operations */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t level);
hal_status_t hal_gpio_read(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t* level);

/* Bad: Coupled operations */
hal_status_t hal_gpio_init_and_write(hal_gpio_port_t port, uint8_t pin,
                                    const hal_gpio_config_t* config,
                                    hal_gpio_level_t initial_level);

4. Discoverability

Make APIs easy to discover:

  • Logical grouping

  • Clear naming

  • Comprehensive documentation

  • Examples and tutorials

5. Safety

Design for safety:

  • Type safety

  • Null pointer checks

  • Bounds checking

  • Resource management

  • Error handling

Naming Conventions

Module Prefix

All public APIs must use module prefix:

Format: <module>_<component>_<action>

Examples:

/* HAL module */
hal_gpio_init()
hal_uart_send()
hal_spi_transfer()

/* OSAL module */
osal_task_create()
osal_mutex_lock()
osal_queue_send()

/* Framework modules */
log_init()
shell_register_command()
config_set_i32()

Function Names

Format: <module>_<noun>_<verb> or <module>_<verb>_<noun>

Verbs:

  • init / deinit - Initialize / deinitialize

  • create / destroy - Create / destroy object

  • open / close - Open / close resource

  • start / stop - Start / stop operation

  • enable / disable - Enable / disable feature

  • set / get - Set / get value

  • read / write - Read / write data

  • send / receive - Send / receive message

  • lock / unlock - Lock / unlock mutex

  • wait / signal - Wait / signal event

Examples:

/* Initialization */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);
hal_status_t hal_gpio_deinit(hal_gpio_port_t port, uint8_t pin);

/* Configuration */
hal_status_t hal_gpio_set_mode(hal_gpio_port_t port, uint8_t pin, hal_gpio_mode_t mode);
hal_status_t hal_gpio_get_mode(hal_gpio_port_t port, uint8_t pin, hal_gpio_mode_t* mode);

/* Operations */
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t level);
hal_status_t hal_gpio_read(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t* level);
hal_status_t hal_gpio_toggle(hal_gpio_port_t port, uint8_t pin);

Type Names

Format: <module>_<name>_t

Examples:

/* Status types */
typedef enum {
    HAL_OK = 0,
    HAL_ERROR,
    HAL_ERROR_PARAM,
} hal_status_t;

/* Configuration structures */
typedef struct {
    hal_gpio_mode_t mode;
    hal_gpio_pull_t pull;
    hal_gpio_speed_t speed;
} hal_gpio_config_t;

/* Handle types */
typedef void* osal_task_handle_t;
typedef void* osal_mutex_handle_t;

Enumeration Values

Format: <MODULE>_<TYPE>_<VALUE>

Examples:

typedef enum {
    HAL_GPIO_MODE_INPUT = 0,
    HAL_GPIO_MODE_OUTPUT_PP,
    HAL_GPIO_MODE_OUTPUT_OD,
    HAL_GPIO_MODE_AF_PP,
    HAL_GPIO_MODE_AF_OD,
} hal_gpio_mode_t;

typedef enum {
    HAL_GPIO_PULL_NONE = 0,
    HAL_GPIO_PULL_UP,
    HAL_GPIO_PULL_DOWN,
} hal_gpio_pull_t;

Macro Names

Format: <MODULE>_<NAME>

Examples:

/* Constants */
#define HAL_GPIO_PORT_MAX    16
#define HAL_GPIO_PIN_MAX     16
#define HAL_UART_BAUDRATE_MAX 921600

/* Configuration macros */
#define HAL_TIMEOUT_DEFAULT  1000
#define HAL_TIMEOUT_INFINITE 0xFFFFFFFF

Function Signatures

Parameter Order

Standard Order:

  1. Handle/Context: Object or context pointer

  2. Input Parameters: Data to be processed

  3. Output Parameters: Results (pointers)

  4. Options/Flags: Optional parameters

Examples:

/* Good: Consistent parameter order */
hal_status_t hal_uart_send(
    hal_uart_id_t id,              /* 1. Handle */
    const uint8_t* data,            /* 2. Input */
    size_t length,                  /* 2. Input */
    uint32_t timeout                /* 4. Options */
);

hal_status_t hal_uart_receive(
    hal_uart_id_t id,              /* 1. Handle */
    uint8_t* buffer,                /* 3. Output */
    size_t buffer_size,             /* 2. Input */
    size_t* received_length,        /* 3. Output */
    uint32_t timeout                /* 4. Options */
);

/* Bad: Inconsistent parameter order */
hal_status_t hal_uart_send(
    const uint8_t* data,
    hal_uart_id_t id,
    uint32_t timeout,
    size_t length
);

Return Values

Always Return Status:

All functions that can fail must return a status code:

/* Good: Returns status */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);

/* Bad: No error indication */
void hal_gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);

Status Code Convention:

typedef enum {
    HAL_OK = 0,                /* Success - always 0 */
    HAL_ERROR,                 /* General error */
    HAL_ERROR_PARAM,           /* Invalid parameter */
    HAL_ERROR_STATE,           /* Invalid state */
    HAL_ERROR_TIMEOUT,         /* Operation timeout */
    HAL_ERROR_NO_MEMORY,       /* Out of memory */
    HAL_ERROR_NOT_SUPPORTED,   /* Not supported */
    HAL_ERROR_BUSY,            /* Resource busy */
} hal_status_t;

Output Parameters:

Use output parameters for returning data:

/* Good: Status return, data via output parameter */
hal_status_t hal_gpio_read(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t* level);

/* Bad: Data return, no error indication */
hal_gpio_level_t hal_gpio_read(hal_gpio_port_t port, uint8_t pin);

Input Parameters

Const Correctness:

Mark input parameters as const:

/* Good: Const input parameters */
hal_status_t hal_uart_send(hal_uart_id_t id, const uint8_t* data, size_t length, uint32_t timeout);
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);

/* Bad: Missing const */
hal_status_t hal_uart_send(hal_uart_id_t id, uint8_t* data, size_t length, uint32_t timeout);

Pointer Parameters:

Always validate pointer parameters:

hal_status_t hal_gpio_read(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t* level) {
    /* Validate pointer */
    if (level == NULL) {
        return HAL_ERROR_PARAM;
    }

    /* Implementation */
    *level = /* read value */;
    return HAL_OK;
}

Array Parameters:

Always include size parameter:

/* Good: Size parameter included */
hal_status_t hal_uart_send(hal_uart_id_t id, const uint8_t* data, size_t length, uint32_t timeout);

/* Bad: No size parameter */
hal_status_t hal_uart_send(hal_uart_id_t id, const uint8_t* data, uint32_t timeout);

Output Parameters

Pointer Convention:

Output parameters must be pointers:

/* Good: Output via pointer */
hal_status_t hal_gpio_read(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t* level);
hal_status_t hal_uart_receive(hal_uart_id_t id, uint8_t* buffer, size_t buffer_size,
                              size_t* received_length, uint32_t timeout);

Validation:

Always validate output pointers:

hal_status_t hal_uart_receive(hal_uart_id_t id, uint8_t* buffer, size_t buffer_size,
                              size_t* received_length, uint32_t timeout) {
    /* Validate output pointers */
    if (buffer == NULL || received_length == NULL) {
        return HAL_ERROR_PARAM;
    }

    /* Validate buffer size */
    if (buffer_size == 0) {
        return HAL_ERROR_PARAM;
    }

    /* Implementation */
    *received_length = /* actual received */;
    return HAL_OK;
}

Optional Parameters

Use NULL for Optional Pointers:

/**
 * \brief           Initialize UART with optional configuration
 * \param[in]       id: UART instance ID
 * \param[in]       config: Configuration (NULL for default)
 * \return          HAL_OK on success
 */
hal_status_t hal_uart_init(hal_uart_id_t id, const hal_uart_config_t* config) {
    hal_uart_config_t default_config;

    /* Use default if config is NULL */
    if (config == NULL) {
        default_config.baudrate = 115200;
        default_config.wordlen = HAL_UART_WORDLEN_8;
        default_config.stopbits = HAL_UART_STOPBITS_1;
        default_config.parity = HAL_UART_PARITY_NONE;
        config = &default_config;
    }

    /* Implementation */
    return HAL_OK;
}

Use Special Values for Optional Integers:

/* Use 0 or MAX value for "default" or "infinite" */
#define HAL_TIMEOUT_DEFAULT  0
#define HAL_TIMEOUT_INFINITE 0xFFFFFFFF

hal_status_t hal_uart_send(hal_uart_id_t id, const uint8_t* data, size_t length, uint32_t timeout);

Data Structures

Structure Design

Configuration Structures:

Use structures for configuration:

/**
 * \brief           GPIO configuration structure
 */
typedef struct {
    hal_gpio_mode_t mode;          /**< GPIO mode */
    hal_gpio_pull_t pull;          /**< Pull-up/down configuration */
    hal_gpio_speed_t speed;        /**< Output speed */
    hal_gpio_level_t init_level;   /**< Initial output level */
} hal_gpio_config_t;

/* Usage */
hal_gpio_config_t config = {
    .mode = HAL_GPIO_MODE_OUTPUT_PP,
    .pull = HAL_GPIO_PULL_NONE,
    .speed = HAL_GPIO_SPEED_LOW,
    .init_level = HAL_GPIO_LEVEL_LOW
};
hal_gpio_init(HAL_GPIO_PORT_A, 5, &config);

Opaque Handles:

Use opaque pointers for handles:

/* Public header - opaque type */
typedef void* osal_task_handle_t;
typedef void* osal_mutex_handle_t;

/* Implementation file - actual structure */
typedef struct {
    /* Internal fields */
    void* native_handle;
    uint32_t priority;
    char name[32];
} osal_task_internal_t;

Benefits:

  • Hide implementation details

  • Allow implementation changes

  • Prevent direct access to internals

  • Type safety

Structure Initialization

Designated Initializers:

Always use designated initializers:

/* Good: Designated initializers */
hal_gpio_config_t config = {
    .mode = HAL_GPIO_MODE_OUTPUT_PP,
    .pull = HAL_GPIO_PULL_NONE,
    .speed = HAL_GPIO_SPEED_LOW,
    .init_level = HAL_GPIO_LEVEL_LOW
};

/* Bad: Positional initializers */
hal_gpio_config_t config = {
    HAL_GPIO_MODE_OUTPUT_PP,
    HAL_GPIO_PULL_NONE,
    HAL_GPIO_SPEED_LOW,
    HAL_GPIO_LEVEL_LOW
};

Default Values:

Provide helper functions for default initialization:

/**
 * \brief           Get default GPIO configuration
 * \param[out]      config: Configuration structure to initialize
 */
void hal_gpio_get_default_config(hal_gpio_config_t* config) {
    if (config == NULL) {
        return;
    }

    config->mode = HAL_GPIO_MODE_INPUT;
    config->pull = HAL_GPIO_PULL_NONE;
    config->speed = HAL_GPIO_SPEED_LOW;
    config->init_level = HAL_GPIO_LEVEL_LOW;
}

/* Usage */
hal_gpio_config_t config;
hal_gpio_get_default_config(&config);
config.mode = HAL_GPIO_MODE_OUTPUT_PP;  /* Override specific fields */
hal_gpio_init(HAL_GPIO_PORT_A, 5, &config);

Enumeration Design

Explicit Values:

Always specify explicit values:

/* Good: Explicit values */
typedef enum {
    HAL_GPIO_MODE_INPUT = 0,
    HAL_GPIO_MODE_OUTPUT_PP = 1,
    HAL_GPIO_MODE_OUTPUT_OD = 2,
    HAL_GPIO_MODE_AF_PP = 3,
    HAL_GPIO_MODE_AF_OD = 4,
} hal_gpio_mode_t;

/* Bad: Implicit values */
typedef enum {
    HAL_GPIO_MODE_INPUT,
    HAL_GPIO_MODE_OUTPUT_PP,
    HAL_GPIO_MODE_OUTPUT_OD,
} hal_gpio_mode_t;

Size Specification:

Specify enum size when needed:

/* Specify size for packed structures */
typedef enum {
    HAL_GPIO_LEVEL_LOW = 0,
    HAL_GPIO_LEVEL_HIGH = 1,
} hal_gpio_level_t;

/* Ensure 8-bit size */
_Static_assert(sizeof(hal_gpio_level_t) <= sizeof(uint8_t),
               "hal_gpio_level_t must fit in uint8_t");

Error Handling

Status Codes

Consistent Status Codes:

All modules use consistent status code pattern:

/* HAL status codes */
typedef enum {
    HAL_OK = 0,                /* Success */
    HAL_ERROR,                 /* General error */
    HAL_ERROR_PARAM,           /* Invalid parameter */
    HAL_ERROR_STATE,           /* Invalid state */
    HAL_ERROR_TIMEOUT,         /* Operation timeout */
    HAL_ERROR_NO_MEMORY,       /* Out of memory */
    HAL_ERROR_NOT_SUPPORTED,   /* Not supported */
    HAL_ERROR_BUSY,            /* Resource busy */
} hal_status_t;

/* OSAL status codes */
typedef enum {
    OSAL_OK = 0,               /* Success */
    OSAL_ERROR,                /* General error */
    OSAL_ERROR_PARAM,          /* Invalid parameter */
    OSAL_ERROR_TIMEOUT,        /* Operation timeout */
    OSAL_ERROR_NO_MEMORY,      /* Out of memory */
} osal_status_t;

Success is Always Zero:

/* Good: Success is 0 */
if (hal_gpio_init(port, pin, &config) == HAL_OK) {
    /* Success */
}

/* Also works */
if (hal_gpio_init(port, pin, &config) != HAL_OK) {
    /* Error */
}

Error Checking

Always Check Return Values:

/* Good: Check return value */
hal_status_t status = hal_gpio_init(HAL_GPIO_PORT_A, 5, &config);
if (status != HAL_OK) {
    LOG_ERROR("GPIO init failed: %d", status);
    return status;
}

/* Bad: Ignore return value */
hal_gpio_init(HAL_GPIO_PORT_A, 5, &config);

Error Propagation:

Propagate errors up the call stack:

hal_status_t initialize_peripherals(void) {
    hal_status_t status;

    /* Initialize GPIO */
    status = hal_gpio_init(HAL_GPIO_PORT_A, 5, &gpio_config);
    if (status != HAL_OK) {
        LOG_ERROR("GPIO init failed: %d", status);
        return status;
    }

    /* Initialize UART */
    status = hal_uart_init(HAL_UART_1, &uart_config);
    if (status != HAL_OK) {
        LOG_ERROR("UART init failed: %d", status);
        /* Cleanup GPIO before returning */
        hal_gpio_deinit(HAL_GPIO_PORT_A, 5);
        return status;
    }

    return HAL_OK;
}

Parameter Validation

Validate All Parameters:

hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin,
                          const hal_gpio_config_t* config) {
    /* Validate port */
    if (port >= HAL_GPIO_PORT_MAX) {
        return HAL_ERROR_PARAM;
    }

    /* Validate pin */
    if (pin >= HAL_GPIO_PIN_MAX) {
        return HAL_ERROR_PARAM;
    }

    /* Validate config pointer */
    if (config == NULL) {
        return HAL_ERROR_PARAM;
    }

    /* Validate config values */
    if (config->mode >= HAL_GPIO_MODE_MAX) {
        return HAL_ERROR_PARAM;
    }

    /* Implementation */
    return HAL_OK;
}

Validation Order:

  1. Null pointer checks

  2. Range checks

  3. State checks

  4. Resource availability checks

State Validation

Check State Before Operations:

hal_status_t hal_uart_send(hal_uart_id_t id, const uint8_t* data,
                          size_t length, uint32_t timeout) {
    /* Validate parameters */
    if (id >= HAL_UART_MAX_INSTANCES) {
        return HAL_ERROR_PARAM;
    }
    if (data == NULL || length == 0) {
        return HAL_ERROR_PARAM;
    }

    /* Check if UART is initialized */
    if (!uart_is_initialized(id)) {
        return HAL_ERROR_STATE;
    }

    /* Check if UART is busy */
    if (uart_is_busy(id)) {
        return HAL_ERROR_BUSY;
    }

    /* Implementation */
    return HAL_OK;
}

Error Messages

Provide Helpful Error Messages:

hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin,
                          const hal_gpio_config_t* config) {
    if (port >= HAL_GPIO_PORT_MAX) {
        LOG_ERROR("Invalid GPIO port: %d (max: %d)", port, HAL_GPIO_PORT_MAX - 1);
        return HAL_ERROR_PARAM;
    }

    if (pin >= HAL_GPIO_PIN_MAX) {
        LOG_ERROR("Invalid GPIO pin: %d (max: %d)", pin, HAL_GPIO_PIN_MAX - 1);
        return HAL_ERROR_PARAM;
    }

    if (config == NULL) {
        LOG_ERROR("GPIO config is NULL");
        return HAL_ERROR_PARAM;
    }

    return HAL_OK;
}

Memory Management

Ownership Rules

Clear Ownership:

Always document who owns memory:

/**
 * \brief           Create GPIO device (caller owns returned pointer)
 * \param[in]       port: GPIO port
 * \param[in]       pin: GPIO pin
 * \return          GPIO device pointer (must be freed with nx_factory_gpio_release)
 */
nx_gpio_t* nx_factory_gpio(uint8_t port, uint8_t pin);

/**
 * \brief           Release GPIO device (frees memory)
 * \param[in]       gpio: GPIO device pointer
 */
void nx_factory_gpio_release(nx_gpio_t* gpio);

Allocation Patterns:

  1. Caller Allocates: Caller provides buffer

    /* Caller allocates buffer */
    hal_status_t hal_uart_receive(hal_uart_id_t id, uint8_t* buffer,
                                  size_t buffer_size, size_t* received_length,
                                  uint32_t timeout);
    
    /* Usage */
    uint8_t buffer[256];
    size_t received;
    hal_uart_receive(HAL_UART_1, buffer, sizeof(buffer), &received, 1000);
    
  2. Callee Allocates: Function allocates and returns

    /* Function allocates memory */
    nx_gpio_t* nx_factory_gpio(uint8_t port, uint8_t pin);
    
    /* Usage */
    nx_gpio_t* gpio = nx_factory_gpio(0, 5);
    /* Use gpio */
    nx_factory_gpio_release(gpio);  /* Caller must free */
    
  3. Static Allocation: Function returns static data

    /* Returns pointer to static data */
    const char* hal_get_version(void);
    
    /* Usage */
    const char* version = hal_get_version();
    /* No need to free */
    

Buffer Management

Size Parameters:

Always include buffer size:

/* Good: Buffer size included */
hal_status_t hal_uart_receive(hal_uart_id_t id, uint8_t* buffer,
                              size_t buffer_size, size_t* received_length,
                              uint32_t timeout);

/* Bad: No size parameter */
hal_status_t hal_uart_receive(hal_uart_id_t id, uint8_t* buffer,
                              size_t* received_length, uint32_t timeout);

Bounds Checking:

Always check buffer bounds:

hal_status_t hal_uart_receive(hal_uart_id_t id, uint8_t* buffer,
                              size_t buffer_size, size_t* received_length,
                              uint32_t timeout) {
    /* Validate buffer */
    if (buffer == NULL || buffer_size == 0) {
        return HAL_ERROR_PARAM;
    }

    /* Check available data */
    size_t available = uart_get_available_data(id);
    if (available > buffer_size) {
        /* Buffer too small */
        return HAL_ERROR_NO_MEMORY;
    }

    /* Copy data with bounds check */
    for (size_t i = 0; i < available && i < buffer_size; i++) {
        buffer[i] = uart_read_byte(id);
    }

    *received_length = available;
    return HAL_OK;
}

String Handling:

Use safe string functions:

/* Good: Size-limited string copy */
hal_status_t config_get_str(const char* key, char* buffer, size_t buffer_size) {
    if (buffer == NULL || buffer_size == 0) {
        return CONFIG_ERROR_PARAM;
    }

    const char* value = config_find_value(key);
    if (value == NULL) {
        return CONFIG_ERROR_NOT_FOUND;
    }

    /* Safe string copy with null termination */
    strncpy(buffer, value, buffer_size - 1);
    buffer[buffer_size - 1] = '\0';

    return CONFIG_OK;
}

/* Bad: Unsafe string copy */
hal_status_t config_get_str(const char* key, char* buffer) {
    const char* value = config_find_value(key);
    strcpy(buffer, value);  /* Buffer overflow risk! */
    return CONFIG_OK;
}

Resource Cleanup

RAII Pattern:

Use init/deinit pairs:

/* Initialize resource */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);

/* Cleanup resource */
hal_status_t hal_gpio_deinit(hal_gpio_port_t port, uint8_t pin);

/* Usage */
hal_status_t status = hal_gpio_init(HAL_GPIO_PORT_A, 5, &config);
if (status != HAL_OK) {
    return status;
}

/* Use GPIO */

/* Always cleanup */
hal_gpio_deinit(HAL_GPIO_PORT_A, 5);

Error Cleanup:

Clean up on error:

hal_status_t initialize_system(void) {
    hal_status_t status;

    /* Initialize GPIO */
    status = hal_gpio_init(HAL_GPIO_PORT_A, 5, &gpio_config);
    if (status != HAL_OK) {
        return status;
    }

    /* Initialize UART */
    status = hal_uart_init(HAL_UART_1, &uart_config);
    if (status != HAL_OK) {
        /* Cleanup GPIO before returning */
        hal_gpio_deinit(HAL_GPIO_PORT_A, 5);
        return status;
    }

    /* Initialize SPI */
    status = hal_spi_init(HAL_SPI_1, &spi_config);
    if (status != HAL_OK) {
        /* Cleanup UART and GPIO */
        hal_uart_deinit(HAL_UART_1);
        hal_gpio_deinit(HAL_GPIO_PORT_A, 5);
        return status;
    }

    return HAL_OK;
}

Thread Safety

Reentrancy

Document Thread Safety:

Always document thread safety guarantees:

/**
 * \brief           Write to GPIO pin (thread-safe)
 * \param[in]       port: GPIO port
 * \param[in]       pin: GPIO pin
 * \param[in]       level: Output level
 * \return          HAL_OK on success
 * \note            This function is thread-safe
 */
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t level);

/**
 * \brief           Initialize GPIO pin (NOT thread-safe)
 * \param[in]       port: GPIO port
 * \param[in]       pin: GPIO pin
 * \param[in]       config: Configuration
 * \return          HAL_OK on success
 * \note            This function is NOT thread-safe. Call only during initialization.
 */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);

Thread-Safe Implementation:

Use mutexes for shared resources:

/* Global mutex for GPIO access */
static osal_mutex_handle_t gpio_mutex;

hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t level) {
    hal_status_t status;

    /* Lock mutex */
    if (osal_mutex_lock(gpio_mutex, OSAL_WAIT_FOREVER) != OSAL_OK) {
        return HAL_ERROR;
    }

    /* Critical section */
    status = platform_gpio_write(port, pin, level);

    /* Unlock mutex */
    osal_mutex_unlock(gpio_mutex);

    return status;
}

Atomic Operations

Use Atomic Operations:

For simple operations, use atomic operations:

#include <stdatomic.h>

/* Atomic counter */
static atomic_uint_fast32_t request_counter = ATOMIC_VAR_INIT(0);

uint32_t get_next_request_id(void) {
    return atomic_fetch_add(&request_counter, 1);
}

Lock-Free Queues:

For high-performance scenarios, consider lock-free data structures:

/* Lock-free ring buffer for interrupt-to-task communication */
typedef struct {
    uint8_t buffer[256];
    atomic_uint_fast32_t head;
    atomic_uint_fast32_t tail;
} lockfree_ringbuf_t;

bool ringbuf_push(lockfree_ringbuf_t* rb, uint8_t data) {
    uint32_t head = atomic_load(&rb->head);
    uint32_t next_head = (head + 1) % 256;

    if (next_head == atomic_load(&rb->tail)) {
        return false;  /* Buffer full */
    }

    rb->buffer[head] = data;
    atomic_store(&rb->head, next_head);
    return true;
}

Interrupt Safety

Document Interrupt Safety:

/**
 * \brief           Write to GPIO pin (interrupt-safe)
 * \param[in]       port: GPIO port
 * \param[in]       pin: GPIO pin
 * \param[in]       level: Output level
 * \return          HAL_OK on success
 * \note            This function is interrupt-safe and can be called from ISR
 */
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t level);

/**
 * \brief           Send data via UART (NOT interrupt-safe)
 * \param[in]       id: UART instance
 * \param[in]       data: Data buffer
 * \param[in]       length: Data length
 * \param[in]       timeout: Timeout in milliseconds
 * \return          HAL_OK on success
 * \note            This function is NOT interrupt-safe. Do not call from ISR.
 */
hal_status_t hal_uart_send(hal_uart_id_t id, const uint8_t* data, size_t length, uint32_t timeout);

ISR-Safe Implementation:

/* ISR-safe function - no blocking, no allocation */
hal_status_t hal_gpio_write_isr(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t level) {
    /* Direct hardware access, no locks */
    platform_gpio_write_direct(port, pin, level);
    return HAL_OK;
}

/* Regular function - may block */
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin, hal_gpio_level_t level) {
    /* Use mutex for thread safety */
    osal_mutex_lock(gpio_mutex, OSAL_WAIT_FOREVER);
    platform_gpio_write(port, pin, level);
    osal_mutex_unlock(gpio_mutex);
    return HAL_OK;
}

Documentation Requirements

Doxygen Comments

File Headers:

Every file must have a header comment:

/**
 * \file            hal_gpio.h
 * \brief           GPIO Hardware Abstraction Layer
 * \author          Nexus Team
 */

Function Documentation:

All public functions must be documented:

/**
 * \brief           Initialize GPIO pin
 * \param[in]       port: GPIO port (HAL_GPIO_PORT_A to HAL_GPIO_PORT_K)
 * \param[in]       pin: GPIO pin number (0-15)
 * \param[in]       config: Pointer to configuration structure
 * \return          HAL_OK on success, error code otherwise
 * \retval          HAL_OK: Success
 * \retval          HAL_ERROR_PARAM: Invalid parameter
 * \retval          HAL_ERROR_STATE: GPIO already initialized
 * \note            Pin must be deinitialized before re-initialization
 * \warning         This function is NOT thread-safe
 * \see             hal_gpio_deinit
 */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin,
                          const hal_gpio_config_t* config);

Structure Documentation:

Document all structures and fields:

/**
 * \brief           GPIO configuration structure
 */
typedef struct {
    hal_gpio_mode_t mode;          /**< GPIO mode (input/output/alternate) */
    hal_gpio_pull_t pull;          /**< Pull-up/down configuration */
    hal_gpio_speed_t speed;        /**< Output speed (low/medium/high/very high) */
    hal_gpio_level_t init_level;   /**< Initial output level (low/high) */
} hal_gpio_config_t;

Enumeration Documentation:

Document all enumerations and values:

/**
 * \brief           GPIO mode enumeration
 */
typedef enum {
    HAL_GPIO_MODE_INPUT = 0,       /**< Input mode */
    HAL_GPIO_MODE_OUTPUT_PP,       /**< Output push-pull mode */
    HAL_GPIO_MODE_OUTPUT_OD,       /**< Output open-drain mode */
    HAL_GPIO_MODE_AF_PP,           /**< Alternate function push-pull */
    HAL_GPIO_MODE_AF_OD,           /**< Alternate function open-drain */
    HAL_GPIO_MODE_ANALOG,          /**< Analog mode */
} hal_gpio_mode_t;

Usage Examples

Provide Examples:

Include usage examples in documentation:

/**
 * \brief           Initialize GPIO pin
 * \param[in]       port: GPIO port
 * \param[in]       pin: GPIO pin number
 * \param[in]       config: Configuration structure
 * \return          HAL_OK on success
 *
 * \par Example:
 * \code
 * // Configure PA5 as output
 * hal_gpio_config_t config = {
 *     .mode = HAL_GPIO_MODE_OUTPUT_PP,
 *     .pull = HAL_GPIO_PULL_NONE,
 *     .speed = HAL_GPIO_SPEED_LOW,
 *     .init_level = HAL_GPIO_LEVEL_LOW
 * };
 *
 * hal_status_t status = hal_gpio_init(HAL_GPIO_PORT_A, 5, &config);
 * if (status != HAL_OK) {
 *     // Handle error
 * }
 *
 * // Write to pin
 * hal_gpio_write(HAL_GPIO_PORT_A, 5, HAL_GPIO_LEVEL_HIGH);
 * \endcode
 */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin,
                          const hal_gpio_config_t* config);

Complex Examples:

For complex APIs, provide detailed examples:

/**
 * \brief           Send data via UART with DMA
 *
 * \par Example: Basic Usage
 * \code
 * uint8_t data[] = "Hello, World!";
 * size_t sent;
 * hal_status_t status = hal_uart_send_dma(HAL_UART_1, data, sizeof(data), &sent, 1000);
 * if (status == HAL_OK) {
 *     printf("Sent %zu bytes\n", sent);
 * }
 * \endcode
 *
 * \par Example: Error Handling
 * \code
 * hal_status_t status = hal_uart_send_dma(HAL_UART_1, data, sizeof(data), &sent, 1000);
 * switch (status) {
 *     case HAL_OK:
 *         printf("Success\n");
 *         break;
 *     case HAL_ERROR_TIMEOUT:
 *         printf("Timeout\n");
 *         break;
 *     case HAL_ERROR_BUSY:
 *         printf("UART busy\n");
 *         break;
 *     default:
 *         printf("Error: %d\n", status);
 *         break;
 * }
 * \endcode
 */
hal_status_t hal_uart_send_dma(hal_uart_id_t id, const uint8_t* data,
                               size_t length, size_t* sent, uint32_t timeout);

Versioning and Compatibility

API Versioning

Semantic Versioning:

Use semantic versioning for APIs:

  • Major version: Breaking changes

  • Minor version: New features (backward compatible)

  • Patch version: Bug fixes (backward compatible)

Version Macros:

/* Version information */
#define HAL_VERSION_MAJOR    1
#define HAL_VERSION_MINOR    2
#define HAL_VERSION_PATCH    3

/* Version as single number */
#define HAL_VERSION          ((HAL_VERSION_MAJOR << 16) | \
                              (HAL_VERSION_MINOR << 8) | \
                              HAL_VERSION_PATCH)

/* Version string */
#define HAL_VERSION_STRING   "1.2.3"

/**
 * \brief           Get HAL version
 * \return          Version as 32-bit number (major.minor.patch)
 */
uint32_t hal_get_version(void);

/**
 * \brief           Get HAL version string
 * \return          Version string (e.g., "1.2.3")
 */
const char* hal_get_version_string(void);

Backward Compatibility

Deprecation Process:

  1. Mark as deprecated in documentation

  2. Add deprecation warning

  3. Provide migration path

  4. Remove in next major version

Deprecation Example:

/**
 * \brief           Old function (DEPRECATED)
 * \deprecated      Use hal_gpio_init() instead
 * \see             hal_gpio_init
 */
__attribute__((deprecated("Use hal_gpio_init() instead")))
hal_status_t hal_gpio_configure(hal_gpio_port_t port, uint8_t pin,
                                const hal_gpio_config_t* config);

/**
 * \brief           New function
 */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin,
                          const hal_gpio_config_t* config);

API Evolution:

When adding new features, maintain backward compatibility:

/* Version 1.0 - Original API */
typedef struct {
    hal_gpio_mode_t mode;
    hal_gpio_pull_t pull;
} hal_gpio_config_t;

/* Version 1.1 - Extended API (backward compatible) */
typedef struct {
    hal_gpio_mode_t mode;
    hal_gpio_pull_t pull;
    hal_gpio_speed_t speed;        /* New field with default */
    hal_gpio_level_t init_level;   /* New field with default */
} hal_gpio_config_t;

/* Helper for backward compatibility */
void hal_gpio_get_default_config(hal_gpio_config_t* config) {
    config->mode = HAL_GPIO_MODE_INPUT;
    config->pull = HAL_GPIO_PULL_NONE;
    config->speed = HAL_GPIO_SPEED_LOW;      /* Default for new field */
    config->init_level = HAL_GPIO_LEVEL_LOW; /* Default for new field */
}

ABI Stability

Maintain ABI Stability:

  • Don't change structure layout

  • Don't change enum values

  • Don't change function signatures

  • Don't remove public symbols

Breaking Changes:

If breaking changes are necessary:

  1. Increment major version

  2. Document all breaking changes

  3. Provide migration guide

  4. Consider compatibility layer

Example Migration Guide:

Migration from v1.x to v2.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**Breaking Changes**:

1. ``hal_gpio_configure()`` renamed to ``hal_gpio_init()``
2. ``hal_gpio_config_t`` structure changed
3. Return type changed from ``int`` to ``hal_status_t``

**Migration Steps**:

Old code (v1.x):

.. code-block:: c

   hal_gpio_config_t config = {
       .mode = GPIO_MODE_OUTPUT,
       .pull = GPIO_PULL_NONE
   };
   int result = hal_gpio_configure(GPIO_PORT_A, 5, &config);

New code (v2.0):

.. code-block:: c

   hal_gpio_config_t config = {
       .mode = HAL_GPIO_MODE_OUTPUT_PP,
       .pull = HAL_GPIO_PULL_NONE,
       .speed = HAL_GPIO_SPEED_LOW,
       .init_level = HAL_GPIO_LEVEL_LOW
   };
   hal_status_t status = hal_gpio_init(HAL_GPIO_PORT_A, 5, &config);

Performance Considerations

Efficiency Guidelines

Minimize Overhead:

Keep API overhead minimal:

/* Good: Minimal overhead */
static inline hal_status_t hal_gpio_write_fast(hal_gpio_port_t port,
                                                uint8_t pin,
                                                hal_gpio_level_t level) {
    /* Direct register access */
    if (level == HAL_GPIO_LEVEL_HIGH) {
        GPIO_PORTS[port]->BSRR = (1U << pin);
    } else {
        GPIO_PORTS[port]->BSRR = (1U << (pin + 16));
    }
    return HAL_OK;
}

/* Bad: Excessive overhead */
hal_status_t hal_gpio_write_slow(hal_gpio_port_t port,
                                 uint8_t pin,
                                 hal_gpio_level_t level) {
    /* Validate parameters */
    if (port >= HAL_GPIO_PORT_MAX) return HAL_ERROR_PARAM;
    if (pin >= HAL_GPIO_PIN_MAX) return HAL_ERROR_PARAM;

    /* Lock mutex */
    osal_mutex_lock(gpio_mutex, OSAL_WAIT_FOREVER);

    /* Log operation */
    LOG_DEBUG("GPIO write: port=%d, pin=%d, level=%d", port, pin, level);

    /* Write value */
    if (level == HAL_GPIO_LEVEL_HIGH) {
        GPIO_PORTS[port]->BSRR = (1U << pin);
    } else {
        GPIO_PORTS[port]->BSRR = (1U << (pin + 16));
    }

    /* Unlock mutex */
    osal_mutex_unlock(gpio_mutex);

    return HAL_OK;
}

Inline Functions:

Use inline for performance-critical functions:

/* Inline for performance */
static inline uint32_t hal_get_tick(void) {
    return SysTick->VAL;
}

/* Regular function for complex operations */
hal_status_t hal_delay_ms(uint32_t ms);

Avoid Allocations:

Minimize dynamic memory allocation:

/* Good: Caller provides buffer */
hal_status_t hal_uart_receive(hal_uart_id_t id, uint8_t* buffer,
                              size_t buffer_size, size_t* received_length,
                              uint32_t timeout);

/* Bad: Function allocates memory */
uint8_t* hal_uart_receive_alloc(hal_uart_id_t id, size_t* length,
                                uint32_t timeout);

Batch Operations

Provide Batch APIs:

For operations on multiple items:

/* Single operation */
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin,
                            hal_gpio_level_t level);

/* Batch operation - more efficient */
hal_status_t hal_gpio_write_multiple(hal_gpio_port_t port,
                                     uint16_t pin_mask,
                                     uint16_t value_mask);

/* Usage */
/* Set pins 0, 2, 4 high; pins 1, 3, 5 low */
hal_gpio_write_multiple(HAL_GPIO_PORT_A,
                       0x003F,  /* Pins 0-5 */
                       0x0015); /* Pins 0, 2, 4 high */

DMA Support:

Provide DMA APIs for bulk transfers:

/* Blocking transfer */
hal_status_t hal_uart_send(hal_uart_id_t id, const uint8_t* data,
                          size_t length, uint32_t timeout);

/* DMA transfer - more efficient for large data */
hal_status_t hal_uart_send_dma(hal_uart_id_t id, const uint8_t* data,
                              size_t length, hal_uart_callback_t callback,
                              void* user_data);

Zero-Copy APIs

Avoid Unnecessary Copies:

/* Good: Zero-copy API */
hal_status_t hal_uart_send_dma(hal_uart_id_t id, const uint8_t* data,
                              size_t length, hal_uart_callback_t callback,
                              void* user_data);

/* Bad: Copies data internally */
hal_status_t hal_uart_send_copy(hal_uart_id_t id, const uint8_t* data,
                                size_t length);

Buffer Ownership:

Document buffer ownership clearly:

/**
 * \brief           Send data via UART using DMA
 * \param[in]       id: UART instance
 * \param[in]       data: Data buffer (must remain valid until callback)
 * \param[in]       length: Data length
 * \param[in]       callback: Completion callback
 * \param[in]       user_data: User data for callback
 * \return          HAL_OK on success
 * \note            Buffer must remain valid until callback is invoked
 * \warning         Do not modify or free buffer until transfer completes
 */
hal_status_t hal_uart_send_dma(hal_uart_id_t id, const uint8_t* data,
                              size_t length, hal_uart_callback_t callback,
                              void* user_data);

Caching Considerations

Cache-Aligned Buffers:

For DMA operations, ensure proper alignment:

/* Cache line size */
#define CACHE_LINE_SIZE 32

/* Aligned buffer for DMA */
__attribute__((aligned(CACHE_LINE_SIZE)))
static uint8_t dma_buffer[256];

/**
 * \brief           Send data via UART using DMA
 * \param[in]       data: Data buffer (must be cache-aligned for DMA)
 * \note            Buffer must be aligned to CACHE_LINE_SIZE
 */
hal_status_t hal_uart_send_dma(hal_uart_id_t id, const uint8_t* data,
                              size_t length, hal_uart_callback_t callback,
                              void* user_data);

Cache Operations:

Provide cache management APIs:

/**
 * \brief           Clean data cache for DMA
 * \param[in]       addr: Buffer address
 * \param[in]       size: Buffer size
 */
void hal_cache_clean(void* addr, size_t size);

/**
 * \brief           Invalidate data cache after DMA
 * \param[in]       addr: Buffer address
 * \param[in]       size: Buffer size
 */
void hal_cache_invalidate(void* addr, size_t size);

Testing Requirements

Unit Testing

Testable Design:

Design APIs for testability:

/* Good: Dependency injection for testing */
typedef struct {
    hal_status_t (*read)(uint32_t addr, uint8_t* data);
    hal_status_t (*write)(uint32_t addr, uint8_t data);
} hal_flash_ops_t;

hal_status_t hal_flash_init(const hal_flash_ops_t* ops);

/* Test with mock operations */
hal_status_t mock_flash_read(uint32_t addr, uint8_t* data) {
    *data = test_data[addr];
    return HAL_OK;
}

hal_flash_ops_t mock_ops = {
    .read = mock_flash_read,
    .write = mock_flash_write
};

hal_flash_init(&mock_ops);

Test Coverage:

Ensure comprehensive test coverage:

  • Normal operation

  • Error conditions

  • Boundary conditions

  • Invalid parameters

  • State transitions

  • Concurrent access

Example Test Cases:

/* Test normal operation */
void test_gpio_write_normal(void) {
    hal_gpio_config_t config = {
        .mode = HAL_GPIO_MODE_OUTPUT_PP,
        .pull = HAL_GPIO_PULL_NONE,
        .speed = HAL_GPIO_SPEED_LOW,
        .init_level = HAL_GPIO_LEVEL_LOW
    };

    assert(hal_gpio_init(HAL_GPIO_PORT_A, 5, &config) == HAL_OK);
    assert(hal_gpio_write(HAL_GPIO_PORT_A, 5, HAL_GPIO_LEVEL_HIGH) == HAL_OK);
    assert(hal_gpio_deinit(HAL_GPIO_PORT_A, 5) == HAL_OK);
}

/* Test invalid parameters */
void test_gpio_write_invalid_port(void) {
    assert(hal_gpio_write(HAL_GPIO_PORT_MAX, 5, HAL_GPIO_LEVEL_HIGH) == HAL_ERROR_PARAM);
}

/* Test invalid state */
void test_gpio_write_not_initialized(void) {
    assert(hal_gpio_write(HAL_GPIO_PORT_A, 5, HAL_GPIO_LEVEL_HIGH) == HAL_ERROR_STATE);
}

Integration Testing

Hardware Testing:

Test on actual hardware:

/* Hardware integration test */
void test_uart_loopback(void) {
    uint8_t tx_data[] = "Hello";
    uint8_t rx_data[16];
    size_t received;

    /* Configure UART in loopback mode */
    hal_uart_config_t config = {
        .baudrate = 115200,
        .wordlen = HAL_UART_WORDLEN_8,
        .stopbits = HAL_UART_STOPBITS_1,
        .parity = HAL_UART_PARITY_NONE,
        .mode = HAL_UART_MODE_LOOPBACK
    };

    assert(hal_uart_init(HAL_UART_1, &config) == HAL_OK);

    /* Send data */
    assert(hal_uart_send(HAL_UART_1, tx_data, sizeof(tx_data), 1000) == HAL_OK);

    /* Receive data */
    assert(hal_uart_receive(HAL_UART_1, rx_data, sizeof(rx_data), &received, 1000) == HAL_OK);

    /* Verify data */
    assert(received == sizeof(tx_data));
    assert(memcmp(tx_data, rx_data, sizeof(tx_data)) == 0);

    hal_uart_deinit(HAL_UART_1);
}

Stress Testing:

Test under stress conditions:

/* Stress test - rapid operations */
void test_gpio_stress(void) {
    hal_gpio_config_t config = {
        .mode = HAL_GPIO_MODE_OUTPUT_PP,
        .pull = HAL_GPIO_PULL_NONE,
        .speed = HAL_GPIO_SPEED_HIGH,
        .init_level = HAL_GPIO_LEVEL_LOW
    };

    assert(hal_gpio_init(HAL_GPIO_PORT_A, 5, &config) == HAL_OK);

    /* Toggle 10000 times */
    for (int i = 0; i < 10000; i++) {
        assert(hal_gpio_toggle(HAL_GPIO_PORT_A, 5) == HAL_OK);
    }

    hal_gpio_deinit(HAL_GPIO_PORT_A, 5);
}

Common Patterns

Initialization Pattern

Standard Init/Deinit:

/* Initialize resource */
hal_status_t hal_xxx_init(hal_xxx_id_t id, const hal_xxx_config_t* config);

/* Deinitialize resource */
hal_status_t hal_xxx_deinit(hal_xxx_id_t id);

/* Usage */
hal_xxx_config_t config;
hal_xxx_get_default_config(&config);
config.param1 = value1;

if (hal_xxx_init(HAL_XXX_1, &config) == HAL_OK) {
    /* Use resource */
    hal_xxx_deinit(HAL_XXX_1);
}

Global Init:

For modules requiring global initialization:

/**
 * \brief           Initialize HAL module
 * \return          HAL_OK on success
 * \note            Must be called before any other HAL functions
 */
hal_status_t hal_init(void);

/**
 * \brief           Deinitialize HAL module
 * \return          HAL_OK on success
 */
hal_status_t hal_deinit(void);

Configuration Pattern

Configuration Structure:

/* Configuration structure */
typedef struct {
    uint32_t param1;
    uint32_t param2;
    bool enable_feature;
} hal_xxx_config_t;

/* Get default configuration */
void hal_xxx_get_default_config(hal_xxx_config_t* config);

/* Initialize with configuration */
hal_status_t hal_xxx_init(hal_xxx_id_t id, const hal_xxx_config_t* config);

/* Runtime configuration */
hal_status_t hal_xxx_set_config(hal_xxx_id_t id, const hal_xxx_config_t* config);
hal_status_t hal_xxx_get_config(hal_xxx_id_t id, hal_xxx_config_t* config);

Callback Pattern

Callback Registration:

/* Callback function type */
typedef void (*hal_xxx_callback_t)(hal_xxx_id_t id, hal_xxx_event_t event,
                                   void* user_data);

/**
 * \brief           Register callback
 * \param[in]       id: Instance ID
 * \param[in]       callback: Callback function (NULL to unregister)
 * \param[in]       user_data: User data passed to callback
 * \return          HAL_OK on success
 */
hal_status_t hal_xxx_register_callback(hal_xxx_id_t id,
                                       hal_xxx_callback_t callback,
                                       void* user_data);

/* Usage */
void my_callback(hal_xxx_id_t id, hal_xxx_event_t event, void* user_data) {
    /* Handle event */
}

hal_xxx_register_callback(HAL_XXX_1, my_callback, &my_context);

Multiple Callbacks:

For multiple event types:

/* Callback structure */
typedef struct {
    void (*on_complete)(hal_xxx_id_t id, void* user_data);
    void (*on_error)(hal_xxx_id_t id, hal_status_t error, void* user_data);
    void (*on_timeout)(hal_xxx_id_t id, void* user_data);
} hal_xxx_callbacks_t;

/**
 * \brief           Register callbacks
 * \param[in]       id: Instance ID
 * \param[in]       callbacks: Callback structure (NULL to unregister all)
 * \param[in]       user_data: User data passed to callbacks
 * \return          HAL_OK on success
 */
hal_status_t hal_xxx_register_callbacks(hal_xxx_id_t id,
                                        const hal_xxx_callbacks_t* callbacks,
                                        void* user_data);

Iterator Pattern

Iteration API:

/* Iterator handle */
typedef void* hal_xxx_iterator_t;

/**
 * \brief           Get first item
 * \param[out]      iterator: Iterator handle
 * \param[out]      item: First item
 * \return          HAL_OK if item found, HAL_ERROR_NOT_FOUND if empty
 */
hal_status_t hal_xxx_get_first(hal_xxx_iterator_t* iterator,
                               hal_xxx_item_t* item);

/**
 * \brief           Get next item
 * \param[in,out]   iterator: Iterator handle
 * \param[out]      item: Next item
 * \return          HAL_OK if item found, HAL_ERROR_NOT_FOUND if end
 */
hal_status_t hal_xxx_get_next(hal_xxx_iterator_t* iterator,
                              hal_xxx_item_t* item);

/* Usage */
hal_xxx_iterator_t iter;
hal_xxx_item_t item;

if (hal_xxx_get_first(&iter, &item) == HAL_OK) {
    do {
        /* Process item */
    } while (hal_xxx_get_next(&iter, &item) == HAL_OK);
}

Factory Pattern

Object Creation:

/**
 * \brief           Create GPIO device
 * \param[in]       port: GPIO port
 * \param[in]       pin: GPIO pin
 * \return          GPIO device pointer (NULL on error)
 * \note            Caller must free with nx_factory_gpio_release()
 */
nx_gpio_t* nx_factory_gpio(uint8_t port, uint8_t pin);

/**
 * \brief           Release GPIO device
 * \param[in]       gpio: GPIO device pointer
 */
void nx_factory_gpio_release(nx_gpio_t* gpio);

/* Usage */
nx_gpio_t* gpio = nx_factory_gpio(0, 5);
if (gpio != NULL) {
    nx_gpio_write(gpio, NX_GPIO_LEVEL_HIGH);
    nx_factory_gpio_release(gpio);
}

Builder Pattern

Complex Object Construction:

/* Builder handle */
typedef struct hal_xxx_builder* hal_xxx_builder_t;

/**
 * \brief           Create builder
 * \return          Builder handle (NULL on error)
 */
hal_xxx_builder_t hal_xxx_builder_create(void);

/**
 * \brief           Set parameter
 * \param[in]       builder: Builder handle
 * \param[in]       value: Parameter value
 * \return          HAL_OK on success
 */
hal_status_t hal_xxx_builder_set_param1(hal_xxx_builder_t builder, uint32_t value);
hal_status_t hal_xxx_builder_set_param2(hal_xxx_builder_t builder, uint32_t value);

/**
 * \brief           Build object
 * \param[in]       builder: Builder handle
 * \param[out]      obj: Created object
 * \return          HAL_OK on success
 */
hal_status_t hal_xxx_builder_build(hal_xxx_builder_t builder, hal_xxx_t* obj);

/**
 * \brief           Destroy builder
 * \param[in]       builder: Builder handle
 */
void hal_xxx_builder_destroy(hal_xxx_builder_t builder);

/* Usage */
hal_xxx_builder_t builder = hal_xxx_builder_create();
hal_xxx_builder_set_param1(builder, 100);
hal_xxx_builder_set_param2(builder, 200);

hal_xxx_t obj;
if (hal_xxx_builder_build(builder, &obj) == HAL_OK) {
    /* Use object */
}
hal_xxx_builder_destroy(builder);

Anti-Patterns to Avoid

Boolean Parameters

Avoid Boolean Parameters:

/* Bad: Boolean parameter is unclear */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin, bool output);

/* Usage - unclear what true means */
hal_gpio_init(HAL_GPIO_PORT_A, 5, true);

/* Good: Use enum for clarity */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin,
                          hal_gpio_mode_t mode);

/* Usage - clear and explicit */
hal_gpio_init(HAL_GPIO_PORT_A, 5, HAL_GPIO_MODE_OUTPUT_PP);

Output Parameters First

Don't Put Output Parameters First:

/* Bad: Output parameter first */
hal_status_t hal_gpio_read(hal_gpio_level_t* level, hal_gpio_port_t port,
                          uint8_t pin);

/* Good: Input parameters first, output last */
hal_status_t hal_gpio_read(hal_gpio_port_t port, uint8_t pin,
                          hal_gpio_level_t* level);

Magic Numbers

Avoid Magic Numbers:

/* Bad: Magic numbers */
hal_status_t hal_uart_init(hal_uart_id_t id, uint32_t config);
hal_uart_init(HAL_UART_1, 0x00001C00);  /* What does this mean? */

/* Good: Named constants */
typedef struct {
    uint32_t baudrate;
    hal_uart_wordlen_t wordlen;
    hal_uart_stopbits_t stopbits;
    hal_uart_parity_t parity;
} hal_uart_config_t;

hal_uart_config_t config = {
    .baudrate = 115200,
    .wordlen = HAL_UART_WORDLEN_8,
    .stopbits = HAL_UART_STOPBITS_1,
    .parity = HAL_UART_PARITY_NONE
};
hal_uart_init(HAL_UART_1, &config);

Inconsistent Naming

Maintain Consistent Naming:

/* Bad: Inconsistent naming */
hal_status_t gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);
hal_status_t hal_uart_initialize(hal_uart_id_t id, const hal_uart_config_t* config);
hal_status_t SPI_Init(hal_spi_id_t id, const hal_spi_config_t* config);

/* Good: Consistent naming */
hal_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin, const hal_gpio_config_t* config);
hal_status_t hal_uart_init(hal_uart_id_t id, const hal_uart_config_t* config);
hal_status_t hal_spi_init(hal_spi_id_t id, const hal_spi_config_t* config);

Global State

Avoid Hidden Global State:

/* Bad: Hidden global state */
static hal_gpio_port_t current_port;

void hal_gpio_set_port(hal_gpio_port_t port) {
    current_port = port;
}

hal_status_t hal_gpio_write(uint8_t pin, hal_gpio_level_t level) {
    /* Uses hidden global state */
    return platform_gpio_write(current_port, pin, level);
}

/* Good: Explicit parameters */
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin,
                            hal_gpio_level_t level) {
    return platform_gpio_write(port, pin, level);
}

String Return Values

Don't Return Strings Directly:

/* Bad: Returns pointer to internal buffer */
char* hal_get_error_string(hal_status_t status) {
    static char buffer[64];
    sprintf(buffer, "Error: %d", status);
    return buffer;  /* Not thread-safe! */
}

/* Good: Caller provides buffer */
hal_status_t hal_get_error_string(hal_status_t status, char* buffer,
                                  size_t buffer_size) {
    if (buffer == NULL || buffer_size == 0) {
        return HAL_ERROR_PARAM;
    }
    snprintf(buffer, buffer_size, "Error: %d", status);
    return HAL_OK;
}

/* Also good: Return const string literal */
const char* hal_get_error_string(hal_status_t status) {
    switch (status) {
        case HAL_OK: return "Success";
        case HAL_ERROR: return "Error";
        case HAL_ERROR_PARAM: return "Invalid parameter";
        default: return "Unknown error";
    }
}

Excessive Parameters

Avoid Too Many Parameters:

/* Bad: Too many parameters */
hal_status_t hal_uart_init(hal_uart_id_t id, uint32_t baudrate,
                          hal_uart_wordlen_t wordlen,
                          hal_uart_stopbits_t stopbits,
                          hal_uart_parity_t parity,
                          hal_uart_flow_t flow,
                          bool enable_dma,
                          uint32_t timeout);

/* Good: Use configuration structure */
typedef struct {
    uint32_t baudrate;
    hal_uart_wordlen_t wordlen;
    hal_uart_stopbits_t stopbits;
    hal_uart_parity_t parity;
    hal_uart_flow_t flow;
    bool enable_dma;
    uint32_t timeout;
} hal_uart_config_t;

hal_status_t hal_uart_init(hal_uart_id_t id, const hal_uart_config_t* config);

Platform-Specific Considerations

Endianness

Handle Endianness:

/* Endianness conversion macros */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define CPU_TO_BE16(x) __builtin_bswap16(x)
#define CPU_TO_BE32(x) __builtin_bswap32(x)
#define BE16_TO_CPU(x) __builtin_bswap16(x)
#define BE32_TO_CPU(x) __builtin_bswap32(x)
#else
#define CPU_TO_BE16(x) (x)
#define CPU_TO_BE32(x) (x)
#define BE16_TO_CPU(x) (x)
#define BE32_TO_CPU(x) (x)
#endif

/* Usage */
uint32_t network_value = CPU_TO_BE32(local_value);
uint32_t local_value = BE32_TO_CPU(network_value);

Alignment

Handle Alignment Requirements:

/* Aligned structure */
typedef struct {
    uint32_t field1;
    uint16_t field2;
    uint8_t field3;
    uint8_t padding;  /* Explicit padding */
} __attribute__((aligned(4))) hal_xxx_data_t;

/* Check alignment */
_Static_assert(sizeof(hal_xxx_data_t) % 4 == 0,
               "hal_xxx_data_t must be 4-byte aligned");

/* Unaligned access helpers */
static inline uint32_t read_unaligned_u32(const uint8_t* ptr) {
    uint32_t value;
    memcpy(&value, ptr, sizeof(value));
    return value;
}

static inline void write_unaligned_u32(uint8_t* ptr, uint32_t value) {
    memcpy(ptr, &value, sizeof(value));
}

Bit Fields

Avoid Bit Fields for Portability:

/* Bad: Bit fields are not portable */
typedef struct {
    uint32_t field1 : 8;
    uint32_t field2 : 8;
    uint32_t field3 : 16;
} hal_xxx_reg_t;

/* Good: Use bit masks and shifts */
#define HAL_XXX_FIELD1_POS   0
#define HAL_XXX_FIELD1_MASK  (0xFF << HAL_XXX_FIELD1_POS)
#define HAL_XXX_FIELD2_POS   8
#define HAL_XXX_FIELD2_MASK  (0xFF << HAL_XXX_FIELD2_POS)
#define HAL_XXX_FIELD3_POS   16
#define HAL_XXX_FIELD3_MASK  (0xFFFF << HAL_XXX_FIELD3_POS)

/* Helper macros */
#define HAL_XXX_SET_FIELD1(reg, val) \
    ((reg) = ((reg) & ~HAL_XXX_FIELD1_MASK) | \
             (((val) << HAL_XXX_FIELD1_POS) & HAL_XXX_FIELD1_MASK))

#define HAL_XXX_GET_FIELD1(reg) \
    (((reg) & HAL_XXX_FIELD1_MASK) >> HAL_XXX_FIELD1_POS)

Integer Sizes

Use Fixed-Width Types:

/* Good: Fixed-width types */
#include <stdint.h>

typedef struct {
    uint8_t byte_field;
    uint16_t word_field;
    uint32_t dword_field;
    uint64_t qword_field;
} hal_xxx_data_t;

/* Bad: Variable-width types */
typedef struct {
    char byte_field;      /* Size varies */
    short word_field;     /* Size varies */
    int dword_field;      /* Size varies */
    long qword_field;     /* Size varies */
} hal_xxx_data_t;

Platform Abstraction

Abstract Platform Differences:

/* Platform-specific implementation */
#if defined(PLATFORM_STM32)
#include "stm32_gpio.h"
#define PLATFORM_GPIO_WRITE(port, pin, level) stm32_gpio_write(port, pin, level)
#elif defined(PLATFORM_NRF52)
#include "nrf52_gpio.h"
#define PLATFORM_GPIO_WRITE(port, pin, level) nrf52_gpio_write(port, pin, level)
#else
#error "Unsupported platform"
#endif

/* Platform-independent API */
hal_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin,
                            hal_gpio_level_t level) {
    PLATFORM_GPIO_WRITE(port, pin, level);
    return HAL_OK;
}

Examples and Case Studies

Example 1: GPIO API

Complete GPIO API Design:

/* hal_gpio.h */

/**
 * \file            hal_gpio.h
 * \brief           GPIO Hardware Abstraction Layer
 * \author          Nexus Team
 */

#ifndef HAL_GPIO_H
#define HAL_GPIO_H

#include <stdint.h>
#include <stdbool.h>

/*---------------------------------------------------------------------------*/
/* Type Definitions                                                          */
/*---------------------------------------------------------------------------*/

/**
 * \brief           GPIO status codes
 */
typedef enum {
    HAL_GPIO_OK = 0,           /**< Success */
    HAL_GPIO_ERROR,            /**< General error */
    HAL_GPIO_ERROR_PARAM,      /**< Invalid parameter */
    HAL_GPIO_ERROR_STATE,      /**< Invalid state */
} hal_gpio_status_t;

/**
 * \brief           GPIO port enumeration
 */
typedef enum {
    HAL_GPIO_PORT_A = 0,       /**< Port A */
    HAL_GPIO_PORT_B,           /**< Port B */
    HAL_GPIO_PORT_C,           /**< Port C */
    HAL_GPIO_PORT_MAX          /**< Maximum port number */
} hal_gpio_port_t;

/**
 * \brief           GPIO mode enumeration
 */
typedef enum {
    HAL_GPIO_MODE_INPUT = 0,   /**< Input mode */
    HAL_GPIO_MODE_OUTPUT_PP,   /**< Output push-pull */
    HAL_GPIO_MODE_OUTPUT_OD,   /**< Output open-drain */
} hal_gpio_mode_t;

/**
 * \brief           GPIO pull configuration
 */
typedef enum {
    HAL_GPIO_PULL_NONE = 0,    /**< No pull */
    HAL_GPIO_PULL_UP,          /**< Pull-up */
    HAL_GPIO_PULL_DOWN,        /**< Pull-down */
} hal_gpio_pull_t;

/**
 * \brief           GPIO level enumeration
 */
typedef enum {
    HAL_GPIO_LEVEL_LOW = 0,    /**< Low level */
    HAL_GPIO_LEVEL_HIGH,       /**< High level */
} hal_gpio_level_t;

/**
 * \brief           GPIO configuration structure
 */
typedef struct {
    hal_gpio_mode_t mode;      /**< GPIO mode */
    hal_gpio_pull_t pull;      /**< Pull configuration */
    hal_gpio_level_t init_level; /**< Initial level */
} hal_gpio_config_t;

/*---------------------------------------------------------------------------*/
/* Public Functions                                                          */
/*---------------------------------------------------------------------------*/

/**
 * \brief           Get default GPIO configuration
 * \param[out]      config: Configuration structure
 */
void hal_gpio_get_default_config(hal_gpio_config_t* config);

/**
 * \brief           Initialize GPIO pin
 * \param[in]       port: GPIO port
 * \param[in]       pin: Pin number (0-15)
 * \param[in]       config: Configuration structure
 * \return          HAL_GPIO_OK on success
 */
hal_gpio_status_t hal_gpio_init(hal_gpio_port_t port, uint8_t pin,
                                const hal_gpio_config_t* config);

/**
 * \brief           Deinitialize GPIO pin
 * \param[in]       port: GPIO port
 * \param[in]       pin: Pin number
 * \return          HAL_GPIO_OK on success
 */
hal_gpio_status_t hal_gpio_deinit(hal_gpio_port_t port, uint8_t pin);

/**
 * \brief           Write to GPIO pin
 * \param[in]       port: GPIO port
 * \param[in]       pin: Pin number
 * \param[in]       level: Output level
 * \return          HAL_GPIO_OK on success
 */
hal_gpio_status_t hal_gpio_write(hal_gpio_port_t port, uint8_t pin,
                                 hal_gpio_level_t level);

/**
 * \brief           Read from GPIO pin
 * \param[in]       port: GPIO port
 * \param[in]       pin: Pin number
 * \param[out]      level: Read level
 * \return          HAL_GPIO_OK on success
 */
hal_gpio_status_t hal_gpio_read(hal_gpio_port_t port, uint8_t pin,
                                hal_gpio_level_t* level);

/**
 * \brief           Toggle GPIO pin
 * \param[in]       port: GPIO port
 * \param[in]       pin: Pin number
 * \return          HAL_GPIO_OK on success
 */
hal_gpio_status_t hal_gpio_toggle(hal_gpio_port_t port, uint8_t pin);

#endif /* HAL_GPIO_H */

Example 2: UART API with DMA

UART API with Async Operations:

/* hal_uart.h */

/**
 * \file            hal_uart.h
 * \brief           UART Hardware Abstraction Layer
 * \author          Nexus Team
 */

#ifndef HAL_UART_H
#define HAL_UART_H

#include <stdint.h>
#include <stddef.h>

/*---------------------------------------------------------------------------*/
/* Type Definitions                                                          */
/*---------------------------------------------------------------------------*/

/**
 * \brief           UART instance ID
 */
typedef enum {
    HAL_UART_1 = 0,            /**< UART instance 1 */
    HAL_UART_2,                /**< UART instance 2 */
    HAL_UART_MAX               /**< Maximum UART instances */
} hal_uart_id_t;

/**
 * \brief           UART status codes
 */
typedef enum {
    HAL_UART_OK = 0,           /**< Success */
    HAL_UART_ERROR,            /**< General error */
    HAL_UART_ERROR_PARAM,      /**< Invalid parameter */
    HAL_UART_ERROR_TIMEOUT,    /**< Operation timeout */
    HAL_UART_ERROR_BUSY,       /**< UART busy */
} hal_uart_status_t;

/**
 * \brief           UART event types
 */
typedef enum {
    HAL_UART_EVENT_TX_COMPLETE = 0, /**< Transmission complete */
    HAL_UART_EVENT_RX_COMPLETE,     /**< Reception complete */
    HAL_UART_EVENT_ERROR,           /**< Error occurred */
} hal_uart_event_t;

/**
 * \brief           UART callback function type
 * \param[in]       id: UART instance ID
 * \param[in]       event: Event type
 * \param[in]       user_data: User data
 */
typedef void (*hal_uart_callback_t)(hal_uart_id_t id,
                                    hal_uart_event_t event,
                                    void* user_data);

/**
 * \brief           UART configuration structure
 */
typedef struct {
    uint32_t baudrate;         /**< Baudrate (e.g., 115200) */
    uint8_t wordlen;           /**< Word length (7, 8, 9 bits) */
    uint8_t stopbits;          /**< Stop bits (1, 2) */
    uint8_t parity;            /**< Parity (none, even, odd) */
} hal_uart_config_t;

/*---------------------------------------------------------------------------*/
/* Public Functions                                                          */
/*---------------------------------------------------------------------------*/

/**
 * \brief           Get default UART configuration
 * \param[out]      config: Configuration structure
 */
void hal_uart_get_default_config(hal_uart_config_t* config);

/**
 * \brief           Initialize UART
 * \param[in]       id: UART instance ID
 * \param[in]       config: Configuration structure
 * \return          HAL_UART_OK on success
 */
hal_uart_status_t hal_uart_init(hal_uart_id_t id,
                                const hal_uart_config_t* config);

/**
 * \brief           Deinitialize UART
 * \param[in]       id: UART instance ID
 * \return          HAL_UART_OK on success
 */
hal_uart_status_t hal_uart_deinit(hal_uart_id_t id);

/**
 * \brief           Send data (blocking)
 * \param[in]       id: UART instance ID
 * \param[in]       data: Data buffer
 * \param[in]       length: Data length
 * \param[in]       timeout: Timeout in milliseconds
 * \return          HAL_UART_OK on success
 */
hal_uart_status_t hal_uart_send(hal_uart_id_t id, const uint8_t* data,
                                size_t length, uint32_t timeout);

/**
 * \brief           Receive data (blocking)
 * \param[in]       id: UART instance ID
 * \param[out]      buffer: Receive buffer
 * \param[in]       buffer_size: Buffer size
 * \param[out]      received: Bytes received
 * \param[in]       timeout: Timeout in milliseconds
 * \return          HAL_UART_OK on success
 */
hal_uart_status_t hal_uart_receive(hal_uart_id_t id, uint8_t* buffer,
                                   size_t buffer_size, size_t* received,
                                   uint32_t timeout);

/**
 * \brief           Send data using DMA (non-blocking)
 * \param[in]       id: UART instance ID
 * \param[in]       data: Data buffer (must remain valid until callback)
 * \param[in]       length: Data length
 * \param[in]       callback: Completion callback
 * \param[in]       user_data: User data for callback
 * \return          HAL_UART_OK on success
 * \note            Buffer must remain valid until callback is invoked
 */
hal_uart_status_t hal_uart_send_dma(hal_uart_id_t id, const uint8_t* data,
                                    size_t length,
                                    hal_uart_callback_t callback,
                                    void* user_data);

/**
 * \brief           Receive data using DMA (non-blocking)
 * \param[in]       id: UART instance ID
 * \param[out]      buffer: Receive buffer (must remain valid until callback)
 * \param[in]       buffer_size: Buffer size
 * \param[in]       callback: Completion callback
 * \param[in]       user_data: User data for callback
 * \return          HAL_UART_OK on success
 * \note            Buffer must remain valid until callback is invoked
 */
hal_uart_status_t hal_uart_receive_dma(hal_uart_id_t id, uint8_t* buffer,
                                       size_t buffer_size,
                                       hal_uart_callback_t callback,
                                       void* user_data);

#endif /* HAL_UART_H */

Example 3: Configuration API

Type-Safe Configuration API:

/* config.h */

/**
 * \file            config.h
 * \brief           Configuration System API
 * \author          Nexus Team
 */

#ifndef CONFIG_H
#define CONFIG_H

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

/*---------------------------------------------------------------------------*/
/* Type Definitions                                                          */
/*---------------------------------------------------------------------------*/

/**
 * \brief           Configuration status codes
 */
typedef enum {
    CONFIG_OK = 0,             /**< Success */
    CONFIG_ERROR,              /**< General error */
    CONFIG_ERROR_NOT_FOUND,    /**< Key not found */
    CONFIG_ERROR_TYPE,         /**< Type mismatch */
    CONFIG_ERROR_RANGE,        /**< Value out of range */
} config_status_t;

/*---------------------------------------------------------------------------*/
/* Public Functions                                                          */
/*---------------------------------------------------------------------------*/

/**
 * \brief           Initialize configuration system
 * \return          CONFIG_OK on success
 */
config_status_t config_init(void);

/**
 * \brief           Set integer value
 * \param[in]       key: Configuration key
 * \param[in]       value: Integer value
 * \return          CONFIG_OK on success
 */
config_status_t config_set_i32(const char* key, int32_t value);

/**
 * \brief           Get integer value
 * \param[in]       key: Configuration key
 * \param[out]      value: Integer value
 * \return          CONFIG_OK on success
 */
config_status_t config_get_i32(const char* key, int32_t* value);

/**
 * \brief           Set string value
 * \param[in]       key: Configuration key
 * \param[in]       value: String value
 * \return          CONFIG_OK on success
 */
config_status_t config_set_str(const char* key, const char* value);

/**
 * \brief           Get string value
 * \param[in]       key: Configuration key
 * \param[out]      buffer: Output buffer
 * \param[in]       buffer_size: Buffer size
 * \return          CONFIG_OK on success
 */
config_status_t config_get_str(const char* key, char* buffer,
                               size_t buffer_size);

/**
 * \brief           Set boolean value
 * \param[in]       key: Configuration key
 * \param[in]       value: Boolean value
 * \return          CONFIG_OK on success
 */
config_status_t config_set_bool(const char* key, bool value);

/**
 * \brief           Get boolean value
 * \param[in]       key: Configuration key
 * \param[out]      value: Boolean value
 * \return          CONFIG_OK on success
 */
config_status_t config_get_bool(const char* key, bool* value);

/**
 * \brief           Check if key exists
 * \param[in]       key: Configuration key
 * \return          true if key exists
 */
bool config_has_key(const char* key);

/**
 * \brief           Delete key
 * \param[in]       key: Configuration key
 * \return          CONFIG_OK on success
 */
config_status_t config_delete(const char* key);

/**
 * \brief           Save configuration to storage
 * \return          CONFIG_OK on success
 */
config_status_t config_save(void);

/**
 * \brief           Load configuration from storage
 * \return          CONFIG_OK on success
 */
config_status_t config_load(void);

#endif /* CONFIG_H */

See Also

External Resources

Summary

This guide provides comprehensive API design guidelines for the Nexus Embedded Platform:

  • Design Principles: Consistency, simplicity, orthogonality, discoverability, safety

  • Naming Conventions: Module prefixes, function names, type names, enumerations

  • Function Signatures: Parameter order, return values, input/output parameters

  • Data Structures: Configuration structures, opaque handles, enumerations

  • Error Handling: Status codes, parameter validation, error propagation

  • Memory Management: Ownership rules, buffer management, resource cleanup

  • Thread Safety: Reentrancy, atomic operations, interrupt safety

  • Documentation: Doxygen comments, usage examples, API documentation

  • Versioning: Semantic versioning, backward compatibility, deprecation

  • Performance: Efficiency, batch operations, zero-copy APIs

  • Testing: Unit testing, integration testing, testable design

  • Common Patterns: Initialization, configuration, callbacks, iterators

  • Anti-Patterns: Boolean parameters, magic numbers, global state

  • Platform Considerations: Endianness, alignment, portability

  • Examples: Complete API designs for GPIO, UART, configuration

Following these guidelines ensures consistent, maintainable, and high-quality APIs across the Nexus platform.