subsys: console: Add buffered output support to console subsystem

Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This commit is contained in:
Paul Sokolovsky 2017-04-10 10:47:28 +03:00 committed by Anas Nashif
commit 3cb13b9687
9 changed files with 127 additions and 12 deletions

View file

@ -13,16 +13,17 @@
extern "C" { extern "C" {
#endif #endif
/** @brief Initialize console_getchar() call. /** @brief Initialize console_getchar()/putchar() calls.
* *
* This function should be called once to initialize pull-style * This function should be called once to initialize pull-style
* access to console via console_getchar() function. This function * access to console via console_getchar() function and buffered
* supersedes, and incompatible with, callback (push-style) console * output using console_putchar() function. This function supercedes,
* handling (via console_input_fn callback, etc.). * and incompatible with, callback (push-style) console handling
* (via console_input_fn callback, etc.).
* *
* @return N/A * @return N/A
*/ */
void console_getchar_init(void); void console_init(void);
/** @brief Get next char from console input buffer. /** @brief Get next char from console input buffer.
* *
@ -38,6 +39,15 @@ void console_getchar_init(void);
*/ */
u8_t console_getchar(void); u8_t console_getchar(void);
/** @brief Output a char to console (buffered).
*
* Puts a character into console output buffer. It will be sent
* to a console asynchronously, e.g. using an IRQ handler.
*
* @return -1 on output buffer overflow, otherwise 0.
*/
int console_putchar(char c);
/** @brief Initialize console_getline() call. /** @brief Initialize console_getline() call.
* *
* This function should be called once to initialize pull-style * This function should be called once to initialize pull-style

View file

@ -0,0 +1,4 @@
BOARD ?= qemu_x86
CONF_FILE = prj.conf
include ${ZEPHYR_BASE}/Makefile.inc

View file

@ -0,0 +1,4 @@
CONFIG_CONSOLE_PULL=y
CONFIG_CONSOLE_GETCHAR=y
CONFIG_CONSOLE_GETCHAR_BUFSIZE=64
CONFIG_CONSOLE_PUTCHAR_BUFSIZE=512

View file

@ -0,0 +1 @@
obj-y += main.o

View file

@ -0,0 +1,16 @@
#include <zephyr.h>
#include <console.h>
void main(void)
{
console_init();
while (1) {
u8_t c = console_getchar();
console_putchar(c);
if (c == '\r') {
console_putchar('\n');
}
}
}

View file

@ -0,0 +1,8 @@
[test]
tags = samples
build_only = true
# TODO:
# #error "Interrupt not available in uart riscv32-qemu"
# #error "Interrupt-driven Altera JTAG UART not implemented yet"
platform_exclude = qemu_riscv32 qemu_nios2
filter = CONFIG_UART_CONSOLE

View file

@ -4,7 +4,7 @@
void main(void) void main(void)
{ {
console_getchar_init(); console_init();
while (1) { while (1) {
u8_t c = console_getchar(); u8_t c = console_getchar();

View file

@ -18,7 +18,7 @@ choice
prompt "Console 'get' function selection" prompt "Console 'get' function selection"
config CONSOLE_GETCHAR config CONSOLE_GETCHAR
bool "Character by character input" bool "Character by character input and output"
select UART_CONSOLE_DEBUG_SERVER_HOOKS select UART_CONSOLE_DEBUG_SERVER_HOOKS
select CONSOLE_HANDLER select CONSOLE_HANDLER
@ -38,6 +38,15 @@ config CONSOLE_GETCHAR_BUFSIZE
default is optimized to save RAM. You may need to increase default is optimized to save RAM. You may need to increase
it e.g. to support large host-side clipboard pastes. it e.g. to support large host-side clipboard pastes.
config CONSOLE_PUTCHAR_BUFSIZE
int "console_putchar() buffer size"
default 16
help
Buffer size for console_putchar(). Must be power of 2. The
default is optimized to save RAM. You may need to increase
it e.g. to support large host-side clipboard pastes (with
echo).
endif # CONSOLE_GETCHAR endif # CONSOLE_GETCHAR
endif # CONSOLE_PULL endif # CONSOLE_PULL

View file

@ -7,6 +7,7 @@
#include <zephyr.h> #include <zephyr.h>
#include <uart.h> #include <uart.h>
#include <misc/printk.h> #include <misc/printk.h>
#include <console.h>
#include <drivers/console/console.h> #include <drivers/console/console.h>
#include <drivers/console/uart_console.h> #include <drivers/console/uart_console.h>
@ -14,16 +15,58 @@
#error CONFIG_CONSOLE_GETCHAR_BUFSIZE must be power of 2 #error CONFIG_CONSOLE_GETCHAR_BUFSIZE must be power of 2
#endif #endif
#if CONFIG_CONSOLE_PUTCHAR_BUFSIZE & (CONFIG_CONSOLE_PUTCHAR_BUFSIZE - 1) != 0
#error CONFIG_CONSOLE_PUTCHAR_BUFSIZE must be power of 2
#endif
static K_SEM_DEFINE(uart_sem, 0, UINT_MAX); static K_SEM_DEFINE(uart_sem, 0, UINT_MAX);
static u8_t uart_ringbuf[CONFIG_CONSOLE_GETCHAR_BUFSIZE]; static u8_t uart_ringbuf[CONFIG_CONSOLE_GETCHAR_BUFSIZE];
static u8_t i_get, i_put; static u8_t i_get, i_put;
static K_SEM_DEFINE(tx_sem, 0, UINT_MAX);
static u8_t tx_ringbuf[CONFIG_CONSOLE_PUTCHAR_BUFSIZE];
static u8_t tx_get, tx_put;
static struct device *uart_dev;
static int console_irq_input_hook(u8_t c);
static void uart_isr(struct device *dev)
{
uart_irq_update(dev);
if (uart_irq_rx_ready(dev)) {
char c;
while (1) {
if (uart_fifo_read(dev, &c, 1) == 0) {
break;
}
console_irq_input_hook(c);
}
}
if (uart_irq_tx_ready(dev)) {
if (tx_get == tx_put) {
/* Output buffer empty, don't bother
* us with tx interrupts
*/
uart_irq_tx_disable(dev);
} else {
uart_fifo_fill(dev, &tx_ringbuf[tx_get++], 1);
tx_get &= CONFIG_CONSOLE_PUTCHAR_BUFSIZE - 1;
}
}
}
static int console_irq_input_hook(u8_t c) static int console_irq_input_hook(u8_t c)
{ {
int i_next = (i_put + 1) & (CONFIG_CONSOLE_GETCHAR_BUFSIZE - 1); int i_next = (i_put + 1) & (CONFIG_CONSOLE_GETCHAR_BUFSIZE - 1);
if (i_next == i_get) { if (i_next == i_get) {
printk("Console buffer overflow - char dropped\n"); /* Try to give a clue to user that some input was lost */
console_putchar('~');
console_putchar('\n');
return 1; return 1;
} }
@ -34,6 +77,26 @@ static int console_irq_input_hook(u8_t c)
return 1; return 1;
} }
int console_putchar(char c)
{
unsigned int key;
int tx_next;
key = irq_lock();
tx_next = (tx_put + 1) & (CONFIG_CONSOLE_PUTCHAR_BUFSIZE - 1);
if (tx_next == tx_get) {
irq_unlock(key);
return -1;
}
tx_ringbuf[tx_put] = c;
tx_put = tx_next;
irq_unlock(key);
uart_irq_tx_enable(uart_dev);
return 0;
}
u8_t console_getchar(void) u8_t console_getchar(void)
{ {
unsigned int key; unsigned int key;
@ -48,9 +111,9 @@ u8_t console_getchar(void)
return c; return c;
} }
void console_getchar_init(void) void console_init(void)
{ {
uart_console_in_debug_hook_install(console_irq_input_hook); uart_dev = device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME);
/* All NULLs because we're interested only in the callback above. */ uart_irq_callback_set(uart_dev, uart_isr);
uart_register_input(NULL, NULL, NULL); uart_irq_rx_enable(uart_dev);
} }