idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
queue.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
22#include <idfxx/chrono>
23#include <idfxx/error>
24#include <idfxx/memory>
25
26#include <chrono>
27#include <cstddef>
28#include <esp_attr.h>
29#include <freertos/FreeRTOS.h>
30#include <freertos/idf_additions.h>
31#include <freertos/queue.h>
32#include <optional>
33#include <type_traits>
34#include <utility>
35
36namespace idfxx {
37
65template<typename T>
66 requires std::is_trivially_copyable_v<T>
67class queue {
68public:
69#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
80 : _handle(nullptr) {
81 if (length == 0) {
82 throw std::system_error(errc::invalid_arg);
83 }
85 if (_handle == nullptr) {
87 }
88 }
89#endif
90
100 if (length == 0) {
101 return error(errc::invalid_arg);
102 }
103 queue q;
104 q._handle = xQueueCreateWithCaps(length, sizeof(T), to_underlying(mem_caps));
105 if (q._handle == nullptr) {
106 raise_no_mem();
107 }
108 return q;
109 }
110
117 if (_handle != nullptr) {
118 vQueueDeleteWithCaps(_handle);
119 }
120 }
121
122 queue(const queue&) = delete;
123 queue& operator=(const queue&) = delete;
124
127 : _handle(std::exchange(other._handle, nullptr)) {}
128
130 queue& operator=(queue&& other) noexcept {
131 if (this != &other) {
132 if (_handle != nullptr) {
133 vQueueDeleteWithCaps(_handle);
134 }
135 _handle = std::exchange(other._handle, nullptr);
136 }
137 return *this;
138 }
139
140 // =========================================================================
141 // Send operations
142 // =========================================================================
143
144#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
154 void send(const T& item) { unwrap(try_send(item)); }
155
169 template<typename Rep, typename Period>
170 void send(const T& item, const std::chrono::duration<Rep, Period>& timeout) {
171 unwrap(try_send(item, timeout));
172 }
173
187 template<typename Clock, typename Duration>
188 void send_until(const T& item, const std::chrono::time_point<Clock, Duration>& deadline) {
190 }
191
202 void send_to_front(const T& item) { unwrap(try_send_to_front(item)); }
203
218 template<typename Rep, typename Period>
219 void send_to_front(const T& item, const std::chrono::duration<Rep, Period>& timeout) {
221 }
222
237 template<typename Clock, typename Duration>
238 void send_to_front_until(const T& item, const std::chrono::time_point<Clock, Duration>& deadline) {
240 }
241#endif
242
252 [[nodiscard]] result<void> try_send(const T& item) { return _try_send(item, portMAX_DELAY); }
253
266 template<typename Rep, typename Period>
267 [[nodiscard]] result<void> try_send(const T& item, const std::chrono::duration<Rep, Period>& timeout) {
268 return _try_send(item, chrono::ticks(timeout));
269 }
270
283 template<typename Clock, typename Duration>
284 [[nodiscard]] result<void> try_send_until(const T& item, const std::chrono::time_point<Clock, Duration>& deadline) {
285 auto remaining = deadline - Clock::now();
286 if (remaining <= decltype(remaining)::zero()) {
287 return _try_send(item, 0);
288 }
289 return _try_send(item, chrono::ticks(remaining));
290 }
291
302 [[nodiscard]] result<void> try_send_to_front(const T& item) { return _try_send_to_front(item, portMAX_DELAY); }
303
317 template<typename Rep, typename Period>
318 [[nodiscard]] result<void> try_send_to_front(const T& item, const std::chrono::duration<Rep, Period>& timeout) {
319 return _try_send_to_front(item, chrono::ticks(timeout));
320 }
321
335 template<typename Clock, typename Duration>
337 try_send_to_front_until(const T& item, const std::chrono::time_point<Clock, Duration>& deadline) {
338 auto remaining = deadline - Clock::now();
339 if (remaining <= decltype(remaining)::zero()) {
340 return _try_send_to_front(item, 0);
341 }
342 return _try_send_to_front(item, chrono::ticks(remaining));
343 }
344
345 // =========================================================================
346 // Overwrite operations
347 // =========================================================================
348
360 void overwrite(const T& item) noexcept {
361 if (_handle == nullptr) {
362 return;
363 }
364 xQueueOverwrite(_handle, &item);
365 }
366
367 // =========================================================================
368 // Receive operations
369 // =========================================================================
370
371#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
381 [[nodiscard]] T receive() { return unwrap(try_receive()); }
382
396 template<typename Rep, typename Period>
397 [[nodiscard]] T receive(const std::chrono::duration<Rep, Period>& timeout) {
398 return unwrap(try_receive(timeout));
399 }
400
414 template<typename Clock, typename Duration>
415 [[nodiscard]] T receive_until(const std::chrono::time_point<Clock, Duration>& deadline) {
417 }
418#endif
419
428 [[nodiscard]] result<T> try_receive() { return _try_receive(portMAX_DELAY); }
429
441 template<typename Rep, typename Period>
442 [[nodiscard]] result<T> try_receive(const std::chrono::duration<Rep, Period>& timeout) {
443 return _try_receive(chrono::ticks(timeout));
444 }
445
457 template<typename Clock, typename Duration>
458 [[nodiscard]] result<T> try_receive_until(const std::chrono::time_point<Clock, Duration>& deadline) {
459 auto remaining = deadline - Clock::now();
460 if (remaining <= decltype(remaining)::zero()) {
461 return _try_receive(0);
462 }
463 return _try_receive(chrono::ticks(remaining));
464 }
465
466 // =========================================================================
467 // Peek operations
468 // =========================================================================
469
470#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
480 [[nodiscard]] T peek() { return unwrap(try_peek()); }
481
496 template<typename Rep, typename Period>
497 [[nodiscard]] T peek(const std::chrono::duration<Rep, Period>& timeout) {
498 return unwrap(try_peek(timeout));
499 }
500
515 template<typename Clock, typename Duration>
516 [[nodiscard]] T peek_until(const std::chrono::time_point<Clock, Duration>& deadline) {
518 }
519#endif
520
529 [[nodiscard]] result<T> try_peek() { return _try_peek(portMAX_DELAY); }
530
543 template<typename Rep, typename Period>
544 [[nodiscard]] result<T> try_peek(const std::chrono::duration<Rep, Period>& timeout) {
545 return _try_peek(chrono::ticks(timeout));
546 }
547
560 template<typename Clock, typename Duration>
561 [[nodiscard]] result<T> try_peek_until(const std::chrono::time_point<Clock, Duration>& deadline) {
562 auto remaining = deadline - Clock::now();
563 if (remaining <= decltype(remaining)::zero()) {
564 return _try_peek(0);
565 }
566 return _try_peek(chrono::ticks(remaining));
567 }
568
569 // =========================================================================
570 // ISR operations
571 // =========================================================================
572
578 bool success;
579 bool yield;
580 };
581
587 std::optional<T> item;
588 bool yield;
589 };
590
609 if (_handle == nullptr) {
610 return {false, false};
611 }
613 BaseType_t ret = xQueueSendFromISR(_handle, &item, &woken);
614 return {ret == pdTRUE, woken == pdTRUE};
615 }
616
635 if (_handle == nullptr) {
636 return {false, false};
637 }
639 BaseType_t ret = xQueueSendToFrontFromISR(_handle, &item, &woken);
640 return {ret == pdTRUE, woken == pdTRUE};
641 }
642
662 [[nodiscard]] bool IRAM_ATTR overwrite_from_isr(const T& item) noexcept {
663 if (_handle == nullptr) {
664 return false;
665 }
667 xQueueOverwriteFromISR(_handle, &item, &woken);
668 return woken == pdTRUE;
669 }
670
691 if (_handle == nullptr) {
692 return {std::nullopt, false};
693 }
694 T item;
696 if (xQueueReceiveFromISR(_handle, &item, &woken) == pdTRUE) {
697 return {item, woken == pdTRUE};
698 }
699 return {std::nullopt, woken == pdTRUE};
700 }
701
716 if (_handle == nullptr) {
717 return std::nullopt;
718 }
719 T item;
720 if (xQueuePeekFromISR(_handle, &item) == pdTRUE) {
721 return item;
722 }
723 return std::nullopt;
724 }
725
726 // =========================================================================
727 // Query and reset
728 // =========================================================================
729
736 if (_handle == nullptr) {
737 return 0;
738 }
739 return uxQueueMessagesWaiting(_handle);
740 }
741
748 if (_handle == nullptr) {
749 return 0;
750 }
751 return uxQueueSpacesAvailable(_handle);
752 }
753
760 if (_handle == nullptr) {
761 return true;
762 }
763 return uxQueueMessagesWaiting(_handle) == 0;
764 }
765
772 if (_handle == nullptr) {
773 return false;
774 }
775 return uxQueueSpacesAvailable(_handle) == 0;
776 }
777
787
794 if (_handle == nullptr) {
795 return;
796 }
797 xQueueReset(_handle);
798 }
799
800private:
802 : _handle(nullptr) {}
803
804 [[nodiscard]] result<void> _try_send(const T& item, TickType_t ticks) {
805 if (_handle == nullptr) {
807 }
808 if (xQueueSend(_handle, &item, ticks) != pdTRUE) {
809 return error(errc::timeout);
810 }
811 return {};
812 }
813
814 [[nodiscard]] result<void> _try_send_to_front(const T& item, TickType_t ticks) {
815 if (_handle == nullptr) {
817 }
818 if (xQueueSendToFront(_handle, &item, ticks) != pdTRUE) {
819 return error(errc::timeout);
820 }
821 return {};
822 }
823
824 [[nodiscard]] result<T> _try_receive(TickType_t ticks) {
825 if (_handle == nullptr) {
827 }
828 T item;
829 if (xQueueReceive(_handle, &item, ticks) != pdTRUE) {
830 return error(errc::timeout);
831 }
832 return item;
833 }
834
835 [[nodiscard]] result<T> _try_peek(TickType_t ticks) {
836 if (_handle == nullptr) {
838 }
839 T item;
840 if (xQueuePeek(_handle, &item, ticks) != pdTRUE) {
841 return error(errc::timeout);
842 }
843 return item;
844 }
845
846 QueueHandle_t _handle = nullptr;
847};
848
// end of idfxx_queue
850
851} // namespace idfxx
Type-safe inter-task message queue.
Definition queue.hpp:67
void send_to_front(const T &item, const std::chrono::duration< Rep, Period > &timeout)
Sends an item to the front of the queue with a timeout.
Definition queue.hpp:219
T peek_until(const std::chrono::time_point< Clock, Duration > &deadline)
Peeks at the front item in the queue without removing it, with a deadline.
Definition queue.hpp:516
size_t size() const noexcept
Returns the number of items currently in the queue.
Definition queue.hpp:735
void send_to_front_until(const T &item, const std::chrono::time_point< Clock, Duration > &deadline)
Sends an item to the front of the queue with a deadline.
Definition queue.hpp:238
queue(size_t length, flags< memory_caps > mem_caps=memory_caps::dram)
Creates a queue with the specified capacity.
Definition queue.hpp:79
queue & operator=(const queue &)=delete
bool empty() const noexcept
Checks if the queue is empty.
Definition queue.hpp:759
T peek(const std::chrono::duration< Rep, Period > &timeout)
Peeks at the front item in the queue without removing it, with a timeout.
Definition queue.hpp:497
bool full() const noexcept
Checks if the queue is full.
Definition queue.hpp:771
result< void > try_send_to_front_until(const T &item, const std::chrono::time_point< Clock, Duration > &deadline)
Sends an item to the front of the queue with a deadline.
Definition queue.hpp:337
isr_send_result IRAM_ATTR send_to_front_from_isr(const T &item) noexcept
Sends an item to the front of the queue from ISR context.
Definition queue.hpp:634
result< T > try_peek_until(const std::chrono::time_point< Clock, Duration > &deadline)
Peeks at the front item in the queue without removing it, with a deadline.
Definition queue.hpp:561
T receive()
Receives an item from the queue, blocking indefinitely.
Definition queue.hpp:381
void send_to_front(const T &item)
Sends an item to the front of the queue, blocking indefinitely.
Definition queue.hpp:202
void reset() noexcept
Removes all items from the queue.
Definition queue.hpp:793
void send(const T &item)
Sends an item to the back of the queue, blocking indefinitely.
Definition queue.hpp:154
~queue()
Destroys the queue and releases all resources.
Definition queue.hpp:116
queue(const queue &)=delete
result< void > try_send(const T &item)
Sends an item to the back of the queue, blocking indefinitely.
Definition queue.hpp:252
size_t available() const noexcept
Returns the number of free spaces in the queue.
Definition queue.hpp:747
result< void > try_send_to_front(const T &item)
Sends an item to the front of the queue, blocking indefinitely.
Definition queue.hpp:302
queue(queue &&other) noexcept
Move constructor.
Definition queue.hpp:126
result< T > try_peek(const std::chrono::duration< Rep, Period > &timeout)
Peeks at the front item in the queue without removing it, with a timeout.
Definition queue.hpp:544
std::optional< T > IRAM_ATTR peek_from_isr() const noexcept
Peeks at the front item in the queue from ISR context without removing it.
Definition queue.hpp:715
T receive_until(const std::chrono::time_point< Clock, Duration > &deadline)
Receives an item from the queue with a deadline.
Definition queue.hpp:415
QueueHandle_t idf_handle() const noexcept
Returns the underlying FreeRTOS queue handle.
Definition queue.hpp:786
queue & operator=(queue &&other) noexcept
Move assignment.
Definition queue.hpp:130
isr_receive_result IRAM_ATTR receive_from_isr() noexcept
Receives an item from the queue in ISR context.
Definition queue.hpp:690
result< void > try_send(const T &item, const std::chrono::duration< Rep, Period > &timeout)
Sends an item to the back of the queue with a timeout.
Definition queue.hpp:267
result< void > try_send_to_front(const T &item, const std::chrono::duration< Rep, Period > &timeout)
Sends an item to the front of the queue with a timeout.
Definition queue.hpp:318
void send_until(const T &item, const std::chrono::time_point< Clock, Duration > &deadline)
Sends an item to the back of the queue with a deadline.
Definition queue.hpp:188
result< T > try_receive()
Receives an item from the queue, blocking indefinitely.
Definition queue.hpp:428
T peek()
Peeks at the front item in the queue without removing it, blocking indefinitely.
Definition queue.hpp:480
result< T > try_receive(const std::chrono::duration< Rep, Period > &timeout)
Receives an item from the queue with a timeout.
Definition queue.hpp:442
bool IRAM_ATTR overwrite_from_isr(const T &item) noexcept
Overwrites the last item in the queue from ISR context.
Definition queue.hpp:662
isr_send_result IRAM_ATTR send_from_isr(const T &item) noexcept
Sends an item to the back of the queue from ISR context.
Definition queue.hpp:608
result< T > try_peek()
Peeks at the front item in the queue without removing it, blocking indefinitely.
Definition queue.hpp:529
result< void > try_send_until(const T &item, const std::chrono::time_point< Clock, Duration > &deadline)
Sends an item to the back of the queue with a deadline.
Definition queue.hpp:284
T receive(const std::chrono::duration< Rep, Period > &timeout)
Receives an item from the queue with a timeout.
Definition queue.hpp:397
result< T > try_receive_until(const std::chrono::time_point< Clock, Duration > &deadline)
Receives an item from the queue with a deadline.
Definition queue.hpp:458
void send(const T &item, const std::chrono::duration< Rep, Period > &timeout)
Sends an item to the back of the queue with a timeout.
Definition queue.hpp:170
void overwrite(const T &item) noexcept
Overwrites the last item in the queue, or sends if the queue is not full.
Definition queue.hpp:360
static result< queue > make(size_t length, flags< memory_caps > mem_caps=memory_caps::dram)
Creates a queue with the specified capacity.
Definition queue.hpp:99
constexpr TickType_t ticks(const std::chrono::duration< Rep, Period > &d)
Converts a std::chrono duration to TickType_t ticks.
Definition chrono.hpp:33
@ dram
Internal DRAM (8-bit accessible)
constexpr std::unexpected< std::error_code > error(E e) noexcept
Creates an unexpected error from an error code enum.
Definition error.hpp:187
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
Definition error.hpp:307
@ invalid_state
Invalid state.
@ timeout
Operation timed out.
@ invalid_arg
Invalid argument.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:120
constexpr auto to_underlying(flags< E > f) noexcept
Returns the underlying integral value of a flags object.
Definition flags.hpp:346
Result of an ISR receive operation.
Definition queue.hpp:586
std::optional< T > item
The received item, or std::nullopt if the queue was empty.
Definition queue.hpp:587
bool yield
true if a context switch should be requested.
Definition queue.hpp:588
Result of an ISR send operation.
Definition queue.hpp:577
bool success
true if the item was sent successfully.
Definition queue.hpp:578
bool yield
true if a context switch should be requested.
Definition queue.hpp:579