添加智能灯固件代码

This commit is contained in:
kerwincui
2021-07-13 17:14:51 +08:00
parent 332f74dd17
commit ecc0b91b8b
2568 changed files with 229441 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(default_event_loop)

View File

@@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := default_event_loop
include $(IDF_PATH)/make/project.mk

View File

@@ -0,0 +1,195 @@
# Default Event Loop Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
Note: Should users need to create their own event loops, refer to the **user event loops** [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_event.html#using-esp-event-apis) and [example](https://github.com/espressif/esp-idf/tree/master/examples/system/esp_event/user_event_loops).
The [**default event loop**](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_event.html#default-event-loop) is an [event loop](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_event.html#) the system uses to post and handle events (e.g. Wi-Fi events). This example demonstrates the usage of the following default event loop features:
### Declaring and Defining Events
This example shows the typical setup of having the event base and event IDs declared in a header file, and having the definitions in a source file. Declaration of the event base makes use of the macro `ESP_EVENT_DECLARE_BASE()`, whilst the event IDs are declared as an `enum` (see `event_source.h`). The source file `main.c` holds the definition of the event base using the `ESP_EVENT_DEFINE_BASE()` macro.
### Creating the Default Event Loop
This example illustrates the creation of the default event loop using the API function `esp_event_loop_create_default()`.
### Posting Events to the Default Event Loop
Simply put, posting an event to a loop is the act of queueing its handlers for execution. For the default loop, this is done using the API `esp_event_post()`. The ability to pass event-specific data to the handler is also demonstrated.
### Handler Registration/Unregistration
This example demonstrates handler registration to the default event loop using `esp_event_handler_register` for (1) specific events, (2) **any** event under a certain base, and (3) **any** event. This also shows the possbility of registering multiple handlers to the same event as well as registering one handler to the same event multiple times.
Unregistering a handler is done using `esp_event_handler_unregister()`. Unregistering a handler means that it no longer executes even when the event it was previously registered to gets posted to the loop.
## How to use example
### Hardware Required
This example should be able to run on any commonly available ESP32 development board.
### Configure the project
```
idf.py menuconfig
```
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
The example should have the following log output:
```
I (328) default_event_loop: setting up
I (338) default_event_loop: starting event sources
I (338) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: posting to default loop
I (338) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 1 out of 5
I (358) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler, instance 0
I (368) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler, instance 1
I (378) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler_2
I (388) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_any_handler
I (388) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: all_event_handler
I (398) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: task_iteration_handler, executed 1 times
I (408) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (858) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 2 out of 5
I (858) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: task_iteration_handler, executed 2 times
I (858) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (1338) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: posting to default loop
I (1338) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_expiry_handler, executed 1 out of 3 times
I (1348) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_any_handler
I (1358) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: all_event_handler
I (1358) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 3 out of 5
I (1368) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: unregistering task_iteration_handler
I (1368) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: task_iteration_handler, executed 3 times
I (1388) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (1898) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 4 out of 5
I (1898) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (2338) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: posting to default loop
I (2338) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_expiry_handler, executed 2 out of 3 times
I (2348) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_any_handler
I (2358) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: all_event_handler
I (2398) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 5 out of 5
I (2398) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (3338) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: posting to default loop
I (3338) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: posting to default loop
I (3348) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_expiry_handler, executed 3 out of 3 times
I (3358) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_any_handler
I (3358) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: all_event_handler
I (3368) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: timer_stopped_handler
I (3378) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: deleted timer event source
I (3388) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: timer_any_handler
I (3398) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: all_event_handler
I (3398) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: deleting task event source
```
## Example Breakdown
### Setting of Event Sources
This example uses two event sources:
- A periodic timer. An event is raised when (1) the timer is started (2) the timer period expires and (3) the timer is stopped
- A task with a loop inside. An event is raised for the when (1) the loop iterates.
All of the events mentioned above have their own specific handler, however there are the following additional handlers.
- One handler executes when **any** event under the periodic timer event is posted
- The other handler executes if **any** event is posted.
The number of periodic timer expiries and loop iterations are limited. When the limit for the number of timer expiries is reached, the timer is stopped. When the limit for the number of iterations is reached, the task is deleted. In the case of the loop iteration, there is another limit: the number of iterations for when its handler will be unregistered.
### Step-by-Step Explanation
The following text explains the important points of the [sample log output](#Example-Output).
#### 1. Setting up of default event loop and event handlers
```
I (297) default_event_loop: setting up
```
At this stage the default event loop is created, and the handlers for the different events are registered.
#### 2. Posting to the event loop
```
I (276) default_event_loop: starting event sources
I (276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: posting to default loop
I (276) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 1 out of 5
```
The two event sources are started. The respective events are posted to the default event loop.
#### 3. Execution of handlers
```
I (358) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler, instance 0
I (368) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler, instance 1
I (378) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler_2
I (306) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_any_handler
I (316) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: all_event_handler
...
I (326) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: task_iteration_handler, executed 1 times
I (336) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
```
The handlers are executed for the events that were posted in **(2)**. Note how `timer_started_handler()` is called twice on the same event post. This shows the ability to register a single event handler to a single event multiple times. Note also how `timer_started_handler_2()` is called on the same event post. This shows that multiple handlers can be registered to a single event.
In addition to the event-specific handlers `timer_started_handler()` (registered twice), `timer_started_handler_2()` and `task_iteration_handler()`, the `timer_any_handler()` and `all_event_handler()` are also executed.
The `timer_any_handler()` executes for **any** timer event. It can be seen executing for the timer expiry and timer stopped events in the subsequent parts of the log.
On the other hand, `all_event_handler()` executes for **any** event, hence why it executes for both ``TIMER_EVENTS:TIMER_EVENT_STARTED`` and ``TASK_EVENTS:TASK_ITERATION_EVENT``.
For both the timer and task events, notice that the handlers are executed in the same order they are registered in the code. This is a guarantee that the `esp_event` library provides.
The subsequent lines of the log follows the same pattern: the event is posted to the loop and the handlers are executed.
#### 4. Unregistering the `task_iteration_handler()`
```
...
I (1316) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: unregistering task_iteration_handler
```
At this point in the execution the handler `task_iteration_handler()` is unregistered, therefore it no longer executes when the event ``TASK_EVENTS:TASK_ITERATION_EVENT`` is posted.
```
I (1867) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 4 out of 5
I (1867) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
...
I (1846) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 4 out of 5
I (1846) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handle
```
The iteration event continues to get posted, but only the `all_event_handler()` gets executed.
#### 5. Iteration Limit
```
...
I (3276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: posting to default loop
I (3276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: posting to default loop
I (3286) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_expiry_handler, executed 3 out of 3 times
I (3296) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_any_handler
I (3306) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: all_event_handler
I (3316) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: timer_stopped_handler
I (3326) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: deleted timer event source
```
When the periodic timer expiry limit is reached, the event ``TIMER_EVENTS:TIMER_EVENT_STOPPED`` is posted to the loop. The periodic timer is consequently deleted in the handler `timer_stopped_handler()`.
```
...
I (3346) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: deleting task event source
...
```
The task containing the loop that posts iteration events also gets deleted. The example ends at this point.

View File

@@ -0,0 +1,93 @@
from __future__ import print_function
import ttfw_idf
# Timer events
TIMER_EVENT_LIMIT = 3
TIMER_EXPIRY_HANDLING = "TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_expiry_handler, executed {} out of " + str(TIMER_EVENT_LIMIT) + " times"
# Task events
TASK_ITERATION_LIMIT = 5
TASK_UNREGISTRATION_LIMIT = 3
TASK_ITERATION_POST = "TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, {} out of " + str(TASK_ITERATION_LIMIT)
TASK_ITERATION_HANDLING = "TASK_EVENTS:TASK_ITERATION_EVENT: task_iteration_handler, executed {} times"
def _test_timer_events(dut):
dut.start_app()
print("Checking timer events posting and handling")
dut.expect("setting up")
dut.expect("starting event sources")
print("Finished setup")
dut.expect("TIMER_EVENTS:TIMER_EVENT_STARTED: posting to default loop")
print("Posted timer started event")
dut.expect("TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler, instance 0")
dut.expect("TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler, instance 1")
dut.expect("TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler_2")
dut.expect("TIMER_EVENTS:TIMER_EVENT_STARTED: timer_any_handler")
dut.expect("TIMER_EVENTS:TIMER_EVENT_STARTED: all_event_handler")
print("Handled timer started event")
for expiries in range(1, TIMER_EVENT_LIMIT + 1):
dut.expect("TIMER_EVENTS:TIMER_EVENT_EXPIRY: posting to default loop")
print("Posted timer expiry event {} out of {}".format(expiries, TIMER_EVENT_LIMIT))
if expiries >= TIMER_EVENT_LIMIT:
dut.expect("TIMER_EVENTS:TIMER_EVENT_STOPPED: posting to default loop")
print("Posted timer stopped event")
dut.expect(TIMER_EXPIRY_HANDLING.format(expiries))
dut.expect("TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_any_handler")
dut.expect("TIMER_EVENTS:TIMER_EVENT_EXPIRY: all_event_handler")
print("Handled timer expiry event {} out of {}".format(expiries, TIMER_EVENT_LIMIT))
dut.expect("TIMER_EVENTS:TIMER_EVENT_STOPPED: timer_stopped_handler")
dut.expect("TIMER_EVENTS:TIMER_EVENT_STOPPED: deleted timer event source")
print("Handled timer stopped event")
def _test_iteration_events(dut):
dut.start_app()
print("Checking iteration events posting and handling")
dut.expect("setting up")
dut.expect("starting event sources")
print("Finished setup")
for iteration in range(1, TASK_ITERATION_LIMIT + 1):
dut.expect(TASK_ITERATION_POST.format(iteration))
print("Posted iteration {} out of {}".format(iteration, TASK_ITERATION_LIMIT))
if iteration < TASK_UNREGISTRATION_LIMIT:
dut.expect(TASK_ITERATION_HANDLING.format(iteration))
dut.expect("TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler")
elif iteration == TASK_UNREGISTRATION_LIMIT:
dut.expect("TASK_EVENTS:TASK_ITERATION_EVENT: unregistering task_iteration_handler")
dut.expect("TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler")
print("Unregistered handler at iteration {} out of {}".format(iteration, TASK_ITERATION_LIMIT))
else:
dut.expect("TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler")
print("Handled iteration {} out of {}".format(iteration, TASK_ITERATION_LIMIT))
dut.expect("TASK_EVENTS:TASK_ITERATION_EVENT: deleting task event source")
print("Deleted task event source")
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
def test_default_event_loop_example(env, extra_data):
dut = env.get_dut('default_event_loop', 'examples/system/esp_event/default_event_loop')
_test_iteration_events(dut)
_test_timer_events(dut)
if __name__ == '__main__':
test_default_event_loop_example()

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")

View File

@@ -0,0 +1,8 @@
#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the
# src/ directory, compile them and link them into lib(subdirectory_name).a
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#

View File

@@ -0,0 +1,52 @@
/* esp_event (event loop library) basic example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef EVENT_SOURCE_H_
#define EVENT_SOURCE_H_
#include "esp_event.h"
#include "esp_timer.h"
#ifdef __cplusplus
extern "C" {
#endif
// This example makes use of two event sources: a periodic timer, and a task.
// Declarations for event source 1: periodic timer
#define TIMER_EXPIRIES_COUNT 3 // number of times the periodic timer expires before being stopped
#define TIMER_PERIOD 1000000 // period of the timer event source in microseconds
extern esp_timer_handle_t g_timer; // the periodic timer object
// 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
};
// Declarations for event source 2: task
#define TASK_ITERATIONS_COUNT 5 // number of times the task iterates
#define TASK_ITERATIONS_UNREGISTER 3 // count at which the task event handler is unregistered
#define TASK_PERIOD 500 // period of the task loop in milliseconds
ESP_EVENT_DECLARE_BASE(TASK_EVENTS); // declaration of the task events family
enum {
TASK_ITERATION_EVENT, // raised during an iteration of the loop within the task
};
#ifdef __cplusplus
}
#endif
#endif // #ifndef EVENT_SOURCE_H_

View File

@@ -0,0 +1,193 @@
/* esp_event (event loop library) basic example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "event_source.h"
static const char* TAG = "default_event_loop";
static esp_event_handler_instance_t s_instance;
static int TIMER_START_HANDLER_0 = 0;
static int TIMER_START_HANDLER_1 = 1;
static char* get_id_string(esp_event_base_t base, int32_t id) {
char* event = "";
if (base == TIMER_EVENTS) {
switch(id) {
case TIMER_EVENT_STARTED:
event = "TIMER_EVENT_STARTED";
break;
case TIMER_EVENT_EXPIRY:
event = "TIMER_EVENT_EXPIRY";
break;
case TIMER_EVENT_STOPPED:
event = "TIMER_EVENT_STOPPED";
break;
}
} else {
event = "TASK_ITERATION_EVENT";
}
return event;
}
/* Event source periodic timer related definitions */
ESP_EVENT_DEFINE_BASE(TIMER_EVENTS);
esp_timer_handle_t TIMER;
// Callback that will be executed when the timer period lapses. Posts the timer expiry event
// to the default event loop.
static void timer_callback(void* arg)
{
ESP_LOGI(TAG, "%s:%s: posting to default loop", TIMER_EVENTS, get_id_string(TIMER_EVENTS, TIMER_EVENT_EXPIRY));
ESP_ERROR_CHECK(esp_event_post(TIMER_EVENTS, TIMER_EVENT_EXPIRY, NULL, 0, portMAX_DELAY));
}
// 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)
{
int start_handler_num = *((int*) handler_args);
ESP_LOGI(TAG, "%s:%s: timer_started_handler, instance %d", base, get_id_string(base, id), start_handler_num);
}
// Second handler which executes when the timer started event gets executed by the loop.
static void timer_started_handler_2(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
ESP_LOGI(TAG, "%s:%s: timer_started_handler_2", base, get_id_string(base, id));
}
// Handler which executes when the timer expiry event gets executed by the loop. This handler keeps track of
// how many times the timer expired. When a set number of expiry is reached, the handler stops the timer
// and sends a timer stopped event.
static void timer_expiry_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
static int count = 0;
count++;
if (count >= TIMER_EXPIRIES_COUNT) {
// Stop the timer
ESP_ERROR_CHECK(esp_timer_stop(TIMER));
ESP_LOGI(TAG, "%s:%s: posting to default loop", base, get_id_string(base, TIMER_EVENT_STOPPED));
// Post the event that the timer has been stopped
ESP_ERROR_CHECK(esp_event_post(TIMER_EVENTS, TIMER_EVENT_STOPPED, NULL, 0, portMAX_DELAY));
}
ESP_LOGI(TAG, "%s:%s: timer_expiry_handler, executed %d out of %d times", base, get_id_string(base, id), count, TIMER_EXPIRIES_COUNT);
}
// Handler which executes when any timer event (started, expiry, stopped) get executed by the loop
static void timer_any_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
ESP_LOGI(TAG, "%s:%s: timer_any_handler", base, get_id_string(base, id));
}
// Handler which executes when the timer stopped event gets executed by the loop. Since the timer has been
// stopped, it is safe to delete it.
static void timer_stopped_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
ESP_LOGI(TAG, "%s:%s: timer_stopped_handler", base, get_id_string(base, id));
// Delete the timer
esp_timer_delete(TIMER);
ESP_LOGI(TAG, "%s:%s: deleted timer event source", base, get_id_string(base, id));
}
/* Event source task related definitions */
ESP_EVENT_DEFINE_BASE(TASK_EVENTS);
static void task_iteration_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
int iteration = *((int*) event_data);
ESP_LOGI(TAG, "%s:%s: task_iteration_handler, executed %d times", base, get_id_string(base, id), iteration);
}
static void task_event_source(void* args)
{
for(int iteration = 1; iteration <= TASK_ITERATIONS_COUNT; iteration++) {
ESP_LOGI(TAG, "%s:%s: posting to default loop, %d out of %d", TASK_EVENTS,
get_id_string(TASK_EVENTS, TASK_ITERATION_EVENT), iteration, TASK_ITERATIONS_COUNT);
// Post that the loop has iterated. Notice that the iteration count is passed to the handler. Take note
// that data passed during event posting is a deep copy of the original data.
ESP_ERROR_CHECK(esp_event_post(TASK_EVENTS, TASK_ITERATION_EVENT, &iteration, sizeof(iteration), portMAX_DELAY));
if (iteration == TASK_ITERATIONS_UNREGISTER) {
ESP_LOGI(TAG, "%s:%s: unregistering task_iteration_handler", TASK_EVENTS, get_id_string(TASK_EVENTS, TASK_ITERATION_EVENT));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(TASK_EVENTS, TASK_ITERATION_EVENT, s_instance));
}
vTaskDelay(pdMS_TO_TICKS(TASK_PERIOD));
}
vTaskDelay(pdMS_TO_TICKS(TASK_PERIOD));
ESP_LOGI(TAG, "%s:%s: deleting task event source", TASK_EVENTS, get_id_string(TASK_EVENTS, TASK_ITERATION_EVENT));
vTaskDelete(NULL);
}
/* Handler for all events */
static void all_event_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
ESP_LOGI(TAG, "%s:%s: all_event_handler", base, get_id_string(base, id));
}
/* Example main */
void app_main(void)
{
ESP_LOGI(TAG, "setting up");
// Create the default event loop
ESP_ERROR_CHECK(esp_event_loop_create_default());
// Register the specific timer event handlers. Timer start handler is registered twice.
ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler, &TIMER_START_HANDLER_0, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler, &TIMER_START_HANDLER_1, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler_2, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_EXPIRY, timer_expiry_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STOPPED, timer_stopped_handler, NULL, NULL));
// Register the handler for all timer family events. This will execute if the timer is started, expired or is stopped.
ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, ESP_EVENT_ANY_ID, timer_any_handler, NULL, NULL));
// Register the handler for task iteration event; need to pass instance handle for later unregistration.
ESP_ERROR_CHECK(esp_event_handler_instance_register(TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler, NULL, &s_instance));
// Register the handler for all event. This will execute if either the timer events or the task iteration event
// is posted to the default loop.
ESP_ERROR_CHECK(esp_event_handler_instance_register(ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, all_event_handler, NULL, NULL));
// Create and start the event sources
esp_timer_create_args_t timer_args = {
.callback = &timer_callback,
};
ESP_ERROR_CHECK(esp_timer_create(&timer_args, &TIMER));
ESP_LOGI(TAG, "starting event sources");
// Create the event source task with the same priority as the current task
xTaskCreate(task_event_source, "task_event_source", 2048, NULL, uxTaskPriorityGet(NULL), NULL);
ESP_ERROR_CHECK(esp_timer_start_periodic(TIMER, TIMER_PERIOD));
// Post the timer started event
ESP_LOGI(TAG, "%s:%s: posting to default loop", TIMER_EVENTS, get_id_string(TIMER_EVENTS, TIMER_EVENT_STARTED));
ESP_ERROR_CHECK(esp_event_post(TIMER_EVENTS, TIMER_EVENT_STARTED, NULL, 0, portMAX_DELAY));
}

