From eb41dd93db544c0426617d45c5fe11aa6773a954 Mon Sep 17 00:00:00 2001 From: "S.J.R. van Schaik" Date: Sun, 12 Mar 2017 00:33:09 +0000 Subject: [PATCH] shell: separate code --- Makefile | 3 +- include/shell.h | 4 +- source/shell/cmd.c | 81 ++++++++++++++++++++ source/shell/flash.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 296 insertions(+), 2 deletions(-) create mode 100644 source/shell/cmd.c create mode 100644 source/shell/flash.c diff --git a/Makefile b/Makefile index a38e3d8..cee6b6d 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,8 @@ CFLAGS += -Wall -Wundef -Wextra -Wshadow -Wimplicit-function-declaration CFLAGS += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes obj-y += source/main.o -obj-y += source/shell.o +obj-y += source/shell/cmd.o +obj-y += source/shell/flash.o obj-y += source/core/flash.o diff --git a/include/shell.h b/include/shell.h index 53ce419..7953af5 100644 --- a/include/shell.h +++ b/include/shell.h @@ -2,7 +2,9 @@ struct cmd { const char *key; - void (* exec)(const char *s); + void (* exec)(const char *line); }; +void do_flash_cmd(const char *line); +void cmd_exec(struct cmd *cmds, const char *line); void cmd_loop(const char *s); diff --git a/source/shell/cmd.c b/source/shell/cmd.c new file mode 100644 index 0000000..cb3fac4 --- /dev/null +++ b/source/shell/cmd.c @@ -0,0 +1,81 @@ +#include +#include +#include + +#include + +struct cmd main_cmds[] = { + { "flash", do_flash_cmd }, + { NULL, NULL }, +}; + +static char *prompt(const char *prefix) +{ + char *alloc, *line, *s; + size_t nbytes = 0, nalloc_bytes = 16; + char c; + + printf(prefix); + + if (!(line = malloc(nalloc_bytes))) + return NULL; + + s = line; + + while ((c = getchar()) && c != '\n') { + putchar(c); + + if (nbytes + 1 >= nalloc_bytes) { + nalloc_bytes *= 2; + + if (!(alloc = realloc(line, nalloc_bytes))) + goto err_free_line; + + line = alloc; + } + + *s++ = c; + nbytes++; + } + + printf("\n"); + *s = '\0'; + + return line; + +err_free_line: + free(line); + return NULL; +} + +void cmd_exec(struct cmd *cmds, const char *line) +{ + struct cmd *cmd; + const char *args; + char *key; + size_t n; + + n = strcspn(line, " \n"); + key = strndup(line, n); + + args = line + n; + args += strspn(args, " \n"); + + for (cmd = cmds; cmd->key; ++cmd) { + if (strcmp(cmd->key, key) == 0) { + cmd->exec(args); + return; + } + } +} + +void cmd_loop(const char *show) +{ + char *line; + + while (1) { + line = prompt(show); + cmd_exec(main_cmds, line); + free(line); + } +} diff --git a/source/shell/flash.c b/source/shell/flash.c new file mode 100644 index 0000000..7bd992e --- /dev/null +++ b/source/shell/flash.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +static void do_flash_probe(const char *s); +static void do_flash_read(const char *s); +static void do_flash_write(const char *s); +static void do_flash_erase(const char *s); + +static struct cmd flash_cmds[] = { + { "probe", do_flash_probe }, + { "read", do_flash_read }, + { "write", do_flash_write }, + { "erase", do_flash_erase }, + { NULL, NULL }, +}; + +static struct flash_dev *flash = NULL; + +/* TODO: implement a parser for hex arrays that is more user-friendly. + * Also implement dry runs for programmers. */ +static void parse_hex(FILE *fp, char *buf, size_t len) +{ + size_t i; + char s[3]; + + for (i = 0; i < len; ++i) { + memset(s, '\0', 3); + + while ((s[0] = getc(fp)) && !isxdigit(s[0])) + putchar(s[0]); + + putchar(s[0]); + + while ((s[1] = getc(fp)) && !isxdigit(s[1])) + putchar(s[1]); + + putchar(s[1]); + + *buf++ = strtoul(s, NULL, 16); + } +} + +static void print_hex_ascii(const char *buf, size_t len) +{ + size_t n, i; + uint8_t c; + + for (; len; buf += n, len -= n) { + n = min(len, 16); + + for (i = 0; i < 16; ++i) { + c = (i < n) ? buf[i] : 0; + printf("%x", c); + } + + printf(" "); + + for (i = 0; i < 16; ++i) { + c = (i < n) ? buf[i] : 0; + printf("%c", isalnum(c) ? c : '.'); + } + + printf("\n"); + } +} + +static void do_flash_probe(const char *s) +{ + (void)s; + + flash = flash_probe(); +} + +static void do_flash_read(const char *s) +{ + char buf[256], *end = NULL; + size_t addr, len, nbytes; + + if (!flash) { + fprintf(stderr, "error: no flash device probed.\n"); + return; + } + + if (strncmp(s, "0x", 2) == 0) + s += 2; + + addr = strtoull(s, &end, 16); + s = end; + + if (errno == EINVAL || errno == ERANGE) + return; + + s += strspn(s, " \n"); + + if (strncmp(s, "0x", 2) == 0) + s += 2; + + len = strtoull(s, &end, 16); + s = end; + + if (errno == EINVAL || errno == ERANGE) + return; + + if (!len) + return; + + while (len) { + nbytes = min(len, 256); + flash_read(flash, addr, buf, nbytes); + print_hex_ascii(buf, nbytes); + + addr += nbytes; + len -= nbytes; + } +} + +static void do_flash_write(const char *s) +{ + char buf[256], *end = NULL; + size_t addr, len, nbytes; + + if (!flash) { + fprintf(stderr, "error: no flash device probed.\n"); + return; + } + + if (strncmp(s, "0x", 2) == 0) + s += 2; + + addr = strtoull(s, &end, 16); + s = end; + + if (errno == EINVAL || errno == ERANGE) + return; + + s += strspn(s, " \n"); + + if (strncmp(s, "0x", 2) == 0) + s += 2; + + len = strtoull(s, &end, 16); + s = end; + + if (errno == EINVAL || errno == ERANGE) + return; + + if (!len) + return; + + while (len) { + nbytes = (len > 256) ? 256 : len; + parse_hex(stdin, buf, nbytes); + printf("\n"); + print_hex_ascii(buf, nbytes); + flash_write(flash, addr, buf, nbytes); + + addr += nbytes; + len -= nbytes; + } +} + +static void do_flash_erase(const char *s) +{ + char *end = NULL; + size_t addr, len; + + if (!flash) { + fprintf(stderr, "error: no flash device probed.\n"); + return; + } + + if (strncmp(s, "0x", 2) == 0) + s += 2; + + addr = strtoull(s, &end, 16); + s = end; + + if (errno == EINVAL || errno == ERANGE) + return; + + s += strspn(s, " \n"); + + if (strncmp(s, "0x", 2) == 0) + s += 2; + + len = strtoull(s, &end, 16); + s = end; + + if (errno == EINVAL || errno == ERANGE) + return; + + if (!len) + return; + + flash_erase(flash, addr, len); +} + +void do_flash_cmd(const char *line) +{ + cmd_exec(flash_cmds, line); +}