配置管理器

概述

配置管理器为 Nexus 嵌入式平台提供灵活、安全、持久化的键值配置存储。它支持多种数据类型、命名空间、变更通知和可选加密。

特性

  • 多类型支持: int32/64、uint32、float、bool、string、blob

  • 命名空间隔离: 按模块分离配置

  • 默认值管理: 注册默认值,支持一键恢复

  • 变更通知: 配置变更时触发回调

  • 持久化存储: RAM、Flash 和自定义后端

  • 导入/导出: 支持二进制和 JSON 格式

  • 可选加密: AES-128/256 加密敏感数据

  • 线程安全: 多任务环境下安全使用

  • 资源可配置: 支持静态分配,适用于资源受限系统

快速开始

基本用法:

#include "config/config.h"

void app_init(void)
{
    // Initialize with default config
    config_init(NULL);

    // Store configuration values
    config_set_i32("app.timeout", 5000);
    config_set_str("app.name", "MyApp");
    config_set_bool("app.debug", true);
    config_set_float("sensor.threshold", 3.14f);

    // Read configuration values
    int32_t timeout = 0;
    config_get_i32("app.timeout", &timeout, 1000);  // Default: 1000

    char name[32];
    config_get_str("app.name", name, sizeof(name));

    bool debug = false;
    config_get_bool("app.debug", &debug, false);

    // Commit to storage
    config_commit();

    // Cleanup
    config_deinit();
}

配置

自定义配置:

config_manager_config_t config = {
    .max_keys = 128,           // Max key count
    .max_key_len = 32,         // Max key length
    .max_value_size = 256,     // Max value size
    .max_namespaces = 8,       // Max namespace count
    .max_callbacks = 16,       // Max callback count
    .auto_commit = true        // Auto-commit mode
};

config_init(&config);

默认配置:

参数

默认值

描述

max_keys

64

最大键数量

max_key_len

32

最大键长度

max_value_size

256

最大值大小

max_namespaces

4

最大命名空间数

max_callbacks

8

最大回调数

auto_commit

false

自动提交模式

数据类型

类型

描述

CONFIG_TYPE_I32

0

32 位有符号整数

CONFIG_TYPE_U32

1

32 位无符号整数

CONFIG_TYPE_I64

2

64 位有符号整数

CONFIG_TYPE_FLOAT

3

单精度浮点数

CONFIG_TYPE_BOOL

4

布尔值

CONFIG_TYPE_STR

5

空终止字符串

CONFIG_TYPE_BLOB

6

二进制数据

类型操作

32-bit Signed Integer (int32)

// Store 32-bit signed integer
config_set_i32("app.timeout", 5000);
config_set_i32("sensor.offset", -100);

// Read with default value
int32_t timeout;
config_get_i32("app.timeout", &timeout, 1000);  // Default: 1000

// Check if exists before reading
bool exists;
config_exists("app.timeout", &exists);
if (exists) {
    config_get_i32("app.timeout", &timeout, 0);
}

32-bit Unsigned Integer (uint32)

// Store 32-bit unsigned integer
config_set_u32("app.count", 100);
config_set_u32("network.retry_count", 5);

// Read with default value
uint32_t count;
config_get_u32("app.count", &count, 0);  // Default: 0

// Use for counters and IDs
uint32_t device_id;
config_get_u32("device.id", &device_id, 0xFFFFFFFF);

64-bit Signed Integer (int64)

// Store 64-bit signed integer (timestamps, large values)
config_set_i64("app.timestamp", 1234567890123LL);
config_set_i64("system.boot_time", -1000000LL);

// Read with default value
int64_t timestamp;
config_get_i64("app.timestamp", &timestamp, 0);

// Use for timestamps
int64_t last_sync;
config_get_i64("network.last_sync", &last_sync, 0);

Float (Single-Precision)

// Store floating-point values
config_set_float("sensor.threshold", 3.14f);
config_set_float("calibration.offset", -0.5f);
config_set_float("pid.kp", 1.2f);

// Read with default value
float threshold;
config_get_float("sensor.threshold", &threshold, 0.0f);

// Use for sensor calibration
float temp_offset;
config_get_float("sensor.temp_offset", &temp_offset, 0.0f);

Boolean

// Store boolean values
config_set_bool("app.debug", true);
config_set_bool("network.dhcp_enabled", false);
config_set_bool("sensor.auto_calibrate", true);

// Read with default value
bool debug;
config_get_bool("app.debug", &debug, false);

// Use for feature flags
bool use_ssl;
config_get_bool("network.use_ssl", &use_ssl, true);

字符串

