CircularBuffer.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* mbed Microcontroller Library
  2. * Copyright (c) 2015 ARM Limited
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef MBED_CIRCULARBUFFER_H
  17. #define MBED_CIRCULARBUFFER_H
  18. #include "platform/mbed_critical.h"
  19. #include "platform/mbed_assert.h"
  20. namespace mbed {
  21. namespace internal {
  22. /* Detect if CounterType of the Circular buffer is of unsigned type. */
  23. template<typename T>
  24. struct is_unsigned {
  25. static const bool value = false;
  26. };
  27. template<>
  28. struct is_unsigned<unsigned char> {
  29. static const bool value = true;
  30. };
  31. template<>
  32. struct is_unsigned<unsigned short> {
  33. static const bool value = true;
  34. };
  35. template<>
  36. struct is_unsigned<unsigned int> {
  37. static const bool value = true;
  38. };
  39. template<>
  40. struct is_unsigned<unsigned long> {
  41. static const bool value = true;
  42. };
  43. template<>
  44. struct is_unsigned<unsigned long long> {
  45. static const bool value = true;
  46. };
  47. };
  48. /** \addtogroup platform */
  49. /** @{*/
  50. /**
  51. * \defgroup platform_CircularBuffer CircularBuffer functions
  52. * @{
  53. */
  54. /** Templated Circular buffer class
  55. *
  56. * @note Synchronization level: Interrupt safe
  57. * @note CounterType must be unsigned and consistent with BufferSize
  58. */
  59. template<typename T, uint32_t BufferSize, typename CounterType = uint32_t>
  60. class CircularBuffer {
  61. public:
  62. CircularBuffer() : _head(0), _tail(0), _full(false)
  63. {
  64. MBED_STATIC_ASSERT(
  65. internal::is_unsigned<CounterType>::value,
  66. "CounterType must be unsigned"
  67. );
  68. MBED_STATIC_ASSERT(
  69. (sizeof(CounterType) >= sizeof(uint32_t)) ||
  70. (BufferSize < (((uint64_t) 1) << (sizeof(CounterType) * 8))),
  71. "Invalid BufferSize for the CounterType"
  72. );
  73. }
  74. ~CircularBuffer()
  75. {
  76. }
  77. /** Push the transaction to the buffer. This overwrites the buffer if it's
  78. * full
  79. *
  80. * @param data Data to be pushed to the buffer
  81. */
  82. void push(const T &data)
  83. {
  84. core_util_critical_section_enter();
  85. if (full()) {
  86. _tail++;
  87. _tail %= BufferSize;
  88. }
  89. _pool[_head++] = data;
  90. _head %= BufferSize;
  91. if (_head == _tail) {
  92. _full = true;
  93. }
  94. core_util_critical_section_exit();
  95. }
  96. /** Pop the transaction from the buffer
  97. *
  98. * @param data Data to be popped from the buffer
  99. * @return True if the buffer is not empty and data contains a transaction, false otherwise
  100. */
  101. bool pop(T &data)
  102. {
  103. bool data_popped = false;
  104. core_util_critical_section_enter();
  105. if (!empty()) {
  106. data = _pool[_tail++];
  107. _tail %= BufferSize;
  108. _full = false;
  109. data_popped = true;
  110. }
  111. core_util_critical_section_exit();
  112. return data_popped;
  113. }
  114. /** Check if the buffer is empty
  115. *
  116. * @return True if the buffer is empty, false if not
  117. */
  118. bool empty() const
  119. {
  120. core_util_critical_section_enter();
  121. bool is_empty = (_head == _tail) && !_full;
  122. core_util_critical_section_exit();
  123. return is_empty;
  124. }
  125. /** Check if the buffer is full
  126. *
  127. * @return True if the buffer is full, false if not
  128. */
  129. bool full() const
  130. {
  131. core_util_critical_section_enter();
  132. bool full = _full;
  133. core_util_critical_section_exit();
  134. return full;
  135. }
  136. /** Reset the buffer
  137. *
  138. */
  139. void reset()
  140. {
  141. core_util_critical_section_enter();
  142. _head = 0;
  143. _tail = 0;
  144. _full = false;
  145. core_util_critical_section_exit();
  146. }
  147. /** Get the number of elements currently stored in the circular_buffer */
  148. CounterType size() const
  149. {
  150. core_util_critical_section_enter();
  151. CounterType elements;
  152. if (!_full) {
  153. if (_head < _tail) {
  154. elements = BufferSize + _head - _tail;
  155. } else {
  156. elements = _head - _tail;
  157. }
  158. } else {
  159. elements = BufferSize;
  160. }
  161. core_util_critical_section_exit();
  162. return elements;
  163. }
  164. /** Peek into circular buffer without popping
  165. *
  166. * @param data Data to be peeked from the buffer
  167. * @return True if the buffer is not empty and data contains a transaction, false otherwise
  168. */
  169. bool peek(T &data) const
  170. {
  171. bool data_updated = false;
  172. core_util_critical_section_enter();
  173. if (!empty()) {
  174. data = _pool[_tail];
  175. data_updated = true;
  176. }
  177. core_util_critical_section_exit();
  178. return data_updated;
  179. }
  180. private:
  181. T _pool[BufferSize];
  182. volatile CounterType _head;
  183. volatile CounterType _tail;
  184. volatile bool _full;
  185. };
  186. /**@}*/
  187. /**@}*/
  188. }
  189. #endif