Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2016 Paul Sokolovsky
7 : : *
8 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : * of this software and associated documentation files (the "Software"), to deal
10 : : * in the Software without restriction, including without limitation the rights
11 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : * copies of the Software, and to permit persons to whom the Software is
13 : : * furnished to do so, subject to the following conditions:
14 : : *
15 : : * The above copyright notice and this permission notice shall be included in
16 : : * all copies or substantial portions of the Software.
17 : : *
18 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 : : * THE SOFTWARE.
25 : : */
26 : : #ifndef MICROPY_INCLUDED_PY_RINGBUF_H
27 : : #define MICROPY_INCLUDED_PY_RINGBUF_H
28 : :
29 : : #include <stddef.h>
30 : : #include <stdint.h>
31 : : #include <string.h>
32 : :
33 : : #include "py/mpconfig.h"
34 : :
35 : : typedef struct _ringbuf_t {
36 : : uint8_t *buf;
37 : : uint16_t size;
38 : : uint16_t iget;
39 : : uint16_t iput;
40 : : } ringbuf_t;
41 : :
42 : : // Static initialization:
43 : : // byte buf_array[N];
44 : : // ringbuf_t buf = {buf_array, sizeof(buf_array)};
45 : :
46 : : // Dynamic initialization. This needs to become findable as a root pointer!
47 : : #define ringbuf_alloc(r, sz) \
48 : : { \
49 : : (r)->buf = m_new(uint8_t, sz); \
50 : : (r)->size = sz; \
51 : : (r)->iget = (r)->iput = 0; \
52 : : }
53 : :
54 : 594 : static inline int ringbuf_get(ringbuf_t *r) {
55 [ + - ]: 594 : if (r->iget == r->iput) {
56 : : return -1;
57 : : }
58 : 594 : uint8_t v = r->buf[r->iget++];
59 [ + + ]: 594 : if (r->iget >= r->size) {
60 : 2 : r->iget = 0;
61 : : }
62 : 594 : return v;
63 : : }
64 : :
65 : : static inline int ringbuf_peek(ringbuf_t *r) {
66 : : if (r->iget == r->iput) {
67 : : return -1;
68 : : }
69 : : return r->buf[r->iget];
70 : : }
71 : :
72 : 790 : static inline int ringbuf_put(ringbuf_t *r, uint8_t v) {
73 : 790 : uint32_t iput_new = r->iput + 1;
74 [ + + ]: 790 : if (iput_new >= r->size) {
75 : 4 : iput_new = 0;
76 : : }
77 [ + - ]: 790 : if (iput_new == r->iget) {
78 : : return -1;
79 : : }
80 : 790 : r->buf[r->iput] = v;
81 : 790 : r->iput = iput_new;
82 : 790 : return 0;
83 : : }
84 : :
85 : 120 : static inline size_t ringbuf_free(ringbuf_t *r) {
86 [ + + + + ]: 217 : return (r->size + r->iget - r->iput - 1) % r->size;
87 : : }
88 : :
89 : 188 : static inline size_t ringbuf_avail(ringbuf_t *r) {
90 [ + + + - ]: 172 : return (r->size + r->iput - r->iget) % r->size;
91 : : }
92 : :
93 : 94 : static inline void ringbuf_memcpy_get_internal(ringbuf_t *r, uint8_t *data, size_t data_len) {
94 : : // No bounds / space checking is performed here so ensure available size is checked before running this
95 : : // otherwise data loss or buffer overflow can occur.
96 : 94 : uint32_t iget = r->iget;
97 : 94 : uint32_t iget_a = (iget + data_len) % r->size;
98 : 94 : uint8_t *datap = data;
99 [ + + ]: 94 : if (iget_a < iget) {
100 : : // Copy part of the data from the space left at the end of the buffer
101 : 32 : memcpy(datap, r->buf + iget, r->size - iget);
102 : 32 : datap += (r->size - iget);
103 : 32 : iget = 0;
104 : : }
105 : 94 : memcpy(datap, r->buf + iget, iget_a - iget);
106 : 94 : r->iget = iget_a;
107 : 94 : }
108 : :
109 : 98 : static inline void ringbuf_memcpy_put_internal(ringbuf_t *r, const uint8_t *data, size_t data_len) {
110 : : // No bounds / space checking is performed here so ensure free size is checked before running this
111 : : // otherwise data loss or buffer overflow can occur.
112 : 98 : uint32_t iput = r->iput;
113 : 98 : uint32_t iput_a = (iput + data_len) % r->size;
114 : 98 : const uint8_t *datap = data;
115 [ + + ]: 98 : if (iput_a < iput) {
116 : : // Copy part of the data to the end of the buffer
117 : 32 : memcpy(r->buf + iput, datap, r->size - iput);
118 : 32 : datap += (r->size - iput);
119 : 32 : iput = 0;
120 : : }
121 : 98 : memcpy(r->buf + iput, datap, iput_a - iput);
122 : 98 : r->iput = iput_a;
123 : 98 : }
124 : :
125 : : // Note: big-endian. No-op if not enough room available for both bytes.
126 : : int ringbuf_get16(ringbuf_t *r);
127 : : int ringbuf_peek16(ringbuf_t *r);
128 : : int ringbuf_put16(ringbuf_t *r, uint16_t v);
129 : :
130 : : int ringbuf_get_bytes(ringbuf_t *r, uint8_t *data, size_t data_len);
131 : : int ringbuf_put_bytes(ringbuf_t *r, const uint8_t *data, size_t data_len);
132 : :
133 : : #endif // MICROPY_INCLUDED_PY_RINGBUF_H
|