1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #19738 from benpicco/stdio_dispatch

stdio_dispatch: allow to select multiple stdio methods at the same time
This commit is contained in:
benpicco 2024-02-09 16:13:27 +00:00 committed by GitHub
commit 55b6728224
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 485 additions and 349 deletions

View File

@ -22,8 +22,7 @@
#include <errno.h>
#include <sys/types.h>
#include "isrpipe.h"
#include "tsrb.h"
#include "stdio_base.h"
#include "irq_arch.h"
#include "esp_attr.h"
@ -33,16 +32,13 @@
#include "soc/periph_defs.h"
#include "rom/ets_sys.h"
static uint8_t _rx_buf_mem[USB_SERIAL_JTAG_PACKET_SZ_BYTES];
static isrpipe_t stdio_serial_isrpipe = ISRPIPE_INIT(_rx_buf_mem);
static tsrb_t serial_tx_rb;
static uint8_t serial_tx_rb_buf[USB_SERIAL_JTAG_PACKET_SZ_BYTES];
#define IRQ_MASK (USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | \
(IS_USED(MODULE_STDIO_USB_SERIAL_JTAG_RX) * USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT))
ssize_t stdio_write(const void *buffer, size_t len)
static ssize_t _write(const void *buffer, size_t len)
{
tsrb_add(&serial_tx_rb, buffer, len);
USB_SERIAL_JTAG.int_ena.val = IRQ_MASK;
@ -50,24 +46,6 @@ ssize_t stdio_write(const void *buffer, size_t len)
return len;
}
ssize_t stdio_read(void* buffer, size_t count)
{
if (IS_USED(MODULE_STDIO_USB_SERIAL_JTAG_RX)) {
return (ssize_t)isrpipe_read(&stdio_serial_isrpipe, buffer, count);
}
return -ENOTSUP;
}
int stdio_available(void)
{
if (IS_USED(MODULE_STDIO_AVAILABLE)) {
return tsrb_avail(&stdio_serial_isrpipe.tsrb);
}
return -ENOTSUP;
}
IRAM_ATTR
static void _serial_intr_handler(void *arg)
{
@ -80,7 +58,7 @@ static void _serial_intr_handler(void *arg)
/* read data if available */
while (IS_USED(MODULE_STDIO_USB_SERIAL_JTAG_RX) &&
usb_serial_jtag_ll_rxfifo_data_available()) {
isrpipe_write_one(&stdio_serial_isrpipe, USB_SERIAL_JTAG.ep1.rdwr_byte);
isrpipe_write_one(&stdin_isrpipe, USB_SERIAL_JTAG.ep1.rdwr_byte);
}
/* write data if there is a free stop */
@ -104,7 +82,7 @@ static void _serial_intr_handler(void *arg)
irq_isr_exit();
}
void stdio_init(void)
static void _init(void)
{
tsrb_init(&serial_tx_rb, serial_tx_rb_buf, sizeof(serial_tx_rb_buf));
@ -128,4 +106,11 @@ void stdio_init(void)
intr_cntrl_ll_set_int_level(CPU_INUM_SERIAL_JTAG, 1);
#endif
}
static void _detach(void)
{
intr_cntrl_ll_disable_interrupts(BIT(CPU_INUM_SERIAL_JTAG));
}
STDIO_PROVIDER(STDIO_ESP32_SERIAL_JTAG, _init, _detach, _write)
/**@}*/

View File

@ -25,6 +25,10 @@
#include "isrpipe.h"
#include "stdio_uart.h"
#ifndef STDIO_UART_RX_BUFSIZE
#define STDIO_UART_RX_BUFSIZE STDIO_RX_BUFSIZE
#endif
extern ethos_t ethos;
static uint8_t _rx_buf_mem[STDIO_UART_RX_BUFSIZE];

View File

@ -62,10 +62,9 @@ static void _slip_rx_cb(void *arg, uint8_t byte)
break;
case SLIPDEV_END:
dev->state = SLIPDEV_STATE_NONE;
byte = 0;
/* fall-through */
break;
default:
isrpipe_write_one(&slipdev_stdio_isrpipe, byte);
isrpipe_write_one(&stdin_isrpipe, byte);
break;
}
return;
@ -79,7 +78,7 @@ static void _slip_rx_cb(void *arg, uint8_t byte)
break;
}
dev->state = SLIPDEV_STATE_STDIN;
isrpipe_write_one(&slipdev_stdio_isrpipe, byte);
isrpipe_write_one(&stdin_isrpipe, byte);
return;
#endif
case SLIPDEV_STATE_NONE:

View File

