ESP Event: multiple registrations to one event

* It's possible now to register the same handler
  several times to one specific event, using
  a dynamic handle object.
This commit is contained in:
Jakob Hasse 2020-01-17 12:37:41 +08:00
parent 7f4309d0f1
commit 9b4815e3c8
9 changed files with 1397 additions and 249 deletions

View file

@ -33,6 +33,24 @@ esp_err_t esp_event_handler_register(esp_event_base_t event_base, int32_t event_
event_handler, event_handler_arg);
}
esp_err_t esp_event_handler_instance_register(esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_t event_handler,
void *event_handler_arg,
esp_event_handler_instance_t *context)
{
if (s_default_loop == NULL) {
return ESP_ERR_INVALID_STATE;
}
return esp_event_handler_instance_register_with(s_default_loop,
event_base,
event_id,
event_handler,
event_handler_arg,
context);
}
esp_err_t esp_event_handler_unregister(esp_event_base_t event_base, int32_t event_id,
esp_event_handler_t event_handler)
{
@ -44,6 +62,17 @@ esp_err_t esp_event_handler_unregister(esp_event_base_t event_base, int32_t even
event_handler);
}
esp_err_t esp_event_handler_instance_unregister(esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_instance_t context)
{
if (s_default_loop == NULL) {
return ESP_ERR_INVALID_STATE;
}
return esp_event_handler_instance_unregister_with(s_default_loop, event_base, event_id, context);
}
esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id,
void* event_data, size_t event_data_size, TickType_t ticks_to_wait)
{

View file

@ -66,7 +66,7 @@ static int esp_event_dump_prepare(void)
esp_event_loop_node_t *loop_node_it;
esp_event_base_node_t* base_node_it;
esp_event_id_node_t* id_node_it;
esp_event_handler_instance_t* handler_it;
esp_event_handler_node_t* handler_it;
// Count the number of items to be printed. This is needed to compute how much memory to reserve.
int loops = 0, handlers = 0;
@ -122,9 +122,9 @@ static void esp_event_loop_run_task(void* args)
vTaskSuspend(NULL);
}
static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_instance_t *handler, esp_event_post_instance_t post)
static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_node_t *handler, esp_event_post_instance_t post)
{
ESP_LOGD(TAG, "running post %s:%d with handler %p on loop %p", post.base, post.id, handler->handler, loop);
ESP_LOGD(TAG, "running post %s:%d with handler %p and context %p on loop %p", post.base, post.id, handler->handler_ctx->handler, &handler->handler_ctx, loop);
#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
int64_t start, diff;
@ -142,9 +142,9 @@ static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_i
}
}
(*(handler->handler))(handler->arg, post.base, post.id, data_ptr);
(*(handler->handler_ctx->handler))(handler->handler_ctx->arg, post.base, post.id, data_ptr);
#else
(*(handler->handler))(handler->arg, post.base, post.id, post.data);
(*(handler->handler_ctx->handler))(handler->handler_ctx->arg, post.base, post.id, post.data);
#endif
#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
@ -159,29 +159,38 @@ static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_i
#endif
}
static esp_err_t handler_instances_add(esp_event_handler_instances_t* handlers, esp_event_handler_t handler, void* handler_arg)
static esp_err_t handler_instances_add(esp_event_handler_nodes_t* handlers, esp_event_handler_t event_handler, void* event_handler_arg, esp_event_handler_instance_context_t **handler_ctx, bool legacy)
{
esp_event_handler_instance_t* handler_instance = calloc(1, sizeof(*handler_instance));
esp_event_handler_node_t *handler_instance = calloc(1, sizeof(*handler_instance));
if (!handler_instance) {
if (!handler_instance) return ESP_ERR_NO_MEM;
esp_event_handler_instance_context_t *context = calloc(1, sizeof(*context));
if (!context) {
free(handler_instance);
return ESP_ERR_NO_MEM;
}
handler_instance->handler = handler;
handler_instance->arg = handler_arg;
context->handler = event_handler;
context->arg = event_handler_arg;
handler_instance->handler_ctx = context;
if (SLIST_EMPTY(handlers)) {
SLIST_INSERT_HEAD(handlers, handler_instance, next);
}
else {
esp_event_handler_instance_t *it = NULL, *last = NULL;
esp_event_handler_node_t *it = NULL, *last = NULL;
SLIST_FOREACH(it, handlers, next) {
if (handler == it->handler) {
it->arg = handler_arg;
ESP_LOGW(TAG, "handler already registered, overwriting");
free(handler_instance);
return ESP_OK;
if (legacy) {
if(event_handler == it->handler_ctx->handler) {
it->handler_ctx->arg = event_handler_arg;
ESP_LOGW(TAG, "handler already registered, overwriting");
free(handler_instance);
free(context);
return ESP_OK;
}
}
last = it;
}
@ -189,13 +198,24 @@ static esp_err_t handler_instances_add(esp_event_handler_instances_t* handlers,
SLIST_INSERT_AFTER(last, handler_instance, next);
}
// If the caller didn't provide the handler instance context, don't set it.
// It will be removed once the event loop is deleted.
if (handler_ctx) {
*handler_ctx = context;
}
return ESP_OK;
}
static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node, int32_t id, esp_event_handler_t handler, void* handler_arg)
static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node,
int32_t id,
esp_event_handler_t event_handler,
void *event_handler_arg,
esp_event_handler_instance_context_t **handler_ctx,
bool legacy)
{
if (id == ESP_EVENT_ANY_ID) {
return handler_instances_add(&(base_node->handlers), handler, handler_arg);
return handler_instances_add(&(base_node->handlers), event_handler, event_handler_arg, handler_ctx, legacy);
}
else {
esp_err_t err = ESP_OK;
@ -220,7 +240,7 @@ static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node, int32_t
SLIST_INIT(&(id_node->handlers));
err = handler_instances_add(&(id_node->handlers), handler, handler_arg);
err = handler_instances_add(&(id_node->handlers), event_handler, event_handler_arg, handler_ctx, legacy);
if (err == ESP_OK) {
if (!last_id_node) {
@ -236,15 +256,21 @@ static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node, int32_t
return err;
}
else {
return handler_instances_add(&(id_node->handlers), handler, handler_arg);
return handler_instances_add(&(id_node->handlers), event_handler, event_handler_arg, handler_ctx, legacy);
}
}
}
static esp_err_t loop_node_add_handler(esp_event_loop_node_t* loop_node, esp_event_base_t base, int32_t id, esp_event_handler_t handler, void* handler_arg)
static esp_err_t loop_node_add_handler(esp_event_loop_node_t* loop_node,
esp_event_base_t base,
int32_t id,
esp_event_handler_t event_handler,
void *event_handler_arg,
esp_event_handler_instance_context_t **handler_ctx,
bool legacy)
{
if (base == esp_event_any_base && id == ESP_EVENT_ANY_ID) {
return handler_instances_add(&(loop_node->handlers), handler, handler_arg);
return handler_instances_add(&(loop_node->handlers), event_handler, event_handler_arg, handler_ctx, legacy);
}
else {
esp_err_t err = ESP_OK;
@ -273,7 +299,7 @@ static esp_err_t loop_node_add_handler(esp_event_loop_node_t* loop_node, esp_eve
SLIST_INIT(&(base_node->handlers));
SLIST_INIT(&(base_node->id_nodes));
err = base_node_add_handler(base_node, id, handler, handler_arg);
err = base_node_add_handler(base_node, id, event_handler, event_handler_arg, handler_ctx, legacy);
if (err == ESP_OK) {
if (!last_base_node) {
@ -288,20 +314,30 @@ static esp_err_t loop_node_add_handler(esp_event_loop_node_t* loop_node, esp_eve
return err;
} else {
return base_node_add_handler(base_node, id, handler, handler_arg);
return base_node_add_handler(base_node, id, event_handler, event_handler_arg, handler_ctx, legacy);
}
}
}
static esp_err_t handler_instances_remove(esp_event_handler_instances_t* handlers, esp_event_handler_t handler)
static esp_err_t handler_instances_remove(esp_event_handler_nodes_t* handlers, esp_event_handler_instance_context_t* handler_ctx, bool legacy)
{
esp_event_handler_instance_t *it, *temp;
esp_event_handler_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, handlers, next, temp) {
if (it->handler == handler) {
SLIST_REMOVE(handlers, it, esp_event_handler_instance, next);
free(it);
return ESP_OK;
if (legacy) {
if (it->handler_ctx->handler == handler_ctx->handler) {
SLIST_REMOVE(handlers, it, esp_event_handler_node, next);
free(it->handler_ctx);
free(it);
return ESP_OK;
}
} else {
if (it->handler_ctx == handler_ctx) {
SLIST_REMOVE(handlers, it, esp_event_handler_node, next);
free(it->handler_ctx);
free(it);
return ESP_OK;
}
}
}
@ -309,16 +345,16 @@ static esp_err_t handler_instances_remove(esp_event_handler_instances_t* handler
}
static esp_err_t base_node_remove_handler(esp_event_base_node_t* base_node, int32_t id, esp_event_handler_t handler)
static esp_err_t base_node_remove_handler(esp_event_base_node_t* base_node, int32_t id, esp_event_handler_instance_context_t* handler_ctx, bool legacy)
{
if (id == ESP_EVENT_ANY_ID) {
return handler_instances_remove(&(base_node->handlers), handler);
return handler_instances_remove(&(base_node->handlers), handler_ctx, legacy);
}
else {
esp_event_id_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, &(base_node->id_nodes), next, temp) {
if (it->id == id) {
esp_err_t res = handler_instances_remove(&(it->handlers), handler);
esp_err_t res = handler_instances_remove(&(it->handlers), handler_ctx, legacy);
if (res == ESP_OK) {
if (SLIST_EMPTY(&(it->handlers))) {
@ -334,16 +370,16 @@ static esp_err_t base_node_remove_handler(esp_event_base_node_t* base_node, int3
return ESP_ERR_NOT_FOUND;
}
static esp_err_t loop_node_remove_handler(esp_event_loop_node_t* loop_node, esp_event_base_t base, int32_t id, esp_event_handler_t handler)
static esp_err_t loop_node_remove_handler(esp_event_loop_node_t* loop_node, esp_event_base_t base, int32_t id, esp_event_handler_instance_context_t* handler_ctx, bool legacy)
{
if (base == esp_event_any_base && id == ESP_EVENT_ANY_ID) {
return handler_instances_remove(&(loop_node->handlers), handler);
return handler_instances_remove(&(loop_node->handlers), handler_ctx, legacy);
}
else {
esp_event_base_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, &(loop_node->base_nodes), next, temp) {
if (it->base == base) {
esp_err_t res = base_node_remove_handler(it, id, handler);
esp_err_t res = base_node_remove_handler(it, id, handler_ctx, legacy);
if (res == ESP_OK) {
if (SLIST_EMPTY(&(it->handlers)) && SLIST_EMPTY(&(it->id_nodes))) {
@ -359,11 +395,12 @@ static esp_err_t loop_node_remove_handler(esp_event_loop_node_t* loop_node, esp_
return ESP_ERR_NOT_FOUND;
}
static void handler_instances_remove_all(esp_event_handler_instances_t* handlers)
static void handler_instances_remove_all(esp_event_handler_nodes_t* handlers)
{
esp_event_handler_instance_t *it, *temp;
esp_event_handler_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, handlers, next, temp) {
SLIST_REMOVE(handlers, it, esp_event_handler_instance, next);
SLIST_REMOVE(handlers, it, esp_event_handler_node, next);
free(it->handler_ctx);
free(it);
}
}
@ -526,7 +563,7 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
bool exec = false;
esp_event_handler_instance_t *handler, *temp_handler;
esp_event_handler_node_t *handler, *temp_handler;
esp_event_loop_node_t *loop_node, *temp_node;
esp_event_base_node_t *base_node, *temp_base;
esp_event_id_node_t *id_node, *temp_id_node;
@ -645,8 +682,9 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop)
return ESP_OK;
}
esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg)
esp_err_t esp_event_handler_register_with_internal(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg,
esp_event_handler_instance_context_t** handler_ctx_arg, bool legacy)
{
assert(event_loop);
assert(event_handler);
@ -687,7 +725,7 @@ esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop, es
SLIST_INIT(&(loop_node->handlers));
SLIST_INIT(&(loop_node->base_nodes));
err = loop_node_add_handler(loop_node, event_base, event_id, event_handler, event_handler_arg);
err = loop_node_add_handler(loop_node, event_base, event_id, event_handler, event_handler_arg, handler_ctx_arg, legacy);
if (err == ESP_OK) {
if (!last_loop_node) {
@ -701,7 +739,7 @@ esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop, es
}
}
else {
err = loop_node_add_handler(last_loop_node, event_base, event_id, event_handler, event_handler_arg);
err = loop_node_add_handler(last_loop_node, event_base, event_id, event_handler, event_handler_arg, handler_ctx_arg, legacy);
}
on_err:
@ -709,11 +747,24 @@ on_err:
return err;
}
esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
int32_t event_id, esp_event_handler_t event_handler)
esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg)
{
return esp_event_handler_register_with_internal(event_loop, event_base, event_id, event_handler, event_handler_arg, NULL, true);
}
esp_err_t esp_event_handler_instance_register_with(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg,
esp_event_handler_instance_t* handler_ctx_arg)
{
return esp_event_handler_register_with_internal(event_loop, event_base, event_id, event_handler, event_handler_arg, (esp_event_handler_instance_context_t**) handler_ctx_arg, false);
}
esp_err_t esp_event_handler_unregister_with_internal(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
int32_t event_id, esp_event_handler_instance_context_t* handler_ctx, bool legacy)
{
assert(event_loop);
assert(event_handler);
assert(handler_ctx);
if (event_base == ESP_EVENT_ANY_BASE && event_id != ESP_EVENT_ANY_ID) {
ESP_LOGE(TAG, "unregistering to any event base with specific id unsupported");
@ -731,7 +782,7 @@ esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
esp_event_loop_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, &(loop->loop_nodes), next, temp) {
esp_err_t res = loop_node_remove_handler(it, event_base, event_id, event_handler);
esp_err_t res = loop_node_remove_handler(it, event_base, event_id, handler_ctx, legacy);
if (res == ESP_OK && SLIST_EMPTY(&(it->base_nodes)) && SLIST_EMPTY(&(it->handlers))) {
SLIST_REMOVE(&(loop->loop_nodes), it, esp_event_loop_node, next);
@ -745,6 +796,24 @@ esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
return ESP_OK;
}
esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
int32_t event_id, esp_event_handler_t event_handler)
{
esp_event_handler_instance_context_t local_handler_ctx;
local_handler_ctx.handler = event_handler;
local_handler_ctx.arg = NULL;
return esp_event_handler_unregister_with_internal(event_loop, event_base, event_id, &local_handler_ctx, true);
}
esp_err_t esp_event_handler_instance_unregister_with(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
int32_t event_id, esp_event_handler_instance_t handler_ctx_arg)
{
if (!handler_ctx_arg) return ESP_ERR_INVALID_ARG;
return esp_event_handler_unregister_with_internal(event_loop, event_base, event_id, (esp_event_handler_instance_context_t*) handler_ctx_arg, false);
}
esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop, esp_event_base_t event_base, int32_t event_id,
void* event_data, size_t event_data_size, TickType_t ticks_to_wait)
{
@ -879,7 +948,7 @@ esp_err_t esp_event_dump(FILE* file)
esp_event_loop_node_t *loop_node_it;
esp_event_base_node_t* base_node_it;
esp_event_id_node_t* id_node_it;
esp_event_handler_instance_t* handler_it;
esp_event_handler_node_t* handler_it;
// Allocate memory for printing
int sz = esp_event_dump_prepare();
@ -904,13 +973,13 @@ esp_err_t esp_event_dump(FILE* file)
SLIST_FOREACH(loop_node_it, &(loop_it->loop_nodes), next) {
SLIST_FOREACH(handler_it, &(loop_node_it->handlers), next) {
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler, "ESP_EVENT_ANY_BASE",
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler_ctx->handler, "ESP_EVENT_ANY_BASE",
"ESP_EVENT_ANY_ID", handler_it->invoked, handler_it->time);
}
SLIST_FOREACH(base_node_it, &(loop_node_it->base_nodes), next) {
SLIST_FOREACH(handler_it, &(base_node_it->handlers), next) {
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler, base_node_it->base ,
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler_ctx->handler, base_node_it->base ,
"ESP_EVENT_ANY_ID", handler_it->invoked, handler_it->time);
}
@ -919,7 +988,7 @@ esp_err_t esp_event_dump(FILE* file)
memset(id_str_buf, 0, sizeof(id_str_buf));
snprintf(id_str_buf, sizeof(id_str_buf), "%d", id_node_it->id);
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler, base_node_it->base ,
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler_ctx->handler, base_node_it->base ,
id_str_buf, handler_it->invoked, handler_it->time);
}
}

View file

@ -26,11 +26,11 @@ bool esp_event_is_handler_registered(esp_event_loop_handle_t event_loop, esp_eve
esp_event_loop_node_t* loop_node;
esp_event_base_node_t* base_node;
esp_event_id_node_t* id_node;
esp_event_handler_instance_t* handler;
esp_event_handler_node_t* handler;
SLIST_FOREACH(loop_node, &(loop->loop_nodes), next) {
SLIST_FOREACH(handler, &(loop_node->handlers), next) {
if(event_base == ESP_EVENT_ANY_BASE && event_id == ESP_EVENT_ANY_ID && handler->handler == event_handler)
if(event_base == ESP_EVENT_ANY_BASE && event_id == ESP_EVENT_ANY_ID && handler->handler_ctx->handler == event_handler)
{
result = true;
goto out;
@ -40,7 +40,7 @@ bool esp_event_is_handler_registered(esp_event_loop_handle_t event_loop, esp_eve
SLIST_FOREACH(base_node, &(loop_node->base_nodes), next) {
if (base_node->base == event_base) {
SLIST_FOREACH(handler, &(base_node->handlers), next) {
if(event_id == ESP_EVENT_ANY_ID && handler->handler == event_handler)
if(event_id == ESP_EVENT_ANY_ID && handler->handler_ctx->handler == event_handler)
{
result = true;
goto out;
@ -50,12 +50,12 @@ bool esp_event_is_handler_registered(esp_event_loop_handle_t event_loop, esp_eve
SLIST_FOREACH(id_node, &(base_node->id_nodes), next) {
if(id_node->id == event_id) {
SLIST_FOREACH(handler, &(id_node->handlers), next) {
if(handler->handler == event_handler)
if(handler->handler_ctx->handler == event_handler)
{
result = true;
goto out;
}
}
}
}
}
}
@ -65,4 +65,4 @@ bool esp_event_is_handler_registered(esp_event_loop_handle_t event_loop, esp_eve
out:
xSemaphoreGive(loop->mutex);
return result;
}
}

View file

@ -32,7 +32,7 @@ extern "C" {
/// Configuration for creating event loops
typedef struct {
int32_t queue_size; /**< size of the event loop queue */
const char* task_name; /**< name of the event loop task; if NULL,
const char *task_name; /**< name of the event loop task; if NULL,
a dedicated task is not created for event loop*/
UBaseType_t task_priority; /**< priority of the event loop task, ignored if task name is NULL */
uint32_t task_stack_size; /**< stack size of the event loop task, ignored if task name is NULL */
@ -52,7 +52,7 @@ typedef struct {
* - ESP_FAIL: Failed to create task loop
* - Others: Fail
*/
esp_err_t esp_event_loop_create(const esp_event_loop_args_t* event_loop_args, esp_event_loop_handle_t* event_loop);
esp_err_t esp_event_loop_create(const esp_event_loop_args_t *event_loop_args, esp_event_loop_handle_t *event_loop);
/**
* @brief Delete an existing event loop.
@ -114,7 +114,10 @@ esp_err_t esp_event_loop_delete_default(void);
esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t ticks_to_run);
/**
* @brief Register an event handler to the system event loop.
* @brief Register an event handler to the system event loop (legacy).
*
* @note This function is obsolete and will be deprecated soon, please use esp_event_handler_instance_register()
* instead.
*
* This function can be used to register a handler for either: (1) specific events,
* (2) all events of a certain event base, or (3) all events known by the system event loop.
@ -142,12 +145,15 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
* - Others: Fail
*/
esp_err_t esp_event_handler_register(esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_t event_handler,
void* event_handler_arg);
int32_t event_id,
esp_event_handler_t event_handler,
void *event_handler_arg);
/**
* @brief Register an event handler to a specific loop.
* @brief Register an event handler to a specific loop (legacy).
*
* @note This function is obsolete and will be deprecated soon, please use esp_event_handler_instance_register_with()
* instead.
*
* This function behaves in the same manner as esp_event_handler_register, except the additional
* specification of the event loop to register the handler to.
@ -168,13 +174,94 @@ esp_err_t esp_event_handler_register(esp_event_base_t event_base,
* - Others: Fail
*/
esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop,
esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_t event_handler,
void* event_handler_arg);
esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_t event_handler,
void *event_handler_arg);
/**
* @brief Unregister a handler with the system event loop.
* @brief Register an instance of event handler to a specific loop.
*
* This function can be used to register a handler for either: (1) specific events,
* (2) all events of a certain event base, or (3) all events known by the system event loop.
*
* - specific events: specify exact event_base and event_id
* - all events of a certain base: specify exact event_base and use ESP_EVENT_ANY_ID as the event_id
* - all events known by the loop: use ESP_EVENT_ANY_BASE for event_base and ESP_EVENT_ANY_ID as the event_id
*
* Besides the error, the function returns an instance object as output parameter to identify each registration.
* This is necessary to remove (unregister) the registration before the event loop is deleted.
*
* Registering multiple handlers to events, registering a single handler to multiple events as well as registering
* the same handler to the same event multiple times is possible.
* Each registration yields a distinct instance object which identifies it over the registration
* lifetime.
*
* @param[in] event_loop the event loop to register this handler function to
* @param[in] event_base the base id of the event to register the handler for
* @param[in] event_id the id of the event to register the handler for
* @param[in] event_handler the handler function which gets called when the event is dispatched
* @param[in] event_handler_arg data, aside from event data, that is passed to the handler when it is called
* @param[out] instance An event handler instance object related to the registered event handler and data, can be NULL.
* This needs to be kept if the specific callback instance should be unregistered before deleting the whole
* event loop. Registering the same event handler multiple times is possible and yields distinct instance
* objects. The data can be the same for all registrations.
* If no unregistration is needed but the handler should be deleted when the event loop is deleted,
* instance can be NULL.
*
* @note the event loop library does not maintain a copy of event_handler_arg, therefore the user should
* ensure that event_handler_arg still points to a valid location by the time the handler gets called
*
* @return
* - ESP_OK: Success
* - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id or instance is NULL
* - Others: Fail
*/
esp_err_t esp_event_handler_instance_register_with(esp_event_loop_handle_t event_loop,
esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_t event_handler,
void *event_handler_arg,
esp_event_handler_instance_t *instance);
/**
* @brief Register an instance of event handler to the default loop.
*
* This function does the same as esp_event_handler_instance_register_with, except that it registers the
* handler to the default event loop.
*
* @param[in] event_base the base id of the event to register the handler for
* @param[in] event_id the id of the event to register the handler for
* @param[in] event_handler the handler function which gets called when the event is dispatched
* @param[in] event_handler_arg data, aside from event data, that is passed to the handler when it is called
* @param[out] instance An event handler instance object related to the registered event handler and data, can be NULL.
* This needs to be kept if the specific callback instance should be unregistered before deleting the whole
* event loop. Registering the same event handler multiple times is possible and yields distinct instance
* objects. The data can be the same for all registrations.
* If no unregistration is needed but the handler should be deleted when the event loop is deleted,
* instance can be NULL.
*
* @note the event loop library does not maintain a copy of event_handler_arg, therefore the user should
* ensure that event_handler_arg still points to a valid location by the time the handler gets called
*
* @return
* - ESP_OK: Success
* - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id or instance is NULL
* - Others: Fail
*/
esp_err_t esp_event_handler_instance_register(esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_t event_handler,
void *event_handler_arg,
esp_event_handler_instance_t *instance);
/**
* @brief Unregister a handler with the system event loop (legacy).
*
* @note This function is obsolete and will be deprecated soon, please use esp_event_handler_instance_unregister()
* instead.
*
* This function can be used to unregister a handler so that it no longer gets called during dispatch.
* Handlers can be unregistered for either: (1) specific events, (2) all events of a certain event base,
@ -194,10 +281,15 @@ esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop,
* @return ESP_ERR_INVALID_ARG invalid combination of event base and event id
* @return others fail
*/
esp_err_t esp_event_handler_unregister(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler);
esp_err_t esp_event_handler_unregister(esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_t event_handler);
/**
* @brief Unregister a handler with the system event loop.
* @brief Unregister a handler from a specific event loop (legacy).
*
* @note This function is obsolete and will be deprecated soon, please use esp_event_handler_instance_unregister_with()
* instead.
*
* This function behaves in the same manner as esp_event_handler_unregister, except the additional specification of
* the event loop to unregister the handler with.
@ -217,6 +309,53 @@ esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
int32_t event_id,
esp_event_handler_t event_handler);
/**
* @brief Unregister a handler instance from a specific event loop.
*
* This function can be used to unregister a handler so that it no longer gets called during dispatch.
* Handlers can be unregistered for either: (1) specific events, (2) all events of a certain event base,
* or (3) all events known by the system event loop
*
* - specific events: specify exact event_base and event_id
* - all events of a certain base: specify exact event_base and use ESP_EVENT_ANY_ID as the event_id
* - all events known by the loop: use ESP_EVENT_ANY_BASE for event_base and ESP_EVENT_ANY_ID as the event_id
*
* This function ignores unregistration of handler instances that have not been previously registered.
*
* @param[in] event_loop the event loop with which to unregister this handler function
* @param[in] event_base the base of the event with which to unregister the handler
* @param[in] event_id the id of the event with which to unregister the handler
* @param[in] instance the instance object of the registration to be unregistered
*
* @return
* - ESP_OK: Success
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
* - Others: Fail
*/
esp_err_t esp_event_handler_instance_unregister_with(esp_event_loop_handle_t event_loop,
esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_instance_t instance);
/**
* @brief Unregister a handler from the system event loop.
*
* This function does the same as esp_event_handler_instance_unregister_with, except that it unregisters the
* handler instance from the default event loop.
*
* @param[in] event_base the base of the event with which to unregister the handler
* @param[in] event_id the id of the event with which to unregister the handler
* @param[in] instance the instance object of the registration to be unregistered
*
* @return
* - ESP_OK: Success
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
* - Others: Fail
*/
esp_err_t esp_event_handler_instance_unregister(esp_event_base_t event_base,
int32_t event_id,
esp_event_handler_instance_t instance);
/**
* @brief Posts an event to the system default event loop. The event loop library keeps a copy of event_data and manages
* the copy's lifetime automatically (allocation + deletion); this ensures that the data the
@ -230,16 +369,16 @@ esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
*
* @return
* - ESP_OK: Success
* - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired,
* - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired,
* queue full when posting from ISR
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
* - Others: Fail
*/
esp_err_t esp_event_post(esp_event_base_t event_base,
int32_t event_id,
void* event_data,
size_t event_data_size,
TickType_t ticks_to_wait);
int32_t event_id,
void *event_data,
size_t event_data_size,
TickType_t ticks_to_wait);
/**
* @brief Posts an event to the specified event loop. The event loop library keeps a copy of event_data and manages
@ -258,7 +397,7 @@ esp_err_t esp_event_post(esp_event_base_t event_base,
*
* @return
* - ESP_OK: Success
* - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired,
* - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired,
* queue full when posting from ISR
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
* - Others: Fail
@ -266,19 +405,19 @@ esp_err_t esp_event_post(esp_event_base_t event_base,
esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop,
esp_event_base_t event_base,
int32_t event_id,
void* event_data,
void *event_data,
size_t event_data_size,
TickType_t ticks_to_wait);
#if CONFIG_ESP_EVENT_POST_FROM_ISR
/**
* @brief Special variant of esp_event_post for posting events from interrupt handlers.
*
*
* @param[in] event_base the event base that identifies the event
* @param[in] event_id the event id that identifies the event
* @param[in] event_data the data, specific to the event occurence, that gets passed to the handler
* @param[in] event_data_size the size of the event data; max is 4 bytes
* @param[out] task_unblocked an optional parameter (can be NULL) which indicates that an event task with
* @param[out] task_unblocked an optional parameter (can be NULL) which indicates that an event task with
* higher priority than currently running task has been unblocked by the posted event;
* a context switch should be requested before the interrupt is existed.
*
@ -290,14 +429,14 @@ esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop,
* - ESP_OK: Success
* - ESP_FAIL: Event queue for the default event loop full
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id,
* data size of more than 4 bytes
* data size of more than 4 bytes
* - Others: Fail
*/
esp_err_t esp_event_isr_post(esp_event_base_t event_base,
int32_t event_id,
void* event_data,
size_t event_data_size,
BaseType_t* task_unblocked);
int32_t event_id,
void *event_data,
size_t event_data_size,
BaseType_t *task_unblocked);
/**
* @brief Special variant of esp_event_post_to for posting events from interrupt handlers
@ -307,7 +446,7 @@ esp_err_t esp_event_isr_post(esp_event_base_t event_base,
* @param[in] event_id the event id that identifies the event
* @param[in] event_data the data, specific to the event occurence, that gets passed to the handler
* @param[in] event_data_size the size of the event data
* @param[out] task_unblocked an optional parameter (can be NULL) which indicates that an event task with
* @param[out] task_unblocked an optional parameter (can be NULL) which indicates that an event task with
* higher priority than currently running task has been unblocked by the posted event;
* a context switch should be requested before the interrupt is existed.
*
@ -319,15 +458,15 @@ esp_err_t esp_event_isr_post(esp_event_base_t event_base,
* - ESP_OK: Success
* - ESP_FAIL: Event queue for the loop full
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id,
* data size of more than 4 bytes
* data size of more than 4 bytes
* - Others: Fail
*/
esp_err_t esp_event_isr_post_to(esp_event_loop_handle_t event_loop,
esp_event_base_t event_base,
int32_t event_id,
void* event_data,
size_t event_data_size,
BaseType_t* task_unblocked);
esp_event_base_t event_base,
int32_t event_id,
void *event_data,
size_t event_data_size,
BaseType_t *task_unblocked);
#endif
/**
@ -374,7 +513,7 @@ esp_err_t esp_event_isr_post_to(esp_event_loop_handle_t event_loop,
* - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
* - Others: Fail
*/
esp_err_t esp_event_dump(FILE* file);
esp_err_t esp_event_dump(FILE *file);
#ifdef __cplusplus
} // extern "C"

View file

@ -26,11 +26,11 @@ extern "C" {
// Event loop library types
typedef const char* esp_event_base_t; /**< unique pointer to a subsystem that exposes events */
typedef void* esp_event_loop_handle_t; /**< a number that identifies an event with respect to a base */
typedef void (*esp_event_handler_t)(void* event_handler_arg,
esp_event_base_t event_base,
int32_t event_id,
typedef void (*esp_event_handler_t)(void* event_handler_arg,
esp_event_base_t event_base,
int32_t event_id,
void* event_data); /**< function called when an event is posted to the queue */
typedef void* esp_event_handler_instance_t; /**< context identifying an instance of a registered event handler */
// Defines for registering/unregistering event handlers
#define ESP_EVENT_ANY_BASE NULL /**< register handler for any event base */

View file

@ -24,23 +24,27 @@ extern "C" {
typedef SLIST_HEAD(base_nodes, base_node) base_nodes_t;
/// Event handler
typedef struct esp_event_handler_instance {
typedef struct esp_event_handler_context {
esp_event_handler_t handler; /**< event handler function*/
void* arg; /**< event handler argument */
void* arg;
} esp_event_handler_instance_context_t; /**< event handler argument */
/// Event handler
typedef struct esp_event_handler_node {
esp_event_handler_instance_context_t* handler_ctx; /**< event handler context*/
#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
uint32_t invoked; /**< number of times this handler has been invoked */
int64_t time; /**< total runtime of this handler across all calls */
#endif
SLIST_ENTRY(esp_event_handler_instance) next; /**< next event handler in the list */
} esp_event_handler_instance_t;
SLIST_ENTRY(esp_event_handler_node) next; /**< next event handler in the list */
} esp_event_handler_node_t;
typedef SLIST_HEAD(esp_event_handler_instances, esp_event_handler_instance) esp_event_handler_instances_t;
typedef SLIST_HEAD(esp_event_handler_instances, esp_event_handler_node) esp_event_handler_nodes_t;
/// Event
typedef struct esp_event_id_node {
int32_t id; /**< id number of the event */
esp_event_handler_instances_t handlers; /**< list of handlers to be executed when
esp_event_handler_nodes_t handlers; /**< list of handlers to be executed when
this event is raised */
SLIST_ENTRY(esp_event_id_node) next; /**< pointer to the next event node on the linked list */
} esp_event_id_node_t;
@ -49,7 +53,7 @@ typedef SLIST_HEAD(esp_event_id_nodes, esp_event_id_node) esp_event_id_nodes_t;
typedef struct esp_event_base_node {
esp_event_base_t base; /**< base identifier of the event */
esp_event_handler_instances_t handlers; /**< event base level handlers, handlers for
esp_event_handler_nodes_t handlers; /**< event base level handlers, handlers for
all events with this base */
esp_event_id_nodes_t id_nodes; /**< list of event ids with this base */
SLIST_ENTRY(esp_event_base_node) next; /**< pointer to the next base node on the linked list */
@ -58,7 +62,7 @@ typedef struct esp_event_base_node {
typedef SLIST_HEAD(esp_event_base_nodes, esp_event_base_node) esp_event_base_nodes_t;
typedef struct esp_event_loop_node {
esp_event_handler_instances_t handlers; /** event loop level handlers */
esp_event_handler_nodes_t handlers; /** event loop level handlers */
esp_event_base_nodes_t base_nodes; /** list of event bases registered to the loop */
SLIST_ENTRY(esp_event_loop_node) next; /** pointer to the next loop node containing
event loop level handlers and the rest of

View file

@ -0,0 +1,157 @@
#include <stdbool.h>
#include <string.h>
#include "esp_event.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/periph_ctrl.h"
#include "driver/timer.h"
#include "esp_event.h"
#include "esp_event_private.h"
#include "esp_event_internal.h"
#include "esp_heap_caps.h"
#include "sdkconfig.h"
#include "unity.h"
#include "test_utils.h"
typedef struct {
void* data;
SemaphoreHandle_t mutex;
} simple_arg_t;
static const char* TAG = "test_event";
ESP_EVENT_DECLARE_BASE(s_default_test_base1);
ESP_EVENT_DECLARE_BASE(s_default_test_base2);
ESP_EVENT_DEFINE_BASE(s_default_test_base1);
ESP_EVENT_DEFINE_BASE(s_default_test_base2);
enum {
TEST_EVENT_BASE1_EV1,
TEST_EVENT_BASE1_EV2,
TEST_EVENT_BASE1_MAX
};
enum {
TEST_EVENT_BASE2_EV1,
TEST_EVENT_BASE2_EV2,
TEST_EVENT_BASE2_MAX
};
// The initial logging "initializing test" is to ensure mutex allocation is not counted against memory not being freed
// during teardown.
#define TEST_SETUP() \
ESP_LOGI(TAG, "initializing test");
static void test_event_simple_handler(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
if (!event_handler_arg) {
return;
}
simple_arg_t* arg = (simple_arg_t*) event_handler_arg;
xSemaphoreTake(arg->mutex, portMAX_DELAY);
int* count = (int*) arg->data;
if (event_data == NULL) {
(*count)++;
} else {
(*count) += *((int*) event_data);
}
xSemaphoreGive(arg->mutex);
}
TEST_CASE("default loop: can create and delete loop", "[event]")
{
TEST_SETUP();
TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(esp_event_loop_delete_default());
}
TEST_CASE("default loop: registering fails on uninitialized default loop", "[event]")
{
TEST_SETUP();
esp_event_handler_instance_t instance;
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_event_handler_instance_register(s_default_test_base1,
TEST_EVENT_BASE1_EV1,
test_event_simple_handler,
NULL,
&instance));
}
TEST_CASE("default loop: registering/unregistering event works", "[event]")
{
TEST_SETUP();
int count = 0;
simple_arg_t arg = {
.data = &count,
.mutex = xSemaphoreCreateMutex()
};
TEST_ESP_OK(esp_event_loop_create_default());
esp_event_handler_instance_t instance;
TEST_ESP_OK(esp_event_handler_instance_register(s_default_test_base1,
TEST_EVENT_BASE1_EV1,
test_event_simple_handler,
&arg,
&instance));
TEST_ASSERT(instance);
TEST_ESP_OK(esp_event_post(s_default_test_base1, TEST_EVENT_BASE1_EV1, NULL, 0, portMAX_DELAY));
vTaskDelay(10);
TEST_ASSERT_EQUAL(1, count);
TEST_ESP_OK(esp_event_handler_instance_unregister(s_default_test_base1,
TEST_EVENT_BASE1_EV1,
&instance));
vTaskDelay(10);
TEST_ASSERT_EQUAL(1, count);
TEST_ESP_OK(esp_event_loop_delete_default());
vSemaphoreDelete(arg.mutex);
}
TEST_CASE("default event loop: registering event handler instance without instance context works", "[event]") {
TEST_SETUP();
int count_1 = 0;
simple_arg_t arg_1 = {
.data = &count_1,
.mutex = xSemaphoreCreateMutex()
};
TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(esp_event_handler_instance_register(ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, test_event_simple_handler, &arg_1, NULL));
TEST_ESP_OK(esp_event_post(s_default_test_base1, TEST_EVENT_BASE1_EV1, NULL, 0, portMAX_DELAY));
vTaskDelay(10);
TEST_ASSERT_EQUAL(1, count_1);
TEST_ESP_OK(esp_event_loop_delete_default());
vSemaphoreDelete(arg_1.mutex);
}

File diff suppressed because it is too large Load diff

View file

@ -345,7 +345,7 @@ UT_001:
UT_002:
extends: .unit_test_template
parallel: 10
parallel: 12
tags:
- ESP32_IDF
- UT_T1_1