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 }
84 _handle = xQueueCreateWithCaps(length, sizeof(T), to_underlying(mem_caps));
85 if (_handle == nullptr) {
87 }
88 }
89#endif
90
99 [[nodiscard]] static result<queue>
101 if (length == 0) {
102 return error(errc::invalid_arg);
103 }
104 queue q;
105 q._handle = xQueueCreateWithCaps(length, sizeof(T), to_underlying(mem_caps));
106 if (q._handle == nullptr) {
107 raise_no_mem();
108 }
109 return q;
110 }
111
118 if (_handle != nullptr) {
119 vQueueDeleteWithCaps(_handle);
120 }
121 }
122
123 queue(const queue&) = delete;
124 queue& operator=(const queue&) = delete;
125
128 : _handle(std::exchange(other._handle, nullptr)) {}
129
131 queue& operator=(queue&& other) noexcept {
132 if (this != &other) {
133 if (_handle != nullptr) {
134 vQueueDeleteWithCaps(_handle);
135 }
136 _handle = std::exchange(other._handle, nullptr);
137 }
138 return *this;
139 }
140
141 // =========================================================================
142 // Send operations
143 // =========================================================================
144
145#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
155 void send(const T& item) { unwrap(try_send(item)); }
156
170 template<typename Rep, typename Period>
171 void send(const T& item, const std::chrono::duration<Rep, Period>& timeout) {
172 unwrap(try_send(item, timeout));
173 }
174
188 template<typename Clock, typename Duration>
189 void send_until(const T& item, const std::chrono::time_point<Clock, Duration>& deadline) {
191 }
192
203 void send_to_front(const T& item) { unwrap(try_send_to_front(item)); }
204
219 template<typename Rep, typename Period>
220 void send_to_front(const T& item, const std::chrono::duration<Rep, Period>& timeout) {
222 }
223
238 template<typename Clock, typename Duration>
239 void send_to_front_until(const T& item, const std::chrono::time_point<Clock, Duration>& deadline) {
241 }
242#endif
243
253 [[nodiscard]] result<void> try_send(const T& item) { return _try_send(item, portMAX_DELAY); }
254
267 template<typename Rep, typename Period>
268 [[nodiscard]] result<void> try_send(const T& item, const std::chrono::duration<Rep, Period>& timeout) {
269 return _try_send(item, chrono::ticks(timeout));
270 }
271
284 template<typename Clock, typename Duration>
285 [[nodiscard]] result<void> try_send_until(const T& item, const std::chrono::time_point<Clock, Duration>& deadline) {
286 auto remaining = deadline - Clock::now();
287 if (remaining <= decltype(remaining)::zero()) {
288 return _try_send(item, 0);
289 }
290 return _try_send(item, chrono::ticks(remaining));
291 }
292
303 [[nodiscard]] result<void> try_send_to_front(const T& item) { return _try_send_to_front(item, portMAX_DELAY); }
304
318 template<typename Rep, typename Period>
319 [[nodiscard]] result<void> try_send_to_front(const T& item, const std::chrono::duration<Rep, Period>& timeout) {
320 return _try_send_to_front(item, chrono::ticks(timeout));
321 }
322
336 template<typename Clock, typename Duration>
338 try_send_to_front_until(const T& item, const std::chrono::time_point<Clock, Duration>& deadline) {
339 auto remaining = deadline - Clock::now();
340 if (remaining <= decltype(remaining)::zero()) {
341 return _try_send_to_front(item, 0);
342 }
343 return _try_send_to_front(item, chrono::ticks(remaining));
344 }
345
346 // =========================================================================
347 // Overwrite operations
348 // =========================================================================
349
361 void overwrite(const T& item) noexcept {
362 if (_handle == nullptr) {
363 return;
364 }
365 xQueueOverwrite(_handle, &item);
366 }
367
368 // =========================================================================
369 // Receive operations
370 // =========================================================================
371
372#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
382 T receive() { return unwrap(try_receive()); }
383
397 template<typename Rep, typename Period>
398 T receive(const std::chrono::duration<Rep, Period>& timeout) {
399 return unwrap(try_receive(timeout));
400 }
401
415 template<typename Clock, typename Duration>
416 T receive_until(const std::chrono::time_point<Clock, Duration>& deadline) {
418 }
419#endif
420
429 [[nodiscard]] result<T> try_receive() { return _try_receive(portMAX_DELAY); }
430
442 template<typename Rep, typename Period>
443 [[nodiscard]] result<T> try_receive(const std::chrono::duration<Rep, Period>& timeout) {
444 return _try_receive(chrono::ticks(timeout));
445 }
446
458 template<typename Clock, typename Duration>
459 [[nodiscard]] result<T> try_receive_until(const std::chrono::time_point<Clock, Duration>& deadline) {
460 auto remaining = deadline - Clock::now();
461 if (remaining <= decltype(remaining)::zero()) {
462 return _try_receive(0);
463 }
464 return _try_receive(chrono::ticks(remaining));
465 }
466
467 // =========================================================================
468 // Peek operations
469 // =========================================================================
470
471#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
481 [[nodiscard]] T peek() { return unwrap(try_peek()); }
482
497 template<typename Rep, typename Period>
498 [[nodiscard]] T peek(const std::chrono::duration<Rep, Period>& timeout) {
499 return unwrap(try_peek(timeout));
500 }
501
516 template<typename Clock, typename Duration>
517 [[nodiscard]] T peek_until(const std::chrono::time_point<Clock, Duration>& deadline) {
519 }
520#endif
521
530 [[nodiscard]] result<T> try_peek() { return _try_peek(portMAX_DELAY); }
531
544 template<typename Rep, typename Period>
545 [[nodiscard]] result<T> try_peek(const std::chrono::duration<Rep, Period>& timeout) {
546 return _try_peek(chrono::ticks(timeout));
547 }
548
561 template<typename Clock, typename Duration>
562 [[nodiscard]] result<T> try_peek_until(const std::chrono::time_point<Clock, Duration>& deadline) {
563 auto remaining = deadline - Clock::now();
564 if (remaining <= decltype(remaining)::zero()) {
565 return _try_peek(0);
566 }
567 return _try_peek(chrono::ticks(remaining));
568 }
569
570 // =========================================================================
571 // ISR operations
572 // =========================================================================
573
579 bool success;
580 bool yield;
581 };
582
588 std::optional<T> item;
589 bool yield;
590 };
591
610 if (_handle == nullptr) {
611 return {false, false};
612 }
614 BaseType_t ret = xQueueSendFromISR(_handle, &item, &woken);
615 return {ret == pdTRUE, woken == pdTRUE};
616 }
617
636 if (_handle == nullptr) {
637 return {false, false};
638 }
640 BaseType_t ret = xQueueSendToFrontFromISR(_handle, &item, &woken);
641 return {ret == pdTRUE, woken == pdTRUE};
642 }
643
663 [[nodiscard]] bool IRAM_ATTR overwrite_from_isr(const T& item) noexcept {
664 if (_handle == nullptr) {
665 return false;
666 }
668 xQueueOverwriteFromISR(_handle, &item, &woken);
669 return woken == pdTRUE;
670 }
671
692 if (_handle == nullptr) {
693 return {std::nullopt, false};
694 }
695 T item;
697 if (xQueueReceiveFromISR(_handle, &item, &woken) == pdTRUE) {
698 return {item, woken == pdTRUE};
699 }
700 return {std::nullopt, woken == pdTRUE};
701 }
702
717 if (_handle == nullptr) {
718 return std::nullopt;
719 }
720 T item;
721 if (xQueuePeekFromISR(_handle, &item) == pdTRUE) {
722 return item;
723 }
724 return std::nullopt;
725 }
726
727 // =========================================================================
728 // Query and reset
729 // =========================================================================
730
737 if (_handle == nullptr) {
738 return 0;
739 }
740 return uxQueueMessagesWaiting(_handle);
741 }
742
749 if (_handle == nullptr) {
750 return 0;
751 }
752 return uxQueueSpacesAvailable(_handle);
753 }
754
761 if (_handle == nullptr) {
762 return true;
763 }
764 return uxQueueMessagesWaiting(_handle) == 0;
765 }
766
773 if (_handle == nullptr) {
774 return false;
775 }
776 return uxQueueSpacesAvailable(_handle) == 0;
777 }
778
788
795 if (_handle == nullptr) {
796 return;
797 }
798 xQueueReset(_handle);
799 }
800
801private:
803 : _handle(nullptr) {}
804
805 [[nodiscard]] result<void> _try_send(const T& item, TickType_t ticks) {
806 if (_handle == nullptr) {
808 }
809 if (xQueueSend(_handle, &item, ticks) != pdTRUE) {
810 return error(errc::timeout);
811 }
812 return {};
813 }
814
815 [[nodiscard]] result<void> _try_send_to_front(const T& item, TickType_t ticks) {
816 if (_handle == nullptr) {
818 }
819 if (xQueueSendToFront(_handle, &item, ticks) != pdTRUE) {
820 return error(errc::timeout);
821 }
822 return {};
823 }
824
825 [[nodiscard]] result<T> _try_receive(TickType_t ticks) {
826 if (_handle == nullptr) {
828 }
829 T item;
830 if (xQueueReceive(_handle, &item, ticks) != pdTRUE) {
831 return error(errc::timeout);
832 }
833 return item;
834 }
835
836 [[nodiscard]] result<T> _try_peek(TickType_t ticks) {
837 if (_handle == nullptr) {
839 }
840 T item;
841 if (xQueuePeek(_handle, &item, ticks) != pdTRUE) {
842 return error(errc::timeout);
843 }
844 return item;
845 }
846
847 QueueHandle_t _handle = nullptr;
848};
849
// end of idfxx_queue
851
852} // 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:220
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:517
size_t size() const noexcept
Returns the number of items currently in the queue.
Definition queue.hpp:736
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:239
queue & operator=(const queue &)=delete
bool empty() const noexcept
Checks if the queue is empty.
Definition queue.hpp:760
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:498
bool full() const noexcept
Checks if the queue is full.
Definition queue.hpp:772
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:338
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:635
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:562
T receive()
Receives an item from the queue, blocking indefinitely.
Definition queue.hpp:382
void send_to_front(const T &item)
Sends an item to the front of the queue, blocking indefinitely.
Definition queue.hpp:203
void reset() noexcept
Removes all items from the queue.
Definition queue.hpp:794
void send(const T &item)
Sends an item to the back of the queue, blocking indefinitely.
Definition queue.hpp:155
~queue()
Destroys the queue and releases all resources.
Definition queue.hpp:117
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:253
size_t available() const noexcept
Returns the number of free spaces in the queue.
Definition queue.hpp:748
result< void > try_send_to_front(const T &item)
Sends an item to the front of the queue, blocking indefinitely.
Definition queue.hpp:303
queue(queue &&other) noexcept
Move constructor.
Definition queue.hpp:127
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:545
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:716
T receive_until(const std::chrono::time_point< Clock, Duration > &deadline)
Receives an item from the queue with a deadline.
Definition queue.hpp:416
QueueHandle_t idf_handle() const noexcept
Returns the underlying FreeRTOS queue handle.
Definition queue.hpp:787
queue & operator=(queue &&other) noexcept
Move assignment.
Definition queue.hpp:131
isr_receive_result IRAM_ATTR receive_from_isr() noexcept
Receives an item from the queue in ISR context.
Definition queue.hpp:691
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:268
queue(size_t length, flags< memory::capabilities > mem_caps=memory::capabilities::dram)
Creates a queue with the specified capacity.
Definition queue.hpp:79
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:319
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:189
result< T > try_receive()
Receives an item from the queue, blocking indefinitely.
Definition queue.hpp:429
T peek()
Peeks at the front item in the queue without removing it, blocking indefinitely.
Definition queue.hpp:481
result< T > try_receive(const std::chrono::duration< Rep, Period > &timeout)
Receives an item from the queue with a timeout.
Definition queue.hpp:443
bool IRAM_ATTR overwrite_from_isr(const T &item) noexcept
Overwrites the last item in the queue from ISR context.
Definition queue.hpp:663
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:609
result< T > try_peek()
Peeks at the front item in the queue without removing it, blocking indefinitely.
Definition queue.hpp:530
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:285
T receive(const std::chrono::duration< Rep, Period > &timeout)
Receives an item from the queue with a timeout.
Definition queue.hpp:398
static result< queue > make(size_t length, flags< memory::capabilities > mem_caps=memory::capabilities::dram)
Creates a queue with the specified capacity.
Definition queue.hpp:100
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:459
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:171
void overwrite(const T &item) noexcept
Overwrites the last item in the queue, or sends if the queue is not full.
Definition queue.hpp:361
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:292
Result of an ISR receive operation.
Definition queue.hpp:587
std::optional< T > item
The received item, or std::nullopt if the queue was empty.
Definition queue.hpp:588
bool yield
true if a context switch should be requested.
Definition queue.hpp:589
Result of an ISR send operation.
Definition queue.hpp:578
bool success
true if the item was sent successfully.
Definition queue.hpp:579
bool yield
true if a context switch should be requested.
Definition queue.hpp:580