subsys: console: Add pull-style console API support.

This change introduces console_getchar() and console_getline() API
calls which can be used to get pending console input (either one
char or whole line), or block waiting for one. In this regard, they
are similar to well-known ANSI C function getchar/gets/fgets, and
are intended to ease porting of existing applications to Zephyr, and
indeed, these functions (shaped as an external module) are already
used by few applications.

The implementation of the functions is structured as a new "console"
subsystem. The intention is that further generic console code may be
pulled there instead of being in drivers/console/. Besides the
functions themselves, initialization code and sample applications
are included.

At this time, there're may limitations of how these functions can
be used. For example, console_getchar() and console_getline() are
mutually exclusive, and both are incompatible with callback
(push-style) console API (and e.g. with console shell subsystem
which uses this API). Again, the intention is to make a first step
towards refactoring console subsystem to allow more flexible
real-world usage, better reusability and composability.

Change-Id: I3f4015bb5b26e0656f82f428b11ba30e980d25a0
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This commit is contained in:
Paul Sokolovsky 2017-03-24 13:50:16 +03:00 committed by Anas Nashif
parent 9f5f6d6283
commit 542c2b93d0
23 changed files with 384 additions and 4 deletions

73
include/console.h Normal file
View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2017 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __CONSOLE_H__
#define __CONSOLE_H__
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Initialize console_getchar() call.
*
* This function should be called once to initialize pull-style
* access to console via console_getchar() function. This function
* supercedes, and incompatible with, callback (push-style) console
* handling (via console_input_fn callback, etc.).
*
* @return N/A
*/
void console_getchar_init(void);
/** @brief Get next char from console input buffer.
*
* Return next input character from console. If no characters available,
* this function will block. This function is similar to ANSI C
* getchar() function and is intended to ease porting of existing
* software. Before this function can be used, console_getchar_init()
* should be called once. This function is incompatible with native
* Zephyr callback-based console input processing, shell subsystem,
* or console_getline().
*
* @return A character read, including control characters.
*/
uint8_t console_getchar(void);
/** @brief Initialize console_getline() call.
*
* This function should be called once to initialize pull-style
* access to console via console_getline() function. This function
* supercedes, and incompatible with, callback (push-style) console
* handling (via console_input_fn callback, etc.).
*
* @return N/A
*/
void console_getline_init(void);
/** @brief Get next line from console input buffer.
*
* Return next input line from console. Until full line is available,
* this function will block. This function is similar to ANSI C
* gets() function (except a line is returned in system-owned buffer,
* and system takes care of the buffer overflow checks) and is
* intended to ease porting of existing software. Before this function
* can be used, console_getline_init() should be called once. This
* function is incompatible with native Zephyr callback-based console
* input processing, shell subsystem, or console_getchar().
*
* @return A pointer to a line read, not including EOL character(s).
* A line resides in a system-owned buffer, so an application
* should finish any processing of this line immediately
* after console_getline() call, or the buffer can be reused.
*/
char *console_getline(void);
#ifdef __cplusplus
}
#endif
#endif /* __CONSOLE_H__ */

View file

