summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/py.mk1
-rw-r--r--py/ringbuf.c109
-rw-r--r--py/ringbuf.h82
3 files changed, 125 insertions, 67 deletions
diff --git a/py/py.mk b/py/py.mk
index bca6ac14c..29d407f7a 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -257,6 +257,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\
repl.o \
smallint.o \
frozenmod.o \
+ ringbuf.o \
)
PY_EXTMOD_O_BASENAME = \
diff --git a/py/ringbuf.c b/py/ringbuf.c
new file mode 100644
index 000000000..70245461f
--- /dev/null
+++ b/py/ringbuf.c
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "ringbuf.h"
+
+// Dynamic initialization. This should be accessible from a root pointer.
+// capacity is the number of bytes the ring buffer can hold. The actual
+// size of the buffer is one greater than that, due to how the buffer
+// handles empty and full statuses.
+bool ringbuf_alloc(ringbuf_t *r, size_t capacity, bool long_lived) {
+ r->buf = gc_alloc(capacity + 1, false, long_lived);
+ r->size = capacity + 1;
+ r->iget = r->iput = 0;
+ return r->buf != NULL;
+}
+
+size_t ringbuf_capacity(ringbuf_t *r) {
+ return r->size - 1;
+}
+
+// Returns -1 if buffer is empty, else returns byte fetched.
+int ringbuf_get(ringbuf_t *r) {
+ if (r->iget == r->iput) {
+ return -1;
+ }
+ uint8_t v = r->buf[r->iget++];
+ if (r->iget >= r->size) {
+ r->iget = 0;
+ }
+ return v;
+}
+
+// Returns -1 if no room in buffer, else returns 0.
+int ringbuf_put(ringbuf_t *r, uint8_t v) {
+ uint32_t iput_new = r->iput + 1;
+ if (iput_new >= r->size) {
+ iput_new = 0;
+ }
+ if (iput_new == r->iget) {
+ return -1;
+ }
+ r->buf[r->iput] = v;
+ r->iput = iput_new;
+ return 0;
+}
+
+void ringbuf_clear(ringbuf_t *r) {
+ r->iput = r->iget = 0;
+}
+
+// Number of free slots that can be written.
+size_t ringbuf_free(ringbuf_t *r) {
+ return (r->size + r->iget - r->iput - 1) % r->size;
+}
+
+// Number of bytes available to read.
+size_t ringbuf_avail(ringbuf_t *r) {
+ return (r->size + r->iput - r->iget) % r->size;
+}
+
+// If the ring buffer fills up, not all bytes will be written.
+// Returns how many bytes were successfully written.
+size_t ringbuf_put_n(ringbuf_t* r, uint8_t* buf, size_t bufsize)
+{
+ for(size_t i=0; i < bufsize; i++) {
+ if ( ringbuf_put(r, buf[i]) < 0 ) {
+ // If ringbuf is full, give up and return how many bytes
+ // we wrote so far.
+ return i;
+ }
+ }
+ return bufsize;
+}
+
+// Returns how many bytes were fetched.
+size_t ringbuf_get_n(ringbuf_t* r, uint8_t* buf, size_t bufsize)
+{
+ for(size_t i=0; i < bufsize; i++) {
+ int b = ringbuf_get(r);
+ if (b < 0) {
+ return i;
+ }
+ buf[i] = b;
+ }
+ return bufsize;
+}
diff --git a/py/ringbuf.h b/py/ringbuf.h
index 7fc35d266..1e01091ab 100644
--- a/py/ringbuf.h
+++ b/py/ringbuf.h
@@ -32,78 +32,26 @@
typedef struct _ringbuf_t {
uint8_t *buf;
- uint16_t size;
- uint16_t iget;
- uint16_t iput;
+ // Allocated size; capacity is one less. Don't reference this directly.
+ uint32_t size;
+ uint32_t iget;
+ uint32_t iput;
} ringbuf_t;
+// Note that the capacity of the buffer is N-1!
+
// Static initialization:
// byte buf_array[N];
// ringbuf_t buf = {buf_array, sizeof(buf_array)};
-// Dynamic initialization. This creates root pointer!
-#define ringbuf_alloc(r, sz, long_lived) \
-{ \
- (r)->buf = gc_alloc(sz, false, long_lived); \
- (r)->size = sz; \
- (r)->iget = (r)->iput = 0; \
-}
-
-static inline int ringbuf_get(ringbuf_t *r) {
- if (r->iget == r->iput) {
- return -1;
- }
- uint8_t v = r->buf[r->iget++];
- if (r->iget >= r->size) {
- r->iget = 0;
- }
- return v;
-}
-
-static inline int ringbuf_put(ringbuf_t *r, uint8_t v) {
- uint32_t iput_new = r->iput + 1;
- if (iput_new >= r->size) {
- iput_new = 0;
- }
- if (iput_new == r->iget) {
- return -1;
- }
- r->buf[r->iput] = v;
- r->iput = iput_new;
- return 0;
-}
-
-static inline uint16_t ringbuf_count(ringbuf_t *r)
-{
- volatile int count = r->iput - r->iget;
- if ( count < 0 ) {
- count += r->size;
- }
-
- return (uint16_t) count;
-}
-
-static inline void ringbuf_clear(ringbuf_t *r)
-{
- r->iput = r->iget = 0;
-}
-
-// will overwrite old data
-static inline void ringbuf_put_n(ringbuf_t* r, uint8_t* buf, uint8_t bufsize)
-{
- for(uint8_t i=0; i < bufsize; i++) {
- if ( ringbuf_put(r, buf[i]) < 0 ) {
- // if full overwrite old data
- (void) ringbuf_get(r);
- ringbuf_put(r, buf[i]);
- }
- }
-}
+bool ringbuf_alloc(ringbuf_t *r, size_t capacity, bool long_lived);
+size_t ringbuf_capacity(ringbuf_t *r);
+int ringbuf_get(ringbuf_t *r);
+int ringbuf_put(ringbuf_t *r, uint8_t v);
+void ringbuf_clear(ringbuf_t *r);
+size_t ringbuf_free(ringbuf_t *r);
+size_t ringbuf_avail(ringbuf_t *r);
+size_t ringbuf_put_n(ringbuf_t* r, uint8_t* buf, size_t bufsize);
+size_t ringbuf_get_n(ringbuf_t* r, uint8_t* buf, size_t bufsize);
-static inline void ringbuf_get_n(ringbuf_t* r, uint8_t* buf, uint8_t bufsize)
-{
- for(uint8_t i=0; i < bufsize; i++) {
- buf[i] = ringbuf_get(r);
- }
-}
#endif // MICROPY_INCLUDED_PY_RINGBUF_H