diff --git a/examples/sysparam_editor/Makefile b/examples/sysparam_editor/Makefile new file mode 100644 index 0000000..a7843f3 --- /dev/null +++ b/examples/sysparam_editor/Makefile @@ -0,0 +1,14 @@ +PROGRAM=sysparam_editor + +# Setting this to 1..3 will add extra debugging output to stdout +EXTRA_CFLAGS=-DSYSPARAM_DEBUG=0 + +include ../../common.mk + +# `make dump-flash` can be used to view the current contents of the sysparam +# regions in flash. +dump-flash: + esptool.py read_flash 0x1fa000 4096 r1.bin + hexdump -C r1.bin + esptool.py read_flash 0x1fb000 4096 r2.bin + hexdump -C r2.bin diff --git a/examples/sysparam_editor/sysparam_editor.c b/examples/sysparam_editor/sysparam_editor.c new file mode 100644 index 0000000..ac8fee1 --- /dev/null +++ b/examples/sysparam_editor/sysparam_editor.c @@ -0,0 +1,158 @@ +#include "FreeRTOS.h" +#include "task.h" +#include +#include +#include +#include + +#define CMD_BUF_SIZE 512 + +// This is just below the upper-4 sdk-reserved sectors for a 16mbit flash +// Note that the sysparam area will take up two sectors (0x1FAxxx and 0x1FBxxx) +#define SYSPARAM_ADDR 0x1fa000 + +const int status_base = -6; +const char *status_messages[] = { + "SYSPARAM_ERR_NOMEM", + "SYSPARAM_ERR_CORRUPT", + "SYSPARAM_ERR_IO", + "SYSPARAM_ERR_FULL", + "SYSPARAM_ERR_BADVALUE", + "SYSPARAM_ERR_NOINIT", + "SYSPARAM_OK", + "SYSPARAM_NOTFOUND", + "SYSPARAM_PARSEFAILED", +}; + +void usage(void) { + printf( + "Available commands:\n" + " ? -- Query the value of \n" + " = -- Set to \n" + " dump -- Show all currently set keys/values\n" + " reformat -- Reinitialize (clear) the sysparam area\n" + " help -- Show this help screen\n" + ); +} + +size_t tty_readline(char *buffer, size_t buf_size, bool echo) { + size_t i = 0; + int c; + + while (true) { + c = getchar(); + if (c == '\r') { + if (echo) putchar('\n'); + break; + } else if (c == '\b' || c == 0x7f) { + if (i) { + if (echo) printf("\b \b"); + i--; + } + } else if (c < 0x20) { + /* Ignore other control characters */ + } else if (i >= buf_size - 1) { + if (echo) putchar('\a'); + } else { + buffer[i++] = c; + if (echo) putchar(c); + } + } + + buffer[i] = 0; + return i; +} + +sysparam_status_t dump_params(void) { + sysparam_status_t status; + sysparam_iter_t iter; + + status = sysparam_iter_start(&iter); + if (status < 0) return status; + while (true) { + status = sysparam_iter_next(&iter); + if (status != SYSPARAM_OK) break; + printf(" %s=%s\n", iter.key, iter.value); + } + sysparam_iter_end(&iter); + + if (status == SYSPARAM_NOTFOUND) { + // This is the normal status when we've reached the end of all entries. + return SYSPARAM_OK; + } else { + // Something apparently went wrong + return status; + } +} + +void sysparam_editor_task(void *pvParameters) { + char *cmd_buffer = malloc(CMD_BUF_SIZE); + sysparam_status_t status; + char *value; + size_t len; + + if (!cmd_buffer) { + printf("ERROR: Cannot allocate command buffer!\n"); + return; + } + + // NOTE: Eventually, this initialization part will be done automatically on + // system startup, so the app won't need to do it. + printf("Initializing sysparam...\n"); + status = sysparam_init(SYSPARAM_ADDR); + printf("(status %d)\n", status); + if (status == SYSPARAM_NOTFOUND) { + printf("Trying to create new sysparam area...\n"); + status = sysparam_create_area(SYSPARAM_ADDR, false); + printf("(status %d)\n", status); + if (status == SYSPARAM_OK) { + status = sysparam_init(SYSPARAM_ADDR); + printf("(status %d)\n", status); + } + } + + while (true) { + printf("==> "); + len = tty_readline(cmd_buffer, CMD_BUF_SIZE, true); + status = 0; + if (!len) continue; + if (cmd_buffer[len - 1] == '?') { + cmd_buffer[len - 1] = 0; + printf("Querying '%s'...\n", cmd_buffer); + status = sysparam_get_string(cmd_buffer, &value); + if (status == SYSPARAM_OK) { + printf(" '%s' = '%s'\n", cmd_buffer, value); + } + free(value); + } else if ((value = strchr(cmd_buffer, '='))) { + *value++ = 0; + printf("Setting '%s' to '%s'...\n", cmd_buffer, value); + status = sysparam_set_string(cmd_buffer, value); + } else if (!strcmp(cmd_buffer, "dump")) { + printf("Dumping all params:\n"); + status = dump_params(); + } else if (!strcmp(cmd_buffer, "reformat")) { + printf("Re-initializing region...\n"); + status = sysparam_create_area(SYSPARAM_ADDR, true); + if (status == SYSPARAM_OK) { + // We need to re-init after wiping out the region we've been + // using. + status = sysparam_init(SYSPARAM_ADDR); + } + } else if (!strcmp(cmd_buffer, "help")) { + usage(); + } else { + printf("Unrecognized command.\n\n"); + usage(); + } + + if (status != SYSPARAM_OK) { + printf("! Operation returned status: %d (%s)\n", status, status_messages[status - status_base]); + } + } +} + +void user_init(void) +{ + xTaskCreate(sysparam_editor_task, (signed char *)"sysparam_editor_task", 512, NULL, 2, NULL); +}