ESPHome 2026.11.0-dev
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
10ESPHOME_LOG_TAG(TAG, "ring_buffer");
11
13 // create() only builds the ring buffer once storage_ is allocated
14 if (this->storage_ != nullptr) {
15 vRingbufferDelete(this->handle_());
16 RAMAllocator<uint8_t> allocator;
17 allocator.deallocate(this->storage_, this->size_);
18 }
19}
20
21std::unique_ptr<RingBuffer> RingBuffer::create(size_t len, MemoryPreference preference) {
22 std::unique_ptr<RingBuffer> rb = make_unique<RingBuffer>();
23
24 rb->size_ = len;
25
28
29 RAMAllocator<uint8_t> allocator(type);
30 rb->storage_ = allocator.allocate(rb->size_);
31 if (rb->storage_ == nullptr) {
32 return nullptr;
33 }
34
35 // handle_() assumes the returned handle is &structure_; NULL means the arguments were rejected
36 if (xRingbufferCreateStatic(rb->size_, RINGBUF_TYPE_BYTEBUF, rb->storage_, &rb->structure_) != rb->handle_()) {
37 allocator.deallocate(rb->storage_, rb->size_);
38 rb->storage_ = nullptr;
39 return nullptr;
40 }
41 ESP_LOGD(TAG, "Created ring buffer with size %u", len);
42
43 return rb;
44}
45
46void *RingBuffer::receive_acquire(size_t &length, size_t max_length, TickType_t ticks_to_wait) {
47 length = 0;
48 void *buffer_data = xRingbufferReceiveUpTo(this->handle_(), &length, ticks_to_wait, max_length);
49 return buffer_data;
50}
51
52void RingBuffer::receive_release(void *item) { vRingbufferReturnItem(this->handle_(), item); }
53
54size_t RingBuffer::read(void *data, size_t len, TickType_t ticks_to_wait) {
55 size_t bytes_read = 0;
56
57 void *buffer_data = xRingbufferReceiveUpTo(this->handle_(), &bytes_read, ticks_to_wait, len);
58
59 if (buffer_data == nullptr) {
60 return 0;
61 }
62
63 std::memcpy(data, buffer_data, bytes_read);
64
65 vRingbufferReturnItem(this->handle_(), buffer_data);
66
67 if (bytes_read < len) {
68 // Data may have wrapped around, so read a second time to receive the remainder
69 size_t follow_up_bytes_read = 0;
70 size_t bytes_remaining = len - bytes_read;
71
72 buffer_data = xRingbufferReceiveUpTo(this->handle_(), &follow_up_bytes_read, 0, bytes_remaining);
73
74 if (buffer_data == nullptr) {
75 return bytes_read;
76 }
77
78 std::memcpy((void *) ((uint8_t *) (data) + bytes_read), buffer_data, follow_up_bytes_read);
79
80 vRingbufferReturnItem(this->handle_(), buffer_data);
81 bytes_read += follow_up_bytes_read;
82 }
83
84 return bytes_read;
85}
86
87size_t RingBuffer::write(const void *data, size_t len) {
88 size_t free = this->free();
89 if (free < len) {
90 // Free enough space in the ring buffer to fit the new data
91 this->discard_bytes_(len - free);
92 }
93 return this->write_without_replacement(data, len, 0);
94}
95
96size_t RingBuffer::write_without_replacement(const void *data, size_t len, TickType_t ticks_to_wait,
97 bool write_partial) {
98 if (!xRingbufferSend(this->handle_(), data, len, ticks_to_wait)) {
99 if (!write_partial) {
100 return 0; // Not enough space available and not allowed to write partial data
101 }
102 // Couldn't fit all the data, write what will fit
103 size_t free = std::min(this->free(), len);
104 if (xRingbufferSend(this->handle_(), data, free, 0)) {
105 return free;
106 }
107 return 0;
108 }
109 return len;
110}
111
112size_t RingBuffer::available() const {
113 UBaseType_t ux_items_waiting = 0;
114 vRingbufferGetInfo(this->handle_(), nullptr, nullptr, nullptr, nullptr, &ux_items_waiting);
115 return ux_items_waiting;
116}
117
118size_t RingBuffer::free() const { return xRingbufferGetCurFreeSize(this->handle_()); }
119
120BaseType_t RingBuffer::reset() {
121 // Discards all the available data
122 return this->discard_bytes_(this->available());
123}
124
125bool RingBuffer::discard_bytes_(size_t discard_bytes) {
126 size_t bytes_read = 0;
127
128 void *buffer_data = xRingbufferReceiveUpTo(this->handle_(), &bytes_read, 0, discard_bytes);
129 if (buffer_data != nullptr)
130 vRingbufferReturnItem(this->handle_(), buffer_data);
131
132 if (bytes_read < discard_bytes) {
133 size_t wrapped_bytes_read = 0;
134 buffer_data = xRingbufferReceiveUpTo(this->handle_(), &wrapped_bytes_read, 0, discard_bytes - bytes_read);
135 if (buffer_data != nullptr) {
136 vRingbufferReturnItem(this->handle_(), buffer_data);
137 bytes_read += wrapped_bytes_read;
138 }
139 }
140
141 return (bytes_read == discard_bytes);
142}
143
144} // namespace esphome::ring_buffer
145
146#endif // USE_ESP32
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:2298
void deallocate(T *p, size_t n)
Definition helpers.h:2355
T * allocate(size_t n)
Definition helpers.h:2325
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.
RingbufHandle_t handle_() const
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.
uint8_t type
ESPHOME_LOG_TAG(TAG, "ring_buffer")
const void size_t len
Definition hal.h:68
uint16_t length
Definition tt21100.cpp:0