2020#include < stdint.h>
2121#include " platform/mbed_critical.h"
2222#include " platform/mbed_assert.h"
23+ #include " platform/Span.h"
2324
2425namespace 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 */
6667template <typename T, uint32_t BufferSize, typename CounterType = uint32_t >
6768class 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
203324private:
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