Config ManagerΒΆ
OverviewΒΆ
The Config Manager provides a flexible, secure, and persistent key-value configuration storage for the Nexus embedded platform. It supports multiple data types, namespaces, change notifications, and optional encryption.
FeaturesΒΆ
Multiple Types: int32/64, uint32, float, bool, string, blob
Namespace Isolation: Separate configurations by module
Default Values: Register defaults with one-click reset
Change Notifications: Callbacks on configuration changes
Persistent Storage: RAM, Flash, and custom backends
Import/Export: Binary and JSON format support
Optional Encryption: AES-128/256 for sensitive data
Thread-Safe: Safe for multi-task environments
Resource Configurable: Static allocation for constrained systems
Quick StartΒΆ
Basic usage:
#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();
}
ConfigurationΒΆ
Custom configuration:
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);
Default configuration:
Parameter |
Default |
Description |
|---|---|---|
|
|
Maximum key count |
|
|
Maximum key length |
|
|
Maximum value size |
|
|
Maximum namespace count |
|
|
Maximum callback count |
|
|
Auto-commit mode |
Data TypesΒΆ
Type |
Value |
Description |
|---|---|---|
|
0 |
32-bit signed integer |
|
1 |
32-bit unsigned integer |
|
2 |
64-bit signed integer |
|
3 |
Single-precision float |
|
4 |
Boolean value |
|
5 |
Null-terminated string |
|
6 |
Binary data |
Type OperationsΒΆ
Integer operations:
// 32-bit signed
config_set_i32("app.timeout", 5000);
int32_t timeout;
config_get_i32("app.timeout", &timeout, 1000);
// 32-bit unsigned
config_set_u32("app.count", 100);
uint32_t count;
config_get_u32("app.count", &count, 0);
// 64-bit signed
config_set_i64("app.timestamp", 1234567890123LL);
int64_t timestamp;
config_get_i64("app.timestamp", ×tamp, 0);
Float and boolean:
// Float
config_set_float("sensor.threshold", 3.14f);
float threshold;
config_get_float("sensor.threshold", &threshold, 0.0f);
// Boolean
config_set_bool("app.debug", true);
bool debug;
config_get_bool("app.debug", &debug, false);
String and blob:
// String
config_set_str("app.name", "MyApp");
char name[32];
config_get_str("app.name", name, sizeof(name));
// Get string length
size_t len;
config_get_str_len("app.name", &len);
// Binary blob
uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
config_set_blob("app.data", data, sizeof(data));
uint8_t buffer[64];
size_t actual_size;
config_get_blob("app.data", buffer, sizeof(buffer), &actual_size);
NamespacesΒΆ
Namespaces isolate configurations for different modules:
// 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");
Default ValuesΒΆ
Single default values:
// 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();
Batch registration:
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]));
Change NotificationsΒΆ
Watch specific key:
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);
Watch all changes:
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);
Storage BackendsΒΆ
RAM BackendΒΆ
For testing and volatile storage:
#include "config/config_backend.h"
// Create RAM backend
config_backend_t* ram = config_backend_ram_create(4096);
config_set_backend(ram);
// When done
config_backend_ram_destroy(ram);
Flash BackendΒΆ
For persistent storage:
// Create Flash backend
config_backend_t* flash = config_backend_flash_create(
FLASH_CONFIG_ADDR, // Flash start address
FLASH_CONFIG_SIZE // Partition size
);
config_set_backend(flash);
// Load from Flash
config_load();
// Save to Flash
config_commit();
Custom BackendΒΆ
static config_status_t my_read(void* ctx, const char* key,
void* value, size_t* size)
{
// Implement read logic
return CONFIG_OK;
}
static config_status_t my_write(void* ctx, const char* key,
const void* value, size_t size)
{
// Implement write logic
return CONFIG_OK;
}
static const config_backend_t my_backend = {
.read = my_read,
.write = my_write,
.erase = my_erase,
.commit = my_commit,
.ctx = &my_context
};
config_set_backend(&my_backend);
Import/ExportΒΆ
Binary format:
// 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 format:
// 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));
Namespace export:
// Export specific namespace only
config_export_namespace("network", CONFIG_FORMAT_JSON, 0,
buffer, buf_size, &actual_size);
EncryptionΒΆ
Set encryption key:
uint8_t key[16] = {0x00, 0x01, 0x02, ...}; // AES-128 key
config_set_encryption_key(key, sizeof(key), CONFIG_CRYPTO_AES128);
Store encrypted data:
// 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);
Key rotation:
// 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);
Query OperationsΒΆ
// 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);
Error HandlingΒΆ
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);
}
Status codes:
Status |
Description |
|---|---|
|
Success |
|
Invalid parameter |
|
Not initialized |
|
Already initialized |
|
Key not found |
|
Type mismatch |
|
Buffer too small |
|
Storage full |
|
Backend error |
|
Encryption error |
Compile-Time ConfigurationΒΆ
Macro |
Default |
Description |
|---|---|---|
|
|
Default max key count |
|
|
Default max key length |
|
|
Default max value size |
|
|
Default max namespaces |
|
|
Default max callbacks |
|
|
Enable encryption |
|
|
Enable JSON support |
DependenciesΒΆ
OSAL: OS Abstraction Layer (Mutex for thread safety)
HAL: Hardware Abstraction Layer (Flash backend)
API ReferenceΒΆ
See Config Manager API Reference for complete API documentation.