View File

@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(user_event_loops)

View File

@@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := user_event_loops
include $(IDF_PATH)/make/project.mk

View File

@@ -0,0 +1,143 @@
# User Event Loops Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates the creation and use of [**user event loops**](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_event.html#). This example is a supplement to the [**default event loop** example](https://github.com/espressif/esp-idf/tree/master/examples/system/esp_event/default_event_loop), if the default event loop is not sufficient for the user's use case.
This example demonstrates the following things regarding user event loops:
### Creating Event Loops
Creating a loop entails populating the structure `esp_event_loop_args_t` with the desired parameters and calling `esp_event_loop_create()`. The call to `esp_event_loop_create()` produces a handle to the loop, which is used to perform actions on that loop such as handler registration/unregistration and posting events.
### Running Event Loops
Depending on the parameters, the user can create either a loop with a dedicated task or one without. The purpose of the dedicated task is to unqueue events from the loop and execute its handlers. For loops without the dedicated task, the user should make a call to `esp_event_loop_run()` in an application task.
### Handler Registration/Unregistration,
Handler registration and unregistration works the same way as the default event loop, just with a different API, `esp_event_handler_instance_register_with()` and `esp_event_handler_instance_unregister_with()` respectively. There are two things this example highlights:
1. The possibility of registering the same handler for different loops
2. The ability to pass static data to handlers.
### Posting Events to the Default Event Loop
Posting events also works the same way as the default event loop, except with a different API, `esp_event_post_to()`.
## How to use example
### Hardware Required
This example should be able to run on any commonly available ESP32 development board.
### Configure the project
```
idf.py menuconfig
```
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
The example should have the following log output:
```
I (296) user_event_loops: setting up
I (296) user_event_loops: starting event source
I (296) user_event_loops: starting application task
I (296) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_without_task, iteration 1 out of 10
I (316) user_event_loops: application_task: running application task
I (326) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_without_task, iteration 1
I (826) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_with_task, iteration 2 out of 10
I (826) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_with_task, iteration 2
I (1326) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_without_task, iteration 3 out of 10
I (1326) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_without_task, iteration 3
I (1426) user_event_loops: application_task: running application task
I (1826) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_with_task, iteration 4 out of 10
I (1826) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_with_task, iteration 4
I (2326) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_without_task, iteration 5 out of 10
I (2326) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_without_task, iteration 5
I (2526) user_event_loops: application_task: running application task
I (2826) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_with_task, iteration 6 out of 10
I (2826) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_with_task, iteration 6
I (3326) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_without_task, iteration 7 out of 10
I (3326) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_without_task, iteration 7
I (3626) user_event_loops: application_task: running application task
I (3826) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_with_task, iteration 8 out of 10
I (3826) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_with_task, iteration 8
I (4326) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_without_task, iteration 9 out of 10
I (4326) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_without_task, iteration 9
I (4726) user_event_loops: application_task: running application task
I (4826) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_with_task, iteration 10 out of 10
I (4826) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_with_task, iteration 10
I (5826) user_event_loops: application_task: running application task
I (5826) user_event_loops: deleting task event source
I (6926) user_event_loops: application_task: running application task
I (8026) user_event_loops: application_task: running application task
I (9126) user_event_loops: application_task: running application task
...
```
## Example Breakdown
### Setting of Event Sources
This example has a single event source: a task with a loop inside. Events are raised for the task event source when the loop iterates.
Two user event loops are created, one with a dedicated task and one without. Events are posted to either loops, depending on whether the iteration is odd or even. For the loop with a dedicated task, event handlers are automatically executed. However, for the loop without the dedicated task, a call to run the loop is made in one of the application tasks. As a result, the execution of the event handlers for this loop is interspersed with the execution of application task code.
### Step-by-Step Explanation
#### 1.Setting up user event loop and event handlers
```
I (296) user_event_loops: setting up
I (296) user_event_loops: starting event source
I (296) user_event_loops: starting application task
```
At this stage the two event loops are created, as well as the handlers for the iteration event registered. The event source is started, which will post the event to the appropriate loop. The application task which makes the call to run the loop without dedicated task, is also created and started.
#### 2. Posting to the event loop
```
I (296) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_without_task, iteration 1 out of 10
I (316) user_event_loops: application_task: running application task
I (326) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_without_task, iteration 1
I (826) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_with_task, iteration 2 out of 10
I (826) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_with_task, iteration 2
I (1326) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_without_task, iteration 3 out of 10
I (1326) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_without_task, iteration 3
I (1426) user_event_loops: application_task: running application task
I (1826) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_with_task, iteration 4 out of 10
...
```
In this section of the log we see the odd iterations posted to the loop without dedicated task, and the even iterations to the loop with a dedicated task. For the event with dedicated task, event handlers are executed automatically. The loop without a dedicated task, on the other hand, runs in the context of the application task.
#### 3. Iteration Limit
```
...
I (4826) user_event_loops: posting TASK_EVENTS:TASK_ITERATION_EVENT to loop_with_task, iteration 10 out of 10
I (4826) user_event_loops: handling TASK_EVENTS:TASK_ITERATION_EVENT from loop_with_task, iteration 10
I (5826) user_event_loops: application_task: running application task
I (5826) user_event_loops: deleting task event source
I (6926) user_event_loops: application_task: running application task
I (8026) user_event_loops: application_task: running application task
I (9126) user_event_loops: application_task: running application task
...
```
The last of the iteration event is posted, and the event source is deleted. Because the loop without the task no longer receive events to execute, only the application task code executes.

