TinyRobotics
Loading...
Searching...
No Matches
Buffers.h
1#pragma once
2
3#include <stdint.h>
4#include <math.h>
5#include <vector>
6
7#include "TinyRobotics/utils/Config.h"
8#include "TinyRobotics/utils/LoggerClass.h"
9
10#ifndef LOGD
11#define LOGD TRLogger.debug
12#define LOGE TRLogger.error
13#define LOGW TRLogger.warn
14#define LOGI TRLogger.info
15#endif
16
17namespace tinyrobotics {
18
19/**
20 * @class BaseBuffer
21 * @ingroup utils
22 * @brief Shared functionality of all buffers
23 * @author Phil Schatzmann
24 */
25template <typename T = int16_t>
26class BaseBuffer {
27 public:
28 BaseBuffer() = default;
29 virtual ~BaseBuffer() = default;
30 BaseBuffer(BaseBuffer&) = default;
31 BaseBuffer& operator=(BaseBuffer&) = default;
32
33 /// reads a single value
34 virtual bool read(T& result) = 0;
35
36 /// reads multiple values
37 virtual int readArray(T data[], int len) {
38 if (data == nullptr) {
39 LOGE("NPE");
40 return 0;
41 }
42 int lenResult = std::min(len, available());
43 for (int j = 0; j < lenResult; j++) {
44 read(data[j]);
45 }
46 LOGD("readArray %d -> %d", len, lenResult);
47 return lenResult;
48 }
49
50 /// Removes the next len entries
51 virtual int clearArray(int len) {
52 int lenResult = std::min(len, available());
53 T dummy[lenResult];
54 readArray(dummy, lenResult);
55 return lenResult;
56 }
57
58 /// Fills the buffer data
59 virtual int writeArray(const T data[], int len) {
60 // LOGD("%s: %d", LOG_METHOD, len);
61 // CHECK_MEMORY();
62
63 int result = 0;
64 for (int j = 0; j < len; j++) {
65 if (!write(data[j])) {
66 break;
67 }
68 result = j + 1;
69 }
70 // CHECK_MEMORY();
71 LOGD("writeArray %d -> %d", len, result);
72 return result;
73 }
74
75 /// Fills the buffer data and overwrites the oldest data if the buffer is full
76 virtual int writeArrayOverwrite(const T data[], int len) {
77 int to_delete = len - availableForWrite();
78 if (to_delete > 0) {
79 clearArray(to_delete);
80 }
81 return writeArray(data, len);
82 }
83
84 /// peeks the actual entry from the buffer
85 virtual bool peek(T& result) = 0;
86
87 /// checks if the buffer is full
88 virtual bool isFull() { return availableForWrite() == 0; }
89
90 bool isEmpty() { return available() == 0; }
91
92 /// write add an entry to the buffer
93 virtual bool write(T data) = 0;
94
95 /// clears the buffer
96 virtual void reset() = 0;
97
98 /// same as reset
99 void clear() { reset(); }
100
101 /// provides the number of entries that are available to read
102 virtual int available() = 0;
103
104 /// provides the number of entries that are available to write
105 virtual int availableForWrite() = 0;
106
107 /// returns the address of the start of the physical read buffer
108 virtual T* address() = 0;
109
110 virtual size_t size() = 0;
111
112 /// Returns the level of the buffer in %
113 virtual float levelPercent() {
114 // prevent div by 0.
115 if (size() == 0) return 0.0f;
116 return 100.0f * static_cast<float>(available()) /
117 static_cast<float>(size());
118 }
119
120 /// Resizes the buffer if supported: returns false if not supported
121 virtual bool resize(int bytes) {
122 LOGE("resize not implemented for this buffer");
123 return false;
124 }
125};
126
127/**
128 * @brief A simple Buffer implementation which just uses a (dynamically sized)
129 * array
130 * @ingroup utils
131 * @author Phil Schatzmann
132
133 */
134
135template <typename T = int16_t>
136class SingleBuffer : public BaseBuffer<T> {
137 public:
138 /**
139 * @brief Construct a new Single Buffer object
140 *
141 * @param size in entries
142 */
143 SingleBuffer(int size) {
144 buffer.resize(size);
145 reset();
146 }
147
148 SingleBuffer(SingleBuffer&) = default;
149 SingleBuffer& operator=(SingleBuffer&) = default;
150
151 /**
152 * @brief Construct a new Single Buffer w/o allocating any memory
153 */
154 SingleBuffer() { reset(); }
155
156 /// notifies that the external buffer has been refilled
157 void onExternalBufferRefilled(void* data, int len) {
158 this->owns_buffer = false;
159 this->buffer = (uint8_t*)data;
160 this->current_read_pos = 0;
161 this->current_write_pos = len;
162 }
163
164 int writeArray(const T data[], int len) override {
165 if (size() == 0) resize(len);
166 return BaseBuffer<T>::writeArray(data, len);
167 }
168
169 bool write(T sample) override {
170 bool result = false;
171 if (current_write_pos < buffer.size()) {
172 buffer[current_write_pos++] = sample;
173 result = true;
174 }
175 return result;
176 }
177
178 bool read(T& result) override {
179 bool success = false;
180 if (current_read_pos < current_write_pos) {
181 result = buffer[current_read_pos++];
182 success = true;
183 }
184 return success;
185 }
186
187 bool peek(T& result) override {
188 bool success = false;
189 if (current_read_pos < current_write_pos) {
190 result = buffer[current_read_pos];
191 success = true;
192 }
193 return success;
194 }
195
196 int available() override {
197 int result = current_write_pos - current_read_pos;
198 return std::max(result, 0);
199 }
200
201 int availableForWrite() override { return buffer.size() - current_write_pos; }
202
203 bool isFull() override { return availableForWrite() <= 0; }
204
205 int peekArray(uint8_t* data, int len) {
206 int len_available = available();
207 if (len > len_available) {
208 len = len_available;
209 }
210 memcpy(data, buffer.data() + current_read_pos, len);
211 return len;
212 }
213
214 /// consumes len bytes and moves current data to the beginning
215 int clearArray(int len) override {
216 int len_available = available();
217 if (len > available()) {
218 reset();
219 return len_available;
220 }
221 current_read_pos += len;
222 len_available -= len;
223 memmove(buffer.data(), buffer.data() + current_read_pos,
224 len_available * sizeof(T));
225 current_read_pos = 0;
226 current_write_pos = len_available;
227
228 if (is_clear_with_zero) {
229 memset(buffer.data() + current_write_pos, 0,
230 buffer.size() - current_write_pos);
231 }
232
233 return len;
234 }
235
236 /// Moves the unprocessed data to the beginning of the buffer
237 void trim() {
238 int av = available();
239 memmove(buffer.data(), buffer.data() + current_read_pos, av * sizeof(T));
240 current_write_pos = av;
241 current_read_pos = 0;
242 }
243
244 /// Provides address to beginning of the buffer
245 T* address() override { return buffer.data(); }
246
247 /// Provides address of actual data
248 T* data() { return buffer.data() + current_read_pos; }
249
250 void reset() override {
251 current_read_pos = 0;
252 current_write_pos = 0;
253 if (is_clear_with_zero) {
254 memset(buffer.data(), 0, buffer.size());
255 }
256 }
257
258 /// If we load values directly into the address we need to set the avialeble
259 /// size
261 size_t result = std::min(available_size, (size_t)buffer.size());
262 current_read_pos = 0;
263 current_write_pos = result;
264 return result;
265 }
266
267 size_t size() override { return buffer.size(); }
268
269 bool resize(int size) {
270 if (buffer.size() < size) {
271
272 buffer.resize(size);
273 }
274 return true;
275 }
276
277 /// Sets the buffer to 0 on clear
278 void setClearWithZero(bool flag) { is_clear_with_zero = flag; }
279
280 /// Updates the actual available data size
281 void setWritePos(int pos) { current_write_pos = pos; }
282
283 /// Optional ID
284 int id = 0;
285 /// Optional active/inactive status
286 bool active = true;
287 /// Optional timestamp
288 uint64_t timestamp = 0;
289
290 protected:
291 int current_read_pos = 0;
292 int current_write_pos = 0;
293 bool owns_buffer = true;
294 bool is_clear_with_zero = false;
295 std::vector<T> buffer{0};
296};
297
298/**
299 * @brief Implements a typed Ringbuffer
300 * @ingroup utils
301 * @tparam T
302 */
303template <typename T = int16_t>
304class RingBuffer : public BaseBuffer<T> {
305 public:
306 RingBuffer(int size) {
307 resize(size);
308 reset();
309 }
310
311 bool read(T& result) override {
312 if (isEmpty()) {
313 return false;
314 }
315
316 result = _aucBuffer[_iTail];
317 _iTail = nextIndex(_iTail);
318 _numElems--;
319
320 return true;
321 }
322
323 // peeks the actual entry from the buffer
324 bool peek(T& result) override {
325 if (isEmpty()) {
326 return false;
327 }
328
329 result = _aucBuffer[_iTail];
330 return true;
331 }
332
333 virtual int peekArray(T* data, int n) {
334 if (isEmpty()) return -1;
335 int result = 0;
336 int count = _numElems;
337 int tail = _iTail;
338 for (int j = 0; j < n; j++) {
339 data[j] = _aucBuffer[tail];
340 tail = nextIndex(tail);
341 count--;
342 result++;
343 if (count == 0) break;
344 }
345 return result;
346 }
347
348 // checks if the buffer is full
349 virtual bool isFull() override { return available() == max_size; }
350
351 bool isEmpty() { return available() == 0; }
352
353 // write add an entry to the buffer
354 virtual bool write(T data) override {
355 bool result = false;
356 if (!isFull()) {
357 _aucBuffer[_iHead] = data;
358 _iHead = nextIndex(_iHead);
359 _numElems++;
360 result = true;
361 }
362 return result;
363 }
364
365 // clears the buffer
366 virtual void reset() override {
367 _iHead = 0;
368 _iTail = 0;
369 _numElems = 0;
370 }
371
372 // provides the number of entries that are available to read
373 virtual int available() override { return _numElems; }
374
375 // provides the number of entries that are available to write
376 virtual int availableForWrite() override { return (max_size - _numElems); }
377
378 // returns the address of the start of the physical read buffer
379 virtual T* address() override { return _aucBuffer.data(); }
380
381 virtual bool resize(int len) {
382 if (max_size != len && len > 0) {
383 LOGI("resize: %d", len);
384 _aucBuffer.resize(len);
385 max_size = len;
386 }
387 return true;
388 }
389
390 /// Returns the maximum capacity of the buffer
391 virtual size_t size() override { return max_size; }
392
393 protected:
394 std::vector<T> _aucBuffer;
395 int _iHead;
396 int _iTail;
397 int _numElems;
398 int max_size = 0;
399
400 int nextIndex(int index) {
401 if (max_size == 0) return 0;
402 return (uint32_t)(index + 1) % max_size;
403 }
404};
405
406} // namespace tinyrobotics
#define LOGI
Definition: ESPNowStream.h:11
#define LOGD
Definition: ESPNowStream.h:12
#define LOGE
Definition: ESPNowStream.h:9
Shared functionality of all buffers.
Definition: Buffers.h:26
virtual bool read(T &result)=0
reads a single value
virtual int readArray(T data[], int len)
reads multiple values
Definition: Buffers.h:37
virtual void reset()=0
clears the buffer
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition: Buffers.h:59
virtual T * address()=0
returns the address of the start of the physical read buffer
virtual int writeArrayOverwrite(const T data[], int len)
Fills the buffer data and overwrites the oldest data if the buffer is full.
Definition: Buffers.h:76
virtual int clearArray(int len)
Removes the next len entries.
Definition: Buffers.h:51
virtual int availableForWrite()=0
provides the number of entries that are available to write
virtual bool isFull()
checks if the buffer is full
Definition: Buffers.h:88
virtual bool peek(T &result)=0
peeks the actual entry from the buffer
virtual float levelPercent()
Returns the level of the buffer in %.
Definition: Buffers.h:113
void clear()
same as reset
Definition: Buffers.h:99
virtual bool write(T data)=0
write add an entry to the buffer
virtual int available()=0
provides the number of entries that are available to read
virtual bool resize(int bytes)
Resizes the buffer if supported: returns false if not supported.
Definition: Buffers.h:121
Implements a typed Ringbuffer.
Definition: Buffers.h:304
bool peek(T &result) override
peeks the actual entry from the buffer
Definition: Buffers.h:324
bool read(T &result) override
reads a single value
Definition: Buffers.h:311
virtual T * address() override
returns the address of the start of the physical read buffer
Definition: Buffers.h:379
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition: Buffers.h:376
virtual bool write(T data) override
write add an entry to the buffer
Definition: Buffers.h:354
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition: Buffers.h:391
virtual void reset() override
clears the buffer
Definition: Buffers.h:366
virtual bool isFull() override
checks if the buffer is full
Definition: Buffers.h:349
virtual bool resize(int len)
Resizes the buffer if supported: returns false if not supported.
Definition: Buffers.h:381
virtual int available() override
provides the number of entries that are available to read
Definition: Buffers.h:373
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition: Buffers.h:136
bool active
Optional active/inactive status.
Definition: Buffers.h:286
size_t setAvailable(size_t available_size)
Definition: Buffers.h:260
void trim()
Moves the unprocessed data to the beginning of the buffer.
Definition: Buffers.h:237
bool write(T sample) override
write add an entry to the buffer
Definition: Buffers.h:169
SingleBuffer(int size)
Construct a new Single Buffer object.
Definition: Buffers.h:143
void setClearWithZero(bool flag)
Sets the buffer to 0 on clear.
Definition: Buffers.h:278
bool peek(T &result) override
peeks the actual entry from the buffer
Definition: Buffers.h:187
uint64_t timestamp
Optional timestamp.
Definition: Buffers.h:288
void setWritePos(int pos)
Updates the actual available data size.
Definition: Buffers.h:281
bool read(T &result) override
reads a single value
Definition: Buffers.h:178
int available() override
provides the number of entries that are available to read
Definition: Buffers.h:196
int id
Optional ID.
Definition: Buffers.h:284
int availableForWrite() override
provides the number of entries that are available to write
Definition: Buffers.h:201
T * address() override
Provides address to beginning of the buffer.
Definition: Buffers.h:245
bool isFull() override
checks if the buffer is full
Definition: Buffers.h:203
void onExternalBufferRefilled(void *data, int len)
notifies that the external buffer has been refilled
Definition: Buffers.h:157
bool resize(int size)
Resizes the buffer if supported: returns false if not supported.
Definition: Buffers.h:269
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition: Buffers.h:164
SingleBuffer()
Construct a new Single Buffer w/o allocating any memory.
Definition: Buffers.h:154
T * data()
Provides address of actual data.
Definition: Buffers.h:248
void reset() override
clears the buffer
Definition: Buffers.h:250
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition: Buffers.h:215