Sysparam code cleanup

This commit is contained in:
Alex Stewart 2016-03-08 12:31:29 -08:00
parent 40266a1e63
commit b67783635b

View file

@ -5,28 +5,60 @@
#include <espressif/spi_flash.h>
//TODO: make this properly threadsafe
//FIXME: reduce stack usage
//TODO: make stderr work for debug output
//TODO: reduce stack usage
//FIXME: CRC calculations/checking
/* The "magic" values that indicate the start of a sysparam region in flash.
* Note that SYSPARAM_STALE_MAGIC is written over SYSPARAM_ACTIVE_MAGIC, so it
* must not contain any set bits which are not set in SYSPARAM_ACTIVE_MAGIC
* (that is, going from SYSPARAM_ACTIVE_MAGIC to SYSPARAM_STALE_MAGIC must only
* clear bits, not set them)
*/
#define SYSPARAM_ACTIVE_MAGIC 0x70524f45 // "EORp" in little-endian
#define SYSPARAM_STALE_MAGIC 0x40524f45 // "EOR@" in little-endian
/* The size of the initial buffer created by sysparam_iter_start, etc, to hold
* returned key-value pairs. Setting this too small may result in a lot of
* unnecessary reallocs. Setting it too large will waste memory when iterating
* through entries.
*/
#define DEFAULT_ITER_BUF_SIZE 64
/* The size of the buffer (in words) used by `sysparam_create_area` when
* scanning a potential area to make sure it's currently empty. Note that this
* space is taken from the stack, so it should not be too large.
*/
#define SCAN_BUFFER_SIZE 8 // words
/* Size of region/entry headers. These should not normally need tweaking (and
* will probably require some code changes if they are tweaked).
*/
#define REGION_HEADER_SIZE 4 // NOTE: Must be multiple of 4
#define ENTRY_HEADER_SIZE 4 // NOTE: Must be multiple of 4
/* Maximum value that can be used for a key_id. This is limited by the format
* to 0x7e (0x7f would produce a corresponding value ID of 0xff, which is
* invalid)
*/
#define MAX_KEY_ID 0x7e
#ifndef SYSPARAM_DEBUG
#define SYSPARAM_DEBUG 0
#endif
#define debug(level, format, ...) if (SYSPARAM_DEBUG >= (level)) { printf("%s" format "\n", "sysparam: ", ## __VA_ARGS__); }
#define SYSPARAM_MAGIC 0x70524f45 // "EORp" in little-endian
#define SYSPARAM_STALEMAGIC 0x40524f45 // "EOR@" in little-endian
#define REGION_HEADER_SIZE 4 // NOTE: Must be multiple of 4
#define ENTRY_HEADER_SIZE 4 // NOTE: Must be multiple of 4
#define DEFAULT_ITER_BUF_SIZE 64
#define MAX_KEY_ID 0x7e
#define SCAN_BUFFER_SIZE 8 // words
/******************************* Useful Macros *******************************/
#define ROUND_TO_WORD_BOUNDARY(x) (((x) + 3) & 0xfffffffc)
#define ENTRY_SIZE(payload_len) (ENTRY_HEADER_SIZE + ROUND_TO_WORD_BOUNDARY(payload_len))
#define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
#define debug(level, format, ...) if (SYSPARAM_DEBUG >= (level)) { printf("%s" format "\n", "sysparam: ", ## __VA_ARGS__); }
#define CHECK_FLASH_OP(x) do { int __x = (x); if ((__x) != SPI_FLASH_RESULT_OK) { debug(1, "FLASH ERR: %d", __x); return SYSPARAM_ERR_IO; } } while (0);
/********************* Internal datatypes and structures *********************/
struct entry_header {
uint8_t prev_len;
@ -43,21 +75,19 @@ struct sysparam_context {
uint8_t max_key_id;
};
/* Internal data structures */
/*************************** Global variables/data ***************************/
struct {
static struct {
uint32_t cur_base;
uint32_t alt_base;
uint32_t end_addr;
size_t region_size;
} sysparam_info;
} _sysparam_info;
/* Internal routines */
/***************************** Internal routines *****************************/
#define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
static sysparam_status_t format_region(uint32_t addr) {
/** Erase the sectors of a region */
static sysparam_status_t _format_region(uint32_t addr) {
uint16_t sector = addr / sdk_flashchip.sector_size;
int i;
@ -67,30 +97,38 @@ static sysparam_status_t format_region(uint32_t addr) {
return SYSPARAM_OK;
}
static inline sysparam_status_t write_region_header(uint32_t addr, bool active) {
uint32_t magic = active ? SYSPARAM_MAGIC : SYSPARAM_STALEMAGIC;
/** Write the magic value at the beginning of a region */
static inline sysparam_status_t _write_region_header(uint32_t addr, bool active) {
uint32_t magic = active ? SYSPARAM_ACTIVE_MAGIC : SYSPARAM_STALE_MAGIC;
debug(3, "write region header (0x%08x) @ 0x%08x", magic, addr);
CHECK_FLASH_OP(sdk_spi_flash_write(addr, &magic, 4));
return SYSPARAM_OK;
}
static void init_context(struct sysparam_context *ctx) {
/** Initialize a context structure at the beginning of the active region */
static void _init_context(struct sysparam_context *ctx) {
memset(ctx, 0, sizeof(*ctx));
ctx->addr = sysparam_info.cur_base;
ctx->addr = _sysparam_info.cur_base;
}
/** Initialize a context structure at the end of the active region */
static sysparam_status_t init_write_context(struct sysparam_context *ctx) {
memset(ctx, 0, sizeof(*ctx));
ctx->addr = sysparam_info.end_addr;
ctx->addr = _sysparam_info.end_addr;
debug(3, "read entry header @ 0x%08x", ctx->addr);
CHECK_FLASH_OP(sdk_spi_flash_read(ctx->addr, &ctx->entry, ENTRY_HEADER_SIZE));
return SYSPARAM_OK;
}
static sysparam_status_t find_entry(struct sysparam_context *ctx, uint8_t match_id) {
/** Search through the region for an entry matching the specified id
*
* @param match_id The id to match, or 0 to match any key, or 0xff to scan
* to the end.
*/
static sysparam_status_t _find_entry(struct sysparam_context *ctx, uint8_t match_id) {
uint8_t prev_len;
while (ctx->addr + ENTRY_SIZE(ctx->entry.len) < sysparam_info.end_addr) {
while (ctx->addr + ENTRY_SIZE(ctx->entry.len) < _sysparam_info.end_addr) {
prev_len = ctx->entry.len;
ctx->addr += ENTRY_SIZE(ctx->entry.len);
@ -102,7 +140,7 @@ static sysparam_status_t find_entry(struct sysparam_context *ctx, uint8_t match_
// been corrupted and we don't even know if we're in the right
// place anymore. We have to bail out.
debug(1, "prev_len mismatch at 0x%08x (%d != %d)", ctx->addr, ctx->entry.prev_len, prev_len);
ctx->addr = sysparam_info.end_addr;
ctx->addr = _sysparam_info.end_addr;
return SYSPARAM_ERR_CORRUPT;
}
@ -132,28 +170,28 @@ static sysparam_status_t find_entry(struct sysparam_context *ctx, uint8_t match_
return SYSPARAM_NOTFOUND;
}
static inline sysparam_status_t read_payload(struct sysparam_context *ctx, uint8_t *buffer, size_t buffer_size) {
/** Read the payload from the current entry pointed to by `ctx` */
static inline sysparam_status_t _read_payload(struct sysparam_context *ctx, uint8_t *buffer, size_t buffer_size) {
debug(3, "read payload (%d) @ 0x%08x", min(buffer_size, ctx->entry.len), ctx->addr);
CHECK_FLASH_OP(sdk_spi_flash_read(ctx->addr + ENTRY_HEADER_SIZE, buffer, min(buffer_size, ctx->entry.len)));
//FIXME: check crc
return SYSPARAM_OK;
}
// Scan through the region to find the location of the key entry matching the
// specified name.
static sysparam_status_t find_key(struct sysparam_context *ctx, const char *key, uint8_t key_len, uint8_t *buffer) {
/** Find the entry corresponding to the specified key name */
static sysparam_status_t _find_key(struct sysparam_context *ctx, const char *key, uint8_t key_len, uint8_t *buffer) {
sysparam_status_t status;
while (true) {
// Find the next key entry
status = find_entry(ctx, 0);
status = _find_entry(ctx, 0);
if (status != SYSPARAM_OK) return status;
if (!key) {
// We're looking for the next (any) key, so we're done.
break;
}
if (ctx->entry.len == key_len) {
status = read_payload(ctx, buffer, key_len);
status = _read_payload(ctx, buffer, key_len);
if (status < 0) return status;
if (!memcmp(key, buffer, key_len)) {
// We have a match
@ -165,7 +203,8 @@ static sysparam_status_t find_key(struct sysparam_context *ctx, const char *key,
return SYSPARAM_OK;
}
static inline sysparam_status_t write_entry(uint32_t addr, uint8_t id, const uint8_t *payload, uint8_t len, uint8_t prev_len) {
/** Write an entry at the specified address */
static inline sysparam_status_t _write_entry(uint32_t addr, uint8_t id, const uint8_t *payload, uint8_t len, uint8_t prev_len) {
struct entry_header entry;
debug(2, "Writing entry 0x%02x @ 0x%08x", id, addr);
@ -181,7 +220,10 @@ static inline sysparam_status_t write_entry(uint32_t addr, uint8_t id, const uin
return SYSPARAM_OK;
}
static inline sysparam_status_t write_entry_tail(uint32_t addr, uint8_t prev_len) {
/** Write the "tail" entry on the end of the region
* (this entry just contains the `prev_len` field with all others set to 0xff)
*/
static inline sysparam_status_t _write_entry_tail(uint32_t addr, uint8_t prev_len) {
struct entry_header entry;
entry.prev_len = prev_len;
@ -194,7 +236,8 @@ static inline sysparam_status_t write_entry_tail(uint32_t addr, uint8_t prev_len
return SYSPARAM_OK;
}
static inline sysparam_status_t delete_entry(uint32_t addr) {
/** Mark an entry as "deleted" so it won't be considered in future reads */
static inline sysparam_status_t _delete_entry(uint32_t addr) {
struct entry_header entry;
debug(2, "Deleting entry @ 0x%08x", addr);
@ -208,16 +251,28 @@ static inline sysparam_status_t delete_entry(uint32_t addr) {
return SYSPARAM_OK;
}
static sysparam_status_t compact_params(struct sysparam_context *ctx, uint8_t *key_id) {
uint32_t new_base = sysparam_info.alt_base;
/** Compact the current region, removing all deleted/unused entries, and write
* the result to the alternate region, then make the new alternate region the
* active one.
*
* @param key_id A pointer to the "current" key ID.
*
* NOTE: The value corresponding to the passed key ID will not be written to
* the output (because it is assumed it will be overwritten as the next step
* in `sysparam_set_data` anyway). When compacting, this routine will
* automatically update *key_id to contain the ID of this key in the new
* compacted result as well.
*/
static sysparam_status_t _compact_params(struct sysparam_context *ctx, uint8_t *key_id) {
uint32_t new_base = _sysparam_info.alt_base;
sysparam_status_t status;
uint32_t addr = new_base + REGION_HEADER_SIZE;
uint8_t current_key_id = 0;
sysparam_iter_t iter;
uint8_t prev_len = 0;
debug(1, "compacting region (current size %d, expect to recover %d%s bytes)...", sysparam_info.end_addr - sysparam_info.cur_base, ctx->compactable, (ctx->unused_keys[0] || ctx->unused_keys[1]) ? "+ (unused keys present)" : "");
status = format_region(new_base);
debug(1, "compacting region (current size %d, expect to recover %d%s bytes)...", _sysparam_info.end_addr - _sysparam_info.cur_base, ctx->compactable, (ctx->unused_keys[0] || ctx->unused_keys[1]) ? "+ (unused keys present)" : "");
status = _format_region(new_base);
if (status < 0) return status;
status = sysparam_iter_start(&iter);
if (status < 0) return status;
@ -230,7 +285,7 @@ static sysparam_status_t compact_params(struct sysparam_context *ctx, uint8_t *k
// Write the key to the new region
debug(2, "writing %d key @ 0x%08x", current_key_id, addr);
status = write_entry(addr, current_key_id, (uint8_t *)iter.key, iter.key_len, prev_len);
status = _write_entry(addr, current_key_id, (uint8_t *)iter.key, iter.key_len, prev_len);
if (status < 0) break;
prev_len = iter.key_len;
addr += ENTRY_SIZE(iter.key_len);
@ -245,7 +300,7 @@ static sysparam_status_t compact_params(struct sysparam_context *ctx, uint8_t *k
// Copy the value to the new region
debug(2, "writing %d value @ 0x%08x", current_key_id, addr);
status = write_entry(addr, current_key_id | 0x80, iter.value, iter.value_len, prev_len);
status = _write_entry(addr, current_key_id | 0x80, iter.value, iter.value_len, prev_len);
if (status < 0) break;
prev_len = iter.value_len;
addr += ENTRY_SIZE(iter.value_len);
@ -253,7 +308,7 @@ static sysparam_status_t compact_params(struct sysparam_context *ctx, uint8_t *k
sysparam_iter_end(&iter);
if (status >= 0) {
status = write_entry_tail(addr, prev_len);
status = _write_entry_tail(addr, prev_len);
}
// If we broke out with an error, return the error instead of continuing.
@ -263,14 +318,14 @@ static sysparam_status_t compact_params(struct sysparam_context *ctx, uint8_t *k
}
// Switch to officially using the new region.
status = write_region_header(new_base, true);
status = _write_region_header(new_base, true);
if (status < 0) return status;
status = write_region_header(sysparam_info.cur_base, false);
status = _write_region_header(_sysparam_info.cur_base, false);
if (status < 0) return status;
sysparam_info.alt_base = sysparam_info.cur_base;
sysparam_info.cur_base = new_base;
sysparam_info.end_addr = addr;
_sysparam_info.alt_base = _sysparam_info.cur_base;
_sysparam_info.cur_base = new_base;
_sysparam_info.end_addr = addr;
// Fix up ctx so it doesn't point to invalid stuff
memset(ctx, 0, sizeof(*ctx));
@ -278,38 +333,38 @@ static sysparam_status_t compact_params(struct sysparam_context *ctx, uint8_t *k
ctx->entry.prev_len = prev_len;
ctx->max_key_id = current_key_id;
debug(1, "done compacting (current size %d)", sysparam_info.end_addr - sysparam_info.cur_base);
debug(1, "done compacting (current size %d)", _sysparam_info.end_addr - _sysparam_info.cur_base);
return SYSPARAM_OK;
}
/* Public Functions */
/***************************** Public Functions ******************************/
sysparam_status_t sysparam_init(uint32_t base_addr) {
sysparam_status_t status;
uint32_t magic0, magic1;
struct sysparam_context ctx;
sysparam_info.region_size = SYSPARAM_REGION_SECTORS * sdk_flashchip.sector_size;
_sysparam_info.region_size = SYSPARAM_REGION_SECTORS * sdk_flashchip.sector_size;
// First, see if we can find an existing one.
debug(3, "read magic @ 0x%08x", base_addr);
CHECK_FLASH_OP(sdk_spi_flash_read(base_addr, &magic0, 4));
debug(3, "read magic @ 0x%08x", base_addr + sysparam_info.region_size);
CHECK_FLASH_OP(sdk_spi_flash_read(base_addr + sysparam_info.region_size, &magic1, 4));
if (magic0 == SYSPARAM_MAGIC && magic1 == SYSPARAM_STALEMAGIC) {
debug(3, "read magic @ 0x%08x", base_addr + _sysparam_info.region_size);
CHECK_FLASH_OP(sdk_spi_flash_read(base_addr + _sysparam_info.region_size, &magic1, 4));
if (magic0 == SYSPARAM_ACTIVE_MAGIC && magic1 == SYSPARAM_STALE_MAGIC) {
// Sysparam area found, first region is active
sysparam_info.cur_base = base_addr;
sysparam_info.alt_base = base_addr + sysparam_info.region_size;
} else if (magic0 == SYSPARAM_STALEMAGIC && magic1 == SYSPARAM_MAGIC) {
_sysparam_info.cur_base = base_addr;
_sysparam_info.alt_base = base_addr + _sysparam_info.region_size;
} else if (magic0 == SYSPARAM_STALE_MAGIC && magic1 == SYSPARAM_ACTIVE_MAGIC) {
// Sysparam area found, second region is active
sysparam_info.cur_base = base_addr + sysparam_info.region_size;
sysparam_info.alt_base = base_addr;
} else if (magic0 == SYSPARAM_MAGIC && magic1 == SYSPARAM_MAGIC) {
_sysparam_info.cur_base = base_addr + _sysparam_info.region_size;
_sysparam_info.alt_base = base_addr;
} else if (magic0 == SYSPARAM_ACTIVE_MAGIC && magic1 == SYSPARAM_ACTIVE_MAGIC) {
// Both regions are marked as active. Not sure which to use.
// This can theoretically happen if something goes wrong at exactly the
// wrong time during compacting.
return SYSPARAM_ERR_CORRUPT;
} else if (magic0 == SYSPARAM_STALEMAGIC && magic1 == SYSPARAM_STALEMAGIC) {
} else if (magic0 == SYSPARAM_STALE_MAGIC && magic1 == SYSPARAM_STALE_MAGIC) {
// Both regions are marked as inactive. This shouldn't ever happen.
return SYSPARAM_ERR_CORRUPT;
} else {
@ -318,17 +373,17 @@ sysparam_status_t sysparam_init(uint32_t base_addr) {
}
// Find the actual end
sysparam_info.end_addr = sysparam_info.cur_base + sysparam_info.region_size;
init_context(&ctx);
status = find_entry(&ctx, 0xff);
_sysparam_info.end_addr = _sysparam_info.cur_base + _sysparam_info.region_size;
_init_context(&ctx);
status = _find_entry(&ctx, 0xff);
if (status < 0) {
sysparam_info.cur_base = 0;
sysparam_info.alt_base = 0;
sysparam_info.end_addr = 0;
_sysparam_info.cur_base = 0;
_sysparam_info.alt_base = 0;
_sysparam_info.end_addr = 0;
return status;
}
if (status == SYSPARAM_OK) {
sysparam_info.end_addr = ctx.addr;
_sysparam_info.end_addr = ctx.addr;
}
return SYSPARAM_OK;
@ -356,21 +411,21 @@ sysparam_status_t sysparam_create_area(uint32_t base_addr, bool force) {
}
}
if (sysparam_info.cur_base == base_addr || sysparam_info.alt_base == base_addr) {
if (_sysparam_info.cur_base == base_addr || _sysparam_info.alt_base == base_addr) {
// We're reformating the same region we're already using.
// De-initialize everything to force the caller to do a clean
// `sysparam_init()` afterwards.
memset(&sysparam_info, 0, sizeof(sysparam_info));
memset(&_sysparam_info, 0, sizeof(_sysparam_info));
}
status = format_region(base_addr);
status = _format_region(base_addr);
if (status < 0) return status;
status = format_region(base_addr + region_size);
status = _format_region(base_addr + region_size);
if (status < 0) return status;
status = write_entry_tail(base_addr + REGION_HEADER_SIZE, 0);
status = _write_entry_tail(base_addr + REGION_HEADER_SIZE, 0);
if (status < 0) return status;
status = write_region_header(base_addr + region_size, false);
status = _write_region_header(base_addr + region_size, false);
if (status < 0) return status;
status = write_region_header(base_addr, true);
status = _write_region_header(base_addr, true);
if (status < 0) return status;
return SYSPARAM_OK;
@ -382,24 +437,24 @@ sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *
size_t key_len = strlen(key);
uint8_t *buffer;
if (!sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
buffer = malloc(key_len + 2);
if (!buffer) return SYSPARAM_ERR_NOMEM;
do {
init_context(&ctx);
status = find_key(&ctx, key, key_len, buffer);
_init_context(&ctx);
status = _find_key(&ctx, key, key_len, buffer);
if (status != SYSPARAM_OK) break;
// Find the associated value
status = find_entry(&ctx, ctx.entry.id | 0x80);
status = _find_entry(&ctx, ctx.entry.id | 0x80);
if (status != SYSPARAM_OK) break;
buffer = realloc(buffer, ctx.entry.len + 1);
if (!buffer) {
return SYSPARAM_ERR_NOMEM;
}
status = read_payload(&ctx, buffer, ctx.entry.len);
status = _read_payload(&ctx, buffer, ctx.entry.len);
if (status != SYSPARAM_OK) break;
// Zero-terminate the result, just in case (doesn't hurt anything for
@ -413,7 +468,6 @@ sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *
} while (false);
free(buffer);
*destptr = NULL;
if (actual_length) *actual_length = 0;
return status;
}
@ -423,7 +477,7 @@ sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *buffer, siz
sysparam_status_t status = SYSPARAM_OK;
size_t key_len = strlen(key);
if (!sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
// Supplied buffer must be at least as large as the key, or 2 bytes,
// whichever is larger.
@ -431,12 +485,12 @@ sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *buffer, siz
if (actual_length) *actual_length = 0;
init_context(&ctx);
status = find_key(&ctx, key, key_len, buffer);
_init_context(&ctx);
status = _find_key(&ctx, key, key_len, buffer);
if (status != SYSPARAM_OK) return status;
status = find_entry(&ctx, ctx.entry.id | 0x80);
status = _find_entry(&ctx, ctx.entry.id | 0x80);
if (status != SYSPARAM_OK) return status;
status = read_payload(&ctx, buffer, buffer_size);
status = _read_payload(&ctx, buffer, buffer_size);
if (status != SYSPARAM_OK) return status;
if (actual_length) *actual_length = ctx.entry.len;
@ -450,54 +504,59 @@ sysparam_status_t sysparam_get_string(const char *key, char **destptr) {
}
sysparam_status_t sysparam_get_int(const char *key, int32_t *result) {
char buffer[32];
size_t len;
char *buffer;
char *endptr;
int32_t value;
sysparam_status_t status;
status = sysparam_get_data_static(key, (uint8_t *)buffer, 12, &len);
status = sysparam_get_string(key, &buffer);
if (status != SYSPARAM_OK) return status;
if (len > 31) return SYSPARAM_PARSEFAILED;
buffer[len] = 0;
value = strtol(buffer, &endptr, 0);
if (*endptr) return SYSPARAM_PARSEFAILED;
if (*endptr) {
// There was extra crap at the end of the string.
free(buffer);
return SYSPARAM_PARSEFAILED;
}
*result = value;
free(buffer);
return SYSPARAM_OK;
}
sysparam_status_t sysparam_get_bool(const char *key, bool *result) {
char buffer[6];
size_t len;
char *buffer;
int i;
sysparam_status_t status;
status = sysparam_get_data_static(key, (uint8_t *)buffer, 12, &len);
status = sysparam_get_string(key, &buffer);
if (status != SYSPARAM_OK) return status;
if (len > 5) return SYSPARAM_PARSEFAILED;
buffer[len] = 0;
for (i = 0; i < len; i++) {
// Quick and dirty tolower(). Not perfect, but works for our purposes,
// and avoids needing to pull in additional libc modules.
if (buffer[i] >= 0x41) buffer[i] |= 0x20;
}
if (!strcmp(buffer, "t")) {
*result = true;
} else if (!strcmp(buffer, "f")) {
*result = false;
} else if (!strcmp(buffer, "true")) {
*result = true;
} else if (!strcmp(buffer, "false")) {
*result = false;
} else if (!strcmp(buffer, "0")) {
*result = true;
} else if (!strcmp(buffer, "1")) {
*result = false;
} else {
return SYSPARAM_PARSEFAILED;
}
return SYSPARAM_OK;
do {
for (i = 0; buffer[i]; i++) {
// Quick-and-dirty tolower(). Not perfect, but works for our
// purposes, and avoids needing to pull in additional libc stuff.
if (buffer[i] >= 0x41) buffer[i] |= 0x20;
}
if (!strcmp(buffer, "y") ||
!strcmp(buffer, "yes") ||
!strcmp(buffer, "t") ||
!strcmp(buffer, "true") ||
!strcmp(buffer, "1")) {
*result = true;
break;
}
if (!strcmp(buffer, "n") ||
!strcmp(buffer, "no") ||
!strcmp(buffer, "f") ||
!strcmp(buffer, "false") ||
!strcmp(buffer, "0")) {
*result = false;
break;
}
status = SYSPARAM_PARSEFAILED;
} while (0);
free(buffer);
return status;
}
sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_t value_len) {
@ -512,7 +571,7 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
uint8_t key_id = 0;
uint32_t old_value_addr = 0;
if (!sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
if (!key_len) return SYSPARAM_ERR_BADVALUE;
if (value_len > 0xff) return SYSPARAM_ERR_BADVALUE;
@ -525,7 +584,7 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
value = buffer;
free_value = true;
}
// Create a working buffer for `find_key` to use.
// Create a working buffer for `_find_key` to use.
buffer = malloc(key_len);
if (!buffer) {
if (free_value) free((void *)value);
@ -533,12 +592,12 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
}
do {
init_context(&ctx);
status = find_key(&ctx, key, key_len, buffer);
_init_context(&ctx);
status = _find_key(&ctx, key, key_len, buffer);
if (status == SYSPARAM_OK) {
// Key already exists, see if there's a current value.
key_id = ctx.entry.id;
status = find_entry(&ctx, key_id | 0x80);
status = _find_entry(&ctx, key_id | 0x80);
if (status == SYSPARAM_OK) {
old_value_addr = ctx.addr;
}
@ -553,7 +612,7 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
buffer = realloc(buffer, value_len);
if (!buffer) return SYSPARAM_ERR_NOMEM;
}
status = read_payload(&ctx, buffer, value_len);
status = _read_payload(&ctx, buffer, value_len);
if (status == SYSPARAM_ERR_CORRUPT) {
// If the CRC check failed, don't worry about it. We're
// going to be deleting this entry anyway.
@ -575,7 +634,7 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
// Append new value to the end, but first make sure we have enough
// space.
free_space = sysparam_info.cur_base + sysparam_info.region_size - sysparam_info.end_addr - 4;
free_space = _sysparam_info.cur_base + _sysparam_info.region_size - _sysparam_info.end_addr - 4;
needed_space = ENTRY_SIZE(value_len);
if (!key_id) {
// We did not find a previous key entry matching this key. We
@ -587,10 +646,10 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
// Can we compact things?
// First, scan all remaining entries up to the end so we can
// get a reasonably accurate "compactable" reading.
find_entry(&ctx, 0xff);
_find_entry(&ctx, 0xff);
if (needed_space <= free_space + ctx.compactable) {
// We should be able to get enough space by compacting.
status = compact_params(&ctx, &key_id);
status = _compact_params(&ctx, &key_id);
if (status < 0) break;
old_value_addr = 0;
} else if (ctx.unused_keys[0] || ctx.unused_keys[1]) {
@ -598,11 +657,11 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
// there are some keys that can be omitted too, but we
// don't know exactly how much that will gain, so all we
// can do is give it a try and see if it gives us enough.
status = compact_params(&ctx, &key_id);
status = _compact_params(&ctx, &key_id);
if (status < 0) break;
old_value_addr = 0;
}
free_space = sysparam_info.cur_base + sysparam_info.region_size - sysparam_info.end_addr - 4;
free_space = _sysparam_info.cur_base + _sysparam_info.region_size - _sysparam_info.end_addr - 4;
}
if (needed_space > free_space) {
// Nothing we can do here.. We're full.
@ -617,14 +676,14 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
if (!key_id) {
// We need to write a key entry for a new key.
// If we didn't find the key, then we already know find_entry
// If we didn't find the key, then we already know _find_entry
// has gone through the entire contents, and thus
// ctx.max_key_id has the largest key_id found in the whole
// region.
key_id = ctx.max_key_id + 1;
if (key_id > MAX_KEY_ID) {
if (ctx.unused_keys[0] || ctx.unused_keys[1]) {
status = compact_params(&ctx, &key_id);
status = _compact_params(&ctx, &key_id);
if (status < 0) break;
old_value_addr = 0;
} else {
@ -633,24 +692,24 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
break;
}
}
status = write_entry(write_ctx.addr, key_id, (uint8_t *)key, key_len, write_ctx.entry.prev_len);
status = _write_entry(write_ctx.addr, key_id, (uint8_t *)key, key_len, write_ctx.entry.prev_len);
if (status < 0) break;
write_ctx.addr += ENTRY_SIZE(key_len);
write_ctx.entry.prev_len = key_len;
}
// Write new value
status = write_entry(write_ctx.addr, key_id | 0x80, value, value_len, write_ctx.entry.prev_len);
status = _write_entry(write_ctx.addr, key_id | 0x80, value, value_len, write_ctx.entry.prev_len);
if (status < 0) break;
write_ctx.addr += ENTRY_SIZE(value_len);
status = write_entry_tail(write_ctx.addr, value_len);
status = _write_entry_tail(write_ctx.addr, value_len);
if (status < 0) break;
sysparam_info.end_addr = write_ctx.addr;
_sysparam_info.end_addr = write_ctx.addr;
}
// Delete old value (if present) by setting it's id to 0x00
if (old_value_addr) {
status = delete_entry(old_value_addr);
status = _delete_entry(old_value_addr);
if (status < 0) break;
}
} while (false);
@ -675,12 +734,12 @@ sysparam_status_t sysparam_set_int(const char *key, int32_t value) {
sysparam_status_t sysparam_set_bool(const char *key, bool value) {
uint8_t buf[4] = {0xff, 0xff, 0xff, 0xff};
buf[0] = value ? 't' : 'f';
buf[0] = value ? 'y' : 'n';
return sysparam_set_data(key, buf, 1);
}
sysparam_status_t sysparam_iter_start(sysparam_iter_t *iter) {
if (!sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
iter->bufsize = DEFAULT_ITER_BUF_SIZE;
iter->key = malloc(iter->bufsize);
@ -696,7 +755,7 @@ sysparam_status_t sysparam_iter_start(sysparam_iter_t *iter) {
iter->bufsize = 0;
return SYSPARAM_ERR_NOMEM;
}
init_context(iter->ctx);
_init_context(iter->ctx);
return SYSPARAM_OK;
}
@ -710,11 +769,11 @@ sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
size_t key_space;
while (true) {
status = find_key(ctx, NULL, 0, buffer);
status = _find_key(ctx, NULL, 0, buffer);
if (status != SYSPARAM_OK) return status;
memcpy(&value_ctx, ctx, sizeof(value_ctx));
status = find_entry(&value_ctx, ctx->entry.id | 0x80);
status = _find_entry(&value_ctx, ctx->entry.id | 0x80);
if (status < 0) return status;
if (status == SYSPARAM_NOTFOUND) continue;
@ -729,14 +788,14 @@ sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
iter->bufsize = required_len;
}
status = read_payload(ctx, (uint8_t *)iter->key, iter->bufsize);
status = _read_payload(ctx, (uint8_t *)iter->key, iter->bufsize);
if (status < 0) return status;
// Null-terminate the key
iter->key[ctx->entry.len] = 0;
iter->key_len = ctx->entry.len;
iter->value = (uint8_t *)(iter->key + key_space);
status = read_payload(&value_ctx, iter->value, iter->bufsize - key_space);
status = _read_payload(&value_ctx, iter->value, iter->bufsize - key_space);
if (status < 0) return status;
// Null-terminate the value (just in case)
iter->value[value_ctx.entry.len] = 0;