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:
commit
55b6728224
@ -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)
|
||||
/**@}*/
|
||||
|
@ -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];
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
||||
/** @} */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
1
sys/stdio/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
80
sys/stdio/stdio.c
Normal file
80
sys/stdio/stdio.c
Normal 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
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user