idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
event_group.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
23#include <idfxx/chrono>
24#include <idfxx/error>
25#include <idfxx/flags>
26
27#include <chrono>
28#include <esp_attr.h>
29#include <freertos/FreeRTOS.h>
30#include <freertos/event_groups.h>
31#include <type_traits>
32#include <utility>
33
34namespace idfxx {
35
40enum class wait_mode {
41 any,
42 all,
43};
44
78template<flag_enum E>
79 requires(sizeof(std::underlying_type_t<E>) <= sizeof(EventBits_t))
81public:
88 : _handle(xEventGroupCreate()) {
89 if (_handle == nullptr) {
91 }
92 }
93
101 if (_handle != nullptr) {
102 vEventGroupDelete(_handle);
103 }
104 }
105
106 event_group(const event_group&) = delete;
108
111 : _handle(std::exchange(other._handle, nullptr)) {}
112
114 event_group& operator=(event_group&& other) noexcept {
115 if (this != &other) {
116 if (_handle != nullptr) {
117 vEventGroupDelete(_handle);
118 }
119 _handle = std::exchange(other._handle, nullptr);
120 }
121 return *this;
122 }
123
124 // =========================================================================
125 // Set operations
126 // =========================================================================
127
141 if (_handle == nullptr) {
142 return {};
143 }
144 return _from_bits(xEventGroupSetBits(_handle, to_underlying(bits)));
145 }
146
147 // =========================================================================
148 // Clear operations
149 // =========================================================================
150
160 if (_handle == nullptr) {
161 return {};
162 }
163 return _from_bits(xEventGroupClearBits(_handle, to_underlying(bits)));
164 }
165
166 // =========================================================================
167 // Get operations
168 // =========================================================================
169
176 if (_handle == nullptr) {
177 return {};
178 }
179 return _from_bits(xEventGroupGetBits(_handle));
180 }
181
182 // =========================================================================
183 // Wait operations
184 // =========================================================================
185
186#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
201 return unwrap(try_wait(bits, mode, clear_on_exit));
202 }
203
220 template<typename Rep, typename Period>
222 wait(flags<E> bits, wait_mode mode, const std::chrono::duration<Rep, Period>& timeout, bool clear_on_exit = true) {
223 return unwrap(try_wait(bits, mode, timeout, clear_on_exit));
224 }
225
242 template<typename Clock, typename Duration>
245 wait_mode mode,
246 const std::chrono::time_point<Clock, Duration>& deadline,
247 bool clear_on_exit = true
248 ) {
249 return unwrap(try_wait_until(bits, mode, deadline, clear_on_exit));
250 }
251#endif
252
265 return _try_wait(bits, mode, clear_on_exit, portMAX_DELAY);
266 }
267
282 template<typename Rep, typename Period>
285 wait_mode mode,
286 const std::chrono::duration<Rep, Period>& timeout,
287 bool clear_on_exit = true
288 ) {
289 return _try_wait(bits, mode, clear_on_exit, chrono::ticks(timeout));
290 }
291
306 template<typename Clock, typename Duration>
309 wait_mode mode,
310 const std::chrono::time_point<Clock, Duration>& deadline,
311 bool clear_on_exit = true
312 ) {
313 auto remaining = deadline - Clock::now();
314 if (remaining <= decltype(remaining)::zero()) {
315 return _try_wait(bits, mode, clear_on_exit, 0);
316 }
317 return _try_wait(bits, mode, clear_on_exit, chrono::ticks(remaining));
318 }
319
320 // =========================================================================
321 // Sync operations
322 // =========================================================================
323
324#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
343
359 template<typename Rep, typename Period>
361 sync(flags<E> set_bits, flags<E> wait_bits, const std::chrono::duration<Rep, Period>& timeout) {
362 return unwrap(try_sync(set_bits, wait_bits, timeout));
363 }
364
380 template<typename Clock, typename Duration>
382 sync_until(flags<E> set_bits, flags<E> wait_bits, const std::chrono::time_point<Clock, Duration>& deadline) {
383 return unwrap(try_sync_until(set_bits, wait_bits, deadline));
384 }
385#endif
386
405
419 template<typename Rep, typename Period>
421 try_sync(flags<E> set_bits, flags<E> wait_bits, const std::chrono::duration<Rep, Period>& timeout) {
422 return _try_sync(set_bits, wait_bits, chrono::ticks(timeout));
423 }
424
438 template<typename Clock, typename Duration>
440 try_sync_until(flags<E> set_bits, flags<E> wait_bits, const std::chrono::time_point<Clock, Duration>& deadline) {
441 auto remaining = deadline - Clock::now();
442 if (remaining <= decltype(remaining)::zero()) {
443 return _try_sync(set_bits, wait_bits, 0);
444 }
445 return _try_sync(set_bits, wait_bits, chrono::ticks(remaining));
446 }
447
448 // =========================================================================
449 // ISR operations
450 // =========================================================================
451
457 bool success;
458 bool yield;
459 };
460
483 if (_handle == nullptr) {
484 return {false, false};
485 }
488 return {ret == pdPASS, woken == pdTRUE};
489 }
490
504 if (_handle == nullptr) {
505 return {};
506 }
507 return _from_bits(xEventGroupClearBitsFromISR(_handle, to_underlying(bits)));
508 }
509
516 if (_handle == nullptr) {
517 return {};
518 }
519 return _from_bits(xEventGroupGetBitsFromISR(_handle));
520 }
521
522 // =========================================================================
523 // Handle access
524 // =========================================================================
525
535
536private:
537 static flags<E> _from_bits(EventBits_t bits) noexcept {
538 return flags<E>(static_cast<std::underlying_type_t<E>>(bits));
539 }
540
541 [[nodiscard]] result<flags<E>> _try_wait(flags<E> bits, wait_mode mode, bool clear_on_exit, TickType_t ticks) {
542 if (_handle == nullptr) {
544 }
546 _handle,
550 ticks
551 );
552 auto result_flags = _from_bits(result_bits);
553 bool satisfied = (mode == wait_mode::all) ? result_flags.contains(bits) : result_flags.contains_any(bits);
554 if (!satisfied) {
555 return error(errc::timeout);
556 }
557 return result_flags;
558 }
559
561 if (_handle == nullptr) {
563 }
565 auto result_flags = _from_bits(result_bits);
566 if (!result_flags.contains(wait_bits)) {
567 return error(errc::timeout);
568 }
569 return result_flags;
570 }
571
572 EventGroupHandle_t _handle = nullptr;
573};
574
// end of idfxx_event_group
576
577} // namespace idfxx
Type-safe inter-task event group for bit-level synchronization.
flags< E > get() const noexcept
Returns the current event bits.
flags< E > sync(flags< E > set_bits, flags< E > wait_bits, const std::chrono::duration< Rep, Period > &timeout)
Atomically sets bits and waits for other bits, with a timeout.
result< flags< E > > try_wait(flags< E > bits, wait_mode mode, const std::chrono::duration< Rep, Period > &timeout, bool clear_on_exit=true)
Waits for event bits to be set, with a timeout.
flags< E > clear(flags< E > bits) noexcept
Clears event bits in the event group.
flags< E > IRAM_ATTR clear_from_isr(flags< E > bits) noexcept
Clears event bits from ISR context.
result< flags< E > > try_sync(flags< E > set_bits, flags< E > wait_bits)
Atomically sets bits and waits for other bits, blocking indefinitely.
flags< E > sync(flags< E > set_bits, flags< E > wait_bits)
Atomically sets bits and waits for other bits, blocking indefinitely.
EventGroupHandle_t idf_handle() const noexcept
Returns the underlying FreeRTOS event group handle.
flags< E > IRAM_ATTR get_from_isr() const noexcept
Returns the current event bits from ISR context.
flags< E > sync_until(flags< E > set_bits, flags< E > wait_bits, const std::chrono::time_point< Clock, Duration > &deadline)
Atomically sets bits and waits for other bits, with a deadline.
result< flags< E > > try_sync_until(flags< E > set_bits, flags< E > wait_bits, const std::chrono::time_point< Clock, Duration > &deadline)
Atomically sets bits and waits for other bits, with a deadline.
~event_group()
Destroys the event group and releases all resources.
event_group(const event_group &)=delete
flags< E > set(flags< E > bits) noexcept
Sets event bits in the event group.
result< flags< E > > try_sync(flags< E > set_bits, flags< E > wait_bits, const std::chrono::duration< Rep, Period > &timeout)
Atomically sets bits and waits for other bits, with a timeout.
result< flags< E > > try_wait_until(flags< E > bits, wait_mode mode, const std::chrono::time_point< Clock, Duration > &deadline, bool clear_on_exit=true)
Waits for event bits to be set, with a deadline.
event_group & operator=(event_group &&other) noexcept
Move assignment.
event_group()
Creates an event group.
flags< E > wait(flags< E > bits, wait_mode mode, const std::chrono::duration< Rep, Period > &timeout, bool clear_on_exit=true)
Waits for event bits to be set, with a timeout.
event_group & operator=(const event_group &)=delete
event_group(event_group &&other) noexcept
Move constructor.
isr_set_result IRAM_ATTR set_from_isr(flags< E > bits) noexcept
Sets event bits from ISR context.
flags< E > wait_until(flags< E > bits, wait_mode mode, const std::chrono::time_point< Clock, Duration > &deadline, bool clear_on_exit=true)
Waits for event bits to be set, with a deadline.
flags< E > wait(flags< E > bits, wait_mode mode, bool clear_on_exit=true)
Waits for event bits to be set, blocking indefinitely.
result< flags< E > > try_wait(flags< E > bits, wait_mode mode, bool clear_on_exit=true)
Waits for event bits to be set, blocking indefinitely.
constexpr TickType_t ticks(const std::chrono::duration< Rep, Period > &d)
Converts a std::chrono duration to TickType_t ticks.
Definition chrono.hpp:33
wait_mode
Specifies whether to wait for any or all of the requested bits.
@ any
Wait for any of the specified bits to be set.
@ all
Wait for all of the specified bits to be set.
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.
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 setting event bits from ISR context.
bool yield
true if a context switch should be requested.
bool success
true if the set was posted to the timer daemon task successfully.