// Store string values
config_set_str("app.name", "MyApp");
config_set_str("network.hostname", "device-001");
config_set_str("wifi.ssid", "MyNetwork");

// Read string
char name[32];
config_get_str("app.name", name, sizeof(name));

// Get string length first
size_t len;
config_get_str_len("app.name", &len);
char* dynamic_buf = malloc(len + 1);
config_get_str("app.name", dynamic_buf, len + 1);

// Use for configuration strings
char server_url[128];
config_get_str("network.server_url", server_url, sizeof(server_url));

Binary Blob

// Store binary data (certificates, keys, raw data)
uint8_t cert_data[] = {0x30, 0x82, 0x01, 0x0A, ...};
config_set_blob("security.certificate", cert_data, sizeof(cert_data));

// Store encryption key
uint8_t aes_key[16] = {0x00, 0x01, 0x02, ...};
config_set_blob("security.aes_key", aes_key, sizeof(aes_key));

// Read binary data
uint8_t buffer[256];
size_t actual_size;
config_get_blob("security.certificate", buffer, sizeof(buffer), &actual_size);

// Get blob size first
size_t blob_size;
config_get_blob_len("security.certificate", &blob_size);
uint8_t* dynamic_buf = malloc(blob_size);
config_get_blob("security.certificate", dynamic_buf, blob_size, &actual_size);

命名空间

命名空间用于隔离不同模块的配置:

// Open namespace
config_ns_handle_t ns;
config_open_namespace("network", &ns);

// Operations within namespace
config_ns_set_i32(ns, "port", 8080);
config_ns_set_str(ns, "host", "192.168.1.1");
config_ns_set_bool(ns, "ssl", true);

// Read from namespace
int32_t port = 0;
config_ns_get_i32(ns, "port", &port, 80);

// Check if key exists
bool exists;
config_ns_exists(ns, "port", &exists);

// Delete key
config_ns_delete(ns, "port");

// Close namespace
config_close_namespace(ns);

// Erase entire namespace
config_erase_namespace("network");

默认值

单个默认值:

// Register defaults
config_set_default_i32("app.timeout", 5000);
config_set_default_str("app.name", "DefaultApp");
config_set_default_bool("app.debug", false);

// Reset to default
config_reset_to_default("app.timeout");

// Reset all to defaults
config_reset_all_to_defaults();

批量注册:

static const config_default_t app_defaults[] = {
    {"app.timeout", CONFIG_TYPE_I32, {.i32_val = 5000}},
    {"app.name", CONFIG_TYPE_STR, {.str_val = "MyApp"}},
    {"app.debug", CONFIG_TYPE_BOOL, {.bool_val = false}},
    {"app.rate", CONFIG_TYPE_FLOAT, {.float_val = 1.5f}},
};

config_register_defaults(app_defaults,
                         sizeof(app_defaults) / sizeof(app_defaults[0]));

变更通知

监听特定键:

void on_timeout_change(const char* key, config_type_t type,
                       const void* old_val, const void* new_val,
                       void* user_data)
{
    int32_t old_timeout = old_val ? *(int32_t*)old_val : 0;
    int32_t new_timeout = *(int32_t*)new_val;
    printf("Timeout changed: %d -> %d\n", old_timeout, new_timeout);
}

config_cb_handle_t handle;
config_register_callback("app.timeout", on_timeout_change, NULL, &handle);

// Triggers callback
config_set_i32("app.timeout", 10000);

// Unregister
config_unregister_callback(handle);

监听所有变更:

void on_any_change(const char* key, config_type_t type,
                   const void* old_val, const void* new_val,
                   void* user_data)
{
    printf("Config changed: %s\n", key);
}

config_cb_handle_t handle;
config_register_wildcard_callback(on_any_change, NULL, &handle);

存储后端

The Config Manager supports multiple storage backends for different use cases. Each backend implements the same interface, allowing easy switching between storage types.

RAM Backend (Volatile)

The RAM backend stores configuration in memory. Data is lost on power cycle. Ideal for testing, temporary storage, and development.

#include "config/config_backend.h"

// Create RAM backend with 4KB buffer
config_backend_t* ram = config_backend_ram_create(4096);
if (ram == NULL) {
    printf("Failed to create RAM backend\n");
    return -1;
}

// Set as active backend
config_set_backend(ram);

// Use configuration normally
config_set_i32("app.timeout", 5000);
config_set_str("app.name", "TestApp");

// Data is stored in RAM
config_commit();  // No-op for RAM backend

// When done, destroy backend
config_backend_ram_destroy(ram);

Use cases: - Unit testing - Temporary configuration - Development and debugging - Systems without persistent storage

Flash Backend (Persistent)

