21#include <idfxx/chrono>
58#define IDFXX_EVENT_DEFINE_BASE(name, id_enum) \
59 inline constexpr char _##name##_base[] = #name; \
60 inline constexpr ::idfxx::event_base<id_enum> name{_##name##_base}; \
61 constexpr ::idfxx::event_base<id_enum> idfxx_get_event_base(id_enum*) { \
67template<
typename IdEnum>
89template<
typename IdEnum>
124 [[nodiscard]]
constexpr esp_event_base_t
idf_base() const noexcept {
return _base; }
127 esp_event_base_t _base;
147 { T::from_opaque(data) } -> std::same_as<T>;
193template<
typename IdEnum,
typename DataType =
void>
196 static_assert(
sizeof(IdEnum) <=
sizeof(int32_t),
"event ID enum must fit in int32_t");
210template<
typename IdEnum>
212 return idfxx_get_event_base(
static_cast<IdEnum*
>(
nullptr));
223T from_opaque_data(
const void* data) {
224 if constexpr (
requires {
225 { T::from_opaque(data) } -> std::same_as<T>;
227 return T::from_opaque(data);
229 return *
static_cast<const T*
>(
data);
236template<
typename DataType>
237struct event_handler_traits {
238 using type = std::move_only_function<void(
const DataType&)
const>;
242struct event_handler_traits<void> {
243 using type = std::move_only_function<void() const>;
256template<typename DataType>
268template<typename IdEnum>
309#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
360 size_t stack_size = 2048;
367 std::optional<core_id> core_affinity = std::nullopt;
370#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
400#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
427 template<
typename IdEnum,
typename DataType>
444 template<
typename IdEnum>
460 template<
typename IdEnum,
typename DataType>
476 template<
typename IdEnum>
484#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
507#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
521 template<
typename IdEnum>
538 template<
typename IdEnum,
typename Rep,
typename Period>
558 template<
typename IdEnum,
typename DataType>
561 unwrap(try_post(evt, data));
578 template<
typename IdEnum,
typename DataType,
typename Rep,
typename Period>
592 template<
typename IdEnum>
594 return _post(event_base_lookup<IdEnum>().idf_base(),
static_cast<int32_t
>(evt.
id),
nullptr, 0, portMAX_DELAY);
607 template<
typename IdEnum,
typename Rep,
typename Period>
610 event_base_lookup<IdEnum>().idf_base(),
static_cast<int32_t
>(evt.
id),
nullptr, 0, chrono::ticks(
timeout)
625 template<
typename IdEnum,
typename DataType>
629 event_base_lookup<IdEnum>().idf_base(),
static_cast<int32_t
>(evt.
id), &data,
sizeof(data), portMAX_DELAY
647 template<
typename IdEnum,
typename DataType,
typename Rep,
typename Period>
652 event_base_lookup<IdEnum>().idf_base(),
653 static_cast<int32_t
>(evt.
id),
664 [[nodiscard]] esp_event_loop_handle_t
idf_handle()
const {
return _handle; }
685 explicit event_loop(esp_event_loop_handle_t handle,
bool system =
false)
691 esp_event_loop_handle_t loop,
692 esp_event_base_t base,
694 std::move_only_function<
void(esp_event_base_t, int32_t,
void*)
const> callback
697 template<
typename IdEnum>
699 esp_event_loop_handle_t loop,
700 esp_event_base_t base,
706 esp_event_loop_handle_t loop,
707 esp_event_handler_instance_t instance,
708 esp_event_base_t base,
712 void _delete() noexcept;
713 result<
void> _post(esp_event_base_t base, int32_t
id, const
void* data,
size_t size, TickType_t ticks);
715 esp_event_loop_handle_t _handle =
nullptr;
716 bool _system = false;
739 esp_event_loop_handle_t loop,
740 esp_event_handler_instance_t instance,
741 esp_event_base_t base,
745 , _instance(instance)
749 esp_event_loop_handle_t _loop =
nullptr;
750 esp_event_handler_instance_t _instance =
nullptr;
751 esp_event_base_t _base =
nullptr;
785 if (
this != &other) {
819 [[nodiscard]] explicit operator
bool() const noexcept {
return _handle._instance !=
nullptr; }
850#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
874#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
890 template<
typename Rep,
typename Period>
891 void run(
const std::chrono::duration<Rep, Period>& duration) {
892 unwrap(try_run(duration));
906 template<
typename Rep,
typename Period>
908 if (idf_handle() ==
nullptr) {
909 return error(errc::invalid_state);
911 return wrap(esp_event_loop_run(idf_handle(), chrono::ticks(duration)));
930#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
931template<
typename IdEnum,
typename DataType>
933 return unwrap(try_listener_add(
event, std::move(callback)));
936template<
typename IdEnum>
939 return unwrap(try_listener_add(
base, std::move(callback)));
943 unwrap(try_listener_remove(handle));
947template<
typename IdEnum>
949 esp_event_loop_handle_t loop,
950 esp_event_base_t base,
954 return register_listener(loop, base,
id, [cb = std::move(callback)](esp_event_base_t b, int32_t i,
void* data) {
959template<
typename IdEnum,
typename DataType>
960result<event_loop::listener_handle>
962 if (!_system && _handle ==
nullptr) {
963 return error(errc::invalid_state);
965 if constexpr (std::is_void_v<DataType>) {
966 return register_listener(
968 event_base_lookup<IdEnum>().idf_base(),
969 static_cast<int32_t
>(
event.
id),
970 [cb = std::move(callback)](esp_event_base_t, int32_t,
void*) { cb(); }
973 return register_listener(
975 event_base_lookup<IdEnum>().idf_base(),
976 static_cast<int32_t
>(
event.
id),
977 [cb = std::move(callback)](esp_event_base_t, int32_t,
void* data) { cb(from_opaque_data<DataType>(data)); }
982template<
typename IdEnum>
985 if (!_system && _handle ==
nullptr) {
986 return error(errc::invalid_state);
988 return register_listener<IdEnum>(_handle,
base.idf_base(), ESP_EVENT_ANY_ID, std::move(callback));
Typed event base template.
constexpr esp_event_base_t idf_base() const noexcept
Returns the underlying ESP-IDF event base.
constexpr event_base(esp_event_base_t base) noexcept
Constructs from an ESP-IDF event base pointer.
IdEnum id_type
The enum type for event IDs.
Handle to a registered event listener.
listener_handle()=default
Default constructor creates an invalid handle.
RAII handle for event listener registration.
unique_listener_handle() noexcept=default
Constructs an empty handle.
unique_listener_handle & operator=(unique_listener_handle &&other) noexcept
Move assignment.
listener_handle release() noexcept
Releases ownership without removing the listener.
unique_listener_handle(const unique_listener_handle &)=delete
~unique_listener_handle()
Destructor.
unique_listener_handle & operator=(const unique_listener_handle &)=delete
unique_listener_handle(unique_listener_handle &&other) noexcept
Move constructor.
void reset() noexcept
Removes the listener and resets to empty.
Base class for event loops.
void post(event< IdEnum > evt)
Posts an event without data, waiting indefinitely.
static result< event_loop > make(task_config task, size_t queue_size=32)
Creates an event loop with a dedicated dispatch task.
result< void > try_listener_remove(listener_handle handle)
Removes a listener by handle.
event_loop(task_config task, size_t queue_size=32)
Creates an event loop with a dedicated dispatch task.
void post(event< IdEnum, DataType > evt, const DataType &data, const std::chrono::duration< Rep, Period > &timeout)
Posts an event with data, with a timeout.
result< void > try_post(event< IdEnum, DataType > evt, const DataType &data, const std::chrono::duration< Rep, Period > &timeout)
Posts an event with data, with a timeout.
static void destroy_system()
Destroys the system (default) event loop.
result< void > try_post(event< IdEnum > evt)
Posts an event without data, waiting indefinitely.
esp_event_loop_handle_t idf_handle() const
Returns the underlying ESP-IDF event loop handle.
static void create_system()
Creates the system (default) event loop.
event_loop & operator=(const event_loop &)=delete
event_loop(event_loop &&other) noexcept
Move constructor.
static event_loop & system()
Returns a reference to the system (default) event loop.
static result< void > try_destroy_system()
Destroys the system (default) event loop.
static result< void > try_create_system()
Creates the system (default) event loop.
event_loop(const event_loop &)=delete
result< void > try_post(event< IdEnum > evt, const std::chrono::duration< Rep, Period > &timeout)
Posts an event without data, with a timeout.
void post(event< IdEnum, DataType > evt, const DataType &data)
Posts an event with data, waiting indefinitely.
result< void > try_post(event< IdEnum, DataType > evt, const DataType &data)
Posts an event with data, waiting indefinitely.
event_loop & operator=(event_loop &&other) noexcept
Move assignment.
event_loop(esp_event_loop_handle_t handle, bool system=false)
Constructs an event_loop with the given handle.
void post(event< IdEnum > evt, const std::chrono::duration< Rep, Period > &timeout)
Posts an event without data, with a timeout.
Type-safe wrapper for FreeRTOS task priority values.
Task lifecycle management.
User-created event loop with manual dispatch.
result< void > try_run(const std::chrono::duration< Rep, Period > &duration)
Dispatches pending events.
user_event_loop & operator=(const user_event_loop &)=delete
static result< user_event_loop > make(size_t queue_size=32)
Creates a user event loop without a dedicated task.
user_event_loop(size_t queue_size)
Creates a user event loop without a dedicated task.
user_event_loop(user_event_loop &&) noexcept=default
user_event_loop(const user_event_loop &)=delete
void run(const std::chrono::duration< Rep, Period > &duration)
Dispatches pending events.
Concept for types that can be both received and posted as event data.
Concept for types that can be received as event data.
std::move_only_function< void(event_base< IdEnum > base, IdEnum id, void *event_data) const > opaque_event_handler
Callback type for wildcard event listeners.
typename event_handler_traits< DataType >::type event_handler
Handler type for typed event listeners.
@ base
Base (factory) MAC address.
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< void > wrap(esp_err_t e)
Wraps an esp_err_t into a result<void>.
Configuration for a dedicated event dispatch task.
std::string_view name
Name of the task.
A typed event that pairs an event ID with its data type.