代码
#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; //传入hanlder的参数
static int TIMER_START_HANDLER_1 = 1;
static char* get_id_string(esp_event_base_t base, int32_t id) { //获取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); //定义EVENT_BASE
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.
//定时器回调函数,会被周期执行,传递expiry event事件到默认的event循环里。
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.
//第一个用于处理timer started event事件的处理函数
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.
//第二个用于处理timer started event事件的处理函数
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.
//定时器循环事件handler,每次发送定时到达事件,同时此回调记录定时器执行次数,达到指定次数的时候会停止定时器并发送定时器停止事件。
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.
//注册一个总处理函数,当事件id是started, expired,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.
//注册一个处理函数用于任务迭代事件(?翻译存疑),需要传递一个instance参数用于之后的注销
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.
//注册一个用于所有事件的handler,定时器事件和任务迭代事件也会触发执行
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));
}
运行结果
解析
我们从主函数开始开启,按执行顺序分析,这样方便理解
/* 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.
//注册一个总处理函数,当事件id是started, expired,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.
//注册一个处理函数用于任务迭代事件(?翻译存疑),需要传递一个instance参数用于之后的注销
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.
//注册一个用于所有事件的handler,定时器事件和任务迭代事件也会触发执行
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));
}
第一步:创建默认事件循环ESP_ERROR_CHECK(esp_event_loop_create_default());
创建了个事件循环
第二步:注册事件
//注册特定的定时器事件处理函数,定时器开始事件处理函数被注册了两次
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));
其中esp_event_handler_instance_register
函数定义
参数说明
- @param[in] event_base :事件类型id //这个翻译我觉得贴切点
- @param[in] event_id the :事件id
- @param[in] event_handler :处理函数入口
- @param[in] event_handler_arg: 处理函数参数
- @param[out] instance:一个与处理函数、数据相关连的 事件处理函数对象,可以为NULL。如果在删除整个event循环之前要注销特定回调实例,则需要保留此选项。我们允许多次注册同一个事件处理函数,但会产生不同的实例对象。如果循环中途不需要注销某特定处理函数实例,且处理函数也会随事件循环一同结束,则该参数可以为NULL。
便于理解参数 instance,扒了下定义,这下明白了,这是一个用于区分实例的上下文标识
接下来:
// Register the handler for all timer family events. This will execute if the timer is started, expired or is stopped.
//注册一个总处理函数,当事件id是started, expired,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.
//注册一个处理函数用于任务迭代事件(?翻译存疑),需要传递一个instance参数用于之后的注销
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.
//注册一个用于所有事件的handler,定时器事件和任务迭代事件也会触发执行
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");
esp_timer_create_args_t
定义:
第四步:创建与当前任务具有相同优先级的事件源任务
// 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));
定义xTaskCreate
用于创建任务
参数解释:
函数入口
进程名称
分配的栈大小
参数
优先级
句柄
定义esp_timer_start_periodic(TIMER, TIMER_PERIOD)
功能:启动一个定时器
参数:
- @param timer:使用esp_timer_create定义的定时器句柄
- @param period:设置定时器周期,单位ms
第五步:给定时器传递启动事件信号
// 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));
定义esp_event_post
- @param[in] event_base:事件类型
- @param[in] event_id :事件id
- @param[in] event_data: 数据,传递给处理程序的特定于事件发生的数据
- @param[in] event_data_size: 数据大小
- @param[in] ticks_to_wait :最大排队等待时间
补充
1.static char* get_id_string(esp_event_base_t base, int32_t id)
static char* get_id_string(esp_event_base_t base, int32_t id) { //获取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;
}
从函数名字和功能我们大概能知道,该函数用于获取当前事件id的。
其中参数@esp_event_base_t定义如下
故我判断这里的变量base是一个字符串类型,通过判断base的内容,即可知道当前是什么状态。
3.ESP_EVENT_DEFINE_BASE(TIMER_EVENTS); //定义EVENT_BASE
查看定义
对于id=#id这个用法我不是很理解
只能猜测是创建了一个esp_event_base_t变量,名称叫做id,且其值为传入的字符串id的值
对于esp_event_base_t:
显而易见,一个字符串常量标识