View File

@@ -0,0 +1,40 @@
from __future__ import print_function
import ttfw_idf
TASK_ITERATION_LIMIT = 10
TASK_ITERATION_POSTING = "posting TASK_EVENTS:TASK_ITERATION_EVENT to {}, iteration {} out of " + str(TASK_ITERATION_LIMIT)
TASK_ITERATION_HANDLING = "handling TASK_EVENTS:TASK_ITERATION_EVENT from {}, iteration {}"
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
def test_user_event_loops_example(env, extra_data):
dut = env.get_dut('user_event_loops', 'examples/system/esp_event/user_event_loops', dut_class=ttfw_idf.ESP32DUT)
dut.start_app()
dut.expect("setting up")
dut.expect("starting event source")
dut.expect("starting application task")
print("Finished setup")
for iteration in range(1, TASK_ITERATION_LIMIT + 1):
loop = None
if (iteration % 2 == 0):
loop = "loop_with_task"
else:
loop = "loop_without_task"
dut.expect(TASK_ITERATION_POSTING.format(loop, iteration))
print("Posted iteration {} to {}".format(iteration, loop))
dut.expect(TASK_ITERATION_HANDLING.format(loop, iteration))
print("Handled iteration {} from {}".format(iteration, loop))
dut.expect("deleting task event source")
print("Deleted task event source")
if __name__ == '__main__':
test_user_event_loops_example()

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")