@ -4,8 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __CONSOLE_H__
#define __CONSOLE_H__
#ifndef __DRIVERS_CONSOLE_CONSOLE_H__
#define __DRIVERS_CONSOLE_CONSOLE_H__
#ifdef __cplusplus
extern "C" {
@ -46,4 +46,4 @@ typedef void (*console_input_fn)(struct k_fifo *avail, struct k_fifo *lines,
}
#endif
#endif /* __CONSOLE_H__ */
#endif /* __DRIVERS_CONSOLE_CONSOLE_H__ */

View file

@ -3,11 +3,12 @@ Samples and Demos
.. toctree::
:maxdepth: 2
:maxdepth: 3
:glob:
kernel
basic/*
subsys/subsys.rst
net/net.rst
bluetooth/bluetooth.rst
sensor/*

View file

@ -0,0 +1,8 @@
Console Samples
###############
.. toctree::
:maxdepth: 1
:glob:
**/*

View file

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

View file

@ -0,0 +1,40 @@
.. _console_getchar_sample:
console_getchar() Sample Application
####################################
Overview
********
This example shows how to use :cpp:func:`console_getchar()` function.
Similar to the well-known ANSI C getchar() function,
:cpp:func:`console_getchar()` either returns the next available input
character or blocks waiting for one. Using this function, it should be
fairly easy to port existing ANSI C, POSIX, or Linux applications which
process console input character by character. The sample also allows to
see key/character codes as returned by the function.
If you are interested in line by line console input, see
:ref:`console_getline_sample`.
Requirements
************
UART console is required to run this simple.
Building and Running
********************
The easiest way to run this sample is using QEMU:
.. code-block:: console
$ cd samples/console/getchar
$ make BOARD=qemu_x86
$ make BOARD=qemu_x86 run
Now start pressing keys on a keyboard, and they will be printed both as
hex values and in character form. Be sure to press Enter, Up/Down, etc.
key to check what control characters are produced for them.

View file

@ -0,0 +1,2 @@
CONFIG_CONSOLE_PULL=y
CONFIG_CONSOLE_GETCHAR=y

View file

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

View file

@ -0,0 +1,14 @@
#include <zephyr.h>
#include <misc/printk.h>
#include <console.h>
void main(void)
{
console_getchar_init();
while (1) {
uint8_t c = console_getchar();
printk("char: [0x%x] %c\n", c, c);
}
}

View file

@ -0,0 +1,7 @@
[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

View file

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

View file

@ -0,0 +1,41 @@
.. _console_getline_sample:
console_getline() Sample Application
####################################
Overview
********
This example shows how to use :cpp:func:`console_getline()` function.
Similar to the well-known ANSI C gets() and fgets() functions,
:cpp:func:`console_getline()` either returns the next available input
line or blocks waiting for one. Using this function, it should be fairly
easy to port existing ANSI C, POSIX, or Linux applications which process
console input line by line. The sample also allows to see details of how
a line is returned by the function.
If you are interested in character by character console input, see
:ref:`console_getchar_sample`.
Requirements
************
UART console is required to run this simple.
Building and Running
********************
The easiest way to run this sample is using QEMU:
.. code-block:: console
$ cd samples/console/getline
$ make BOARD=qemu_x86
$ make BOARD=qemu_x86 run
Now start pressing keys on a keyboard, followed by Enter. The input line
will be printed back, with a hex code of the last character, to show that
line does not include any special "end of line" characters (like LF, CR,
etc.)

View file

@ -0,0 +1,2 @@
CONFIG_CONSOLE_PULL=y
CONFIG_CONSOLE_GETLINE=y

View file

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

View file

@ -0,0 +1,16 @@
#include <string.h>
#include <zephyr.h>
#include <misc/printk.h>
#include <console.h>
void main(void)
{
console_getline_init();
while (1) {
char *s = console_getline();
printk("line: %s\n", s);
printk("last char was: 0x%x\n", s[strlen(s) - 1]);
}
}

View file

@ -0,0 +1,7 @@
[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

View file

@ -0,0 +1,8 @@
Various Subsystems Samples
##########################
.. toctree::
:maxdepth: 2
:glob:
*/*

View file

@ -11,6 +11,8 @@ source "subsys/usb/Kconfig"
source "subsys/bluetooth/Kconfig"
source "subsys/console/Kconfig"
source "subsys/disk/Kconfig"
source "subsys/net/Kconfig"

View file

@ -3,6 +3,7 @@ obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_BLUETOOTH) += bluetooth/
obj-$(CONFIG_NET_BUF) += net/
obj-$(CONFIG_CONSOLE_SHELL) += shell/
obj-$(CONFIG_CONSOLE_PULL) += console/
obj-$(CONFIG_DISK_ACCESS) += disk/
obj-y += logging/
obj-y += debug/

44
subsys/console/Kconfig Normal file
View file

@ -0,0 +1,44 @@
#
# Copyright (c) 2017 Linaro Limited
#
# SPDX-License-Identifier: Apache-2.0
#
menu "Console (pull-style)"
config CONSOLE_PULL
bool
default n
prompt "Enable pull-style Console access"
help
Get data from console using getchar/getline calls
if CONSOLE_PULL
choice
prompt "Console 'get' function selection"
config CONSOLE_GETCHAR
bool "Character by character input"
select UART_CONSOLE_DEBUG_SERVER_HOOKS
select CONSOLE_HANDLER
config CONSOLE_GETLINE
bool "Line by line input"
select CONSOLE_HANDLER
endchoice
if CONSOLE_GETCHAR
config CONSOLE_GETCHAR_BUFSIZE
int "console_getchar() buffer size"
default 16
help
Buffer size for console_getchar(). 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.
endif # CONSOLE_GETCHAR
endif # CONSOLE_PULL
endmenu

2
subsys/console/Makefile Normal file
View file

@ -0,0 +1,2 @@
obj-$(CONFIG_CONSOLE_GETCHAR) += getchar.o
obj-$(CONFIG_CONSOLE_GETLINE) += getline.o

56
subsys/console/getchar.c Normal file
View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2017 Linaro Limited.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <uart.h>
#include <misc/printk.h>
#include <drivers/console/console.h>
#include <drivers/console/uart_console.h>
#if CONFIG_CONSOLE_GETCHAR_BUFSIZE & (CONFIG_CONSOLE_GETCHAR_BUFSIZE - 1) != 0
#error CONFIG_CONSOLE_GETCHAR_BUFSIZE must be power of 2
#endif
static K_SEM_DEFINE(uart_sem, 0, UINT_MAX);
static uint8_t uart_ringbuf[CONFIG_CONSOLE_GETCHAR_BUFSIZE];
static uint8_t i_get, i_put;
static int console_irq_input_hook(uint8_t c)
{
int i_next = (i_put + 1) & (CONFIG_CONSOLE_GETCHAR_BUFSIZE - 1);
if (i_next == i_get) {
printk("Console buffer overflow - char dropped\n");
return 1;
}
uart_ringbuf[i_put] = c;
i_put = i_next;
k_sem_give(&uart_sem);
return 1;
}
uint8_t console_getchar(void)
{
unsigned int key;
uint8_t c;
k_sem_take(&uart_sem, K_FOREVER);
key = irq_lock();
c = uart_ringbuf[i_get++];
i_get &= CONFIG_CONSOLE_GETCHAR_BUFSIZE - 1;
irq_unlock(key);
return c;
}
void console_getchar_init(void)
{
uart_console_in_debug_hook_install(console_irq_input_hook);
/* All NULLs because we're interested only in the callback above. */
uart_register_input(NULL, NULL, NULL);
}

46
subsys/console/getline.c Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2017 Linaro Limited.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <uart.h>
#include <drivers/console/console.h>
#include <drivers/console/uart_console.h>
/* While app processes one input line, Zephyr will have another line
* buffer to accumulate more console input.
*/
static struct console_input line_bufs[2];
static K_FIFO_DEFINE(free_queue);
static K_FIFO_DEFINE(used_queue);
char *console_getline(void)
{
static struct console_input *cmd;
/* Recycle cmd buffer returned previous time */
if (cmd != NULL) {
k_fifo_put(&free_queue, cmd);
}
cmd = k_fifo_get(&used_queue, K_FOREVER);
return cmd->line;
}
void console_getline_init(void)
{
int i;
for (i = 0; i < sizeof(line_bufs) / sizeof(*line_bufs); i++) {
k_fifo_put(&free_queue, &line_bufs[i]);
}
/* Zephyr UART handler takes an empty buffer from free_queue,
* stores UART input in it until EOL, and then puts it into
* used_queue.
*/
uart_register_input(&free_queue, &used_queue, NULL);
}