Skip to content

RingIO is limited to 64kB #16560

Description

@ma261065

Description

Discussion: #9458 (comment)

Currently RingIO is limited to creating ring buffers of 64kB by the use of the following uint16_t variables in ringbuf.h:

typedef struct _ringbuf_t {
    uint8_t *buf;
    uint16_t size;
    uint16_t iget;
    uint16_t iput;
} ringbuf_t;

The suggestion is to change these to uint32_t to allow for >64kB ringbuffers. This would only be useful in ports with more than 64kB of heap available, so it may be worthwhile having different versions for different ports.

Or maybe the extra 6 bytes is acceptable across all ports for the sake of simplicity/consistency?

I note that other structures (like bytearray) don't have a 64kB limit, so this would seem to be some sort of precedent for changing the limit.

Code Size

This change would add 6 bytes to RAM usage whenever RingIO is invoked

Implementation

I hope the MicroPython maintainers or community will implement this feature

Code of Conduct

Yes, I agree

Activity

  1. added
    enhancementFeature requests, new feature implementations
    on Jan 9, 2025
  2. stephanelsmith commented on Jan 29, 2025

    @stephanelsmith
    SponsorContributor

    Just jumping into RingIO, already want to make mega ringIO buffers for sampling adc!

  3. agatti commented on May 26, 2026

    @agatti
    Contributor

    The cheapest way to achieve that could be something like this:

    diff --git i/py/ringbuf.c w/py/ringbuf.c
    index 5f77271a0..0f43194f5 100644
    --- i/py/ringbuf.c
    +++ w/py/ringbuf.c
    @@ -42,7 +42,7 @@ int ringbuf_peek16(ringbuf_t *r) {
         if (r->iget == r->iput) {
             return -1;
         }
    -    uint32_t iget_a = r->iget + 1;
    +    ringbuf_size_overflow_t iget_a = r->iget + 1;
         if (iget_a == r->size) {
             iget_a = 0;
         }
    @@ -52,15 +52,15 @@ int ringbuf_peek16(ringbuf_t *r) {
         return (r->buf[r->iget] << 8) | (r->buf[iget_a]);
     }
     
    -int ringbuf_put16(ringbuf_t *r, uint16_t v) {
    -    uint32_t iput_a = r->iput + 1;
    +int ringbuf_put16(ringbuf_t *r, ringbuf_size_t v) {
    +    ringbuf_size_overflow_t iput_a = r->iput + 1;
         if (iput_a == r->size) {
             iput_a = 0;
         }
         if (iput_a == r->iget) {
             return -1;
         }
    -    uint32_t iput_b = iput_a + 1;
    +    ringbuf_size_overflow_t iput_b = iput_a + 1;
         if (iput_b == r->size) {
             iput_b = 0;
         }
    diff --git i/py/ringbuf.h w/py/ringbuf.h
    index d3c0f4601..96faeb917 100644
    --- i/py/ringbuf.h
    +++ w/py/ringbuf.h
    @@ -32,11 +32,18 @@
     
     #include "py/mpconfig.h"
     
    +#ifndef ringbuf_size_t
    +#define ringbuf_size_t uint16_t
    +#endif
    +#ifndef ringbuf_size_overflow_t
    +#define ringbuf_size_overflow_t uint32_t
    +#endif
    +
     typedef struct _ringbuf_t {
         uint8_t *buf;
    -    uint16_t size;
    -    uint16_t iget;
    -    uint16_t iput;
    +    ringbuf_size_t size;
    +    ringbuf_size_t iget;
    +    ringbuf_size_t iput;
     } ringbuf_t;
     
     // Static initialization:
    @@ -75,7 +82,7 @@ static inline int ringbuf_peek(ringbuf_t *r) {
     }
     
     static inline int ringbuf_put(ringbuf_t *r, uint8_t v) {
    -    uint32_t iput_new = r->iput + 1;
    +    ringbuf_size_overflow_t iput_new = r->iput + 1;
         if (iput_new >= r->size) {
             iput_new = 0;
         }
    @@ -98,8 +105,8 @@ static inline size_t ringbuf_avail(ringbuf_t *r) {
     static inline void ringbuf_memcpy_get_internal(ringbuf_t *r, uint8_t *data, size_t data_len) {
         // No bounds / space checking is performed here so ensure available size is checked before running this
         // otherwise data loss or buffer overflow can occur.
    -    uint32_t iget = r->iget;
    -    uint32_t iget_a = (iget + data_len) % r->size;
    +    ringbuf_size_overflow_t iget = r->iget;
    +    ringbuf_size_overflow_t iget_a = (iget + data_len) % r->size;
         uint8_t *datap = data;
         if (iget_a < iget) {
             // Copy part of the data from the space left at the end of the buffer
    @@ -114,8 +121,8 @@ static inline void ringbuf_memcpy_get_internal(ringbuf_t *r, uint8_t *data, size
     static inline void ringbuf_memcpy_put_internal(ringbuf_t *r, const uint8_t *data, size_t data_len) {
         // No bounds / space checking is performed here so ensure free size is checked before running this
         // otherwise data loss or buffer overflow can occur.
    -    uint32_t iput = r->iput;
    -    uint32_t iput_a = (iput + data_len) % r->size;
    +    ringbuf_size_overflow_t iput = r->iput;
    +    ringbuf_size_overflow_t iput_a = (iput + data_len) % r->size;
         const uint8_t *datap = data;
         if (iput_a < iput) {
             // Copy part of the data to the end of the buffer
    @@ -130,7 +137,7 @@ static inline void ringbuf_memcpy_put_internal(ringbuf_t *r, const uint8_t *data
     // Note: big-endian. No-op if not enough room available for both bytes.
     int ringbuf_get16(ringbuf_t *r);
     int ringbuf_peek16(ringbuf_t *r);
    -int ringbuf_put16(ringbuf_t *r, uint16_t v);
    +int ringbuf_put16(ringbuf_t *r, ringbuf_size_t v);
     
     int ringbuf_get_bytes(ringbuf_t *r, uint8_t *data, size_t data_len);
     int ringbuf_put_bytes(ringbuf_t *r, const uint8_t *data, size_t data_len);

    Not sure if this should end up in core or not, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementFeature requests, new feature implementationspy-coreRelates to py/ directory in source

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions