Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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-2019 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 <stdint.h>
00021 #include "platform/mbed_critical.h"
00022 #include "platform/mbed_assert.h"
00023 
00024 namespace mbed {
00025 
00026 namespace internal {
00027 /* Detect if CounterType of the Circular buffer is of unsigned type. */
00028 template<typename T>
00029 struct is_unsigned {
00030     static const bool value = false;
00031 };
00032 template<>
00033 struct is_unsigned<unsigned char> {
00034     static const bool value = true;
00035 };
00036 template<>
00037 struct is_unsigned<unsigned short> {
00038     static const bool value = true;
00039 };
00040 template<>
00041 struct is_unsigned<unsigned int> {
00042     static const bool value = true;
00043 };
00044 template<>
00045 struct is_unsigned<unsigned long> {
00046     static const bool value = true;
00047 };
00048 template<>
00049 struct is_unsigned<unsigned long long> {
00050     static const bool value = true;
00051 };
00052 };
00053 
00054 /** \addtogroup platform-public-api */
00055 /** @{*/
00056 /**
00057  * \defgroup platform_CircularBuffer CircularBuffer functions
00058  * @{
00059  */
00060 
00061 /** Templated Circular buffer class
00062  *
00063  *  @note Synchronization level: Interrupt safe
00064  *  @note CounterType must be unsigned and consistent with BufferSize
00065  */
00066 template<typename T, uint32_t BufferSize, typename CounterType = uint32_t>
00067 class CircularBuffer {
00068 public:
00069     CircularBuffer() : _head(0), _tail(0), _full(false)
00070     {
00071         MBED_STATIC_ASSERT(
00072             internal::is_unsigned<CounterType>::value,
00073             "CounterType must be unsigned"
00074         );
00075 
00076         MBED_STATIC_ASSERT(
00077             (sizeof(CounterType) >= sizeof(uint32_t)) ||
00078             (BufferSize < (((uint64_t) 1) << (sizeof(CounterType) * 8))),
00079             "Invalid BufferSize for the CounterType"
00080         );
00081     }
00082 
00083     ~CircularBuffer()
00084     {
00085     }
00086 
00087     /** Push the transaction to the buffer. This overwrites the buffer if it's
00088      *  full
00089      *
00090      * @param data Data to be pushed to the buffer
00091      */
00092     void push(const T &data)
00093     {
00094         core_util_critical_section_enter();
00095         if (full()) {
00096             _tail++;
00097             if (_tail == BufferSize) {
00098                 _tail = 0;
00099             }
00100         }
00101         _pool[_head++] = data;
00102         if (_head == BufferSize) {
00103             _head = 0;
00104         }
00105         if (_head == _tail) {
00106             _full = true;
00107         }
00108         core_util_critical_section_exit();
00109     }
00110 
00111     /** Pop the transaction from the buffer
00112      *
00113      * @param data Data to be popped from the buffer
00114      * @return True if the buffer is not empty and data contains a transaction, false otherwise
00115      */
00116     bool pop(T &data)
00117     {
00118         bool data_popped = false;
00119         core_util_critical_section_enter();
00120         if (!empty()) {
00121             data = _pool[_tail++];
00122             if (_tail == BufferSize) {
00123                 _tail = 0;
00124             }
00125             _full = false;
00126             data_popped = true;
00127         }
00128         core_util_critical_section_exit();
00129         return data_popped;
00130     }
00131 
00132     /** Check if the buffer is empty
00133      *
00134      * @return True if the buffer is empty, false if not
00135      */
00136     bool empty() const
00137     {
00138         core_util_critical_section_enter();
00139         bool is_empty = (_head == _tail) && !_full;
00140         core_util_critical_section_exit();
00141         return is_empty;
00142     }
00143 
00144     /** Check if the buffer is full
00145      *
00146      * @return True if the buffer is full, false if not
00147      */
00148     bool full() const
00149     {
00150         core_util_critical_section_enter();
00151         bool full = _full;
00152         core_util_critical_section_exit();
00153         return full;
00154     }
00155 
00156     /** Reset the buffer
00157      *
00158      */
00159     void reset()
00160     {
00161         core_util_critical_section_enter();
00162         _head = 0;
00163         _tail = 0;
00164         _full = false;
00165         core_util_critical_section_exit();
00166     }
00167 
00168     /** Get the number of elements currently stored in the circular_buffer */
00169     CounterType size() const
00170     {
00171         core_util_critical_section_enter();
00172         CounterType elements;
00173         if (!_full) {
00174             if (_head < _tail) {
00175                 elements = BufferSize + _head - _tail;
00176             } else {
00177                 elements = _head - _tail;
00178             }
00179         } else {
00180             elements = BufferSize;
00181         }
00182         core_util_critical_section_exit();
00183         return elements;
00184     }
00185 
00186     /** Peek into circular buffer without popping
00187      *
00188      * @param data Data to be peeked from the buffer
00189      * @return True if the buffer is not empty and data contains a transaction, false otherwise
00190      */
00191     bool peek(T &data) const
00192     {
00193         bool data_updated = false;
00194         core_util_critical_section_enter();
00195         if (!empty()) {
00196             data = _pool[_tail];
00197             data_updated = true;
00198         }
00199         core_util_critical_section_exit();
00200         return data_updated;
00201     }
00202 
00203 private:
00204     T _pool[BufferSize];
00205     CounterType _head;
00206     CounterType _tail;
00207     bool _full;
00208 };
00209 
00210 /**@}*/
00211 
00212 /**@}*/
00213 
00214 }
00215 
00216 #endif