@ -24,9 +24,6 @@
#include "stdio_base.h"
#include "stdio_uart.h"
static uint8_t _rx_buf_mem[STDIO_UART_RX_BUFSIZE];
isrpipe_t slipdev_stdio_isrpipe = ISRPIPE_INIT(_rx_buf_mem);
mutex_t slipdev_mutex = MUTEX_INIT;
static void _isrpipe_write(void *arg, uint8_t data)
@ -34,36 +31,15 @@ static void _isrpipe_write(void *arg, uint8_t data)
isrpipe_write_one(arg, (char)data);
}
void stdio_init(void)
static void _init(void)
{
/* intentionally overwritten in netdev init so we have stdio before
* the network device is initialized is initialized */
uart_init(slipdev_params[0].uart, slipdev_params[0].baudrate,
_isrpipe_write, &slipdev_stdio_isrpipe);
_isrpipe_write, &stdin_isrpipe);
}
ssize_t stdio_read(void *buffer, size_t len)
{
uint8_t *ptr = buffer;
while (len) {
int read = isrpipe_read(&slipdev_stdio_isrpipe, ptr, 1);
if (read == 0) {
continue;
}
if (*ptr == 0) {
break;
}
++ptr;
--len;
}
return ptr - (uint8_t *)buffer;
}
ssize_t stdio_write(const void *buffer, size_t len)
static ssize_t _write(const void *buffer, size_t len)
{
mutex_lock(&slipdev_mutex);
slipdev_write_byte(slipdev_params[0].uart, SLIPDEV_STDIO_START);
@ -73,4 +49,6 @@ ssize_t stdio_write(const void *buffer, size_t len)
return len;
}
STDIO_PROVIDER(STDIO_SLIP, _init, NULL, _write)
/** @} */

View File

@ -538,6 +538,7 @@ PSEUDOMODULES += soft_uart_modecfg
PSEUDOMODULES += stdin
PSEUDOMODULES += stdio_available
PSEUDOMODULES += stdio_cdc_acm
PSEUDOMODULES += stdio_dispatch
PSEUDOMODULES += stdio_ethos
PSEUDOMODULES += stdio_nimble_debug
PSEUDOMODULES += stdio_telnet

View File

@ -14,11 +14,29 @@ STDIO_MODULES = \
stdio_usb_serial_jtag \
#
STDIO_LEGACY_MODULES = \
ethos_stdio \
stdio_ethos \
stdio_native # requires #19002 \
#
# select stdio_uart if no other stdio module is slected
ifeq (,$(filter $(STDIO_MODULES),$(USEMODULE)))
USEMODULE += stdio_uart
endif
ifeq (,$(filter $(STDIO_LEGACY_MODULES),$(USEMODULE)))
USEMODULE += stdio
endif
ifneq (,$(filter stdin,$(USEMODULE)))
USEMODULE += isrpipe
endif
ifneq (1, $(words $(filter $(STDIO_MODULES),$(USEMODULE))))
USEMODULE += stdio_dispatch
endif
ifneq (,$(filter stdio_cdc_acm,$(USEMODULE)))
USEMODULE += usbus_cdc_acm
USEMODULE += isrpipe
@ -78,6 +96,7 @@ endif
ifneq (,$(filter stdio_udp,$(USEMODULE)))
USEMODULE += sock_udp
USEMODULE += sock_async
endif
# enable stdout buffering for modules that benefit from sending out buffers in larger chunks

View File

@ -24,30 +24,12 @@
#include <stdio.h>
#include <sys/types.h>
#include "stdio_base.h"
#include "tusb.h"
#include "tinyusb.h"
static mutex_t data_lock = MUTEX_INIT_LOCKED;
void stdio_init(void)
{
}
#if IS_USED(MODULE_STDIO_AVAILABLE)
int stdio_available(void)
{
return tud_cdc_available();
}
#endif
ssize_t stdio_read(void* buffer, size_t len)
{
mutex_lock(&data_lock);
return tud_cdc_read(buffer, len);
}
ssize_t stdio_write(const void* buffer, size_t len)
static ssize_t _write(const void* buffer, size_t len)
{
const char *start = buffer;
@ -62,9 +44,15 @@ ssize_t stdio_write(const void* buffer, size_t len)
return (char *)buffer - start;
}
#ifdef MODULE_STDIN
void tud_cdc_rx_cb(uint8_t itf)
{
(void)itf;
mutex_unlock(&data_lock);
uint8_t buffer[64];
unsigned res = tud_cdc_read(buffer, sizeof(buffer));
isrpipe_write(&stdin_isrpipe, buffer, res);
}
#endif
STDIO_PROVIDER(STDIO_TINYUSB_CDC_ACM, NULL, NULL, _write)

View File

@ -27,7 +27,8 @@
#include "kernel_defines.h"
#include "fmt.h"
#include "stdio_base.h"
extern ssize_t stdio_write(const void* buffer, size_t len);
static const char _hex_chars[16] = "0123456789ABCDEF";

View File

