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