diff --git a/sys/include/tsrb.h b/sys/include/tsrb.h index 99890ad1da41..45c472411545 100644 --- a/sys/include/tsrb.h +++ b/sys/include/tsrb.h @@ -33,7 +33,7 @@ extern "C" { #endif /** - * @brief thread-safe ringbuffer struct + * @brief thread-safe ringbuffer struct */ typedef struct tsrb { uint8_t *buf; /**< Buffer to operate on. */ @@ -43,22 +43,22 @@ typedef struct tsrb { } tsrb_t; /** - * @brief Static initializer + * @brief Static initializer * * @note The size of the buffer (`sizeof(@p BUF)`) must be a power of two. * - * @param[in] BUF Buffer to use by tsrb. + * @param[in] BUF Buffer to use by tsrb. */ #define TSRB_INIT(BUF) { (BUF), sizeof (BUF), 0, 0 } /** - * @brief Initialize a tsrb. + * @brief Initialize a tsrb. * * @note The size of the buffer (@p bufsize) must be a power of two. * - * @param[out] rb Datum to initialize. - * @param[in] buffer Buffer to use by tsrb. - * @param[in] bufsize Size of @p buffer. + * @param[out] rb Datum to initialize. + * @param[in] buffer Buffer to use by tsrb. + * @param[in] bufsize Size of @p buffer. */ static inline void tsrb_init(tsrb_t *rb, uint8_t *buffer, unsigned bufsize) { @@ -74,8 +74,8 @@ static inline void tsrb_init(tsrb_t *rb, uint8_t *buffer, unsigned bufsize) } /** - * @brief Clear a tsrb. - * @param[out] rb Ringbuffer to operate on + * @brief Clear a tsrb. + * @param[out] rb Ringbuffer to operate on */ static inline void tsrb_clear(tsrb_t *rb) { @@ -106,7 +106,7 @@ static inline int tsrb_empty(const tsrb_t *rb) static inline unsigned int tsrb_avail(const tsrb_t *rb) { unsigned irq_state = irq_disable(); - int retval = (rb->writes - rb->reads); + unsigned int retval = (rb->writes - rb->reads); irq_restore(irq_state); return retval; } @@ -133,7 +133,7 @@ static inline int tsrb_full(const tsrb_t *rb) static inline unsigned int tsrb_free(const tsrb_t *rb) { unsigned irq_state = irq_disable(); - int retval = (rb->size - rb->writes + rb->reads); + unsigned int retval = (rb->size - rb->writes + rb->reads); irq_restore(irq_state); return retval; } diff --git a/sys/include/turb.h b/sys/include/turb.h new file mode 100644 index 000000000000..7943e335cd19 --- /dev/null +++ b/sys/include/turb.h @@ -0,0 +1,232 @@ +/* + * SPDX-FileCopyrightText: 2015 Kaspar Schleiser + * SPDX-FileCopyrightText: 2025 Karl Fessel ML!PA Consulting GmbH + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +/** + * @ingroup sys_tsrb + * @brief Thread Unsafe access to Thread-safe ringbuffer + * @{ + * + * @attention use only if you ensurred thread safety otherwise + * e.g.: by an irq guard + * @file + * @brief Thread-unsafe ringbuffer interface definition + * + * @author Kaspar Schleiser + * @author Karl Fessel + */ + +#include "tsrb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Clear a tsrb. + * @attention use only if you ensurred thread safety otherwise + * @param[out] rb Ringbuffer to operate on + */ +static inline void turb_clear(tsrb_t *rb) +{ + rb->reads = rb->writes; +} + +/** + * @brief Test if the tsrb is empty. + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @return 0 if not empty + * @return 1 otherwise + */ +static inline int turb_empty(const tsrb_t *rb) +{ + int retval = (rb->reads == rb->writes); + return retval; +} + +/** + * @brief Get number of bytes available for reading + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @return nr of available bytes + */ +static inline unsigned int turb_avail(const tsrb_t *rb) +{ + unsigned retval = (rb->writes - rb->reads); + return retval; +} + +/** + * @brief Test if the tsrb is full + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @return 0 if not full + * @return 1 otherwise + */ +static inline int turb_full(const tsrb_t *rb) +{ + int retval = (rb->writes - rb->reads) == rb->size; + return retval; +} + +/** + * @brief Get free space in ringbuffer + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @return nr of available bytes + */ +static inline unsigned int turb_free(const tsrb_t *rb) +{ + unsigned int retval = (rb->size - rb->writes + rb->reads); + return retval; +} + +#ifndef DOXYGEN +/* these are internal function */ +static inline void _turb_push(tsrb_t *rb, uint8_t c) +{ + rb->buf[rb->writes++ & (rb->size - 1)] = c; +} + +static inline uint8_t _turb_pop(tsrb_t *rb) +{ + return rb->buf[rb->reads++ & (rb->size - 1)]; +} + +static inline uint8_t _turb_peek(tsrb_t *rb, unsigned int idx) +{ + return rb->buf[(rb->reads + idx) & (rb->size - 1)]; +} +#endif + +/** + * @brief Get a byte from ringbuffer + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @return >=0 byte that has been read + * @return -1 if no byte available + */ +static inline int turb_get_one(tsrb_t *rb) +{ + int retval = -1; + if (!turb_empty(rb)) { + retval = _turb_pop(rb); + } + return retval; +} + +/** + * @brief Get a byte from ringbuffer, without removing it + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @return >=0 byte that has been read + * @return -1 if no byte available + */ +static inline int turb_peek_one(tsrb_t *rb) +{ + int retval = -1; + if (!turb_empty(rb)) { + retval = _turb_peek(rb, 0); + } + return retval; +} + +/** + * @brief Get bytes from ringbuffer + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @param[out] dst buffer to write to + * @param[in] n max number of bytes to write to @p dst + * @return nr of bytes written to @p dst + */ +static inline int turb_get(tsrb_t *rb, uint8_t *dst, size_t n) +{ + size_t cnt = 0; + while (n-- && !turb_empty(rb)) { + *dst++ = _turb_pop(rb); + cnt++; + } + return (int) cnt; +} + +/** + * @brief Get bytes from ringbuffer, without removing them + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @param[out] dst buffer to write to + * @param[in] n max number of bytes to write to @p dst + * @return nr of bytes written to @p dst + */ +static inline int turb_peek(tsrb_t *rb, uint8_t *dst, size_t n) +{ + size_t idx = 0; + unsigned int avail = turb_avail(rb); + while (idx < n && idx != avail) { + *dst++ = _turb_peek(rb, idx++); + } + return (int) idx; +} + +/** + * @brief Drop bytes from ringbuffer + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @param[in] n max number of bytes to drop + * @return nr of bytes dropped + */ +static inline int turb_drop(tsrb_t *rb, size_t n) +{ + size_t cnt = 0; + while (n-- && !turb_empty(rb)) { + _turb_pop(rb); + cnt++; + } + return (int) cnt; +} + +/** + * @brief Add a byte to ringbuffer + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @param[in] c Character to add to ringbuffer + * @return 0 on success + * @return -1 if no space available + */ +static inline int turb_add_one(tsrb_t *rb, uint8_t c) +{ + int retval = -1; + if (!turb_full(rb)) { + _turb_push(rb, c); + retval = 0; + } + return retval; +} + +/** + * @brief Add bytes to ringbuffer + * @attention use only if you ensurred thread safety otherwise + * @param[in] rb Ringbuffer to operate on + * @param[in] src buffer to read from + * @param[in] n max number of bytes to read from @p src + * @return nr of bytes read from @p src + */ +static inline int turb_add(tsrb_t *rb, const uint8_t *src, size_t n) +{ + size_t ret = 0; + while (n-- && !turb_full(rb)) { + _turb_push(rb, *src++); + ret++; + } + return (int) ret; +} + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/sys/tsrb/tsrb.c b/sys/tsrb/tsrb.c index 90bd72e2bc9f..a8e594b768cf 100644 --- a/sys/tsrb/tsrb.c +++ b/sys/tsrb/tsrb.c @@ -19,100 +19,60 @@ #include "irq.h" #include "tsrb.h" - -static void _push(tsrb_t *rb, uint8_t c) -{ - rb->buf[rb->writes++ & (rb->size - 1)] = c; -} - -static uint8_t _pop(tsrb_t *rb) -{ - return rb->buf[rb->reads++ & (rb->size - 1)]; -} - -static uint8_t _peek(tsrb_t *rb, unsigned int idx) -{ - return rb->buf[(rb->reads + idx) & (rb->size - 1)]; -} +#include "turb.h" int tsrb_get_one(tsrb_t *rb) { - int retval = -1; unsigned irq_state = irq_disable(); - if (!tsrb_empty(rb)) { - retval = _pop(rb); - } + int retval = turb_get_one(rb); irq_restore(irq_state); return retval; } int tsrb_peek_one(tsrb_t *rb) { - int retval = -1; unsigned irq_state = irq_disable(); - if (!tsrb_empty(rb)) { - retval = _peek(rb, 0); - } + int retval = turb_peek_one(rb); irq_restore(irq_state); return retval; } int tsrb_get(tsrb_t *rb, uint8_t *dst, size_t n) { - size_t tmp = n; unsigned irq_state = irq_disable(); - while (tmp && !tsrb_empty(rb)) { - *dst++ = _pop(rb); - tmp--; - } + int cnt = turb_get(rb, dst, n); irq_restore(irq_state); - return (n - tmp); + return cnt; } int tsrb_peek(tsrb_t *rb, uint8_t *dst, size_t n) { - size_t idx = 0; unsigned irq_state = irq_disable(); - unsigned int avail = tsrb_avail(rb); - while (idx < n && idx != avail) { - *dst++ = _peek(rb, idx++); - } + int idx = turb_peek(rb, dst, n); irq_restore(irq_state); return idx; } int tsrb_drop(tsrb_t *rb, size_t n) { - size_t tmp = n; unsigned irq_state = irq_disable(); - while (tmp && !tsrb_empty(rb)) { - _pop(rb); - tmp--; - } + int cnt = turb_drop(rb, n); irq_restore(irq_state); - return (n - tmp); + return cnt; } int tsrb_add_one(tsrb_t *rb, uint8_t c) { - int retval = -1; unsigned irq_state = irq_disable(); - if (!tsrb_full(rb)) { - _push(rb, c); - retval = 0; - } + int retval = turb_add_one(rb, c); irq_restore(irq_state); return retval; } int tsrb_add(tsrb_t *rb, const uint8_t *src, size_t n) { - size_t tmp = n; unsigned irq_state = irq_disable(); - while (tmp && !tsrb_full(rb)) { - _push(rb, *src++); - tmp--; - } + int cnt = turb_add(rb, src, n); irq_restore(irq_state); - return (n - tmp); + return cnt; } diff --git a/sys/usb/usbus/cdc/acm/cdc_acm.c b/sys/usb/usbus/cdc/acm/cdc_acm.c index 77c93bcb5a6c..4d65762e8a64 100644 --- a/sys/usb/usbus/cdc/acm/cdc_acm.c +++ b/sys/usb/usbus/cdc/acm/cdc_acm.c @@ -22,7 +22,7 @@ #include #include "tsrb.h" -#include "usb/descriptor.h" +#include "turb.h" #include "usb/cdc.h" #include "usb/descriptor.h" #include "usb/usbus.h" @@ -154,20 +154,20 @@ size_t usbus_cdc_acm_submit(usbus_cdcacm_device_t *cdcacm, const uint8_t *buf, s unsigned old; if (cdcacm->state != USBUS_CDC_ACM_LINE_STATE_DISCONNECTED) { old = irq_disable(); - n = tsrb_add(&cdcacm->tsrb, buf, len); + n = turb_add(&cdcacm->tsrb, buf, len); irq_restore(old); return n; } /* stuff as much data as possible into tsrb, discarding the oldest */ old = irq_disable(); - n = tsrb_free(&cdcacm->tsrb); + n = turb_free(&cdcacm->tsrb); if (len > n) { - n += tsrb_drop(&cdcacm->tsrb, len - n); + n += turb_drop(&cdcacm->tsrb, len - n); buf += len - n; } else { n = len; } - tsrb_add(&cdcacm->tsrb, buf, n); + turb_add(&cdcacm->tsrb, buf, n); /* behave as if everything has been written correctly */ irq_restore(old); return len; @@ -341,8 +341,8 @@ static void _handle_in(usbus_cdcacm_device_t *cdcacm, } /* copy at most CONFIG_USBUS_CDC_ACM_BULK_EP_SIZE chars from input into ep->buf */ unsigned old = irq_disable(); - while (!tsrb_empty(&cdcacm->tsrb)) { - int c = tsrb_get_one(&cdcacm->tsrb); + while (!turb_empty(&cdcacm->tsrb)) { + int c = turb_get_one(&cdcacm->tsrb); cdcacm->in_buf[cdcacm->occupied++] = (uint8_t)c; if (cdcacm->occupied >= CONFIG_USBUS_CDC_ACM_BULK_EP_SIZE) { break;