ESPHome  2024.12.2
ring_buffer.cpp
Go to the documentation of this file.
1 #include "ring_buffer.h"
2 
3 #include "esphome/core/helpers.h"
4 #include "esphome/core/log.h"
5 
6 #ifdef USE_ESP32
7 
8 #include "helpers.h"
9 
10 namespace esphome {
11 
12 static const char *const TAG = "ring_buffer";
13 
15  if (this->handle_ != nullptr) {
16  vRingbufferDelete(this->handle_);
18  allocator.deallocate(this->storage_, this->size_);
19  }
20 }
21 
22 std::unique_ptr<RingBuffer> RingBuffer::create(size_t len) {
23  std::unique_ptr<RingBuffer> rb = make_unique<RingBuffer>();
24 
25  rb->size_ = len;
26 
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 
39 size_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 
72 size_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 
81 size_t RingBuffer::write_without_replacement(const void *data, size_t len, TickType_t ticks_to_wait) {
82  if (!xRingbufferSend(this->handle_, data, len, ticks_to_wait)) {
83  // Couldn't fit all the data, so only write what will fit
84  size_t free = std::min(this->free(), len);
85  if (xRingbufferSend(this->handle_, data, free, 0)) {
86  return free;
87  }
88  return 0;
89  }
90  return len;
91 }
92 
93 size_t RingBuffer::available() const {
94  UBaseType_t ux_items_waiting = 0;
95  vRingbufferGetInfo(this->handle_, nullptr, nullptr, nullptr, nullptr, &ux_items_waiting);
96  return ux_items_waiting;
97 }
98 
99 size_t RingBuffer::free() const { return xRingbufferGetCurFreeSize(this->handle_); }
100 
101 BaseType_t RingBuffer::reset() {
102  // Discards all the available data
103  return this->discard_bytes_(this->available());
104 }
105 
106 bool RingBuffer::discard_bytes_(size_t discard_bytes) {
107  size_t bytes_read = 0;
108 
109  void *buffer_data = xRingbufferReceiveUpTo(this->handle_, &bytes_read, 0, discard_bytes);
110  if (buffer_data != nullptr)
111  vRingbufferReturnItem(this->handle_, buffer_data);
112 
113  if (bytes_read < discard_bytes) {
114  size_t wrapped_bytes_read = 0;
115  buffer_data = xRingbufferReceiveUpTo(this->handle_, &wrapped_bytes_read, 0, discard_bytes - bytes_read);
116  if (buffer_data != nullptr) {
117  vRingbufferReturnItem(this->handle_, buffer_data);
118  bytes_read += wrapped_bytes_read;
119  }
120  }
121 
122  return (bytes_read == discard_bytes);
123 }
124 
125 } // namespace esphome
126 
127 #endif
RingbufHandle_t handle_
Definition: ring_buffer.h:90
uint8_t * storage_
Definition: ring_buffer.h:92
bool discard_bytes_(size_t discard_bytes)
Discards data from the ring buffer.
size_t free() const
Returns the number of free bytes in the ring buffer.
Definition: ring_buffer.cpp:99
T * allocate(size_t n)
Definition: helpers.h:690
size_t write_without_replacement(const void *data, size_t len, TickType_t ticks_to_wait=0)
Writes to the ring buffer without overwriting oldest data.
Definition: ring_buffer.cpp:81
BaseType_t reset()
Resets the ring buffer, discarding all stored data.
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.
Definition: ring_buffer.cpp:39
const char *const TAG
Definition: spi.cpp:8
size_t available() const
Returns the number of available bytes in the ring buffer.
Definition: ring_buffer.cpp:93
void deallocate(T *p, size_t n)
Definition: helpers.h:709
std::string size_t len
Definition: helpers.h:293
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
size_t write(const void *data, size_t len)
Writes to the ring buffer, overwriting oldest data if necessary.
Definition: ring_buffer.cpp:72
static std::unique_ptr< RingBuffer > create(size_t len)
Definition: ring_buffer.cpp:22