20
20
#include < stdint.h>
21
21
#include " platform/mbed_critical.h"
22
22
#include " platform/mbed_assert.h"
23
+ #include " platform/Span.h"
23
24
24
25
namespace mbed {
25
26
@@ -60,8 +61,8 @@ struct is_unsigned<unsigned long long> {
60
61
61
62
/* * Templated Circular buffer class
62
63
*
63
- * @note Synchronization level: Interrupt safe
64
- * @note CounterType must be unsigned and consistent with BufferSize
64
+ * @note Synchronization level: Interrupt safe.
65
+ * @note CounterType must be unsigned and consistent with BufferSize.
65
66
*/
66
67
template <typename T, uint32_t BufferSize, typename CounterType = uint32_t >
67
68
class CircularBuffer {
@@ -84,10 +85,9 @@ class CircularBuffer {
84
85
{
85
86
}
86
87
87
- /* * Push the transaction to the buffer. This overwrites the buffer if it's
88
- * full
88
+ /* * Push the transaction to the buffer. This overwrites the buffer if it's full.
89
89
*
90
- * @param data Data to be pushed to the buffer
90
+ * @param data Data to be pushed to the buffer.
91
91
*/
92
92
void push (const T &data)
93
93
{
@@ -98,63 +98,191 @@ class CircularBuffer {
98
98
_tail = 0 ;
99
99
}
100
100
}
101
- _pool [_head++] = data;
101
+ _buffer [_head++] = data;
102
102
if (_head == BufferSize) {
103
103
_head = 0 ;
104
104
}
105
+
105
106
if (_head == _tail) {
106
107
_full = true ;
107
108
}
109
+
110
+ core_util_critical_section_exit ();
111
+ }
112
+
113
+ /* * Push the transaction to the buffer. This overwrites the buffer if it's full.
114
+ *
115
+ * @param src Data to be pushed to the buffer.
116
+ * @param len Number of items to be pushed to the buffer.
117
+ */
118
+ void push (const T* src, CounterType len)
119
+ {
120
+ core_util_critical_section_enter ();
121
+
122
+ /* if we try to write more bytes than the buffer can hold we only bother writing the last bytes */
123
+ if (len > BufferSize) {
124
+ _tail = 0 ;
125
+ _head = 0 ;
126
+ _full = true ;
127
+ std::copy (src, src + len, _buffer);
128
+ } else {
129
+ /* we need to adjust the tail at the end if we're filling the buffer of overflowing */
130
+ bool adjust_tail = ((BufferSize - non_critical_size ()) <= len);
131
+
132
+ CounterType written = len;
133
+
134
+ /* on first pass we write as much as we can to the right of head */
135
+ if ((_head + len) > BufferSize) {
136
+ written = BufferSize - _head;
137
+ }
138
+
139
+ std::copy (src, src + written, _buffer + _head);
140
+
141
+ CounterType left_to_write = len - written;
142
+ _head += written;
143
+ _head %= BufferSize;
144
+
145
+ /* we might need to continue to write from the start of the buffer */
146
+ if (left_to_write) {
147
+ std::copy (src + written, src + written + left_to_write, _buffer + left_to_write);
148
+ _head = written;
149
+ }
150
+
151
+ if (adjust_tail) {
152
+ _tail = _head;
153
+ _full = true ;
154
+ }
155
+ }
156
+
108
157
core_util_critical_section_exit ();
109
158
}
110
159
111
- /* * Pop the transaction from the buffer
160
+ /* * Push the transaction to the buffer. This overwrites the buffer if it's full.
161
+ *
162
+ * @param src Data to be pushed to the buffer.
163
+ */
164
+ template <CounterType N>
165
+ void push (T (&src)[N])
166
+ {
167
+ push (src, N);
168
+ }
169
+
170
+ /* * Push the transaction to the buffer. This overwrites the buffer if it's full.
112
171
*
113
- * @param data Data to be popped from the buffer
114
- * @return True if the buffer is not empty and data contains a transaction, false otherwise
172
+ * @param src Data to be pushed to the buffer.
115
173
*/
116
- bool pop (T &data)
174
+ void push (const mbed::Span<const T>& src)
175
+ {
176
+ push (src.data (), src.size ());
177
+ }
178
+
179
+ /* * Pop from the buffer.
180
+ *
181
+ * @param data Container to store the data to be popped from the buffer.
182
+ * @return True if data popped.
183
+ */
184
+ bool pop (T& data)
117
185
{
118
186
bool data_popped = false ;
187
+
119
188
core_util_critical_section_enter ();
120
- if (!empty ()) {
121
- data = _pool[_tail++];
122
- if (_tail == BufferSize) {
123
- _tail = 0 ;
189
+
190
+ if (!non_critical_empty ()) {
191
+ data_popped = true ;
192
+
193
+ data = _buffer[_tail];
194
+ _tail = incrementCounter (_tail);
195
+ _full = false ;
196
+ }
197
+
198
+ core_util_critical_section_exit ();
199
+
200
+ return data_popped;
201
+ }
202
+
203
+ /* *
204
+ * Pop multiple elements from the buffer.
205
+ *
206
+ * @param dest The array which will receive the elements.
207
+ * @param len The number of elements to pop.
208
+ *
209
+ * @return The number of elements popped.
210
+ */
211
+ CounterType pop (T* dest, CounterType len)
212
+ {
213
+ CounterType data_popped = 0 ;
214
+
215
+ core_util_critical_section_enter ();
216
+
217
+ if (!non_critical_empty ()) {
218
+ /* make sure we only try to read as much as we have items present */
219
+ if (len > non_critical_size ()) {
220
+ len = non_critical_size ();
124
221
}
222
+ data_popped = len;
223
+
224
+ /* items may be split by overlap, take only the number we have to the right of tail */
225
+ if ((_tail + data_popped) > BufferSize) {
226
+ data_popped = BufferSize - _tail;
227
+ }
228
+
229
+ std::copy (_buffer + _tail, _buffer + _tail + data_popped, dest);
230
+
231
+ /* if we looped over the end we may need to pop again */
232
+ CounterType left_to_pop = len - data_popped;
233
+
234
+ if (left_to_pop) {
235
+ std::copy (_buffer, _buffer + left_to_pop, dest + data_popped);
236
+
237
+ data_popped += left_to_pop;
238
+ }
239
+
240
+ _tail += data_popped;
241
+ _tail %= BufferSize;
125
242
_full = false ;
126
- data_popped = true ;
127
243
}
244
+
128
245
core_util_critical_section_exit ();
246
+
129
247
return data_popped;
130
248
}
131
249
132
- /* * Check if the buffer is empty
250
+ /* *
251
+ * Pop multiple elements from the buffer.
252
+ *
253
+ * @param dest The array which will receive the elements.
254
+ *
255
+ * @return The number of elements popped.
256
+ */
257
+ template <CounterType N>
258
+ CounterType pop (T (&dest)[N])
259
+ {
260
+ return pop (dest, N);
261
+ }
262
+
263
+ /* * Check if the buffer is empty.
133
264
*
134
- * @return True if the buffer is empty, false if not
265
+ * @return True if the buffer is empty, false if not.
135
266
*/
136
267
bool empty () const
137
268
{
138
269
core_util_critical_section_enter ();
139
- bool is_empty = (_head == _tail) && !_full ;
270
+ bool is_empty = non_critical_empty () ;
140
271
core_util_critical_section_exit ();
141
272
return is_empty;
142
273
}
143
274
144
- /* * Check if the buffer is full
275
+ /* * Check if the buffer is full.
145
276
*
146
277
* @return True if the buffer is full, false if not
147
278
*/
148
279
bool full () const
149
280
{
150
- core_util_critical_section_enter ();
151
- bool full = _full;
152
- core_util_critical_section_exit ();
153
- return full;
281
+ return _full;
154
282
}
155
283
156
- /* * Reset the buffer
157
- *
284
+ /* *
285
+ * Reset the buffer.
158
286
*/
159
287
void reset ()
160
288
{
@@ -165,43 +293,63 @@ class CircularBuffer {
165
293
core_util_critical_section_exit ();
166
294
}
167
295
168
- /* * Get the number of elements currently stored in the circular_buffer */
296
+ /* *
297
+ * Get the number of elements currently stored in the circular_buffer.
298
+ */
169
299
CounterType size () const
170
300
{
171
301
core_util_critical_section_enter ();
172
- CounterType elements;
173
- if (!_full) {
174
- if (_head < _tail) {
175
- elements = BufferSize + _head - _tail;
176
- } else {
177
- elements = _head - _tail;
178
- }
179
- } else {
180
- elements = BufferSize;
181
- }
302
+ CounterType elements = non_critical_size ();
182
303
core_util_critical_section_exit ();
183
304
return elements;
184
305
}
185
306
186
- /* * Peek into circular buffer without popping
307
+ /* * Peek into circular buffer without popping.
187
308
*
188
- * @param data Data to be peeked from the buffer
189
- * @return True if the buffer is not empty and data contains a transaction, false otherwise
309
+ * @param data Data to be peeked from the buffer.
310
+ * @return True if the buffer is not empty and data contains a transaction, false otherwise.
190
311
*/
191
312
bool peek (T &data) const
192
313
{
193
314
bool data_updated = false ;
194
315
core_util_critical_section_enter ();
195
316
if (!empty ()) {
196
- data = _pool [_tail];
317
+ data = _buffer [_tail];
197
318
data_updated = true ;
198
319
}
199
320
core_util_critical_section_exit ();
200
321
return data_updated;
201
322
}
202
323
203
324
private:
204
- T _pool[BufferSize];
325
+ bool non_critical_empty () const
326
+ {
327
+ bool is_empty = (_head == _tail) && !_full;
328
+ return is_empty;
329
+ }
330
+
331
+ bool non_critical_size () const
332
+ {
333
+ CounterType elements;
334
+ if (!_full) {
335
+ if (_head < _tail) {
336
+ elements = BufferSize + _head - _tail;
337
+ } else {
338
+ elements = _head - _tail;
339
+ }
340
+ } else {
341
+ elements = BufferSize;
342
+ }
343
+ return elements;
344
+ }
345
+
346
+ CounterType incrementCounter (CounterType val)
347
+ {
348
+ return (++val) % BufferSize;
349
+ }
350
+
351
+ private:
352
+ T _buffer[BufferSize];
205
353
CounterType _head;
206
354
CounterType _tail;
207
355
bool _full;
0 commit comments