ESPHome 2026.5.3
Loading...
Searching...
No Matches
ring_buffer.cpp
Go to the documentation of this file.
1#include "ring_buffer.h"
2
3#ifdef USE_ESP32
4
6#include "esphome/core/log.h"
7
9
10static const char *const TAG = "ring_buffer";
11
13 if (this->handle_ != nullptr) {
14 vRingbufferDelete(this->handle_);
15 RAMAllocator<uint8_t> allocator;
16 allocator.deallocate(this->storage_, this->size_);
17 }
18}
19
20std::unique_ptr<RingBuffer> RingBuffer::create(size_t len, MemoryPreference preference) {
21 std::unique_ptr<RingBuffer> rb = make_unique<RingBuffer>();
22
23 rb->size_ = len;
24
27
28 RAMAllocator<uint8_t> allocator(type);
29 rb->storage_ = allocator.allocate(rb->size_);
30 if (rb->storage_ == nullptr) {
31 return nullptr;
32 }
33
34 rb->handle_ = xRingbufferCreateStatic(rb->size_, RINGBUF_TYPE_BYTEBUF, rb->storage_, &rb->structure_);
35 ESP_LOGD(TAG, "Created ring buffer with size %u", len);
36
37 return rb;
38}
39
40void *RingBuffer::receive_acquire(size_t &length, size_t max_length, TickType_t ticks_to_wait) {
41 length = 0;
42 void *buffer_data = xRingbufferReceiveUpTo(this->handle_, &length, ticks_to_wait, max_length);
43 return buffer_data;
44}
45
46void RingBuffer::receive_release(void *item) { vRingbufferReturnItem(this->handle_, item); }
47
48size_t RingBuffer::read(void *data, size_t len, TickType_t ticks_to_wait) {
49 size_t bytes_read = 0;
50
51 void *buffer_data = xRingbufferReceiveUpTo(this->handle_, &bytes_read, ticks_to_wait, len);
52
53 if (buffer_data == nullptr) {
54 return 0;
55 }
56
57 std::memcpy(data, buffer_data, bytes_read);
58
59 vRingbufferReturnItem(this->handle_, buffer_data);
60
61 if (bytes_read < len) {
62 // Data may have wrapped around, so read a second time to receive the remainder
63 size_t follow_up_bytes_read = 0;
64 size_t bytes_remaining = len - bytes_read;
65
66 buffer_data = xRingbufferReceiveUpTo(this->handle_, &follow_up_bytes_read, 0, bytes_remaining);
67
68 if (buffer_data == nullptr) {
69 return bytes_read;
70 }
71
72 std::memcpy((void *) ((uint8_t *) (data) + bytes_read), buffer_data, follow_up_bytes_read);
73
74 vRingbufferReturnItem(this->handle_, buffer_data);
75 bytes_read += follow_up_bytes_read;
76 }
77
78 return bytes_read;
79}
80
81size_t RingBuffer::write(const void *data, size_t len) {
82 size_t free = this->free();
83 if (free < len) {
84 // Free enough space in the ring buffer to fit the new data
85 this->discard_bytes_(len - free);
86 }
87 return this->write_without_replacement(data, len, 0);
88}
89
90size_t RingBuffer::write_without_replacement(const void *data, size_t len, TickType_t ticks_to_wait,
91 bool write_partial) {
92 if (!xRingbufferSend(this->handle_, data, len, ticks_to_wait)) {
93 if (!write_partial) {
94 return 0; // Not enough space available and not allowed to write partial data
95 }
96 // Couldn't fit all the data, write what will fit
97 size_t free = std::min(this->free(), len);
98 if (xRingbufferSend(this->handle_, data, free, 0)) {
99 return free;
100 }
101 return 0;
102 }
103 return len;
104}
105
106size_t RingBuffer::available() const {
107 UBaseType_t ux_items_waiting = 0;
108 vRingbufferGetInfo(this->handle_, nullptr, nullptr, nullptr, nullptr, &ux_items_waiting);
109 return ux_items_waiting;
110}
111
112size_t RingBuffer::free() const { return xRingbufferGetCurFreeSize(this->handle_); }
113
114BaseType_t RingBuffer::reset() {
115 // Discards all the available data
116 return this->discard_bytes_(this->available());
117}
118
119bool RingBuffer::discard_bytes_(size_t discard_bytes) {
120 size_t bytes_read = 0;
121
122 void *buffer_data = xRingbufferReceiveUpTo(this->handle_, &bytes_read, 0, discard_bytes);
123 if (buffer_data != nullptr)
124 vRingbufferReturnItem(this->handle_, buffer_data);
125
126 if (bytes_read < discard_bytes) {
127 size_t wrapped_bytes_read = 0;
128 buffer_data = xRingbufferReceiveUpTo(this->handle_, &wrapped_bytes_read, 0, discard_bytes - bytes_read);
129 if (buffer_data != nullptr) {
130 vRingbufferReturnItem(this->handle_, buffer_data);
131 bytes_read += wrapped_bytes_read;
132 }
133 }
134
135 return (bytes_read == discard_bytes);
136}
137
138} // namespace esphome::ring_buffer
139
140#endif // USE_ESP32
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:2053
void deallocate(T *p, size_t n)
Definition helpers.h:2110
T * allocate(size_t n)
Definition helpers.h:2080
BaseType_t reset()
Resets the ring buffer, discarding all stored data.
size_t write(const void *data, size_t len)
Writes to the ring buffer, overwriting oldest data if necessary.
size_t write_without_replacement(const void *data, size_t len, TickType_t ticks_to_wait=0, bool write_partial=true)
Writes to the ring buffer without overwriting oldest data.
size_t free() const
Returns the number of free bytes in the ring buffer.
size_t available() const
Returns the number of available bytes in the ring buffer.
bool discard_bytes_(size_t discard_bytes)
Discards data from the ring buffer.
void receive_release(void *item)
Releases a previously acquired ring buffer item.
static std::unique_ptr< RingBuffer > create(size_t len, MemoryPreference preference=MemoryPreference::EXTERNAL_FIRST)
size_t read(void *data, size_t len, TickType_t ticks_to_wait=0)
Reads from the ring buffer, waiting up to a specified number of ticks if necessary.
void * receive_acquire(size_t &length, size_t max_length, TickType_t ticks_to_wait=0)
Acquires a pointer into the ring buffer's internal storage without copying.
uint16_t type
std::string size_t len
uint16_t length
Definition tt21100.cpp:0