TinyRobotics
Loading...
Searching...
No Matches
BufferRTOS.h
1#pragma once
2#include "TinyRobotics/utils/Config.h"
3#include "TinyRobotics/utils/Buffers.h"
4#include "TinyRobotics/utils/LoggerClass.h"
5#include "TinyRobotics/utils/AllocatorPSRAM.h"
6
7#ifdef ESP32
8# include <freertos/stream_buffer.h>
9# include "freertos/FreeRTOS.h"
10#elif defined(__linux__)
11#else
12# include "FreeRTOS.h"
13# include "stream_buffer.h"
14#endif
15
16namespace tinyrobotics {
17
18/**
19 * @brief Buffer implementation which is using a FreeRTOS StreamBuffer. The
20 * default allocator uses psram is available.
21 * @ingroup concurrency
22 * @author Phil Schatzmann
23 *
24 * @tparam T
25 */
26template <typename T, class TAllocator = AllocatorPSRAM<T>>
27class BufferRTOS : public BaseBuffer<T> {
28 public:
29 BufferRTOS(size_t streamBufferSize, size_t xTriggerLevel = 1,
30 TickType_t writeMaxWait = portMAX_DELAY,
31 TickType_t readMaxWait = portMAX_DELAY)
32 : BaseBuffer<T>() {
33 readWait = readMaxWait;
34 writeWait = writeMaxWait;
35 current_size_bytes = (streamBufferSize+1) * sizeof(T);
36 trigger_level = xTriggerLevel;
37
38 if (streamBufferSize > 0) {
39 setup();
40 }
41 }
42
43 ~BufferRTOS() { end(); }
44
45 /// Re-Allocats the memory and the queue
46 bool resize(size_t size) {
47 bool result = true;
48 int req_size_bytes = (size + 1)*sizeof(T);
49 if (current_size_bytes != req_size_bytes) {
50 end();
51 current_size_bytes = req_size_bytes;
52 result = setup();
53 }
54 return result;
55 }
56
57 void setReadMaxWait(TickType_t ticks) { readWait = ticks; }
58
59 void setWriteMaxWait(TickType_t ticks) { writeWait = ticks; }
60
61 void setWriteFromISR(bool active) { write_from_isr = active; }
62
63 void setReadFromISR(bool active) { read_from_isr = active; }
64
65 // reads a single value
66 bool read(T &result) override {
67 return readArray(&result, 1)==1;
68 }
69
70 // reads multiple values
71 int readArray(T data[], int len) {
72 if (read_from_isr) {
73 xHigherPriorityTaskWoken = pdFALSE;
74 int result = xStreamBufferReceiveFromISR(xStreamBuffer, (void *)data,
75 sizeof(T) * len,
76 &xHigherPriorityTaskWoken);
77#ifdef ESP32X
78 portYIELD_FROM_ISR();
79#else
80 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
81#endif
82 return result / sizeof(T);
83 } else {
84 return xStreamBufferReceive(xStreamBuffer, (void *)data, sizeof(T) * len,
85 readWait) / sizeof(T);
86 }
87 }
88
89 int writeArray(const T data[], int len) {
90 // LOGD("%s: %d", LOG_METHOD, len);
91 if (write_from_isr) {
92 xHigherPriorityTaskWoken = pdFALSE;
93 int result =
94 xStreamBufferSendFromISR(xStreamBuffer, (void *)data, sizeof(T) * len,
95 &xHigherPriorityTaskWoken);
96#ifdef ESP32X
97 portYIELD_FROM_ISR();
98#else
99 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
100#endif
101 return result / sizeof(T);
102 } else {
103 return xStreamBufferSend(xStreamBuffer, (void *)data, sizeof(T) * len,
104 writeWait) / sizeof(T);
105 }
106 }
107
108 // peeks the actual entry from the buffer
109 bool peek(T &result) override {
110 LOGE("peek not implemented");
111 return false;
112 }
113
114 // checks if the buffer is full
115 bool isFull() override {
116 return xStreamBufferIsFull(xStreamBuffer) == pdTRUE;
117 }
118
119 bool isEmpty() { return xStreamBufferIsEmpty(xStreamBuffer) == pdTRUE; }
120
121 // write add an entry to the buffer
122 bool write(T data) override {
123 int len = sizeof(T);
124 return writeArray(&data, len) == len;
125 }
126
127 // clears the buffer
128 void reset() override { xStreamBufferReset(xStreamBuffer); }
129
130 // provides the number of entries that are available to read
131 int available() override {
132 return xStreamBufferBytesAvailable(xStreamBuffer) / sizeof(T);
133 }
134
135 // provides the number of entries that are available to write
136 int availableForWrite() override {
137 return xStreamBufferSpacesAvailable(xStreamBuffer) / sizeof(T);
138 }
139
140 // returns the address of the start of the physical read buffer
141 T *address() override {
142 LOGE("address() not implemented");
143 return nullptr;
144 }
145
146 size_t size() { return current_size_bytes / sizeof(T); }
147
148 operator bool() { return xStreamBuffer != nullptr && size()>0;}
149
150 void end() {
151 if (xStreamBuffer != nullptr) vStreamBufferDelete(xStreamBuffer);
152 allocator.deallocate((T*)p_data, allocated_size);
153 current_size_bytes = 0;
154 p_data = nullptr;
155 xStreamBuffer = nullptr;
156 }
157
158 protected:
159 TAllocator allocator;
160 StreamBufferHandle_t xStreamBuffer = nullptr;
161 StaticStreamBuffer_t static_stream_buffer;
162 uint8_t *p_data = nullptr;
163 BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
164 int readWait = portMAX_DELAY;
165 int writeWait = portMAX_DELAY;
166 bool read_from_isr = false;
167 bool write_from_isr = false;
168 size_t current_size_bytes = 0;
169 size_t trigger_level = 0;
170 size_t allocated_size = 0;
171
172 /// The allocation has been postponed to be done here, so that we can e.g. use
173 /// psram
174 bool setup() {
175 if (current_size_bytes == 0) return true;
176
177 // allocate data if necessary
178 allocated_size = (current_size_bytes + 1) * sizeof(T);
179 if (p_data == nullptr) {
180 p_data = (uint8_t *)allocator.allocate(allocated_size);
181 // check allocation
182 if (p_data == nullptr) {
183 LOGE("allocate falied for %d bytes", allocated_size);
184 return false;
185 }
186 }
187
188 // create stream buffer if necessary
189 if (xStreamBuffer == nullptr) {
190 xStreamBuffer = xStreamBufferCreateStatic(current_size_bytes, trigger_level,
191 p_data, &static_stream_buffer);
192 }
193 if (xStreamBuffer == nullptr) {
194 LOGE("xStreamBufferCreateStatic failed");
195 return false;
196 }
197 // make sure that the data is empty
198 reset();
199 return true;
200 }
201
202};
203
204/// @brief Template alias for RTOS-based synchronized buffer
205/// @ingroup concurrency
206template <class T, class TAllocator = AllocatorPSRAM<T>>
207using SynchronizedBufferRTOS = BufferRTOS<T, TAllocator>;
208
209} // namespace tinyrobotics
#define LOGE
Definition: ESPNowStream.h:9
Custom allocator that uses ESP32's PSRAM for memory allocation.
Definition: AllocatorPSRAM.h:21
Shared functionality of all buffers.
Definition: Buffers.h:26
Buffer implementation which is using a FreeRTOS StreamBuffer. The default allocator uses psram is ava...
Definition: BufferRTOS.h:27
bool peek(T &result) override
peeks the actual entry from the buffer
Definition: BufferRTOS.h:109
bool read(T &result) override
reads a single value
Definition: BufferRTOS.h:66
bool write(T data) override
write add an entry to the buffer
Definition: BufferRTOS.h:122
int available() override
provides the number of entries that are available to read
Definition: BufferRTOS.h:131
int availableForWrite() override
provides the number of entries that are available to write
Definition: BufferRTOS.h:136
T * address() override
returns the address of the start of the physical read buffer
Definition: BufferRTOS.h:141
bool isFull() override
checks if the buffer is full
Definition: BufferRTOS.h:115
int writeArray(const T data[], int len)
Fills the buffer data.
Definition: BufferRTOS.h:89
bool resize(size_t size)
Re-Allocats the memory and the queue.
Definition: BufferRTOS.h:46
void reset() override
clears the buffer
Definition: BufferRTOS.h:128
bool setup()
Definition: BufferRTOS.h:174
int readArray(T data[], int len)
reads multiple values
Definition: BufferRTOS.h:71