From 5e95d35f6c0b49f202c0ab3c5241186da253948c Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 15 Aug 2024 11:54:35 +1000 Subject: [PATCH] py/ringbuf: Add micropython.ringbuffer() interface for general use. Signed-off-by: Andrew Leech --- py/ringbuf.c | 62 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/py/ringbuf.c b/py/ringbuf.c index ad82528ea18ae..91220a0bbbd63 100644 --- a/py/ringbuf.c +++ b/py/ringbuf.c @@ -75,14 +75,8 @@ int ringbuf_put16(ringbuf_t *r, uint16_t v) { return 0; } -// Returns: -// 0: Success -// -1: Not enough data available to complete read (try again later) -// -2: Requested read is larger than buffer - will never succeed -int ringbuf_get_bytes(ringbuf_t *r, uint8_t *data, size_t data_len) { - if (ringbuf_avail(r) < data_len) { - return (r->size <= data_len) ? -2 : -1; - } +static inline __attribute__((always_inline)) void _ringbuf_memcpy_get(ringbuf_t *r, uint8_t *data, size_t data_len) { + // Ensure bounds / space checking is done before running this uint32_t iget = r->iget; uint32_t iget_a = (iget + data_len) % r->size; uint8_t *datap = data; @@ -94,17 +88,10 @@ int ringbuf_get_bytes(ringbuf_t *r, uint8_t *data, size_t data_len) { } memcpy(datap, r->buf + iget, iget_a - iget); r->iget = iget_a; - return 0; } -// Returns: -// 0: Success -// -1: Not enough free space available to complete write (try again later) -// -2: Requested write is larger than buffer - will never succeed -int ringbuf_put_bytes(ringbuf_t *r, const uint8_t *data, size_t data_len) { - if (ringbuf_free(r) < data_len) { - return (r->size <= data_len) ? -2 : -1; - } +static inline __attribute__((always_inline)) void _ringbuf_memcpy_put(ringbuf_t *r, const uint8_t *data, size_t data_len) { + // Ensure bounds / space checking is done before running this uint32_t iput = r->iput; uint32_t iput_a = (iput + data_len) % r->size; const uint8_t *datap = data; @@ -116,6 +103,29 @@ int ringbuf_put_bytes(ringbuf_t *r, const uint8_t *data, size_t data_len) { } memcpy(r->buf + iput, datap, iput_a - iput); r->iput = iput_a; +} + +// Returns: +// 0: Success +// -1: Not enough data available to complete read (try again later) +// -2: Requested read is larger than buffer - will never succeed +int ringbuf_get_bytes(ringbuf_t *r, uint8_t *data, size_t data_len) { + if (ringbuf_avail(r) < data_len) { + return (r->size <= data_len) ? -2 : -1; + } + _ringbuf_memcpy_get(r, data, data_len); + return 0; +} + +// Returns: +// 0: Success +// -1: Not enough free space available to complete write (try again later) +// -2: Requested write is larger than buffer - will never succeed +int ringbuf_put_bytes(ringbuf_t *r, const uint8_t *data, size_t data_len) { + if (ringbuf_free(r) < data_len) { + return (r->size <= data_len) ? -2 : -1; + } + _ringbuf_memcpy_put(r, data, data_len); return 0; } @@ -124,6 +134,10 @@ int ringbuf_put_bytes(ringbuf_t *r, const uint8_t *data, size_t data_len) { #include "py/stream.h" #include "py/mphal.h" +#ifndef MICROPY_PY_MICROPYTHON_RINGBUFFER_USE_MEMCPY +#define MICROPY_PY_MICROPYTHON_RINGBUFFER_USE_MEMCPY (1) +#endif + typedef struct _micropython_ringbuffer_obj_t { mp_obj_base_t base; ringbuf_t ringbuffer; @@ -154,10 +168,15 @@ static mp_obj_t micropython_ringbuffer_make_new(const mp_obj_type_t *type, size_ static mp_uint_t micropython_ringbuffer_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { micropython_ringbuffer_obj_t *self = MP_OBJ_TO_PTR(self_in); size = MIN(size, ringbuf_avail(&self->ringbuffer)); + #if MICROPY_PY_MICROPYTHON_RINGBUFFER_USE_MEMCPY + _ringbuf_memcpy_get(&(self->ringbuffer), buf_in, size); + #else uint8_t *dest = buf_in; - for (mp_uint_t i = 0; i < size; i++) { + const uint8_t *dest_end = dest + size; + while (dest < dest_end) { *dest++ = ringbuf_get(&(self->ringbuffer)); } + #endif *errcode = 0; return size; } @@ -165,10 +184,15 @@ static mp_uint_t micropython_ringbuffer_read(mp_obj_t self_in, void *buf_in, mp_ static mp_uint_t micropython_ringbuffer_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { micropython_ringbuffer_obj_t *self = MP_OBJ_TO_PTR(self_in); size = MIN(size, ringbuf_free(&self->ringbuffer)); + #if MICROPY_PY_MICROPYTHON_RINGBUFFER_USE_MEMCPY + _ringbuf_memcpy_put(&(self->ringbuffer), buf_in, size); + #else const uint8_t *src = buf_in; - for (mp_uint_t i = 0; i < size; i++) { + const uint8_t *src_end = src + size; + while (src < src_end) { ringbuf_put(&(self->ringbuffer), *src++); } + #endif *errcode = 0; return size; }