diff --git a/Makefile.dep b/Makefile.dep index 65411f6db73347a28da47caa42e1be5ec43a6851..0b4d6df2bd71df169b5b2ec7345ba6458da924e7 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -373,6 +373,10 @@ ifneq (,$(filter rtt_stdio,$(USEMODULE))) endif ifneq (,$(filter uart_stdio,$(USEMODULE))) + USEMODULE += isrpipe +endif + +ifneq (,$(filter isrpipe,$(USEMODULE))) USEMODULE += tsrb endif diff --git a/drivers/ethos/ethos.c b/drivers/ethos/ethos.c index 698a365d70960f84d2d4da70c8f0414a01b779d9..8a2c2a680e9e7ece6c56b53a10a29f3649ff5e84 100644 --- a/drivers/ethos/ethos.c +++ b/drivers/ethos/ethos.c @@ -35,6 +35,8 @@ #ifdef USE_ETHOS_FOR_STDIO #include "uart_stdio.h" +#include "isrpipe.h" +extern isrpipe_t uart_stdio_isrpipe; #endif #define ENABLE_DEBUG (0) @@ -100,7 +102,7 @@ static void _handle_char(ethos_t *dev, char c) #ifdef USE_ETHOS_FOR_STDIO case ETHOS_FRAME_TYPE_TEXT: dev->framesize++; - uart_stdio_rx_cb(NULL, c); + isrpipe_write_one(&uart_stdio_isrpipe, c); #endif } } diff --git a/sys/include/isrpipe.h b/sys/include/isrpipe.h new file mode 100644 index 0000000000000000000000000000000000000000..3d4590b07f336d30ba0588a29e5bb1cad652f329 --- /dev/null +++ b/sys/include/isrpipe.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de> + * + * 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 + * @{ + * @file + * @brief ISR -> userspace pipe interface + * + * @author Kaspar Schleiser <kaspar@schleiser.de> + * + */ + +#ifndef ISRPIPE_H +#define ISRPIPE_H + +#include <stdint.h> + +#include "mutex.h" +#include "tsrb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Context structure for isrpipe + */ +typedef struct { + mutex_t mutex; /**< isrpipe mutex */ + tsrb_t tsrb; /**< isrpipe thread safe ringbuffer */ +} isrpipe_t; + +/** + * @brief Static initializer for irspipe + */ +#define ISRPIPE_INIT(tsrb_buf) { .mutex = MUTEX_INIT, .tsrb = TSRB_INIT(tsrb_buf) } + +/** + * @brief Initialisation function for isrpipe + * + * @param[in] isrpipe isrpipe object to initialize + * @param[in] buf buffer to use as ringbuffer (must be power of two sized!) + * @param[in] bufsize size of @p buf + */ +void isrpipe_init(isrpipe_t *isrpipe, char *buf, size_t bufsize); + +/** + * @brief Put one character into the isrpipe's buffer + * + * @param[in] isrpipe isrpipe object to initialize + * @param[in] c character to add to isrpipe buffer + * + * @returns 0 if character could be added + * @returns -1 if buffer was full + */ +int isrpipe_write_one(isrpipe_t *isrpipe, char c); + +/** + * @brief Read data from isrpipe (blocking) + * + * @param[in] isrpipe isrpipe object to operate on + * @param[in] buf buffer to write to + * @param[in] count number of bytes to read + * + * @returns number of bytes read + */ +int isrpipe_read(isrpipe_t *isrpipe, char *buf, size_t count); + +/** + * @brief Read data from isrpipe (with timeout, blocking) + * + * Currently, the timeout parameter is applied on every underlying read, which + * might be *per single byte*. + * + * @note This function might return less than @p count bytes + * + * @param[in] isrpipe isrpipe object to operate on + * @param[in] buf buffer to write to + * @param[in] count number of bytes to read + * @param[in] timeout timeout in ms + * + * @returns number of bytes read + * @returns -ETIMEDOUT on timeout + */ +int isrpipe_read_timeout(isrpipe_t *isrpipe, char *buf, size_t count, uint32_t timeout); + +/** + * @brief Read data from isrpipe (with timeout, blocking, wait until all read) + * + * This function is like @ref isrpipe_read_timeout, but will only return on + * timeout or when @p count bytes have been received. + * + * @param[in] isrpipe isrpipe object to operate on + * @param[in] buf buffer to write to + * @param[in] count number of bytes to read + * @param[in] timeout timeout in ms + * + * @returns number of bytes read + * @returns -ETIMEDOUT on timeout + */ +int isrpipe_read_all_timeout(isrpipe_t *isrpipe, char *buf, size_t count, uint32_t timeout); + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* ISRPIPE_H */ diff --git a/sys/isrpipe/Makefile b/sys/isrpipe/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2 --- /dev/null +++ b/sys/isrpipe/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/isrpipe/isrpipe.c b/sys/isrpipe/isrpipe.c new file mode 100644 index 0000000000000000000000000000000000000000..c9f6e1926acbc10950afc73b61af471a3c226a0a --- /dev/null +++ b/sys/isrpipe/isrpipe.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de> + * + * 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 + * @{ + * @file + * @brief ISR -> userspace pipe implementation + * + * @author Kaspar Schleiser <kaspar@schleiser.de> + * + * @} + */ + +#include <errno.h> + +#include "isrpipe.h" +#include "xtimer.h" + +void isrpipe_init(isrpipe_t *isrpipe, char *buf, size_t bufsize) +{ + mutex_init(&isrpipe->mutex); + tsrb_init(&isrpipe->tsrb, buf, bufsize); +} + +int isrpipe_write_one(isrpipe_t *isrpipe, char c) +{ + int res = tsrb_add_one(&isrpipe->tsrb, c); + + /* `res` is either 0 on success or -1 when the buffer is full. Either way, + * unlocking the mutex is fine. + */ + mutex_unlock(&isrpipe->mutex); + + return res; +} + +int isrpipe_read(isrpipe_t *isrpipe, char *buffer, size_t count) +{ + int res; + + while (!(res = tsrb_get(&isrpipe->tsrb, buffer, count))) { + mutex_lock(&isrpipe->mutex); + } + return res; +} + +typedef struct { + mutex_t *mutex; + int flag; +} _isrpipe_timeout_t; + +static void _cb(void *arg) +{ + _isrpipe_timeout_t *_timeout = (_isrpipe_timeout_t *) arg; + + _timeout->flag = 1; + mutex_unlock(_timeout->mutex); +} + +int isrpipe_read_timeout(isrpipe_t *isrpipe, char *buffer, size_t count, uint32_t timeout) +{ + int res; + + _isrpipe_timeout_t _timeout = { .mutex = &isrpipe->mutex, .flag = 0 }; + + xtimer_t timer = { .callback = _cb, .arg = &_timeout }; + + xtimer_set(&timer, timeout); + while (!(res = tsrb_get(&isrpipe->tsrb, buffer, count))) { + mutex_lock(&isrpipe->mutex); + if (_timeout.flag) { + res = -ETIMEDOUT; + break; + } + } + + xtimer_remove(&timer); + return res; +} + + +int isrpipe_read_all_timeout(isrpipe_t *isrpipe, char *buffer, size_t count, uint32_t timeout) +{ + char *pos = buffer; + + while (count) { + int res = isrpipe_read_timeout(isrpipe, pos, count, timeout); + if (res >= 0) { + count -= res; + pos += res; + } + else { + return res; + } + } + + return pos - buffer; +} diff --git a/sys/uart_stdio/uart_stdio.c b/sys/uart_stdio/uart_stdio.c index 14dace5e5c86255ff8b4bf34f9a5ce0e87144572..55f2a395be8f55d88db5a1126784f4882185629b 100644 --- a/sys/uart_stdio/uart_stdio.c +++ b/sys/uart_stdio/uart_stdio.c @@ -24,15 +24,12 @@ */ #include <stdio.h> -#include "uart_stdio.h" -#include "tsrb.h" -#include "thread.h" -#include "mutex.h" -#include "irq.h" +#include "uart_stdio.h" #include "board.h" #include "periph/uart.h" +#include "isrpipe.h" #ifdef USE_ETHOS_FOR_STDIO #include "ethos.h" @@ -42,39 +39,21 @@ extern ethos_t ethos; #define ENABLE_DEBUG 0 #include "debug.h" -/** - * @brief use mutex for waiting on incoming UART chars - */ -static mutex_t _rx_mutex = MUTEX_INIT; static char _rx_buf_mem[UART_STDIO_RX_BUFSIZE]; -static tsrb_t _rx_buf = TSRB_INIT(_rx_buf_mem); - -/** - * @brief Receive a new character from the UART and put it into the receive buffer - */ -void uart_stdio_rx_cb(void *arg, uint8_t data) -{ - (void)arg; - tsrb_add_one(&_rx_buf, (uint8_t)data); - mutex_unlock(&_rx_mutex); -} +isrpipe_t uart_stdio_isrpipe = ISRPIPE_INIT(_rx_buf_mem); void uart_stdio_init(void) { #ifndef USE_ETHOS_FOR_STDIO - uart_init(UART_STDIO_DEV, UART_STDIO_BAUDRATE, uart_stdio_rx_cb, NULL); + uart_init(UART_STDIO_DEV, UART_STDIO_BAUDRATE, (uart_rx_cb_t) isrpipe_write_one, &uart_stdio_isrpipe); #else - uart_init(ETHOS_UART, ETHOS_BAUDRATE, uart_stdio_rx_cb, NULL); + uart_init(ETHOS_UART, ETHOS_BAUDRATE, (uart_rx_cb_t) isrpipe_write_one, &uart_stdio_isrpipe); #endif } int uart_stdio_read(char* buffer, int count) { - int res; - while (!(res = tsrb_get(&_rx_buf, buffer, count))) { - mutex_lock(&_rx_mutex); - } - return res; + return isrpipe_read(&uart_stdio_isrpipe, buffer, count); } int uart_stdio_write(const char* buffer, int len)