ESP32 IDF开发 应用篇⑬ 连接Wifi回调函数esp_event_handler_register专题
- 1、博主写这篇技术文章的目的:
- 2、 概述
- 3、 esp_event_handler_register函数的详细介绍
- 4、 总结
别迷路-导航栏
快速导航找到你想要的(文章目录)
此篇文章如果对你有用,请点赞收藏,您的支持就是博主坚持的动力。
1、博主写这篇技术文章的目的:
(1)、灵活运用wifi联网的全过程;
2、 概述
在前面章节已经为大家介绍了ESP32 WIFI STA 及AP模式的基本应用,本章是基于上一个章节的详细解析篇
所以理论不多说,直接主题。
3、 esp_event_handler_register函数的详细介绍
函数的实现是在esp-idf\components\esp_event\default_event_loop.c文件中
函数的功能:将事件处理程序注册到系统事件循环,在这里也列数来几个参数的功能
/**
* @brief 将事件处理程序注册到系统事件循环。
*
*此函数可用于注册以下任一处理程序:(1)特定事件,
*(2)某个事件基础的所有事件,或(3)系统事件循环已知的所有事件。
*
*-特定事件:指定确切的event_base和event_id
*-具有特定基准的所有事件:指定确切的event_base并将ESP_EVENT_ANY_ID用作event_id
*-循环已知的所有事件:将ESP_EVENT_ANY_BASE用作event_base,将ESP_EVENT_ANY_ID用作event_id
*
*可以将多个处理程序注册到事件。将单个处理程序注册到多个事件是
*也可以。但是,将同一处理程序多次注册到同一事件将导致
*以前的注册将被覆盖。
*
* @param [in] event_base事件的基本ID,用于为其注册处理程序
* @param [in] event_id要为其注册处理程序的事件的ID
* @param [in] event_handler处理程序函数,在调度事件时将调用该函数
* @param [in] event_handler_arg数据,除事件数据外,在调用时传递给处理程序
*
* @note 事件循环库不维护event_handler_arg的副本,因此用户应
*确保在调用处理程序时event_handler_arg仍指向有效位置
*
* @返回
*-ESP_OK:成功
*-ESP_ERR_NO_MEM:无法为处理程序分配内存
*-ESP_ERR_INVALID_ARG:事件库和事件ID的无效组合
*-其他:失败
*/
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);
以上是官方对改函数的介绍,下面我们具体分析函数的每一个参数的意义,及回调函数是怎么被执行的。
带着一下几个问题来分析:
(1)、函数
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,&event_handler, NULL)
中的WIFI_EVENT参数的原型是什么,event_base还可以传递哪些参数?
(2)、event_id有哪些,在回调函数中执行顺序是怎么样的?
(3)、系统时如何执行回调函数的?
解答上上问题:
(1)、event_base的分析:
①、首先event_base的数据类型是:
typedef const char* esp_event_base_t; /**< unique pointer to a subsystem that exposes events */
说明此传递的是一个字符串;
②、将传递的参数直接跳转到定义处发现有如下定义:
const char * WIFI_EVENT = "wifi_event";
const char * IP_EVENT = "ip_event";
const char * ETH_EVENT = "eth_event";
编写程序验证:在上一章的idf_wifi_sta.c文件中添加2条调试信息
//注册wifi 连接过程中回调函数
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
ESP_LOGI(TAG, "WIFI_EVENT :%s",WIFI_EVENT);
ESP_LOGI(TAG, "IP_EVENT :%s",IP_EVENT);
调试结果:
发现并不是上面的字符串。在使用Source Insight搜索WIFI_EVENT关键字时发现在esp-idf\components\esp_wifi\include\esp_wifi_types.h文件中有如下定义:
/** @brief WiFi event base declaration */
ESP_EVENT_DECLARE_BASE(WIFI_EVENT);
此处申明了WiFi event base declaration(wifi 事件的基本声明)
// Defines for declaring and defining event base
#define ESP_EVENT_DECLARE_BASE(id) extern esp_event_base_t id
搜索宏ESP_EVENT_DECLARE_BASE会发现系统中定义的回调事件还有:
•ETH_EVENT:以太网接口事件回调名称; •MESH_EVENT:wifi mesh事件回调名称;
•IP_EVENT:获得IP过程事件回调名称; •SC_EVENT:smartconfig过程事件回调名称;
•WEBSOCKET_EVENTS:websocket事件回调名称; •WIFI_EVENT:连接wifi事件回调名称;
•WIFI_PROV_EVENT:暂时不清楚;
(2)、event_id的解析
在每一个ESP_EVENT_DECLARE_BASE上面都有事件ID的枚举,以ESP_EVENT_DECLARE_BASE(WIFI_EVENT)为例:
/** WiFi event declarations */
typedef enum {
WIFI_EVENT_WIFI_READY = 0, /**< ESP32 WiFi ready */
WIFI_EVENT_SCAN_DONE, /**< ESP32 finish scanning AP */
WIFI_EVENT_STA_START, /**< ESP32 station start */
WIFI_EVENT_STA_STOP, /**< ESP32 station stop */
WIFI_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */
WIFI_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
WIFI_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */
WIFI_EVENT_STA_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */
WIFI_EVENT_STA_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */
WIFI_EVENT_STA_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */
WIFI_EVENT_STA_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */
WIFI_EVENT_STA_WPS_ER_PBC_OVERLAP, /**< ESP32 station wps overlap in enrollee mode */
WIFI_EVENT_AP_START, /**< ESP32 soft-AP start */
WIFI_EVENT_AP_STOP, /**< ESP32 soft-AP stop */
WIFI_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
WIFI_EVENT_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */
WIFI_EVENT_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */
WIFI_EVENT_MAX, /**< Invalid WiFi event ID */
} wifi_event_t;
以上就是WIFI_EVENT的所有ID。在实例中只用到:
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
{
}
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) //wifi断开时
{
}
(3)、回调函数esp_event_handler_t event_handler的执行:
在esp_event_loop_create_default函数中调用esp_event_loop_create,此函数中创建了回调函数的一些消息队列和信号量和创建任务:
esp_err_t esp_event_loop_create(const esp_event_loop_args_t* event_loop_args, esp_event_loop_handle_t* event_loop)
{
。。。
loop->queue = xQueueCreate(event_loop_args->queue_size , sizeof(esp_event_post_instance_t))
loop->mutex = xSemaphoreCreateRecursiveMutex();BaseType_t task_created = xTaskCreatePinnedToCore(esp_event_loop_run_task, event_loop_args->task_name,
event_loop_args->task_stack_size, (void*) loop,
event_loop_args->task_priority, &(loop->task), event_loop_args->task_core_id);
。。。。
}
在任务中等到消息队列和互斥信号量,接收到了就执行回调函数
static void esp_event_loop_run_task(void* args)
{
while(1) {
err = esp_event_loop_run(event_loop, portMAX_DELAY);
}
esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t ticks_to_run)
{
while(xQueueReceive(loop->queue, &post, ticks_to_run) == pdTRUE) {//等待有消息来
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);//等待接收信号
。。。
handler_execute(loop, handler, post);//执行回调函数
}
}
而函数esp_event_handler_register的主要功能就是把回调函数event_handler赋值给结构体
esp_event_handler_instance_t
一路跟踪代码最后在
static esp_err_t handler_instances_add(esp_event_handler_instances_t* handlers, esp_event_handler_t handler, void* handler_arg)
{
esp_event_handler_instance_t* handler_instance = calloc(1, sizeof(*handler_instance));
handler_instance->handler = handler;
handler_instance->arg = handler_arg;
}
最后在handler_execute函数中执行结构体esp_event_handler_instance_t
static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_instance_t *handler, esp_event_post_instance_t post)
{
(*(handler->handler))(handler->arg, post.base, post.id, post.data);
}
然而我找了半天也没有发现发送信号和消息的函数,只能猜测应该是在esp_wifi_start()函数发送,此函数被封装看不到代码。
4、 总结
经过上面的分析我们大概可以分为总结一下:
(1)。系统在初始化wifi的时候创建了一个wifi任务,通过消息和互斥信号的方式来控制任务的执行。
(2)、在启动wifi之后在连接AP或连接sta时会发送不同消息来触发不同事件ID这样,在回调函数中根据事件和id就知道wifi连接的全过程。
在函数:
static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{
ESP_LOGI(TAG, "event_base: %s ; event_id : %d",event_base,event_id);
}
打印所有的连接调试消息。