mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CircularBuffer.h Source File

CircularBuffer.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2015 ARM Limited
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #ifndef MBED_CIRCULARBUFFER_H
00018 #define MBED_CIRCULARBUFFER_H
00019 
00020 #include "platform/mbed_critical.h"
00021 #include "platform/mbed_assert.h"
00022 
00023 namespace mbed {
00024 
00025 namespace internal {
00026 /* Detect if CounterType of the Circular buffer is of unsigned type. */
00027 template<typename T>
00028 struct is_unsigned {
00029     static const bool value = false;
00030 };
00031 template<>
00032 struct is_unsigned<unsigned char> {
00033     static const bool value = true;
00034 };
00035 template<>
00036 struct is_unsigned<unsigned short> {
00037     static const bool value = true;
00038 };
00039 template<>
00040 struct is_unsigned<unsigned int> {
00041     static const bool value = true;
00042 };
00043 template<>
00044 struct is_unsigned<unsigned long> {
00045     static const bool value = true;
00046 };
00047 template<>
00048 struct is_unsigned<unsigned long long> {
00049     static const bool value = true;
00050 };
00051 };
00052 
00053 /** \addtogroup platform */
00054 /** @{*/
00055 /**
00056  * \defgroup platform_CircularBuffer CircularBuffer functions
00057  * @{
00058  */
00059 
00060 /** Templated Circular buffer class
00061  *
00062  *  @note Synchronization level: Interrupt safe
00063  *  @note CounterType must be unsigned and consistent with BufferSize
00064  */
00065 template<typename T, uint32_t BufferSize, typename CounterType = uint32_t>
00066 class CircularBuffer {
00067 public:
00068     CircularBuffer() : _head(0), _tail(0), _full(false)
00069     {
00070         MBED_STATIC_ASSERT(
00071             internal::is_unsigned<CounterType>::value,
00072             "CounterType must be unsigned"
00073         );
00074 
00075         MBED_STATIC_ASSERT(
00076             (sizeof(CounterType) >= sizeof(uint32_t)) ||
00077             (BufferSize < (((uint64_t) 1) << (sizeof(CounterType) * 8))),
00078             "Invalid BufferSize for the CounterType"
00079         );
00080     }
00081 
00082     ~CircularBuffer()
00083     {
00084     }
00085 
00086     /** Push the transaction to the buffer. This overwrites the buffer if it's
00087      *  full
00088      *
00089      * @param data Data to be pushed to the buffer
00090      */
00091     void push(const T &data)
00092     {
00093         core_util_critical_section_enter();
00094         if (full()) {
00095             _tail++;
00096             if (_tail == BufferSize) {
00097                 _tail = 0;
00098             }
00099         }
00100         _pool[_head++] = data;
00101         if (_head == BufferSize) {
00102             _head = 0;
00103         }
00104         if (_head == _tail) {
00105             _full = true;
00106         }
00107         core_util_critical_section_exit();
00108     }
00109 
00110     /** Pop the transaction from the buffer
00111      *
00112      * @param data Data to be popped from the buffer
00113      * @return True if the buffer is not empty and data contains a transaction, false otherwise
00114      */
00115     bool pop(T &data)
00116     {
00117         bool data_popped = false;
00118         core_util_critical_section_enter();
00119         if (!empty()) {
00120             data = _pool[_tail++];
00121             if (_tail == BufferSize) {
00122                 _tail = 0;
00123             }
00124             _full = false;
00125             data_popped = true;
00126         }
00127         core_util_critical_section_exit();
00128         return data_popped;
00129     }
00130 
00131     /** Check if the buffer is empty
00132      *
00133      * @return True if the buffer is empty, false if not
00134      */
00135     bool empty() const
00136     {
00137         core_util_critical_section_enter();
00138         bool is_empty = (_head == _tail) && !_full;
00139         core_util_critical_section_exit();
00140         return is_empty;
00141     }
00142 
00143     /** Check if the buffer is full
00144      *
00145      * @return True if the buffer is full, false if not
00146      */
00147     bool full() const
00148     {
00149         core_util_critical_section_enter();
00150         bool full = _full;
00151         core_util_critical_section_exit();
00152         return full;
00153     }
00154 
00155     /** Reset the buffer
00156      *
00157      */
00158     void reset()
00159     {
00160         core_util_critical_section_enter();
00161         _head = 0;
00162         _tail = 0;
00163         _full = false;
00164         core_util_critical_section_exit();
00165     }
00166 
00167     /** Get the number of elements currently stored in the circular_buffer */
00168     CounterType size() const
00169     {
00170         core_util_critical_section_enter();
00171         CounterType elements;
00172         if (!_full) {
00173             if (_head < _tail) {
00174                 elements = BufferSize + _head - _tail;
00175             } else {
00176                 elements = _head - _tail;
00177             }
00178         } else {
00179             elements = BufferSize;
00180         }
00181         core_util_critical_section_exit();
00182         return elements;
00183     }
00184 
00185     /** Peek into circular buffer without popping
00186      *
00187      * @param data Data to be peeked from the buffer
00188      * @return True if the buffer is not empty and data contains a transaction, false otherwise
00189      */
00190     bool peek(T &data) const
00191     {
00192         bool data_updated = false;
00193         core_util_critical_section_enter();
00194         if (!empty()) {
00195             data = _pool[_tail];
00196             data_updated = true;
00197         }
00198         core_util_critical_section_exit();
00199         return data_updated;
00200     }
00201 
00202 private:
00203     T _pool[BufferSize];
00204     CounterType _head;
00205     CounterType _tail;
00206     bool _full;
00207 };
00208 
00209 /**@}*/
00210 
00211 /**@}*/
00212 
00213 }
00214 
00215 #endif