Skip to content

Commit 821c9fc

Browse files
allow poppiong and pushing of multiplke items in circular buf
1 parent 9767ae8 commit 821c9fc

File tree

1 file changed

+189
-41
lines changed

1 file changed

+189
-41
lines changed

platform/include/platform/CircularBuffer.h

Lines changed: 189 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <stdint.h>
2121
#include "platform/mbed_critical.h"
2222
#include "platform/mbed_assert.h"
23+
#include "platform/Span.h"
2324

2425
namespace mbed {
2526

@@ -60,8 +61,8 @@ struct is_unsigned<unsigned long long> {
6061

6162
/** Templated Circular buffer class
6263
*
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.
6566
*/
6667
template<typename T, uint32_t BufferSize, typename CounterType = uint32_t>
6768
class CircularBuffer {
@@ -84,10 +85,9 @@ class CircularBuffer {
8485
{
8586
}
8687

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.
8989
*
90-
* @param data Data to be pushed to the buffer
90+
* @param data Data to be pushed to the buffer.
9191
*/
9292
void push(const T &data)
9393
{
@@ -98,63 +98,191 @@ class CircularBuffer {
9898
_tail = 0;
9999
}
100100
}
101-
_pool[_head++] = data;
101+
_buffer[_head++] = data;
102102
if (_head == BufferSize) {
103103
_head = 0;
104104
}
105+
105106
if (_head == _tail) {
106107
_full = true;
107108
}
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+
108157
core_util_critical_section_exit();
109158
}
110159

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.
112171
*
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.
115173
*/
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)
117185
{
118186
bool data_popped = false;
187+
119188
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();
124221
}
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;
125242
_full = false;
126-
data_popped = true;
127243
}
244+
128245
core_util_critical_section_exit();
246+
129247
return data_popped;
130248
}
131249

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.
133264
*
134-
* @return True if the buffer is empty, false if not
265+
* @return True if the buffer is empty, false if not.
135266
*/
136267
bool empty() const
137268
{
138269
core_util_critical_section_enter();
139-
bool is_empty = (_head == _tail) && !_full;
270+
bool is_empty = non_critical_empty();
140271
core_util_critical_section_exit();
141272
return is_empty;
142273
}
143274

144-
/** Check if the buffer is full
275+
/** Check if the buffer is full.
145276
*
146277
* @return True if the buffer is full, false if not
147278
*/
148279
bool full() const
149280
{
150-
core_util_critical_section_enter();
151-
bool full = _full;
152-
core_util_critical_section_exit();
153-
return full;
281+
return _full;
154282
}
155283

156-
/** Reset the buffer
157-
*
284+
/**
285+
* Reset the buffer.
158286
*/
159287
void reset()
160288
{
@@ -165,43 +293,63 @@ class CircularBuffer {
165293
core_util_critical_section_exit();
166294
}
167295

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+
*/
169299
CounterType size() const
170300
{
171301
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();
182303
core_util_critical_section_exit();
183304
return elements;
184305
}
185306

186-
/** Peek into circular buffer without popping
307+
/** Peek into circular buffer without popping.
187308
*
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.
190311
*/
191312
bool peek(T &data) const
192313
{
193314
bool data_updated = false;
194315
core_util_critical_section_enter();
195316
if (!empty()) {
196-
data = _pool[_tail];
317+
data = _buffer[_tail];
197318
data_updated = true;
198319
}
199320
core_util_critical_section_exit();
200321
return data_updated;
201322
}
202323

203324
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];
205353
CounterType _head;
206354
CounterType _tail;
207355
bool _full;

0 commit comments

Comments
 (0)