1 /*
2  * SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ESP_EVENT_H_
8 #define ESP_EVENT_H_
9 
10 #include "esp_err.h"
11 
12 
13 #include "esp_event_base.h"
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /// Configuration for creating event loops
20 typedef struct {
21     int32_t queue_size;                         /**< size of the event loop queue */
22     const char *task_name;                      /**< name of the event loop task; if NULL,
23                                                         a dedicated task is not created for event loop*/
24     unsigned int task_priority;                  /**< priority of the event loop task, ignored if task name is NULL */
25     uint32_t task_stack_size;                   /**< stack size of the event loop task, ignored if task name is NULL */
26     int task_core_id;                    /**< core to which the event loop task is pinned to,
27                                                         ignored if task name is NULL */
28 } esp_event_loop_args_t;
29 
30 /**
31  * @brief Create a new event loop.
32  *
33  * @param[in] event_loop_args configuration structure for the event loop to create
34  * @param[out] event_loop handle to the created event loop
35  *
36  * @return
37  *  - ESP_OK: Success
38  *  - ESP_ERR_INVALID_ARG: event_loop_args or event_loop was NULL
39  *  - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
40  *  - ESP_FAIL: Failed to create task loop
41  *  - Others: Fail
42  */
43 esp_err_t esp_event_loop_create(const esp_event_loop_args_t *event_loop_args, esp_event_loop_handle_t *event_loop);
44 
45 /**
46  * @brief Delete an existing event loop.
47  *
48  * @param[in] event_loop event loop to delete, must not be NULL
49  *
50  * @return
51  *  - ESP_OK: Success
52  *  - Others: Fail
53  */
54 esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop);
55 
56 /**
57  * @brief Create default event loop
58  *
59  * @return
60  *  - ESP_OK: Success
61  *  - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
62  *  - ESP_ERR_INVALID_STATE: Default event loop has already been created
63  *  - ESP_FAIL: Failed to create task loop
64  *  - Others: Fail
65  */
66 esp_err_t esp_event_loop_create_default(void);
67 
68 /**
69  * @brief Delete the default event loop
70  *
71  * @return
72  *  - ESP_OK: Success
73  *  - Others: Fail
74  */
75 esp_err_t esp_event_loop_delete_default(void);
76 
77 /**
78  * @brief Dispatch events posted to an event loop.
79  *
80  * This function is used to dispatch events posted to a loop with no dedicated task, i.e. task name was set to NULL
81  * in event_loop_args argument during loop creation. This function includes an argument to limit the amount of time
82  * it runs, returning control to the caller when that time expires (or some time afterwards). There is no guarantee
83  * that a call to this function will exit at exactly the time of expiry. There is also no guarantee that events have
84  * been dispatched during the call, as the function might have spent all the allotted time waiting on the event queue.
85  * Once an event has been dequeued, however, it is guaranteed to be dispatched. This guarantee contributes to not being
86  * able to exit exactly at time of expiry as (1) blocking on internal mutexes is necessary for dispatching the dequeued
87  * event, and (2) during  dispatch of the dequeued event there is no way to control the time occupied by handler code
88  * execution. The guaranteed time of exit is therefore the allotted time + amount of time required to dispatch
89  * the last dequeued event.
90  *
91  * In cases where waiting on the queue times out, ESP_OK is returned and not ESP_ERR_TIMEOUT, since it is
92  * normal behavior.
93  *
94  * @param[in] event_loop event loop to dispatch posted events from, must not be NULL
95  * @param[in] ticks_to_run number of ticks to run the loop
96  *
97  * @note encountering an unknown event that has been posted to the loop will only generate a warning, not an error.
98  *
99  * @return
100  *  - ESP_OK: Success
101  *  - Others: Fail
102  */
103 esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, uint32_t ticks_to_run);
104 
105 /**
106  * @brief Register an event handler to the system event loop (legacy).
107  *
108  * This function can be used to register a handler for either: (1) specific events,
109  * (2) all events of a certain event base, or (3) all events known by the system event loop.
110  *
111  *  - specific events: specify exact event_base and event_id
112  *  - all events of a certain base: specify exact event_base and use ESP_EVENT_ANY_ID as the event_id
113  *  - all events known by the loop: use ESP_EVENT_ANY_BASE for event_base and ESP_EVENT_ANY_ID as the event_id
114  *
115  * Registering multiple handlers to events is possible. Registering a single handler to multiple events is
116  * also possible. However, registering the same handler to the same event multiple times would cause the
117  * previous registrations to be overwritten.
118  *
119  * @param[in] event_base the base ID of the event to register the handler for
120  * @param[in] event_id the ID of the event to register the handler for
121  * @param[in] event_handler the handler function which gets called when the event is dispatched
122  * @param[in] event_handler_arg data, aside from event data, that is passed to the handler when it is called
123  *
124  * @note the event loop library does not maintain a copy of event_handler_arg, therefore the user should
125  * ensure that event_handler_arg still points to a valid location by the time the handler gets called
126  *
127  * @return
128  *  - ESP_OK: Success
129  *  - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
130  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID
131  *  - Others: Fail
132  */
133 esp_err_t esp_event_handler_register(esp_event_base_t event_base,
134                                      int32_t event_id,
135                                      esp_event_handler_t event_handler,
136                                      void *event_handler_arg);
137 
138 /**
139  * @brief Register an event handler to a specific loop (legacy).
140  *
141  * This function behaves in the same manner as esp_event_handler_register, except the additional
142  * specification of the event loop to register the handler to.
143  *
144  * @param[in] event_loop the event loop to register this handler function to, must not be NULL
145  * @param[in] event_base the base ID of the event to register the handler for
146  * @param[in] event_id the ID of the event to register the handler for
147  * @param[in] event_handler the handler function which gets called when the event is dispatched
148  * @param[in] event_handler_arg data, aside from event data, that is passed to the handler when it is called
149  *
150  * @note the event loop library does not maintain a copy of event_handler_arg, therefore the user should
151  * ensure that event_handler_arg still points to a valid location by the time the handler gets called
152  *
153  * @return
154  *  - ESP_OK: Success
155  *  - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
156  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID
157  *  - Others: Fail
158  */
159 esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop,
160                                           esp_event_base_t event_base,
161                                           int32_t event_id,
162                                           esp_event_handler_t event_handler,
163                                           void *event_handler_arg);
164 
165 /**
166  * @brief Register an instance of event handler to a specific loop.
167  *
168  * This function can be used to register a handler for either: (1) specific events,
169  * (2) all events of a certain event base, or (3) all events known by the system event loop.
170  *
171  *  - specific events: specify exact event_base and event_id
172  *  - all events of a certain base: specify exact event_base and use ESP_EVENT_ANY_ID as the event_id
173  *  - all events known by the loop: use ESP_EVENT_ANY_BASE for event_base and ESP_EVENT_ANY_ID as the event_id
174  *
175  * Besides the error, the function returns an instance object as output parameter to identify each registration.
176  * This is necessary to remove (unregister) the registration before the event loop is deleted.
177  *
178  * Registering multiple handlers to events, registering a single handler to multiple events as well as registering
179  * the same handler to the same event multiple times is possible.
180  * Each registration yields a distinct instance object which identifies it over the registration
181  * lifetime.
182  *
183  * @param[in] event_loop the event loop to register this handler function to, must not be NULL
184  * @param[in] event_base the base ID of the event to register the handler for
185  * @param[in] event_id the ID of the event to register the handler for
186  * @param[in] event_handler the handler function which gets called when the event is dispatched
187  * @param[in] event_handler_arg data, aside from event data, that is passed to the handler when it is called
188  * @param[out] instance An event handler instance object related to the registered event handler and data, can be NULL.
189  *             This needs to be kept if the specific callback instance should be unregistered before deleting the whole
190  *             event loop. Registering the same event handler multiple times is possible and yields distinct instance
191  *             objects. The data can be the same for all registrations.
192  *             If no unregistration is needed, but the handler should be deleted when the event loop is deleted,
193  *             instance can be NULL.
194  *
195  * @note the event loop library does not maintain a copy of event_handler_arg, therefore the user should
196  * ensure that event_handler_arg still points to a valid location by the time the handler gets called
197  *
198  * @return
199  *  - ESP_OK: Success
200  *  - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
201  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID or instance is NULL
202  *  - Others: Fail
203  */
204 esp_err_t esp_event_handler_instance_register_with(esp_event_loop_handle_t event_loop,
205                                                   esp_event_base_t event_base,
206                                                   int32_t event_id,
207                                                   esp_event_handler_t event_handler,
208                                                   void *event_handler_arg,
209                                                   esp_event_handler_instance_t *instance);
210 
211 /**
212  * @brief Register an instance of event handler to the default loop.
213  *
214  * This function does the same as esp_event_handler_instance_register_with, except that it registers the
215  * handler to the default event loop.
216  *
217  * @param[in] event_base the base ID of the event to register the handler for
218  * @param[in] event_id the ID of the event to register the handler for
219  * @param[in] event_handler the handler function which gets called when the event is dispatched
220  * @param[in] event_handler_arg data, aside from event data, that is passed to the handler when it is called
221  * @param[out] instance An event handler instance object related to the registered event handler and data, can be NULL.
222  *             This needs to be kept if the specific callback instance should be unregistered before deleting the whole
223  *             event loop. Registering the same event handler multiple times is possible and yields distinct instance
224  *             objects. The data can be the same for all registrations.
225  *             If no unregistration is needed, but the handler should be deleted when the event loop is deleted,
226  *             instance can be NULL.
227  *
228  * @note the event loop library does not maintain a copy of event_handler_arg, therefore the user should
229  * ensure that event_handler_arg still points to a valid location by the time the handler gets called
230  *
231  * @return
232  *  - ESP_OK: Success
233  *  - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
234  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID or instance is NULL
235  *  - Others: Fail
236  */
237 esp_err_t esp_event_handler_instance_register(esp_event_base_t event_base,
238                                              int32_t event_id,
239                                              esp_event_handler_t event_handler,
240                                              void *event_handler_arg,
241                                              esp_event_handler_instance_t *instance);
242 
243 /**
244  * @brief Unregister a handler with the system event loop (legacy).
245  *
246  * Unregisters a handler, so it will no longer be called during dispatch.
247  * Handlers can be unregistered for any combination of event_base and event_id which were previously registered.
248  * To unregister a handler, the event_base and event_id arguments must match exactly the arguments passed to
249  * esp_event_handler_register() when that handler was registered. Passing ESP_EVENT_ANY_BASE and/or ESP_EVENT_ANY_ID
250  * will only unregister handlers that were registered with the same wildcard arguments.
251  *
252  * @note When using ESP_EVENT_ANY_ID, handlers registered to specific event IDs using the same base will not be
253  *       unregistered. When using ESP_EVENT_ANY_BASE, events registered to specific bases will also not be
254  *       unregistered. This avoids accidental unregistration of handlers registered by other users or components.
255  *
256  * @param[in] event_base the base of the event with which to unregister the handler
257  * @param[in] event_id the ID of the event with which to unregister the handler
258  * @param[in] event_handler the handler to unregister
259  *
260  * @return ESP_OK success
261  * @return ESP_ERR_INVALID_ARG invalid combination of event base and event ID
262  * @return others fail
263  */
264 esp_err_t esp_event_handler_unregister(esp_event_base_t event_base,
265                                        int32_t event_id,
266                                        esp_event_handler_t event_handler);
267 
268 /**
269  * @brief Unregister a handler from a specific event loop (legacy).
270  *
271  * This function behaves in the same manner as esp_event_handler_unregister, except the additional specification of
272  * the event loop to unregister the handler with.
273  *
274  * @param[in] event_loop the event loop with which to unregister this handler function, must not be NULL
275  * @param[in] event_base the base of the event with which to unregister the handler
276  * @param[in] event_id the ID of the event with which to unregister the handler
277  * @param[in] event_handler the handler to unregister
278  *
279  * @return
280  *  - ESP_OK: Success
281  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID
282  *  - Others: Fail
283  */
284 esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
285                                             esp_event_base_t event_base,
286                                             int32_t event_id,
287                                             esp_event_handler_t event_handler);
288 
289 /**
290  * @brief Unregister a handler instance from a specific event loop.
291  *
292  * Unregisters a handler instance, so it will no longer be called during dispatch.
293  * Handler instances can be unregistered for any combination of event_base and event_id which were previously
294  * registered. To unregister a handler instance, the event_base and event_id arguments must match exactly the
295  * arguments passed to esp_event_handler_instance_register() when that handler instance was registered.
296  * Passing ESP_EVENT_ANY_BASE and/or ESP_EVENT_ANY_ID will only unregister handler instances that were registered
297  * with the same wildcard arguments.
298  *
299  * @note When using ESP_EVENT_ANY_ID, handlers registered to specific event IDs using the same base will not be
300  *       unregistered. When using ESP_EVENT_ANY_BASE, events registered to specific bases will also not be
301  *       unregistered. This avoids accidental unregistration of handlers registered by other users or components.
302  *
303  * @param[in] event_loop the event loop with which to unregister this handler function, must not be NULL
304  * @param[in] event_base the base of the event with which to unregister the handler
305  * @param[in] event_id the ID of the event with which to unregister the handler
306  * @param[in] instance the instance object of the registration to be unregistered
307  *
308  * @return
309  *  - ESP_OK: Success
310  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID
311  *  - Others: Fail
312  */
313 esp_err_t esp_event_handler_instance_unregister_with(esp_event_loop_handle_t event_loop,
314                                                      esp_event_base_t event_base,
315                                                      int32_t event_id,
316                                                      esp_event_handler_instance_t instance);
317 
318 /**
319  * @brief Unregister a handler from the system event loop.
320  *
321  * This function does the same as esp_event_handler_instance_unregister_with, except that it unregisters the
322  * handler instance from the default event loop.
323  *
324  * @param[in] event_base the base of the event with which to unregister the handler
325  * @param[in] event_id the ID of the event with which to unregister the handler
326  * @param[in] instance the instance object of the registration to be unregistered
327  *
328  * @return
329  *  - ESP_OK: Success
330  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID
331  *  - Others: Fail
332  */
333 esp_err_t esp_event_handler_instance_unregister(esp_event_base_t event_base,
334                                                 int32_t event_id,
335                                                 esp_event_handler_instance_t instance);
336 
337 /**
338  * @brief Posts an event to the system default event loop. The event loop library keeps a copy of event_data and manages
339  * the copy's lifetime automatically (allocation + deletion); this ensures that the data the
340  * handler receives is always valid.
341  *
342  * @param[in] event_base the event base that identifies the event
343  * @param[in] event_id the event ID that identifies the event
344  * @param[in] event_data the data, specific to the event occurrence, that gets passed to the handler
345  * @param[in] event_data_size the size of the event data
346  * @param[in] ticks_to_wait number of ticks to block on a full event queue
347  *
348  * @return
349  *  - ESP_OK: Success
350  *  - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired,
351  *                      queue full when posting from ISR
352  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID
353  *  - Others: Fail
354  */
355 esp_err_t esp_event_post(esp_event_base_t event_base,
356                          int32_t event_id,
357                          const void *event_data,
358                          size_t event_data_size,
359                          uint32_t ticks_to_wait);
360 
361 /**
362  * @brief Posts an event to the specified event loop. The event loop library keeps a copy of event_data and manages
363  * the copy's lifetime automatically (allocation + deletion); this ensures that the data the
364  * handler receives is always valid.
365  *
366  * This function behaves in the same manner as esp_event_post, except the additional specification of the event loop
367  * to post the event to.
368  *
369  * @param[in] event_loop the event loop to post to, must not be NULL
370  * @param[in] event_base the event base that identifies the event
371  * @param[in] event_id the event ID that identifies the event
372  * @param[in] event_data the data, specific to the event occurrence, that gets passed to the handler
373  * @param[in] event_data_size the size of the event data
374  * @param[in] ticks_to_wait number of ticks to block on a full event queue
375  *
376  * @return
377  *  - ESP_OK: Success
378  *  - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired,
379  *                      queue full when posting from ISR
380  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID
381  *  - Others: Fail
382  */
383 esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop,
384                             esp_event_base_t event_base,
385                             int32_t event_id,
386                             const void *event_data,
387                             size_t event_data_size,
388                             uint32_t ticks_to_wait);
389 
390 #if CONFIG_ESP_EVENT_POST_FROM_ISR
391 /**
392  * @brief Special variant of esp_event_post for posting events from interrupt handlers.
393  *
394  * @param[in] event_base the event base that identifies the event
395  * @param[in] event_id the event ID that identifies the event
396  * @param[in] event_data the data, specific to the event occurrence, that gets passed to the handler
397  * @param[in] event_data_size the size of the event data; max is 4 bytes
398  * @param[out] task_unblocked an optional parameter (can be NULL) which indicates that an event task with
399  *                            higher priority than currently running task has been unblocked by the posted event;
400  *                            a context switch should be requested before the interrupt is existed.
401  *
402  * @note this function is only available when CONFIG_ESP_EVENT_POST_FROM_ISR is enabled
403  * @note when this function is called from an interrupt handler placed in IRAM, this function should
404  *       be placed in IRAM as well by enabling CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR
405  *
406  * @return
407  *  - ESP_OK: Success
408  *  - ESP_FAIL: Event queue for the default event loop full
409  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID,
410  *                          data size of more than 4 bytes
411  *  - Others: Fail
412  */
413 esp_err_t esp_event_isr_post(esp_event_base_t event_base,
414                              int32_t event_id,
415                              const void *event_data,
416                              size_t event_data_size,
417                              int *task_unblocked);
418 
419 /**
420  * @brief Special variant of esp_event_post_to for posting events from interrupt handlers
421  *
422  * @param[in] event_loop the event loop to post to, must not be NULL
423  * @param[in] event_base the event base that identifies the event
424  * @param[in] event_id the event ID that identifies the event
425  * @param[in] event_data the data, specific to the event occurrence, that gets passed to the handler
426  * @param[in] event_data_size the size of the event data
427  * @param[out] task_unblocked an optional parameter (can be NULL) which indicates that an event task with
428  *                            higher priority than currently running task has been unblocked by the posted event;
429  *                            a context switch should be requested before the interrupt is existed.
430  *
431  * @note this function is only available when CONFIG_ESP_EVENT_POST_FROM_ISR is enabled
432  * @note when this function is called from an interrupt handler placed in IRAM, this function should
433  *       be placed in IRAM as well by enabling CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR
434  *
435  * @return
436  *  - ESP_OK: Success
437  *  - ESP_FAIL: Event queue for the loop full
438  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID,
439  *                          data size of more than 4 bytes
440  *  - Others: Fail
441  */
442 esp_err_t esp_event_isr_post_to(esp_event_loop_handle_t event_loop,
443                                 esp_event_base_t event_base,
444                                 int32_t event_id,
445                                 const void *event_data,
446                                 size_t event_data_size,
447                                 int *task_unblocked);
448 #endif
449 
450 /**
451  * @brief Dumps statistics of all event loops.
452  *
453  * Dumps event loop info in the format:
454  *
455  @verbatim
456        event loop
457            handler
458            handler
459            ...
460        event loop
461            handler
462            handler
463            ...
464 
465   where:
466 
467    event loop
468        format: address,name rx:total_received dr:total_dropped
469        where:
470            address - memory address of the event loop
471            name - name of the event loop, 'none' if no dedicated task
472            total_received - number of successfully posted events
473            total_dropped - number of events unsuccessfully posted due to queue being full
474 
475    handler
476        format: address ev:base,id inv:total_invoked run:total_runtime
477        where:
478            address - address of the handler function
479            base,id - the event specified by event base and ID this handler executes
480            total_invoked - number of times this handler has been invoked
481            total_runtime - total amount of time used for invoking this handler
482 
483  @endverbatim
484  *
485  * @param[in] file the file stream to output to
486  *
487  * @note this function is a noop when CONFIG_ESP_EVENT_LOOP_PROFILING is disabled
488  *
489  * @return
490  *  - ESP_OK: Success
491  *  - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
492  *  - Others: Fail
493  */
494 esp_err_t esp_event_dump(FILE *file);
495 
496 #ifdef __cplusplus
497 } // extern "C"
498 #endif
499 
500 #endif // #ifndef ESP_EVENT_H_
501