The Flash backend stores configuration in non-volatile Flash memory. Data persists across power cycles. Requires HAL Flash driver.

#include "config/config_backend.h"
#include "hal/hal_flash.h"

// Define Flash partition for configuration
#define CONFIG_FLASH_ADDR   0x08080000  // Flash address
#define CONFIG_FLASH_SIZE   0x00010000  // 64KB partition

// Initialize Flash HAL
hal_flash_init();

// Create Flash backend
config_backend_t* flash = config_backend_flash_create(
    CONFIG_FLASH_ADDR,
    CONFIG_FLASH_SIZE
);
if (flash == NULL) {
    printf("Failed to create Flash backend\n");
    return -1;
}

// Set as active backend
config_set_backend(flash);

// Load existing configuration from Flash
config_status_t status = config_load();
if (status != CONFIG_OK) {
    printf("No existing config, using defaults\n");
    // Set default values
    config_set_i32("app.timeout", 5000);
    config_set_str("app.name", "MyApp");
}

// Modify configuration
config_set_bool("app.debug", true);

// Save to Flash
config_commit();

// When done, destroy backend
config_backend_flash_destroy(flash);
hal_flash_deinit();

Use cases: - Production systems - Persistent user settings - Device configuration - Calibration data

Flash considerations: - Wear leveling: Flash has limited write cycles - Erase granularity: Flash erases in sectors/pages - Write time: Flash writes are slower than RAM - Power loss: Use atomic writes or checksums

自定义后端

Implement a custom backend for specialized storage needs (EEPROM, SD card, network storage, etc.).

#include "config/config_backend.h"

// Custom context (your storage state)
typedef struct {
    void* storage_handle;
    uint32_t base_address;
} my_backend_ctx_t;

// Read function
static config_status_t my_backend_read(void* ctx, const char* key,
                                       void* value, size_t* size)
{
    my_backend_ctx_t* backend = (my_backend_ctx_t*)ctx;

    // Implement read logic
    // 1. Find key in storage
    // 2. Read value
    // 3. Copy to value buffer
    // 4. Set size

    return CONFIG_OK;
}

// Write function
static config_status_t my_backend_write(void* ctx, const char* key,
                                        const void* value, size_t size)
{
    my_backend_ctx_t* backend = (my_backend_ctx_t*)ctx;

    // Implement write logic
    // 1. Find or allocate space for key
    // 2. Write value
    // 3. Update metadata

    return CONFIG_OK;
}

// Erase function
static config_status_t my_backend_erase(void* ctx, const char* key)
{
    my_backend_ctx_t* backend = (my_backend_ctx_t*)ctx;

    // Implement erase logic
    // 1. Find key
    // 2. Mark as deleted or reclaim space

    return CONFIG_OK;
}

// Commit function (flush to storage)
static config_status_t my_backend_commit(void* ctx)
{
    my_backend_ctx_t* backend = (my_backend_ctx_t*)ctx;

    // Implement commit logic
    // 1. Flush any cached writes
    // 2. Update checksums
    // 3. Ensure data integrity

    return CONFIG_OK;
}

// Create custom backend
config_backend_t* my_backend_create(void)
{
    // Allocate context
    my_backend_ctx_t* ctx = malloc(sizeof(my_backend_ctx_t));
    if (ctx == NULL) {
        return NULL;
    }

    // Initialize context
    ctx->storage_handle = open_storage();
    ctx->base_address = 0x1000;

    // Allocate backend structure
    config_backend_t* backend = malloc(sizeof(config_backend_t));
    if (backend == NULL) {
        free(ctx);
        return NULL;
    }

    // Set function pointers
    backend->read = my_backend_read;
    backend->write = my_backend_write;
    backend->erase = my_backend_erase;
    backend->commit = my_backend_commit;
    backend->ctx = ctx;

    return backend;
}

// Destroy custom backend
void my_backend_destroy(config_backend_t* backend)
{
    if (backend != NULL) {
        my_backend_ctx_t* ctx = (my_backend_ctx_t*)backend->ctx;
        if (ctx != NULL) {
            close_storage(ctx->storage_handle);
            free(ctx);
        }
        free(backend);
    }
}

// Usage
config_backend_t* backend = my_backend_create();
config_set_backend(backend);

// Use configuration
config_set_i32("app.value", 42);
config_commit();

// Cleanup
my_backend_destroy(backend);

Custom backend use cases: - EEPROM storage - SD card configuration files - Network-based configuration (cloud sync) - Database storage - Encrypted storage with custom crypto

Backend Comparison

Feature

RAM

Flash

Custom

注意事项

Persistent

Depends

Across reboot

速度

Fast

Medium

Varies

Read/write

Wear leveling

