diff --git a/Makefile.dep b/Makefile.dep index 7db3606932..0a15db0046 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -436,7 +436,7 @@ ifneq (,$(filter newlib,$(USEMODULE))) ifeq (,$(filter newlib_syscalls_%,$(USEMODULE))) USEMODULE += newlib_syscalls_default endif - ifeq (,$(filter stdio_cdc_acm stdio_native stdio_null stdio_rtt,$(USEMODULE))) + ifeq (,$(filter stdio_cdc_acm stdio_native stdio_null stdio_rtt slipdev_stdio,$(USEMODULE))) USEMODULE += stdio_uart endif endif @@ -483,7 +483,7 @@ ifneq (,$(filter stdio_uart,$(USEMODULE))) FEATURES_REQUIRED += periph_uart endif -ifneq (,$(filter stdio_cdc_acm stdio_null stdio_uart,$(USEMODULE))) +ifneq (,$(filter stdio_cdc_acm stdio_null stdio_uart slipdev_stdio,$(USEMODULE))) # stdio_rtt cannot be used when another STDIO is loaded DISABLE_MODULE += stdio_rtt endif diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 7edbff1a29..e8d4d2e8c5 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -601,6 +601,12 @@ ifneq (,$(filter slipdev,$(USEMODULE))) FEATURES_REQUIRED += periph_uart endif +ifneq (,$(filter slipdev_stdio,$(USEMODULE))) + USEMODULE += isrpipe + USEMODULE += slipdev + FEATURES_REQUIRED += periph_uart +endif + ifneq (,$(filter soft_spi,$(USEMODULE))) FEATURES_REQUIRED += periph_gpio USEMODULE += xtimer diff --git a/drivers/include/slipdev.h b/drivers/include/slipdev.h index a4b625984b..435c8703bd 100644 --- a/drivers/include/slipdev.h +++ b/drivers/include/slipdev.h @@ -44,6 +44,27 @@ extern "C" { #define SLIPDEV_BUFSIZE (2048U) #endif +/** + * @name Device state definitions + * @anchor drivers_slipdev_states + * @{ + */ +enum { + /** + * @brief Device is in no mode (currently did not receiving any data frame) + */ + SLIPDEV_STATE_NONE = 0, + /** + * @brief Device writes handles data as network device + */ + SLIPDEV_STATE_NET, + /** + * @brief Device writes received data to stdin + */ + SLIPDEV_STATE_STDIN, +}; +/** @} */ + /** * @brief Configuration parameters for a slipdev */ @@ -62,6 +83,11 @@ typedef struct { slipdev_params_t config; /**< configuration parameters */ tsrb_t inbuf; /**< RX buffer */ uint8_t rxmem[SLIPDEV_BUFSIZE]; /**< memory used by RX buffer */ + /** + * @brief Device state + * @see [Device state definitions](@ref drivers_slipdev_states) + */ + uint8_t state; } slipdev_t; /** diff --git a/drivers/slipdev/Makefile b/drivers/slipdev/Makefile index 48422e909a..7c6f250804 100644 --- a/drivers/slipdev/Makefile +++ b/drivers/slipdev/Makefile @@ -1 +1,7 @@ +# exclude submodule sources from *.c wildcard source selection +SRC := $(filter-out stdio.c,$(wildcard *.c)) + +# enable submodules +SUBMODULES := 1 + include $(RIOTBASE)/Makefile.base diff --git a/drivers/slipdev/include/slipdev_internal.h b/drivers/slipdev/include/slipdev_internal.h index 07a39751a2..d0b90270d5 100644 --- a/drivers/slipdev/include/slipdev_internal.h +++ b/drivers/slipdev/include/slipdev_internal.h @@ -22,7 +22,9 @@ #include #include +#include "isrpipe.h" #include "periph/uart.h" +#include "mutex.h" #ifdef __cplusplus extern "C" { @@ -37,8 +39,26 @@ extern "C" { #define SLIPDEV_ESC (0xdbU) #define SLIPDEV_END_ESC (0xdcU) #define SLIPDEV_ESC_ESC (0xddU) + +/** + * @brief Marker byte for beginning of stdio + * @see taken from diagnostic transfer from + * [SLIPMUX](https://tools.ietf.org/html/draft-bormann-t2trg-slipmux-02#section-4) + */ +#define SLIPDEV_STDIO_START (0x0aU) /** @} */ +/** + * @brief ISR pipe to hand read bytes to stdin + */ +extern isrpipe_t slipdev_stdio_isrpipe; + +/** + * @brief Mutex to synchronize write operations to the UART between stdio + * sub-module and normal SLIP. + */ +extern mutex_t slipdev_mutex; + /** * @brief Writes one byte to UART * diff --git a/drivers/slipdev/slipdev.c b/drivers/slipdev/slipdev.c index 5bb6a0008d..effb7c9658 100644 --- a/drivers/slipdev/slipdev.c +++ b/drivers/slipdev/slipdev.c @@ -21,16 +21,54 @@ #include "slipdev.h" #include "slipdev_internal.h" +/* XXX: BE CAREFUL ABOUT USING OUTPUT WITH MODULE_SLIPDEV_STDIO IN SENDING + * FUNCTIONALITY! MIGHT CAUSE DEADLOCK!!!1!! */ #define ENABLE_DEBUG (0) #include "debug.h" +#include "isrpipe.h" +#include "mutex.h" +#include "stdio_uart.h" + +static inline void slipdev_lock(void) +{ + if (IS_USED(MODULE_SLIPDEV_STDIO)) { + mutex_lock(&slipdev_mutex); + } +} + +static inline void slipdev_unlock(void) +{ + if (IS_USED(MODULE_SLIPDEV_STDIO)) { + mutex_unlock(&slipdev_mutex); + } +} + static void _slip_rx_cb(void *arg, uint8_t byte) { slipdev_t *dev = arg; + if (IS_USED(MODULE_SLIPDEV_STDIO)) { + if (dev->state == SLIPDEV_STATE_STDIN) { + isrpipe_write_one(&slipdev_stdio_isrpipe, byte); + goto check_end; + } + else if ((byte == SLIPDEV_STDIO_START) && + (dev->config.uart == STDIO_UART_DEV) && + (dev->state == SLIPDEV_STATE_NONE)) { + dev->state = SLIPDEV_STATE_STDIN; + return; + } + } + dev->state = SLIPDEV_STATE_NET; tsrb_add_one(&dev->inbuf, byte); - if ((byte == SLIPDEV_END) && (dev->netdev.event_callback != NULL)) { - dev->netdev.event_callback((netdev_t *)dev, NETDEV_EVENT_ISR); +check_end: + if (byte == SLIPDEV_END) { + if ((dev->state == SLIPDEV_STATE_NET) && + (dev->netdev.event_callback != NULL)) { + dev->netdev.event_callback((netdev_t *)dev, NETDEV_EVENT_ISR); + } + dev->state = SLIPDEV_STATE_NONE; } } @@ -112,12 +150,14 @@ static int _send(netdev_t *netdev, const iolist_t *iolist) int bytes = 0; DEBUG("slipdev: sending iolist\n"); + slipdev_lock(); for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) { uint8_t *data = iol->iol_base; slipdev_write_bytes(dev->config.uart, data, iol->iol_len); bytes += iol->iol_len; } slipdev_write_byte(dev->config.uart, SLIPDEV_END); + slipdev_unlock(); return bytes; } @@ -209,6 +249,7 @@ void slipdev_setup(slipdev_t *dev, const slipdev_params_t *params) { /* set device descriptor fields */ dev->config = *params; + dev->state = 0; dev->netdev.driver = &slip_driver; } diff --git a/drivers/slipdev/stdio.c b/drivers/slipdev/stdio.c new file mode 100644 index 0000000000..d36c8d4746 --- /dev/null +++ b/drivers/slipdev/stdio.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * 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. + */ + +/** + * @{ + * + * @file + * @author Martine Lenders + */ + +#include "board.h" +#include "isrpipe.h" +#include "periph/uart.h" + +#include "slipdev.h" +#include "slipdev_internal.h" +#include "slipdev_params.h" + +#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) +{ + isrpipe_write_one(arg, (char)data); +} + +void stdio_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, + (uart_rx_cb_t)_isrpipe_write, &slipdev_stdio_isrpipe); +} + +ssize_t stdio_read(void *buffer, size_t len) +{ + uint8_t *ptr = buffer; + bool escaped = false; + uint8_t byte; + + do { + int read = isrpipe_read(&slipdev_stdio_isrpipe, &byte, 1); + int tmp; + + if (read == 0) { + continue; + } + else if (len == 0) { + return -ENOBUFS; + } + tmp = slipdev_unstuff_readbyte(ptr, byte, &escaped); + ptr += tmp; + if ((unsigned)(ptr - (uint8_t *)buffer) > len) { + while (byte != SLIPDEV_END) { + /* clear out unreceived packet */ + isrpipe_read(&slipdev_stdio_isrpipe, &byte, 1); + } + return -ENOBUFS; + } + } while (byte != SLIPDEV_END); + return ptr - (uint8_t *)buffer; +} + +ssize_t stdio_write(const void *buffer, size_t len) +{ + mutex_lock(&slipdev_mutex); + slipdev_write_byte(slipdev_params[0].uart, SLIPDEV_STDIO_START); + slipdev_write_bytes(slipdev_params[0].uart, buffer, len); + slipdev_write_byte(slipdev_params[0].uart, SLIPDEV_END); + mutex_unlock(&slipdev_mutex); + return len; +} + +/** @} */ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 1d0f9c19d9..362b54a1a2 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -82,6 +82,7 @@ PSEUDOMODULES += saul_nrf_temperature PSEUDOMODULES += scanf_float PSEUDOMODULES += sched_cb PSEUDOMODULES += semtech_loramac_rx +PSEUDOMODULES += slipdev_stdio PSEUDOMODULES += sock PSEUDOMODULES += sock_async PSEUDOMODULES += sock_dtls