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