@ -18,6 +18,7 @@
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*/
#ifndef STDIO_BASE_H
@ -26,11 +27,64 @@
#include <unistd.h>
#include "modules.h"
#include "isrpipe.h"
#include "xfa.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef STDIO_RX_BUFSIZE
/**
* @brief Buffer size for STDIO
*/
#define STDIO_RX_BUFSIZE (64)
#endif
enum {
STDIO_NULL, /**< dummy stdio */
STDIO_UART, /**< stdio via UART */
STDIO_RTT, /**< stdio via Segger RTT */
STDIO_SEMIHOSTING, /**< stdio via Semihosting */
STDIO_USBUS_CDC_ACM, /**< stdio via USB CDC ACM (usbus) */
STDIO_TINYUSB_CDC_ACM, /**< tdio via USB CDC ACM (TinyUSB) */
STDIO_ESP32_SERIAL_JTAG, /**< stdio via ESP32 debug Serial/JTAG */
STDIO_NIMBLE, /**< stdio via BLE (NimBLE) */
STDIO_UDP, /**< stdio via UDP */
STDIO_TELNET, /**< stdio via telnet */
STDIO_ETHOS, /**< stdio via ethos (mutiplex) */
STDIO_SLIP, /*<< stdio via SLIP (mutiplex) */
};
/**
* @brief stdio provider struct
*/
typedef struct {
/**
* @brief Initialize and attach the stdio provider
*/
void (*open)(void);
/**
* @brief Detach the stdio provider
*/
void (*close)(void);
/**
* @brief Write @p len bytes from @p src into stdout
*
* @param[in] src buffer to read from
* @param[in] len nr of bytes to write
*
* @return nr of bytes written
* @return <0 on error
*/
ssize_t (*write)(const void *src, size_t len);
} stdio_provider_t;
/**
* @brief isrpipe for writing stdin input to
*/
extern isrpipe_t stdin_isrpipe;
/**
* @brief initialize the module
*/
@ -60,7 +114,11 @@ int stdio_available(void);
ssize_t stdio_read(void* buffer, size_t max_len);
/**
* @brief write @p len bytes from @p buffer into uart
* @brief write @p len bytes from @p buffer into STDOUT
*
* @note Depending on the stdio backend(s) used, not all bytes might
* be written to stdout and accounted for if multiple backends are
* active, as not all stdout backends will do a blocking write.
*
* @param[in] buffer buffer to read from
* @param[in] len nr of bytes to write
@ -70,6 +128,45 @@ ssize_t stdio_read(void* buffer, size_t max_len);
*/
ssize_t stdio_write(const void* buffer, size_t len);
/**
* @brief Disable stdio and detach stdio providers
*/
void stdio_close(void);
#if defined(MODULE_STDIO_DISPATCH) || DOXYGEN
/**
* @brief stdio implementation methods
*
* @param _type stdio provider type, for identification
* @param _open attach / init function
* @param _close close / disable function
* @param _write write function
*/
#define STDIO_PROVIDER(_type, _open, _close, _write) \
XFA_CONST(stdio_provider_xfa, 0) stdio_provider_t stdio_ ##_type = { \
.open = _open, \
.close = _close, \
.write = _write, \
};
#else
#define STDIO_PROVIDER(_type, _open, _close, _write) \
void stdio_init(void) { \
void (*f)(void) = _open; \
if (f != NULL) { \
f(); \
} \
} \
void stdio_close(void) { \
void (*f)(void) = _close; \
if (f != NULL) { \
f(); \
} \
} \
ssize_t stdio_write(const void* buffer, size_t len) { \
return _write(buffer, len); \
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -111,13 +111,6 @@ extern "C" {
#define STDIO_UART_BAUDRATE (115200)
#endif
#ifndef STDIO_UART_RX_BUFSIZE
/**
* @brief Buffer size for STDIO
*/
#define STDIO_UART_RX_BUFSIZE (64)
#endif
#ifdef __cplusplus
}
#endif

View File

@ -26,55 +26,6 @@
#include "board.h"
#include "kernel_defines.h"
#include "net/telnet.h"
#if IS_USED(MODULE_PERIPH_UART)
#include "stdio_uart.h"
#include "periph/uart.h"
#endif
#ifdef CPU_NATIVE
#include "native_internal.h"
#endif
#include "stdio_base.h"
#define ENABLE_DEBUG 0
#include "debug.h"
static inline void _init_fallback(void)
{
#if defined(STDIO_UART_DEV) && IS_USED(MODULE_PERIPH_UART)
uart_init(STDIO_UART_DEV, STDIO_UART_BAUDRATE, NULL, NULL);
#endif
}
static inline int _write_fallback(const void* buffer, size_t len)
{
#if defined(CPU_NATIVE)
real_write(STDOUT_FILENO, buffer, len);
#elif defined(STDIO_UART_DEV) && IS_USED(MODULE_PERIPH_UART)
uart_write(STDIO_UART_DEV, buffer, len);
#else
(void)buffer;
#endif
return len;
}
void stdio_init(void)
{
_init_fallback();
}
ssize_t stdio_read(void* buffer, size_t count)
{
return telnet_server_read(buffer, count);
}
ssize_t stdio_write(const void* buffer, size_t len)
{
int res = telnet_server_write(buffer, len);
/* write to UART if no client is connected */
if (res == -ENOTCONN) {
return _write_fallback(buffer, len);
}
return res;
}
STDIO_PROVIDER(STDIO_TELNET, NULL, telnet_server_disconnect, telnet_server_write)

View File

@ -21,6 +21,7 @@
#include <fcntl.h>
#include "net/sock/tcp.h"
#include "net/telnet.h"
#include "stdio_base.h"
#include "pipe.h"
#define ENABLE_DEBUG 0
@ -106,17 +107,26 @@ static void _connected(void)
telnet_cb_pre_connected(client);
connected = true;
mutex_unlock(&connected_mutex);
if (!IS_USED(MODULE_STDIO_TELNET)) {
mutex_unlock(&connected_mutex);
}
telnet_cb_connected(client);
}
static void _disconnect(void)
{
mutex_trylock(&connected_mutex);
if (!IS_USED(MODULE_STDIO_TELNET)) {
mutex_trylock(&connected_mutex);
}
connected = false;
DEBUG("telnet disconnect\n");
telnet_cb_disconneced();
_acquire();
sock_tcp_disconnect(client);
_release();
}
static int _write_buffer(const void* buffer, size_t len)
@ -185,6 +195,17 @@ static void _process_cmd(uint8_t cmd, uint8_t option)
}
}
static void _send_opts(void)
{
if (IS_USED(MODULE_STDIO_TELNET)) {
/* RIOT will echo stdio, disable local echo */
const uint8_t opt_echo[] = {
TELNET_CMD_IAC, TELNET_CMD_WILL, TELNET_OPT_ECHO
};
_write_buffer(opt_echo, sizeof(opt_echo));
}
}
static void *telnet_thread(void *arg)
{
(void)arg;
@ -200,6 +221,7 @@ static void *telnet_thread(void *arg)
DEBUG("connected\n");
_connected();
_send_opts();
bool is_cmd = false;
uint8_t is_option = 0;
@ -217,7 +239,7 @@ static void *telnet_thread(void *arg)
continue;
}
if (res < 0) {
if (res <= 0) {
break;
}
@ -252,12 +274,16 @@ static void *telnet_thread(void *arg)
continue;
}
write:
pipe_write(&_stdin_pipe, &c, 1);
if (IS_USED(MODULE_STDIO_TELNET)) {
isrpipe_write_one(&stdin_isrpipe, c);
}
else {
pipe_write(&_stdin_pipe, &c, 1);
}
}
}
disco:
_disconnect();
sock_tcp_disconnect(client);
if (res < 0) {
DEBUG("telnet: read: %s\n", strerror(res));
@ -276,6 +302,7 @@ int telnet_server_write(const void* buffer, size_t len)
return -ENOTCONN;
}
#ifndef MODULE_STDIO_TELNET
int telnet_server_read(void* buffer, size_t count)
{
/* block until a connection is established */
@ -286,6 +313,7 @@ int telnet_server_read(void* buffer, size_t count)
}
return res;
}
#endif
void telnet_server_disconnect(void)
{
@ -304,9 +332,11 @@ int telnet_server_start(void)
return res;
}
/* init RX ringbuffer */
ringbuffer_init(&_stdin_ringbuffer, _stdin_pipe_buf, sizeof(_stdin_pipe_buf));
pipe_init(&_stdin_pipe, &_stdin_ringbuffer, NULL);
if (!IS_USED(MODULE_STDIO_TELNET)) {
/* init RX ringbuffer */
ringbuffer_init(&_stdin_ringbuffer, _stdin_pipe_buf, sizeof(_stdin_pipe_buf));
pipe_init(&_stdin_pipe, &_stdin_ringbuffer, NULL);
}
/* initiate telnet server */
thread_create(telnet_stack, sizeof(telnet_stack),

1
sys/stdio/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

80
sys/stdio/stdio.c Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2023 ML!PA Consulting GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_stdio
* @{
*
* @file
* @brief STDIO common layer
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*
* @}
*/
#include "errno.h"
#include "isrpipe.h"
#include "stdio_base.h"
#include "macros/utils.h"
#include "xfa.h"
static uint8_t _rx_buf_mem[STDIO_RX_BUFSIZE];
isrpipe_t stdin_isrpipe = ISRPIPE_INIT(_rx_buf_mem);
#ifdef MODULE_STDIO_DISPATCH
XFA_INIT_CONST(stdio_provider_t, stdio_provider_xfa);
void stdio_init(void)
{
for (unsigned i = 0; i < XFA_LEN(stdio_provider_t, stdio_provider_xfa); ++i) {
if (stdio_provider_xfa[i].open) {
stdio_provider_xfa[i].open();
}
}
}
ssize_t stdio_write(const void* buffer, size_t len)
{
for (unsigned i = 0; i < XFA_LEN(stdio_provider_t, stdio_provider_xfa); ++i) {
stdio_provider_xfa[i].write(buffer, len);
}
return len;
}
void stdio_close(void) {
for (unsigned i = 0; i < XFA_LEN(stdio_provider_t, stdio_provider_xfa); ++i) {
if (stdio_provider_xfa[i].close) {
stdio_provider_xfa[i].close();
}
}
}
#define MAYBE_WEAK
#else
#define MAYBE_WEAK __attribute__((weak))
#endif
MAYBE_WEAK
ssize_t stdio_read(void* buffer, size_t len)
{
if (!IS_USED(MODULE_STDIN)) {
return -ENOTSUP;
}
return isrpipe_read(&stdin_isrpipe, buffer, len);
}
#if IS_USED(MODULE_STDIO_AVAILABLE)
MAYBE_WEAK
int stdio_available(void)
{
return tsrb_avail(&stdin_isrpipe.tsrb);
}
#endif

View File

@ -39,8 +39,7 @@
#include "periph/uart.h"
#endif /* IS_USED(MODULE_STDIO_NIMBLE_DEBUG) */
#include "tsrb.h"
#include "isrpipe.h"
#include "stdio_base.h"
#include "stdio_nimble.h"
#define NIMBLE_MAX_PAYLOAD MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE)
@ -55,10 +54,6 @@ enum {
STDIO_NIMBLE_SENDING,
};
/* isrpipe for stdin */
static uint8_t _isrpipe_stdin_mem[CONFIG_STDIO_NIMBLE_STDIN_BUFSIZE];
static isrpipe_t _isrpipe_stdin = ISRPIPE_INIT(_isrpipe_stdin_mem);
/* tsrb for stdout */
static uint8_t _tsrb_stdout_mem[CONFIG_STDIO_NIMBLE_STDOUT_BUFSIZE];
static tsrb_t _tsrb_stdout = TSRB_INIT(_tsrb_stdout_mem);
@ -176,11 +171,11 @@ static const struct ble_gatt_svc_def _gatt_svr_svcs[] =
static void _purge_buffer(void)
{
tsrb_clear(&_isrpipe_stdin.tsrb);
tsrb_clear(&stdin_isrpipe.tsrb);
#if IS_USED(MODULE_SHELL)
/* send Ctrl-C to the shell to reset the input */
isrpipe_write_one(&_isrpipe_stdin, '\x03');
isrpipe_write_one(&stdin_isrpipe, '\x03');
#endif
tsrb_clear(&_tsrb_stdout);
@ -295,12 +290,12 @@ static int gatt_svr_chr_access_stdin(
/* read sent data */
int rc = ble_hs_mbuf_to_flat(ctxt->om, _stdin_read_buf, sizeof(_stdin_read_buf), &om_len);
isrpipe_write(&_isrpipe_stdin, _stdin_read_buf, om_len);
isrpipe_write(&stdin_isrpipe, _stdin_read_buf, om_len);
return rc;
}
void stdio_init(void)
static void _init(void)
{
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
uart_init(STDIO_UART_DEV, STDIO_UART_BAUDRATE, NULL, NULL);
@ -310,30 +305,7 @@ void stdio_init(void)
_send_stdout, NULL);
}
#if IS_USED(MODULE_STDIO_AVAILABLE)
int stdio_available(void)
{
return tsrb_avail(&_isrpipe_stdin.tsrb);
}
#endif
ssize_t stdio_read(void *buffer, size_t count)
{
/* blocks until at least one character was read */
ssize_t res = isrpipe_read(&_isrpipe_stdin, buffer, count);
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
unsigned state = irq_disable();
uart_write(STDIO_UART_DEV, (const uint8_t *)PREFIX_STDIN, strlen(PREFIX_STDIN));
uart_write(STDIO_UART_DEV, (const uint8_t *)buffer, res);
uart_write(STDIO_UART_DEV, (const uint8_t *)"\n", 1);
irq_restore(state);
#endif
return res;
}
ssize_t stdio_write(const void *buffer, size_t len)
static ssize_t _write(const void *buffer, size_t len)
{
unsigned state = irq_disable();
@ -378,3 +350,5 @@ void stdio_nimble_init(void)
/* fix compilation error when using DEVELHELP=0 */
(void)rc;
}
STDIO_PROVIDER(STDIO_NIMBLE, _init, NULL, _write)

View File

@ -25,22 +25,12 @@
#define ENABLE_DEBUG 0
#include "debug.h"
void stdio_init(void)
{
}
ssize_t stdio_read(void* buffer, size_t count)
{
(void) buffer;
(void) count;
return 0;
}
ssize_t stdio_write(const void* buffer, size_t len)
static ssize_t _write(const void* buffer, size_t len)
{
(void) buffer;
(void) len;
return 0;
}
STDIO_PROVIDER(STDIO_NULL, NULL, NULL, _write)

View File

@ -80,7 +80,7 @@
#include "mutex.h"
#include "stdio_rtt.h"
#include "thread.h"
#include "ztimer.h"
#include "ztimer/periodic.h"
/* This parameter affects the bandwidth of both input and output. Decreasing
it will significantly improve bandwidth at the cost of CPU time. */
@ -96,10 +96,9 @@
#define STDIO_RX_BUFSIZE (32)
#endif
/**
* @brief use mutex for waiting on stdin being enabled
*/
static mutex_t _rx_mutex = MUTEX_INIT;
#if !defined(MODULE_STDIN) && !defined(STDIO_RTT_DISABLE_STDIN)
#define STDIO_RTT_DISABLE_STDIN 1
#endif
/**
* @brief buffer holding stdout
@ -111,15 +110,12 @@ static char up_buffer [STDIO_TX_BUFSIZE];
*/
static char down_buffer [STDIO_RX_BUFSIZE];
/**
* @brief flag that enables stdin polling
*/
static char stdin_enabled = 0;
/**
* @brief flag that enables stdout blocking/polling
*/
static char blocking_stdout = 0;
static char blocking_stdout = IS_USED(STDIO_RTT_ENABLE_BLOCKING_STDOUT);
static ztimer_periodic_t stdin_timer;
/**
* @brief SEGGER's ring buffer implementation
@ -170,6 +166,22 @@ static segger_rtt_cb_t rtt_cb = {
{{ "Terminal", &down_buffer[0], sizeof(down_buffer), 0, 0, 0 }},
};
static int rtt_read_bytes_avail(void)
{
int16_t rd_off;
int16_t wr_off;
rd_off = rtt_cb.down[0].rd_off;
wr_off = rtt_cb.down[0].wr_off;
/* Read from current read position to wrap-around of buffer, first */
if (rd_off > wr_off) {
return rtt_cb.down[0].buf_size - rd_off;
} else {
return wr_off - rd_off;
}
}
/**
* @brief read bytes from the down buffer. This function does not block.
* The logic here is unmodified from SEGGER's reference, it is just
@ -177,7 +189,7 @@ static segger_rtt_cb_t rtt_cb = {
*
* @return the number of bytes read
*/
static int rtt_read(char* buf_ptr, uint16_t buf_size) {
static int rtt_read(uint8_t* buf_ptr, uint16_t buf_size) {
int16_t num_bytes_rem;
uint16_t num_bytes_read;
int16_t rd_off;
@ -269,61 +281,64 @@ int rtt_write(const char* buf_ptr, unsigned num_bytes) {
return num_bytes_written;
}
void stdio_init(void) {
#ifndef STDIO_RTT_DISABLE_STDIN
stdin_enabled = 1;
#endif
static bool _rtt_read_cb(void *arg)
{
int bytes = rtt_read_bytes_avail();
uint8_t buffer[STDIO_RX_BUFSIZE];
#ifdef STDIO_RTT_ENABLE_BLOCKING_STDOUT
blocking_stdout = 1;
#endif
if (bytes) {
bytes = rtt_read(buffer, sizeof(buffer));
isrpipe_write(arg, buffer, bytes);
}
/* the mutex should start locked */
mutex_lock(&_rx_mutex);
return true;
}
void rtt_stdio_enable_stdin(void) {
stdin_enabled = 1;
mutex_unlock(&_rx_mutex);
static bool _init_done;
static void _init(void) {
if (IS_USED(STDIO_RTT_DISABLE_STDIN)) {
return;
}
if (!thread_getpid()) {
/* we can't use ztimer in early init */
return;
}
ztimer_periodic_init(ZTIMER_MSEC, &stdin_timer, _rtt_read_cb, &stdin_isrpipe,
STDIO_POLL_INTERVAL_MS);
ztimer_periodic_start(&stdin_timer);
_init_done = true;
}
static void _detach(void)
{
if (!IS_USED(STDIO_RTT_DISABLE_STDIN)) {
ztimer_periodic_stop(&stdin_timer);
}
}
void rtt_stdio_enable_blocking_stdout(void) {
blocking_stdout = 1;
}
/* The reason we have this strange logic is as follows:
If we have an RTT console, we are powered, and so don't care
that polling uses a lot of power. If however, we do not
actually have an RTT console (because we are deployed on
a battery somewhere) then we REALLY don't want to poll
especially since we are not expecting to EVER get input. */
ssize_t stdio_read(void* buffer, size_t count) {
int res = rtt_read((void *)buffer, (uint16_t)count);
if (res == 0) {
if (!stdin_enabled) {
mutex_lock(&_rx_mutex);
/* We only unlock when rtt_stdio_enable_stdin is called
Note that we assume only one caller invoked this function */
}
uint32_t last_wakeup = ztimer_now(ZTIMER_MSEC);
while(1) {
ztimer_periodic_wakeup(ZTIMER_MSEC, &last_wakeup,
STDIO_POLL_INTERVAL_MS);
res = rtt_read(buffer, count);
if (res > 0)
return res;
}
}
return (ssize_t)res;
}
static ssize_t _write(const void* in, size_t len) {
const char *buffer = in;
int written = rtt_write(buffer, len);
ssize_t stdio_write(const void* in, size_t len) {
const char *buffer = (const char *)in;
int written = rtt_write(buffer, (unsigned)len);
uint32_t last_wakeup = ztimer_now(ZTIMER_MSEC);
while (blocking_stdout && ((size_t)written < len)) {
ztimer_periodic_wakeup(ZTIMER_MSEC, &last_wakeup, STDIO_POLL_INTERVAL_MS);
written += rtt_write(&buffer[written], len-written);
/* we have to postpone ztimer init */
if (!_init_done) {
_init();
}
if (blocking_stdout) {
uint32_t last_wakeup = ztimer_now(ZTIMER_MSEC);
while ((size_t)written < len) {
ztimer_periodic_wakeup(ZTIMER_MSEC, &last_wakeup, STDIO_POLL_INTERVAL_MS);
written += rtt_write(&buffer[written], len-written);
}
}
return (ssize_t)written;
}
STDIO_PROVIDER(STDIO_RTT, _init, _detach, _write)

View File

@ -25,7 +25,7 @@
#include <string.h>
#include "stdio_semihosting.h"
#include "ztimer.h"
#include "ztimer/periodic.h"
/**
* @brief Rate at which the stdin read polls (breaks) the debugger for input
@ -55,10 +55,9 @@
#define STDIO_SEMIHOSTING_SYS_READ (0x06) /**< Read command */
/** @} */
static ztimer_periodic_t stdin_timer;
#if defined(MODULE_RISCV_COMMON)
static bool _semihosting_connected(void) {
return true;
}
static uint32_t _semihosting_raw(int cmd, uint32_t *args)
{
@ -90,15 +89,6 @@ static uint32_t _semihosting_raw(int cmd, uint32_t *args)
#elif defined(MODULE_CORTEXM_COMMON)
static bool _semihosting_connected(void) {
#ifdef CoreDebug_DHCSR_C_DEBUGEN_Msk
/* Best effort attempt to detect if a debug session is active */
return CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk;
#else
return true;
#endif
}
static uint32_t _semihosting_raw(int cmd, uint32_t *args)
{
uint32_t result = 0;
@ -122,6 +112,15 @@ static uint32_t _semihosting_raw(int cmd, uint32_t *args)
}
#endif
static bool _semihosting_connected(void) {
#ifdef CoreDebug_DHCSR_C_DEBUGEN_Msk
/* Best effort attempt to detect if a debug session is active */
return CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk;
#else
return true;
#endif
}
static size_t _semihosting_write(const uint8_t *buffer, size_t len)
{
uint32_t args[3] = {
@ -143,30 +142,81 @@ static ssize_t _semihosting_read(uint8_t *buffer, size_t len)
return len - remaining;
}
void stdio_init(void)
static bool _read_cb(void *arg)
{
uint8_t buffer[STDIO_RX_BUFSIZE];
if (!_semihosting_connected()) {
return true;
}
int bytes = _semihosting_read(buffer, sizeof(buffer));
if (bytes > 0) {
isrpipe_write(arg, buffer, bytes);
}
return true;
}
ssize_t stdio_read(void* buffer, size_t count)
static bool _init_done;
static void _init(void) {
if (!STDIO_SEMIHOSTING_RX || !IS_USED(MODULE_STDIO_DISPATCH)) {
return;
}
if (!thread_getpid()) {
/* we can't use ztimer in early init */
return;
}
ztimer_periodic_init(ZTIMER_MSEC, &stdin_timer, _read_cb, &stdin_isrpipe,
STDIO_SEMIHOSTING_POLL_RATE_MS);
ztimer_periodic_start(&stdin_timer);
_init_done = true;
}
static void _detach(void)
{
if (STDIO_SEMIHOSTING_RX) {
uint32_t last_wakeup = ztimer_now(ZTIMER_MSEC);
ssize_t bytes_read = _semihosting_read(buffer, count);
while (bytes_read == 0) {
ztimer_periodic_wakeup(ZTIMER_MSEC, &last_wakeup,
STDIO_SEMIHOSTING_POLL_RATE_MS);
bytes_read = _semihosting_read(buffer, count);
}
return bytes_read;
ztimer_periodic_stop(&stdin_timer);
}
return -ENOTSUP;
}
ssize_t stdio_write(const void* buffer, size_t len)
static ssize_t _write(const void* buffer, size_t len)
{
if (!_semihosting_connected()) {
return len;
}
if (STDIO_SEMIHOSTING_RX && IS_USED(MODULE_STDIO_DISPATCH)
&& !_init_done) {
_init();
}
size_t remaining = _semihosting_write(buffer, len);
return len - remaining;
}
#ifndef MODULE_STDIO_DISPATCH
ssize_t stdio_read(void* buffer, size_t count)
{
if (!STDIO_SEMIHOSTING_RX) {
return -ENOTSUP;
}
uint32_t last_wakeup = ztimer_now(ZTIMER_MSEC);
ssize_t bytes_read = _semihosting_read(buffer, count);
while (bytes_read == 0) {
ztimer_periodic_wakeup(ZTIMER_MSEC, &last_wakeup,
STDIO_SEMIHOSTING_POLL_RATE_MS);
bytes_read = _semihosting_read(buffer, count);
}
return bytes_read;
}
int stdio_available(void)
{
return -ENOTSUP;
}
#endif
STDIO_PROVIDER(STDIO_SEMIHOSTING, _init, _detach, _write)

View File

@ -31,51 +31,33 @@
#include <string.h>
#include "board.h"
#include "isrpipe.h"
#include "kernel_defines.h"
#include "periph/uart.h"
#include "stdio_base.h"
#include "stdio_uart.h"
#define ENABLE_DEBUG 0
#include "debug.h"
static uint8_t _rx_buf_mem[STDIO_UART_RX_BUFSIZE];
isrpipe_t stdio_uart_isrpipe = ISRPIPE_INIT(_rx_buf_mem);
static void _isrpipe_write_one_wrapper(void *arg, uint8_t value)
{
isrpipe_write_one(arg, value);
}
void stdio_init(void)
static void _init(void)
{
uart_rx_cb_t cb = NULL;
void *arg = NULL;
if (IS_USED(MODULE_STDIO_UART_RX)) {
cb = _isrpipe_write_one_wrapper;
arg = &stdio_uart_isrpipe;
arg = &stdin_isrpipe;
}
uart_init(STDIO_UART_DEV, STDIO_UART_BAUDRATE, cb, arg);
}
#if IS_USED(MODULE_STDIO_AVAILABLE)
int stdio_available(void)
{
return tsrb_avail(&stdio_uart_isrpipe.tsrb);
}
#endif
ssize_t stdio_read(void* buffer, size_t count)
{
if (IS_USED(MODULE_STDIO_UART_RX)) {
return (ssize_t)isrpipe_read(&stdio_uart_isrpipe, buffer, count);
}
return -ENOTSUP;
}
ssize_t stdio_write(const void *buffer, size_t len)
static ssize_t _write(const void *buffer, size_t len)
{
ssize_t result = len;
if (IS_USED(MODULE_STDIO_UART_ONLCR)) {
@ -101,3 +83,10 @@ ssize_t stdio_write(const void *buffer, size_t len)
}
return result;
}
static void _detach(void)
{
uart_poweroff(STDIO_UART_DEV);
}
STDIO_PROVIDER(STDIO_UART, _init, _detach, _write)

View File

@ -19,22 +19,48 @@
*/
#include <errno.h>
#include <stdio.h>
#include "stdio_base.h"
#include "macros/utils.h"
#include "net/sock/async.h"
#include "net/sock/udp.h"
#ifndef CONFIG_STDIO_UDP_PORT
#define CONFIG_STDIO_UDP_PORT 2323
#endif
#ifndef CONFIG_STDIO_UDP_RX_BUF_LEN
#define CONFIG_STDIO_UDP_RX_BUF_LEN 64
#ifndef EOT
#define EOT 0x4
#endif
static sock_udp_t sock;
static sock_udp_ep_t remote;
void stdio_init(void)
static void _sock_cb(sock_udp_t *sock, sock_async_flags_t flags, void *arg)
{
(void)arg;
if ((flags & SOCK_ASYNC_MSG_RECV) == 0) {
return;
}
void *data, *ctx = NULL;
int res;
while ((res = sock_udp_recv_buf(sock, &data, &ctx, 0, &remote)) > 0) {
isrpipe_write(&stdin_isrpipe, data, res);
/* detach remote */
if (res == 1 && *(int8_t *)data == EOT) {
const char msg[] = "\nremote detached\n";
sock_udp_send(sock, msg, sizeof(msg), &remote);
memset(&remote, 0, sizeof(remote));
}
}
}
static void _init(void)
{
const sock_udp_ep_t local = {
.family = AF_INET6,
@ -43,36 +69,10 @@ void stdio_init(void)
};
sock_udp_create(&sock, &local, NULL, 0);
sock_udp_set_cb(&sock, _sock_cb, NULL);
}
ssize_t stdio_read(void* buffer, size_t count)
{
static uint8_t rx_buf[CONFIG_STDIO_UDP_RX_BUF_LEN];
static uint8_t *pos;
static size_t left;
/* shell will only read one byte at a time, so we buffer the input */
if (left == 0) {
int res = sock_udp_recv(&sock, rx_buf, sizeof(rx_buf),
SOCK_NO_TIMEOUT, &remote);
if (res > 0) {
left = res;
pos = rx_buf;
} else {
return res;
}
}
count = MIN(left, count);
memcpy(buffer, pos, count);
left -= count;
pos += count;
return count;
}
ssize_t stdio_write(const void* buffer, size_t len)
static ssize_t _write(const void* buffer, size_t len)
{
if (remote.port == 0) {
return -ENOTCONN;
@ -83,3 +83,11 @@ ssize_t stdio_write(const void* buffer, size_t len)
return sock_udp_send(&sock, buffer, len, &remote);
}
static void _detach(void)
{
sock_udp_close(&sock);
memset(&remote, 0, sizeof(remote));
}
STDIO_PROVIDER(STDIO_UDP, _init, _detach, _write)

View File

@ -26,34 +26,15 @@
#include "log.h"
#include "isrpipe.h"
#include "stdio_base.h"
#include "usb/usbus.h"
#include "usb/usbus/cdc/acm.h"
static usbus_cdcacm_device_t cdcacm;
static uint8_t _cdc_tx_buf_mem[CONFIG_USBUS_CDC_ACM_STDIO_BUF_SIZE];
static uint8_t _cdc_rx_buf_mem[CONFIG_USBUS_CDC_ACM_STDIO_BUF_SIZE];
static isrpipe_t _cdc_stdio_isrpipe = ISRPIPE_INIT(_cdc_rx_buf_mem);
void stdio_init(void)
{
}
#if IS_USED(MODULE_STDIO_AVAILABLE)
int stdio_available(void)
{
return tsrb_avail(&_cdc_stdio_isrpipe.tsrb);
}
#endif
ssize_t stdio_read(void* buffer, size_t len)
{
(void)buffer;
(void)len;
return isrpipe_read(&_cdc_stdio_isrpipe, buffer, len);
}
ssize_t stdio_write(const void* buffer, size_t len)
static ssize_t _write(const void* buffer, size_t len)
{
const char *start = buffer;
do {
@ -71,7 +52,7 @@ static void _cdc_acm_rx_pipe(usbus_cdcacm_device_t *cdcacm,
{
(void)cdcacm;
for (size_t i = 0; i < len; i++) {
isrpipe_write_one(&_cdc_stdio_isrpipe, data[i]);
isrpipe_write_one(&stdin_isrpipe, data[i]);
}
}
@ -80,3 +61,5 @@ void usb_cdc_acm_stdio_init(usbus_t *usbus)
usbus_cdc_acm_init(usbus, &cdcacm, _cdc_acm_rx_pipe, NULL,
_cdc_tx_buf_mem, sizeof(_cdc_tx_buf_mem));
}
STDIO_PROVIDER(STDIO_USBUS_CDC_ACM, NULL, NULL, _write)