integrate microvty

This commit is contained in:
Harald Welte 2021-03-28 15:32:31 +02:00
parent 8bcec75693
commit f962556911
9 changed files with 198 additions and 7 deletions

View File

@ -0,0 +1,44 @@
#pragma once
#include <stdbool.h>
/* micrVTY - small implementation of a limited feature command line interface
* (C) 2019 by Harald Welte <laforge@gnumonks.org>
*
* 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 __attribute__((unused)), \
char **argv __attribute__((unused)))
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);

View File

@ -35,3 +35,10 @@ static int my_flush(FILE *file)
static FILE __stdio = FDEV_SETUP_STREAM(my_putc, my_getc, my_flush, _FDEV_SETUP_RW);
FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio };
#include <libcommon/microvty.h>
bool microvty_cb_uart_rx_not_empty(void)
{
return usart_get_flag(stdio_usart, USART_SR_RXNE);
}

View File

@ -89,3 +89,11 @@ static FILE __stdout = FDEV_SETUP_STREAM(my_stdout_putc, NULL, my_stdout_flush,
static FILE __stderr = FDEV_SETUP_STREAM(my_stderr_putc, NULL, NULL, _FDEV_SETUP_WRITE);
FILE *const __iob[3] = { &__stdin, &__stdout, &__stderr };
#include <libcommon/microvty.h>
bool microvty_cb_uart_rx_not_empty(void)
{
return !ringbuf_empty(&inring);
}

124
libcommon/src/microvty.c Normal file
View File

@ -0,0 +1,124 @@
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <libcommon/utils.h>
#include <libcommon/microvty.h>
/* microVTY - small implementation of a limited feature command line interface
* (C) 2019 by Harald Welte <laforge@gnumonks.org>
*
* 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(void)
{
char *argv[16];
unsigned int i;
unsigned int argc = 0;
char *cur, *saveptr = NULL;
printf("\r\n");
memset(argv, 0, sizeof(argv));
for (cur = strtok_r(g_cmds.buf, " ", &saveptr); cur; cur = strtok_r(NULL, " ", &saveptr)) {
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);
}

View File

@ -41,9 +41,9 @@ OOCD_TARGET ?= stm32f1x
ARCH_FLAGS += --specs=/usr/lib/picolibc/arm-none-eabi/picolibc.specs
LIBCOMMON_DIR = ../../libcommon
CPPFLAGS += -I$(LIBCOMMON_DIR)/include
CPPFLAGS += -I$(LIBCOMMON_DIR)/include -D_GNU_SOURCE
vpath %.c $(LIBCOMMON_DIR)/src/
OBJS += watchdog.o fault.o iob_stm32_nonblocking.o kill.o
OBJS += watchdog.o fault.o iob_stm32_nonblocking.o kill.o microvty.o
all: elf bin srec

View File

@ -6,8 +6,9 @@
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <libcommon/utils.h>
#include "attenuator.h"
#include "utils.h"
static const struct attenuator_cfg *g_att_cfg;
static struct attenuator_state **g_att_state;

View File

@ -1,8 +1,9 @@
#include <libopencm3/stm32/gpio.h>
#include <libcommon/utils.h>
#include "attenuator.h"
#include "utils.h"
#define NUM_CHAN 4
#define NUM_STAGE 2

View File

@ -25,6 +25,7 @@
#include <libopencm3/cm3/systick.h>
#include <libcommon/iob.h>
#include <libcommon/microvty.h>
#include <stdio.h>
@ -104,7 +105,7 @@ static void usart_setup(void)
usart_set_baudrate(USART1, 115200);
usart_set_databits(USART1, 8);
usart_set_stopbits(USART1, USART_STOPBITS_1);
usart_set_mode(USART1, USART_MODE_TX);
usart_set_mode(USART1, USART_MODE_TX_RX);
usart_set_parity(USART1, USART_PARITY_NONE);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
/* Finally enable the USART. */
@ -119,7 +120,7 @@ static void usart_setup(void)
usart_set_baudrate(USART2, 115200);
usart_set_databits(USART2, 8);
usart_set_stopbits(USART2, USART_STOPBITS_1);
usart_set_mode(USART2, USART_MODE_TX);
usart_set_mode(USART2, USART_MODE_TX_RX);
usart_set_parity(USART2, USART_PARITY_NONE);
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
/* Finally enable the USART. */
@ -141,12 +142,17 @@ int main(void)
iob_init(USART2);
i2c_setup();
attenuator_init(&board_att_cfg, board_att_st);
microvty_init("rfdsat4ch> ");
printf("Welcome to RFDSATT\r\n");
fprintf(stderr, "Welcome to stderr\r\n");
/* Blink the LED (PB15) on the board with every transmitted byte. */
while (1) {
int i;
gpio_toggle(GPIOB, GPIO15); /* LED on/off */
printf("Hello world\r\n");
//printf("Hello world\r\n");
microvty_try_recv();
for (i = 0; i < 800000; i++) /* Wait a bit. */
__asm__("nop");
}