Default Event Loop

ESP-IDF has an Event Loop Library . This Library allows you to create an Event Loop and declare Events to which other components of your code can register handlers. Handler is a function which gets executed when a particular event occurs.

A default Event loop is already prepared by the IDF; it is responsible for generating major events like

  • WIFI_EVENT
  • IP_EVENT
  • IP_EVENT_STA_GOT_IP

You only need to call a function which will create the default event loop .

After that you don’t have to create/run any freertos task to run the default event loop . the default Loop runs internally

You can register to the default event loop for events like WIFI_EVENT and handle the event according to your needs . You can also create your own events and post them to the default event loop . Other code components of yours can register by the events created by you.

In this way the default event loop can generate/dispatch major system Events as well as user-created ones . I guess This is sufficient for most of the application design , but if you really need an event loop other than the default you can create one , but then you will also have to run it by a freeRtos Task.

To distinguish between default & User event loop the API provided by the esp_event library is slightly different for both the cases

Default Event Loops User Event Loops
esp_event_loop_create_default() esp_event_loop_create()
esp_event_loop_delete_default() esp_event_loop_delete()
esp_event_handler_register() esp_event_handler_register_with()
esp_event_handler_unregister() esp_event_handler_unregister_with()
esp_event_post() esp_event_post_to()

EVENTS

An Event consists of 2 identifiers

  • The Event Base
  • The Event ID

There can be multiple event ID under 1 Event Base

The esp_event library has Macros to declare and define events

Now we will follow the following example code to know how to use the default event loop

https://github.com/espressif/esp-idf/tree/master/examples/system/esp_event/default_event_loop

In The example a timer is made using esp_timer API and 3 event sources are created related to the timer. The events are

  • An event is generated when timer is raised
  • An event is generated when timer period expires
  • An event is generated when the time is stopped

first declare Event in the event_source.h header file

// event_source.h
// Declare an event base
ESP_EVENT_DECLARE_BASE(TIMER_EVENTS); // declaration of the timer events family

enum {               // declaration of the specific events under the timer event family
    TIMER_EVENT_STARTED,       // raised when the timer is first started
    TIMER_EVENT_EXPIRY,        // raised when a period of the timer has elapsed
    TIMER_EVENT_STOPPED        // raised when the timer has been stopped
};

Then define the event in main.c implementation file

/* Event source periodic timer related definitions */
ESP_EVENT_DEFINE_BASE(TIMER_EVENTS);

Create the default event loop as

// Create the default event loop
ESP_ERROR_CHECK(esp_event_loop_create_default());

To register an Event to the default event loop we have to use the following function

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
                );

For example to register the event of timer start the event base & Event ID is passed as follows

// Register the specific timer event handlers.
ESP_ERROR_CHECK(esp_event_handler_register(
                                 TIMER_EVENTS, 
                                 TIMER_EVENT_STARTED, 
                                 timer_started_handler, 
                                 NULL));

To Post an Event to the default loop you have to use the following function . Remember you have to post your events to the default loop , default loop will then dispatch the event to the listening subscribers

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
                    );

So the example code starts the timer and posts this very starting event to the default loop

ESP_ERROR_CHECK(esp_timer_start_periodic(TIMER, TIMER_PERIOD));
ESP_ERROR_CHECK(esp_event_post(
                               TIMER_EVENTS, 
                               TIMER_EVENT_STARTED, 
                               NULL, 
                               0, 
                               portMAX_DELAY)
                               );

As soon as this event is got by the default loop , it dispatches the event to the corresponding handler which was registered before for this event

// Handler which executes when the timer started event gets executed by the loop.
static void timer_started_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
    ESP_LOGI(TAG, "%s:%s: timer_started_handler", base, get_id_string(base, id));
}

The handler basically prints a log about the event

So this is how you can use the default event loop to design an event driven application

Reference

https://github.com/espressif/esp-idf/tree/master/examples/system/esp_event/default_event_loop

Written on November 18, 2019