View File

@@ -0,0 +1,8 @@
#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the
# src/ directory, compile them and link them into lib(subdirectory_name).a
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#

View File

@@ -0,0 +1,34 @@
/* esp_event (event loop library) basic example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef EVENT_SOURCE_H_
#define EVENT_SOURCE_H_
#include "esp_event.h"
#include "esp_timer.h"
#ifdef __cplusplus
extern "C" {
#endif
// Declarations for the event source
#define TASK_ITERATIONS_COUNT 10 // number of times the task iterates
#define TASK_PERIOD 500 // period of the task loop in milliseconds
ESP_EVENT_DECLARE_BASE(TASK_EVENTS); // declaration of the task events family
enum {
TASK_ITERATION_EVENT // raised during an iteration of the loop within the task
};
#ifdef __cplusplus
}
#endif
#endif // #ifndef EVENT_SOURCE_H_

View File

@@ -0,0 +1,123 @@
/* esp_event (event loop library) basic example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "event_source.h"
#include "esp_event_base.h"
static const char* TAG = "user_event_loops";
// Event loops
esp_event_loop_handle_t loop_with_task;
esp_event_loop_handle_t loop_without_task;
static void application_task(void* args)
{
while(1) {
ESP_LOGI(TAG, "application_task: running application task");
esp_event_loop_run(loop_without_task, 100);
vTaskDelay(10);
}
}
/* Event source task related definitions */
ESP_EVENT_DEFINE_BASE(TASK_EVENTS);
TaskHandle_t g_task;
static void task_iteration_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
// Two types of data can be passed in to the event handler: the handler specific data and the event-specific data.
//
// The handler specific data (handler_args) is a pointer to the original data, therefore, the user should ensure that
// the memory location it points to is still valid when the handler executes.
//
// The event-specific data (event_data) is a pointer to a deep copy of the original data, and is managed automatically.
int iteration = *((int*) event_data);
char* loop;
if (handler_args == loop_with_task) {
loop = "loop_with_task";
} else {
loop = "loop_without_task";
}
ESP_LOGI(TAG, "handling %s:%s from %s, iteration %d", base, "TASK_ITERATION_EVENT", loop, iteration);
}
static void task_event_source(void* args)
{
for(int iteration = 1; iteration <= TASK_ITERATIONS_COUNT; iteration++) {
esp_event_loop_handle_t loop_to_post_to;
if (iteration % 2 == 0) {
// if even, post to the event loop with dedicated task
loop_to_post_to = loop_with_task;
} else {
// if odd, post to the event loop without a dedicated task
loop_to_post_to = loop_without_task;
}
ESP_LOGI(TAG, "posting %s:%s to %s, iteration %d out of %d", TASK_EVENTS, "TASK_ITERATION_EVENT",
loop_to_post_to == loop_with_task ? "loop_with_task" : "loop_without_task",
iteration, TASK_ITERATIONS_COUNT);
ESP_ERROR_CHECK(esp_event_post_to(loop_to_post_to, TASK_EVENTS, TASK_ITERATION_EVENT, &iteration, sizeof(iteration), portMAX_DELAY));
vTaskDelay(pdMS_TO_TICKS(TASK_PERIOD));
}
vTaskDelay(pdMS_TO_TICKS(TASK_PERIOD));
ESP_LOGI(TAG, "deleting task event source");
vTaskDelete(NULL);
}
/* Example main */
void app_main(void)
{
ESP_LOGI(TAG, "setting up");
esp_event_loop_args_t loop_with_task_args = {
.queue_size = 5,
.task_name = "loop_task", // task will be created
.task_priority = uxTaskPriorityGet(NULL),
.task_stack_size = 2048,
.task_core_id = tskNO_AFFINITY
};
esp_event_loop_args_t loop_without_task_args = {
.queue_size = 5,
.task_name = NULL // no task will be created
};
// Create the event loops
ESP_ERROR_CHECK(esp_event_loop_create(&loop_with_task_args, &loop_with_task));
ESP_ERROR_CHECK(esp_event_loop_create(&loop_without_task_args, &loop_without_task));
// Register the handler for task iteration event. Notice that the same handler is used for handling event on different loops.
// The loop handle is provided as an argument in order for this example to display the loop the handler is being run on.
ESP_ERROR_CHECK(esp_event_handler_instance_register_with(loop_with_task, TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler, loop_with_task, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register_with(loop_without_task, TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler, loop_without_task, NULL));
ESP_LOGI(TAG, "starting event source");
// Create the event source task with the same priority as the current task
xTaskCreate(task_event_source, "task_event_source", 2048, NULL, uxTaskPriorityGet(NULL), NULL);
ESP_LOGI(TAG, "starting application task");
// Create the application task with the same priority as the current task
xTaskCreate(application_task, "application_task", 2048, NULL, uxTaskPriorityGet(NULL), NULL);
}