ESPHome 2026.5.0b1
Loading...
Searching...
No Matches
freertos_queue.h
Go to the documentation of this file.
1#pragma once
2
4
5#ifdef ESPHOME_THREAD_MULTI_NO_ATOMICS
6
7#include <cstddef>
8#include <cstdint>
9
10#include <FreeRTOS.h>
11#include <queue.h>
12
13/*
14 * FreeRTOS queue wrapper for single-producer single-consumer scenarios on
15 * platforms without hardware atomic support (e.g. BK72xx ARM968E-S).
16 *
17 * Provides the same API as LockFreeQueue (push, pop, get_and_reset_dropped_count,
18 * empty, full, size) but uses xQueue internally, which synchronizes via
19 * FreeRTOS critical sections. Uses xQueueCreateStatic so the queue storage
20 * lives in BSS with zero runtime heap allocation.
21 *
22 * @tparam T The type of elements stored in the queue (stored as pointers)
23 * @tparam SIZE The maximum number of elements
24 */
25
26namespace esphome {
27
28template<class T, uint8_t SIZE> class FreeRTOSQueue {
29 public:
31 this->handle_ = xQueueCreateStatic(SIZE, sizeof(T *), this->storage_, &this->queue_buf_);
32 }
33
34 // No destructor — ESPHome components are never destroyed. Intentionally
35 // omitted to avoid pulling in vQueueDelete code on resource-constrained targets.
36
37 // Non-copyable, non-movable — queue handle is not transferable
38 FreeRTOSQueue(const FreeRTOSQueue &) = delete;
42
43 bool push(T *element) {
44 if (element == nullptr)
45 return false;
46
47 if (xQueueSend(this->handle_, &element, 0) != pdPASS) {
49 return false;
50 }
51 return true;
52 }
53
54 T *pop() {
55 T *element;
56 if (xQueueReceive(this->handle_, &element, 0) != pdTRUE) {
57 return nullptr;
58 }
59 return element;
60 }
61
63 // Fast path: plain read of aligned uint16_t is a single ARM load instruction.
64 // Worst case is reading a stale zero and reporting drops one iteration later.
65 // Avoids critical section overhead on every loop() call since drops are rare.
66 if (this->dropped_count_ == 0)
67 return 0;
68 // Declare outside critical section — BK72xx portENTER_CRITICAL may introduce a scope
69 uint16_t count;
70 portENTER_CRITICAL();
71 count = this->dropped_count_;
72 this->dropped_count_ = 0;
73 portEXIT_CRITICAL();
74 return count;
75 }
76
78 portENTER_CRITICAL();
79 this->dropped_count_++;
80 portEXIT_CRITICAL();
81 }
82
83 bool empty() const { return uxQueueMessagesWaiting(this->handle_) == 0; }
84
85 bool full() const { return uxQueueSpacesAvailable(this->handle_) == 0; }
86
87 size_t size() const { return uxQueueMessagesWaiting(this->handle_); }
88
89 protected:
90 // Static storage for the queue — lives in BSS, no heap allocation
91 uint8_t storage_[SIZE * sizeof(T *)];
92 StaticQueue_t queue_buf_;
93 QueueHandle_t handle_;
95};
96
97} // namespace esphome
98
99#endif // ESPHOME_THREAD_MULTI_NO_ATOMICS
FreeRTOSQueue(FreeRTOSQueue &&)=delete
uint8_t storage_[SIZE *sizeof(T *)]
FreeRTOSQueue(const FreeRTOSQueue &)=delete
bool push(T *element)
uint16_t get_and_reset_dropped_count()
FreeRTOSQueue & operator=(const FreeRTOSQueue &)=delete
FreeRTOSQueue & operator=(FreeRTOSQueue &&)=delete