23#include <idfxx/chrono>
29#include <freertos/FreeRTOS.h>
30#include <freertos/event_groups.h>
79 requires(
sizeof(std::underlying_type_t<E>) <=
sizeof(EventBits_t))
82#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
90 : _handle(xEventGroupCreate()) {
91 if (_handle ==
nullptr) {
104 auto eg = std::unique_ptr<event_group>(
new event_group(private_tag{}));
105 if (eg->_handle ==
nullptr) {
118 if (_handle !=
nullptr) {
119 vEventGroupDelete(_handle);
146 return flags<E>::from_raw(
static_cast<std::underlying_type_t<E>
>(xEventGroupSetBits(_handle, bits.value())));
162 return flags<E>::from_raw(
static_cast<std::underlying_type_t<E>
>(xEventGroupClearBits(_handle, bits.value())));
175 return flags<E>::from_raw(
static_cast<std::underlying_type_t<E>
>(xEventGroupGetBits(_handle)));
182#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
197 return unwrap(try_wait(bits, mode, clear_on_exit));
216 template<
typename Rep,
typename Period>
238 template<
typename Clock,
typename Duration>
242 const std::chrono::time_point<Clock, Duration>& deadline,
243 bool clear_on_exit =
true
245 return unwrap(try_wait_until(bits, mode, deadline, clear_on_exit));
261 return _try_wait(bits, mode, clear_on_exit, portMAX_DELAY);
278 template<
typename Rep,
typename Period>
282 const std::chrono::duration<Rep, Period>&
timeout,
283 bool clear_on_exit =
true
302 template<
typename Clock,
typename Duration>
306 const std::chrono::time_point<Clock, Duration>& deadline,
307 bool clear_on_exit =
true
309 auto remaining = deadline - Clock::now();
310 if (remaining <=
decltype(remaining)::zero()) {
311 return _try_wait(bits, mode, clear_on_exit, 0);
313 return _try_wait(bits, mode, clear_on_exit,
chrono::ticks(remaining));
320#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
355 template<
typename Rep,
typename Period>
376 template<
typename Clock,
typename Duration>
379 return unwrap(try_sync_until(set_bits, wait_bits, deadline));
399 return _try_sync(set_bits, wait_bits, portMAX_DELAY);
415 template<
typename Rep,
typename Period>
434 template<
typename Clock,
typename Duration>
437 auto remaining = deadline - Clock::now();
438 if (remaining <=
decltype(remaining)::zero()) {
439 return _try_sync(set_bits, wait_bits, 0);
441 return _try_sync(set_bits, wait_bits,
chrono::ticks(remaining));
479 BaseType_t woken = pdFALSE;
480 BaseType_t ret = xEventGroupSetBitsFromISR(_handle, bits.value(), &woken);
481 return {ret == pdPASS, woken == pdTRUE};
498 static_cast<std::underlying_type_t<E>
>(xEventGroupClearBitsFromISR(_handle, bits.value()))
508 return flags<E>::from_raw(
static_cast<std::underlying_type_t<E>
>(xEventGroupGetBitsFromISR(_handle)));
523 [[nodiscard]] EventGroupHandle_t
idf_handle() const noexcept {
return _handle; }
526 struct private_tag {};
528 event_group(private_tag) noexcept
529 : _handle(xEventGroupCreate()) {}
531 [[nodiscard]] result<flags<E>> _try_wait(flags<E> bits,
wait_mode mode,
bool clear_on_exit, TickType_t ticks) {
532 EventBits_t result_bits = xEventGroupWaitBits(
533 _handle, bits.value(), clear_on_exit ? pdTRUE : pdFALSE, mode ==
wait_mode::
all ? pdTRUE : pdFALSE,
ticks
535 auto result_flags =
flags<E>::from_raw(
static_cast<std::underlying_type_t<E>
>(result_bits));
536 bool satisfied = (mode ==
wait_mode::all) ? result_flags.contains(bits) : result_flags.contains_any(bits);
543 [[nodiscard]] result<flags<E>> _try_sync(flags<E> set_bits, flags<E> wait_bits, TickType_t ticks) {
544 EventBits_t result_bits = xEventGroupSync(_handle, set_bits.value(), wait_bits.value(), ticks);
545 auto result_flags =
flags<E>::from_raw(
static_cast<std::underlying_type_t<E>
>(result_bits));
546 if (!result_flags.contains(wait_bits)) {
552 EventGroupHandle_t _handle;
Type-safe inter-task event group for bit-level synchronization.
event_group & operator=(event_group &&)=delete
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.
event_group(event_group &&)=delete
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.
static result< std::unique_ptr< event_group > > make()
Creates an event group.
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()
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
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.
Type-safe set of flags from a scoped enum.
static constexpr flags from_raw(underlying v) noexcept
Constructs flags from a raw underlying value.
constexpr TickType_t ticks(const std::chrono::duration< Rep, Period > &d)
Converts a std::chrono duration to TickType_t ticks.
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.
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
@ timeout
Operation timed out.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
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.