N/A

必需

Depends

Write cycles

Size limit

RAM size

Flash size

Varies

Storage cap

Power loss

Data lost

Safe

Depends

Data integrity

Complexity

Simple

Medium

High

Implementation

Backend Selection Guide

Choose RAM backend when: - Testing and development - Temporary configuration - No persistent storage needed - Maximum performance required

Choose Flash backend when: - Production deployment - Configuration must persist - Limited RAM available - Standard embedded system

Choose Custom backend when: - Special storage requirements - External storage (SD, EEPROM) - Network/cloud synchronization - Custom encryption or compression

导入/导出

二进制格式:

// Export
size_t export_size;
config_get_export_size(CONFIG_FORMAT_BINARY, 0, &export_size);

uint8_t* buffer = malloc(export_size);
size_t actual_size;
config_export(CONFIG_FORMAT_BINARY, 0, buffer, export_size, &actual_size);

// Import
config_import(CONFIG_FORMAT_BINARY, 0, buffer, actual_size);

JSON 格式:

// Export as JSON
char json_buffer[1024];
size_t json_size;
config_export(CONFIG_FORMAT_JSON, 0, json_buffer,
              sizeof(json_buffer), &json_size);

// Import JSON
const char* json = "{\"app.timeout\": 5000, \"app.name\": \"Test\"}";
config_import(CONFIG_FORMAT_JSON, 0, json, strlen(json));

命名空间导出:

// Export specific namespace only
config_export_namespace("network", CONFIG_FORMAT_JSON, 0,
                        buffer, buf_size, &actual_size);

加密

设置加密密钥:

uint8_t key[16] = {0x00, 0x01, 0x02, ...};  // AES-128 key
config_set_encryption_key(key, sizeof(key), CONFIG_CRYPTO_AES128);

存储加密数据:

// Encrypt and store string
config_set_str_encrypted("auth.password", "secret123");

// Encrypt and store binary
uint8_t token[32] = {...};
config_set_blob_encrypted("auth.token", token, sizeof(token));

// Reading auto-decrypts
char password[64];
config_get_str("auth.password", password, sizeof(password));

// Check if key is encrypted
bool encrypted;
config_is_encrypted("auth.password", &encrypted);

密钥轮换:

// Re-encrypt all encrypted data with new key
uint8_t new_key[16] = {...};
config_rotate_encryption_key(new_key, sizeof(new_key), CONFIG_CRYPTO_AES128);

查询操作

// Check if key exists
bool exists;
config_exists("app.timeout", &exists);

// Get value type
config_type_t type;
config_get_type("app.timeout", &type);

// Delete key
config_delete("app.timeout");

// Get key count
size_t count;
config_get_count(&count);

// Iterate all entries
bool print_entry(const config_entry_info_t* info, void* user_data)
{
    printf("Key: %s, Type: %d, Size: %d\n",
           info->key, info->type, info->value_size);
    return true;  // Continue iteration
}

config_iterate(print_entry, NULL);

错误处理

config_status_t status = config_set_i32("key", 100);
if (status != CONFIG_OK) {
    const char* msg = config_error_to_str(status);
    printf("Error: %s\n", msg);
}

状态码:

状态

描述

CONFIG_OK

成功

CONFIG_ERROR_INVALID_PARAM

无效参数

CONFIG_ERROR_NOT_INIT

未初始化

CONFIG_ERROR_ALREADY_INIT

已初始化

CONFIG_ERROR_NOT_FOUND

键未找到

CONFIG_ERROR_TYPE_MISMATCH

类型不匹配

CONFIG_ERROR_BUFFER_TOO_SMALL

缓冲区太小

CONFIG_ERROR_STORAGE_FULL

存储已满

CONFIG_ERROR_BACKEND

后端错误

CONFIG_ERROR_CRYPTO

加密错误

编译时配置

宏定义

默认值

描述

CONFIG_DEFAULT_MAX_KEYS

64

默认最大键数

CONFIG_DEFAULT_MAX_KEY_LEN

32

默认最大键长度

CONFIG_DEFAULT_MAX_VALUE_SIZE

256

默认最大值大小

CONFIG_DEFAULT_MAX_NAMESPACES

4

默认最大命名空间数

CONFIG_DEFAULT_MAX_CALLBACKS

8

默认最大回调数

CONFIG_ENABLE_ENCRYPTION

1

启用加密

CONFIG_ENABLE_JSON

1

启用 JSON 支持

依赖

  • OSAL: 操作系统抽象层(Mutex 用于线程安全)

  • HAL: 硬件抽象层(Flash 后端)

API 参考

完整 API 文档请参阅 配置管理器 API 参考