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