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