diff --git a/sam/utils/make/Makefile.sam.in b/sam/utils/make/Makefile.sam.in index 23c66977..96f41bbf 100644 --- a/sam/utils/make/Makefile.sam.in +++ b/sam/utils/make/Makefile.sam.in @@ -132,7 +132,7 @@ AS := $(CROSS)as CC := $(CROSS)gcc CPP := $(CROSS)gcc -E CXX := $(CROSS)g++ -LD := $(CROSS)g++ +LD := $(CROSS)gcc NM := $(CROSS)nm OBJCOPY := $(CROSS)objcopy OBJDUMP := $(CROSS)objdump diff --git a/thirdparty/microvty/microvty.c b/thirdparty/microvty/microvty.c new file mode 100644 index 00000000..27b3a8e4 --- /dev/null +++ b/thirdparty/microvty/microvty.c @@ -0,0 +1,124 @@ +#include +#include +#include + +#include +#include "microvty.h" + +/* microVTY - small implementation of a limited feature command line interface + * (C) 2019 by Harald Welte + * + * modelled after libosmovty (part of libosmocore.git), which in turn is a fork + * of the command line interface of GNU zebra / quagga. + * + * microVTY is intended for very small bare-iron microcontroller. It doesn't need + * any dynamic allocations/heap, and tries to stay very simplistic to conserve + * resources. + */ + +struct microvty_state { + const char *prompt; + char buf[MICROVTY_CMD_BUF_SIZE]; + unsigned int buf_idx; + const struct microvty_fn *cmd[MICROVTY_MAX_CMD]; + unsigned int cmd_idx; +}; + +static struct microvty_state g_cmds; + +/*! register a command with microVTY */ +int microvty_register(const struct microvty_fn *cmd) +{ + if (g_cmds.cmd_idx >= ARRAY_SIZE(g_cmds.cmd)) + return -1; + g_cmds.cmd[g_cmds.cmd_idx++] = cmd; + return 0; +} + +/*! built-in help command */ +DEFUN(help, help_cmd, "help", "Print command reference") +{ + unsigned int i; + printf("Help:\r\n"); + printf(" Command Help\r\n"); + printf(" ---------------- ----\r\n"); + for (i = 0; i < g_cmds.cmd_idx; i++) + printf(" %-16s %s\r\n", g_cmds.cmd[i]->command, g_cmds.cmd[i]->help); +} + +static void cmd_execute() +{ + char *argv[16]; + unsigned int i; + int argc = 0; + char *cur; + + printf("\r\n"); + memset(argv, 0, sizeof(argv)); + + for (cur = strtok(g_cmds.buf, " "); cur; cur = strtok(NULL, " ")) { + if (argc >= ARRAY_SIZE(argv)) + break; + argv[argc++] = cur; + } + + for (i = 0; i < g_cmds.cmd_idx; i++) { + if (!strcmp(g_cmds.cmd[i]->command, argv[0])) { + g_cmds.cmd[i]->fn(argc, argv); + return; + } + } + printf("Unknown command: '%s'\r\n", argv[0]); +} + +static void cmd_buf_reset(void) +{ + memset(g_cmds.buf, 0, sizeof(g_cmds.buf)); + g_cmds.buf_idx = 0; +} + +static void cmd_buf_append(char c) +{ + g_cmds.buf[g_cmds.buf_idx++] = c; +} + +/*! print the prompt to the console (stdout) */ +void microvty_print_prompt(void) +{ + printf(g_cmds.prompt); +} + +/*! try to receive characters from the console, dispatching them */ +void microvty_try_recv(void) +{ + unsigned int i = 0; + + /* yield CPU after maximum of 10 received characters */ + while (microvty_cb_uart_rx_not_empty() && (i < 10)) { + int c = getchar(); + if (c < 0) + return; + if (c == '\r' || c == '\n' || g_cmds.buf_idx >= sizeof(g_cmds.buf)-1) { + /* skip empty commands */ + if (g_cmds.buf_idx == 0) + return; + cmd_execute(); + cmd_buf_reset(); + printf(g_cmds.prompt); + return; + } else { + /* print + append character */ + putchar(c); + cmd_buf_append(c); + } + + i++; + } +} + +/* initialize microVTY. Should be called once on start-up */ +void microvty_init(const char *prompt) +{ + g_cmds.prompt = prompt; + microvty_register(&help_cmd); +} diff --git a/thirdparty/microvty/microvty.h b/thirdparty/microvty/microvty.h new file mode 100644 index 00000000..17aca559 --- /dev/null +++ b/thirdparty/microvty/microvty.h @@ -0,0 +1,42 @@ +#pragma once + +/* micrVTY - small implementation of a limited feature command line interface + * (C) 2019 by Harald Welte + * + * modelled after libosmovty (part of libosmocore.git), which in turn is a fork + * of the command line interface of GNU zebra / quagga. + * + * microVTY is intended for very small bare-iron microcontroller. It doesn't need + * any dynamic allocations/heap, and tries to stay very simplistic to conserve + * resources. + */ + +/*! Total size in bytes for microvty command buffer (max command line length) */ +#define MICROVTY_CMD_BUF_SIZE 128 + +/*! Maximum number of VTY commands that can be registered with microvty_register() */ +#define MICROVTY_MAX_CMD 32 + +struct microvty_fn { + const char *command; + const char *help; + void (*fn)(int argc, char **argv); +}; + +#define DEFUN(funcname, cmdname, cmdstr, helpstr) \ + static void funcname(int argc, char **argv); \ + static struct microvty_fn cmdname = { \ + .command = cmdstr, \ + .help = helpstr, \ + .fn = funcname, \ + }; \ + static void funcname(int argc, char **argv) + +void microvty_init(const char *prompt); +int microvty_register(const struct microvty_fn *cmd); +void microvty_try_recv(void); +void microvty_print_prompt(void); + +/* to be provided by implementation: tell the code if UART Rx is non- + * empty and hence if a subsequent getchar() would return something */ +bool microvty_cb_uart_rx_not_empty(void);