目录
ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(配网外设之WIFI)
版本信息: ESP-ADF v2.7-65-gcf908721
简介
ESP-ADF连接类外设为应用层提供了对WiFi、BLUFI(蓝牙WiFi配网)等多种网络连接设备的统一管理和接入方式,极大简化了网络设备的初始化、连接、断开以及事件通知流程。通过标准化的外设接口和事件机制,应用程序可以方便地感知和处理网络状态变化等事件,无需关心底层驱动和协议栈的具体实现细节。
连接类外设作为ESP-ADF外设子系统的重要组成部分,支持多种连接方式和配网方式,并与外设事件系统深度集成,能够满足音频应用对网络连接高可靠性、易用性和安全性的需求。
模块概述
功能定义
连接类外设主要实现以下功能:
- 统一管理WiFi等网络连接的初始化、连接、断开流程
- 对外提供标准化的事件通知接口,便于应用层感知网络状态变化
- 支持多种连接模式和灵活的配置参数,适应不同硬件和业务需求
- 提供蓝牙WiFi配网(BLUFI)功能,简化用户设备配网过程
- 通过esp_peripherals事件机制,实现连接外设与应用层的解耦,提升系统健壮性和可维护性
架构位置
连接类外设位于硬件网络驱动(如ESP32-WiFi驱动、ESP32-BLE驱动)与应用层之间,作为外设子系统的派生模块,负责对底层网络驱动的封装和统一管理。其架构位置如下图所示:
如图所示,BLUFI外设与WiFi外设存在合作关系,通过蓝牙传输WiFi配置信息,实现网络无缘配置。
核心特性
- 多种连接方式支持:支持WiFi的STA模式、AP模式、混合模式等多种连接方式,满足多样化的网络需求
- 自动重连与状态恢复:具备网络断开自动重连、状态恢复等能力,提高网络连接的可靠性
- 多种配网方式:支持SmartConfig、BLUFI(蓝牙WiFi配网)等多种配网方式,提高用户体验
- 统一事件模型:所有连接外设均采用统一的事件模型和接口,便于应用层集中处理
- 灵活配置参数:支持SSID、密码、安全模式、连接超时、重试次数等可配置参数,适应不同场景
- 安全数据传输:在BLUFI配网中实现数据加密和完整性验证,保障配网过程的安全性
- 与事件系统集成:与esp_peripherals事件系统深度集成,实现网络状态变化的实时通知和回调处理
WiFi外设(periph_wifi)
概述
WiFi外设为ESP-ADF提供统一的WiFi网络初始化、连接/断开、事件上报、配网等接口,屏蔽底层驱动细节。它支持自动重连、多种配网方式(SmartConfig、BLUFI、WPS等)和WPA2企业级安全认证,能满足各种网络连接场景的需求。
WiFi外设实现分为两个层次:
-
外设层:负责将WiFi集成到ESP-ADF外设系统中,处理事件分发和生命周期管理。
- 头文件:
components/esp_peripherals/include/periph_wifi.h
- 实现文件:
components/esp_peripherals/periph_wifi.c
- 头文件:
-
底层驱动层:由ESP-IDF的WiFi和网络组件提供,负责实际的网络处理和协议实现。
- ESP-IDF组件:
esp_wifi
、esp_netif
、esp_event
- ESP-IDF组件:
WiFi外设层次架构图
WiFi外设数据结构与API
外设层API
源文件:components/esp_peripherals/include/periph_wifi.h
和components/esp_peripherals/periph_wifi.c
公共API
// WiFi外设初始化函数
esp_periph_handle_t periph_wifi_init(periph_wifi_cfg_t* config);
// 等待WiFi连接成功
esp_err_t periph_wifi_wait_for_connected(esp_periph_handle_t periph, TickType_t tick_to_wait);
// 检查WiFi连接状态
periph_wifi_state_t periph_wifi_is_connected(esp_periph_handle_t periph);
// 设置WiFi监听间隔
esp_err_t esp_wifi_set_listen_interval(esp_periph_handle_t periph, int interval);
// 启动WiFi配网模式
esp_err_t periph_wifi_config_start(esp_periph_handle_t periph, periph_wifi_config_mode_t mode);
// 等待WiFi配网完成
esp_err_t periph_wifi_config_wait_done(esp_periph_handle_t periph, TickType_t tick_to_wait);
// WiFi事件类型
typedef enum {
PERIPH_WIFI_UNCHANGE = 0, // WiFi状态无变化
PERIPH_WIFI_CONNECTING, // WiFi正在连接
PERIPH_WIFI_CONNECTED, // WiFi已连接
PERIPH_WIFI_DISCONNECTED, // WiFi已断开
PERIPH_WIFI_SETTING, // WiFi配置中
PERIPH_WIFI_CONFIG_DONE, // WiFi配置完成
PERIPH_WIFI_CONFIG_ERROR, // WiFi配置错误
PERIPH_WIFI_ERROR, // WiFi错误
} periph_wifi_state_t;
// WiFi配网模式
typedef enum {
WIFI_CONFIG_ESPTOUCH, // 使用ESPTOUCH协议配网
WIFI_CONFIG_AIRKISS, // 使用AIRKISS协议配网
WIFI_CONFIG_ESPTOUCH_AIRKISS, // 同时支持ESPTOUCH和AIRKISS配网
WIFI_CONFIG_WPS, // 使用WPS配网(当前不支持)
WIFI_CONFIG_BLUEFI, // 使用BLUFI配网
WIFI_CONFIG_WEB, // 使用Web配网(当前不支持)
} periph_wifi_config_mode_t;
// WPA2企业级认证配置结构体
typedef struct {
bool diasble_wpa2_e; // 禁用WPA2企业级认证
int eap_method; // 认证方法(TLS: 0, PEAP: 1, TTLS: 2)
char *ca_pem_start; // CA证书PEM格式开始指针
char *ca_pem_end; // CA证书PEM格式结束指针
char *wpa2_e_cert_start; // 客户端证书开始指针
char *wpa2_e_cert_end; // 客户端证书结束指针
char *wpa2_e_key_start; // 客户端密钥开始指针
char *wpa2_e_key_end; // 客户端密钥结束指针
const char *eap_id; // EAP认证第一阶段的身份标识
const char *eap_username; // EAP方法的用户名(PEAP和TTLS模式)
const char *eap_password; // EAP方法的密码(PEAP和TTLS模式)
} periph_wpa2_enterprise_cfg_t;
// WiFi外设配置结构体
typedef struct {
bool disable_auto_reconnect; // 禁用自动重连
int reconnect_timeout_ms; // 重连超时时间
wifi_config_t wifi_config; // WiFi基本配置
periph_wpa2_enterprise_cfg_t wpa2_e_cfg; // WPA2企业级配置
} periph_wifi_cfg_t;
内部数据结构
// 默认重连超时时间
#define DEFAULT_RECONNECT_TIMEOUT_MS (1000)
// WiFi外设内部结构体 (定义在periph_wifi.c中)
struct periph_wifi {
periph_wifi_state_t wifi_state; // WiFi状态
bool disable_auto_reconnect; // 是否禁用自动重连
bool is_open; // WiFi是否已打开
uint8_t max_recon_time; // 最大重连次数
wifi_config_t wifi_config; // WiFi配置参数
EventGroupHandle_t state_event; // 状态事件组
int reconnect_timeout_ms; // 重连超时时间
periph_wifi_config_mode_t config_mode; // 配网模式
periph_wpa2_enterprise_cfg_t *wpa2_e_cfg; // WPA2企业级配置
};
WiFi外设配置选项
WiFi外设通过periph_wifi_cfg_t
结构体提供以下配置选项:
配置项 | 说明 | 默认值 | 示例值 |
---|---|---|---|
disable_auto_reconnect | 是否禁用自动重连功能 | false | true |
reconnect_timeout_ms | WiFi断开后重连的超时时间(毫秒) | 1000 | 5000 |
wifi_config | WiFi配置参数,包括SSID、密码等 | 空 | 见示例 |
wpa2_e_cfg | WPA2企业级认证配置 | 禁用 | 见示例 |
WiFi外设初始化流程
WiFi外设的初始化流程主要关注ESP-ADF框架中的外设层实现,该层负责将WiFi功能集成到ESP-ADF的外设系统中。虽然WiFi外设最终会调用ESP-IDF提供的底层WiFi API,但本节主要分析ESP-ADF中的外设封装实现。
外设层初始化过程(periph_wifi.c)
外设层初始化主要通过periph_wifi_init
函数(位于periph_wifi.c
)完成,主要包括以下步骤:
- 创建外设句柄:调用
esp_periph_create
函数创建外设句柄 - 分配内部数据结构:分配
periph_wifi_t
结构体内存 - 创建事件组:创建状态事件组用于同步状态
- 设置配置参数:设置重连超时、自动重连标志等
- 配置WPA2企业级认证:如果需要,分配并配置WPA2企业级认证
- 注册回调函数:设置初始化、运行和销毁回调函数
// 文件:components/esp_peripherals/periph_wifi.c
esp_periph_handle_t periph_wifi_init(periph_wifi_cfg_t *config)
{
// 声明外设句柄和WiFi外设结构指针
esp_periph_handle_t periph = NULL;
periph_wifi_handle_t periph_wifi = NULL;
// 一次性完成三个关键操作:
// 1. 创建外设句柄(PERIPH_ID_WIFI标识为WiFi外设)
// 2. 分配WiFi外设结构体内存
// 3. 创建FreeRTOS事件组用于同步WiFi连接状态
bool _success = ((periph = esp_periph_create(PERIPH_ID_WIFI, "periph_wifi"))
&& (periph_wifi = audio_calloc(1, sizeof(struct periph_wifi)))
&& (periph_wifi->state_event = xEventGroupCreate()));
// 检查上述操作是否全部成功,如果有任何一步失败则跳转到错误处理
AUDIO_MEM_CHECK(TAG, _success, goto _periph_wifi_init_failed);
// 设置WiFi重连超时时间,如果用户未指定则使用默认值
periph_wifi->reconnect_timeout_ms = config->reconnect_timeout_ms;
if (periph_wifi->reconnect_timeout_ms == 0) {
periph_wifi->reconnect_timeout_ms = DEFAULT_RECONNECT_TIMEOUT_MS; // 默认10秒
}
// 设置是否禁用自动重连功能
periph_wifi->disable_auto_reconnect = config->disable_auto_reconnect;
// 为WPA2企业级认证配置分配内存
periph_wifi->wpa2_e_cfg = audio_malloc(sizeof(periph_wpa2_enterprise_cfg_t));
AUDIO_NULL_CHECK(TAG, periph_wifi->wpa2_e_cfg, {
audio_free(periph); // 释放之前分配的外设句柄
goto _periph_wifi_init_failed;
});
// 复制WPA2企业级认证配置和WiFi连接配置
memcpy(periph_wifi->wpa2_e_cfg, &config->wpa2_e_cfg, sizeof(periph_wpa2_enterprise_cfg_t));
memcpy(&periph_wifi->wifi_config, &config->wifi_config, sizeof(wifi_config_t));
// 将WiFi外设结构与外设句柄关联
esp_periph_set_data(periph, periph_wifi);
// 设置外设的初始化、运行和销毁回调函数
esp_periph_set_function(periph, _wifi_init, _wifi_run, _wifi_destroy);
// 保存全局外设句柄(用于某些全局操作)
g_periph = periph;
return periph;
// 错误处理:清理已分配的资源
_periph_wifi_init_failed:
if (periph_wifi) {
vEventGroupDelete(periph_wifi->state_event); // 删除事件组
audio_free(periph_wifi); // 释放WiFi外设结构内存
}
return NULL;
}
当外设被添加到外设集合并启动时,会调用_wifi_init
函数(位于periph_wifi.c
),该函数负责实际的WiFi驱动初始化:
// 文件:components/esp_peripherals/periph_wifi.c
static esp_err_t _wifi_init(esp_periph_handle_t self)
{
// 从外设句柄中获取WiFi外设结构
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(self);
// 检查WiFi是否已经初始化,避免重复初始化
if (periph_wifi->is_open) {
ESP_LOGE(TAG, "Wifi has initialized");
return ESP_FAIL;
}
// 1. 创建事件循环并注册事件处理程序
// 根据ESP-IDF版本使用不同的事件处理方式
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
// ESP-IDF 4.0及以上版本使用新的事件循环 API
ESP_ERROR_CHECK(esp_event_loop_create_default());
// ESP-IDF 4.4及以上版本需要保存网络接口句柄
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0))
sta = esp_netif_create_default_wifi_sta();
#elif (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0))
// ESP-IDF 4.1-4.3版本不需要保存句柄
esp_netif_create_default_wifi_sta();
#endif
// 注册所有WiFi事件和IP获取事件的回调函数
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &_wifi_event_callback, self));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &_wifi_event_callback, self));
#else
// ESP-IDF 3.x版本使用旧的事件循环 API
if (esp_event_loop_get_queue() == NULL) {
// 如果事件循环尚未创建,则创建新的事件循环
ESP_ERROR_CHECK(esp_event_loop_init(_wifi_event_callback, self));
} else {
// 如果事件循环已存在,只需要设置回调函数
esp_event_loop_set_cb(_wifi_event_callback, self);
}
#endif
// 2. 初始化WiFi驱动
// 使用默认配置初始化WiFi驱动
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// 设置WiFi配置存储在RAM中(非持久化)
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
// 设置WiFi工作模式为站点模式(客户端模式)
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
// 设置WiFi连接参数(SSID、密码等)
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &periph_wifi->wifi_config));
// 设置电源管理模式为最小调制器模式(节省电力但保持连接)
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_MIN_MODEM));
// 3. 配置WPA2企业级认证(如果需要)
#ifdef CONFIG_ESP_WIFI_ENABLED
if (periph_wifi->wpa2_e_cfg->diasble_wpa2_e) {
// 这里实际会设置WPA2企业级认证的证书、密钥和身份信息
// 包括:
// - esp_wifi_sta_wpa2_ent_set_ca_cert() 设置CA证书
// - esp_wifi_sta_wpa2_ent_set_cert_key() 设置客户端证书和密钥
// - esp_wifi_sta_wpa2_ent_set_identity() 设置身份信息
// - esp_wifi_sta_wpa2_ent_set_username() 设置用户名
// - esp_wifi_sta_wpa2_ent_set_password() 设置密码
// ...省略细节代码...
// 启用WPA2企业级认证
ESP_ERROR_CHECK(esp_wifi_sta_wpa2_ent_enable());
}
#endif
// 4. 启动WiFi驱动并初始化状态
ESP_ERROR_CHECK(esp_wifi_start());
// 标记WiFi已经初始化
periph_wifi->is_open = true;
// 设置初始状态为未连接
periph_wifi->wifi_state = PERIPH_WIFI_DISCONNECTED;
// 清除连接标志位并设置断开连接标志位
xEventGroupClearBits(periph_wifi->state_event, CONNECTED_BIT);
xEventGroupSetBits(periph_wifi->state_event, DISCONNECTED_BIT);
return ESP_OK;
}
WiFi驱动初始化过程
WiFi驱动的初始化过程通过_wifi_init
函数完成,主要包括以下步骤:
- 验证初始化状态:确保WiFi尚未初始化
- 创建事件循环:根据ESP-IDF版本创建事件循环并注册事件处理程序
- 创建网络接口:创建默认WiFi站点接口
- 注册事件处理程序:注册WiFi和IP事件的回调函数
- 初始化WiFi驱动:使用默认配置初始化WiFi驱动
- 配置WiFi参数:设置WiFi工作模式、连接参数和电源管理模式
- 配置WPA2企业级认证:如果需要,设置证书、密钥和身份信息
- 启动WiFi:启动WiFi驱动并初始化状态标志
WiFi外设完整初始化时序图
下图展示了WiFi外设从应用程序调用到底层驱动完成初始化的完整流程:
WiFi事件回调函数
WiFi事件回调函数(_wifi_event_callback
)是WiFi外设实现的核心部分,负责处理WiFi连接过程中的各种事件,并触发相应的状态变化和通知。该函数根据ESP-IDF版本有两种不同的实现方式,但功能基本相同。
事件回调函数的主要功能
- 处理WiFi站点启动事件:当WiFi站点启动时,自动发起连接请求
- 处理IP获取事件:当成功获取IP地址时,更新连接状态并发送连接成功事件
- 处理断开连接事件:当WiFi断开连接时,更新状态并根据配置决定是否自动重连
- 维护WiFi状态:使用事件组和状态变量跟踪WiFi连接状态
ESP-IDF 4.0及以上版本的实现
// 文件:components/esp_peripherals/periph_wifi.c
static void _wifi_event_callback(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
// 获取外设句柄和WiFi外设结构
esp_periph_handle_t self = (esp_periph_handle_t)arg;
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(self);
// 处理WiFi站点启动事件
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
// WiFi驱动启动后,自动发起连接
esp_wifi_connect();
}
// 处理IP获取事件
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
// 获取IP地址信息并打印
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
ESP_LOGI(TAG, "Got ip:" IPSTR, IP2STR(&event->ip_info.ip));
// 更新WiFi状态为已连接
periph_wifi->wifi_state = PERIPH_WIFI_CONNECTED;
// 清除断开连接标志位,设置连接标志位
xEventGroupClearBits(periph_wifi->state_event, DISCONNECTED_BIT);
xEventGroupSetBits(periph_wifi->state_event, CONNECTED_BIT);
// 发送WiFi连接成功事件
esp_periph_send_event(self, PERIPH_WIFI_CONNECTED, NULL, 0);
// 保存当前连接的WiFi配置
wifi_config_t w_config;
memset(&w_config, 0x00, sizeof(wifi_config_t));
esp_wifi_get_config(WIFI_IF_STA, &w_config);
memcpy(&periph_wifi->wifi_config.sta.ssid, (char *)w_config.sta.ssid, sizeof(periph_wifi->wifi_config.sta.ssid));
}
// 处理WiFi断开连接事件
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
wifi_event_sta_disconnected_t *event = (wifi_event_sta_disconnected_t *) event_data;
// 如果是漫游导致的断开,则忽略
if (event->reason == WIFI_REASON_ROAMING) {
ESP_LOGI(TAG, "Wi-Fi Station Roaming");
return;
}
// 更新WiFi状态为已断开
periph_wifi->wifi_state = PERIPH_WIFI_DISCONNECTED;
// 清除连接标志位,设置断开连接标志位
xEventGroupClearBits(periph_wifi->state_event, CONNECTED_BIT);
xEventGroupSetBits(periph_wifi->state_event, DISCONNECTED_BIT);
// 发送WiFi断开连接事件
esp_periph_send_event(self, PERIPH_WIFI_DISCONNECTED, NULL, 0);
// 记录断开连接信息
ESP_LOGW(TAG, "Wi-Fi disconnected from SSID %s, auto-reconnect %s, reconnect after %d ms",
periph_wifi->wifi_config.sta.ssid,
periph_wifi->disable_auto_reconnect == 0 ? "enabled" : "disabled",
periph_wifi->reconnect_timeout_ms);
// 如果禁用自动重连,则直接返回
if (periph_wifi->disable_auto_reconnect) {
return;
}
// 启动重连定时器
esp_periph_start_timer(self, periph_wifi->reconnect_timeout_ms / portTICK_RATE_MS, wifi_reconnect_timer);
}
// 处理其他未处理的事件
else {
ESP_LOGW(TAG, "WiFi Event cb, Unhandle event_base:%s, event_id:%d", event_base, (int)event_id);
}
}
ESP-IDF 3.x版本的实现
// 文件:components/esp_peripherals/periph_wifi.c
static esp_err_t _wifi_event_callback(void *ctx, system_event_t *event)
{
// 获取外设句柄和WiFi外设结构
esp_periph_handle_t self = (esp_periph_handle_t)ctx;
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(self);
// 根据不同事件类型处理
switch (event->event_id) {
// WiFi站点启动事件
case SYSTEM_EVENT_STA_START:
periph_wifi->wifi_state = PERIPH_WIFI_CONNECTING;
esp_wifi_connect();
break;
// WiFi站点已连接事件(仅连接到AP,尚未获取IP)
case SYSTEM_EVENT_STA_CONNECTED:
break;
// 获取IP地址事件
case SYSTEM_EVENT_STA_GOT_IP:
// 更新WiFi状态为已连接
periph_wifi->wifi_state = PERIPH_WIFI_CONNECTED;
// 清除断开连接标志位,设置连接标志位
xEventGroupClearBits(periph_wifi->state_event, DISCONNECTED_BIT);
xEventGroupSetBits(periph_wifi->state_event, CONNECTED_BIT);
// 发送WiFi连接成功事件
esp_periph_send_event(self, PERIPH_WIFI_CONNECTED, NULL, 0);
// 保存当前连接的WiFi配置
wifi_config_t w_config;
memset(&w_config, 0x00, sizeof(wifi_config_t));
esp_wifi_get_config(WIFI_IF_STA, &w_config);
memcpy(&periph_wifi->wifi_config.sta.ssid, (char *)w_config.sta.ssid, sizeof(periph_wifi->wifi_config.sta.ssid));
break;
// WiFi断开连接事件
case SYSTEM_EVENT_STA_DISCONNECTED:
// 更新WiFi状态为已断开
periph_wifi->wifi_state = PERIPH_WIFI_DISCONNECTED;
// 清除连接标志位,设置断开连接标志位
xEventGroupClearBits(periph_wifi->state_event, CONNECTED_BIT);
xEventGroupSetBits(periph_wifi->state_event, DISCONNECTED_BIT);
// 发送WiFi断开连接事件
esp_periph_send_event(self, PERIPH_WIFI_DISCONNECTED, NULL, 0);
// 记录断开连接信息
ESP_LOGW(TAG, "Wi-Fi disconnected from SSID %s, auto-reconnect %s, reconnect after %d ms",
periph_wifi->wifi_config.sta.ssid,
periph_wifi->disable_auto_reconnect == 0 ? "enabled" : "disabled",
periph_wifi->reconnect_timeout_ms);
// 如果禁用自动重连,则直接跳出
if (periph_wifi->disable_auto_reconnect) {
break;
}
// 启动重连定时器
esp_periph_start_timer(self, periph_wifi->reconnect_timeout_ms / portTICK_RATE_MS, wifi_reconnect_timer);
break;
// 其他未处理的事件
default:
break;
}
return ESP_OK;
}
WiFi事件处理流程图
WiFi事件回调的关键作用
- 状态管理:通过事件组和状态变量维护WiFi连接状态,使应用程序可以查询当前状态
- 事件通知:通过
esp_periph_send_event
向应用程序发送WiFi状态变化事件 - 自动重连:在断开连接时,根据配置自动启动重连定时器
- 版本兼容:针对不同ESP-IDF版本提供不同的实现,保证代码兼容性
通过这个事件回调函数,WiFi外设能够自动处理连接、断开和重连过程,为应用程序提供稳定的WiFi连接服务。
WiFi外设销毁流程
WiFi外设的销毁流程主要通过_wifi_destroy
函数(位于periph_wifi.c
)完成,主要包括以下步骤:
- 停止定时器:停止可能正在运行的重连定时器
- 禁用自动重连:设置标志位禁止自动重连
- 断开WiFi连接:主动断开当前WiFi连接
- 等待断开完成:等待WiFi完全断开连接
- 停止WiFi驱动:停止并反初始化WiFi驱动
- 释放资源:删除事件组、释放内存等
销毁函数实现
// 文件:components/esp_peripherals/periph_wifi.c
static esp_err_t _wifi_destroy(esp_periph_handle_t self)
{
// 获取WiFi外设结构
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(self);
// 停止可能正在运行的重连定时器
esp_periph_stop_timer(self);
// 禁用自动重连功能,防止在销毁过程中触发重连
periph_wifi->disable_auto_reconnect = true;
// 主动断开当前WiFi连接
esp_wifi_disconnect();
// 等待WiFi完全断开连接
periph_wifi_wait_for_disconnected(self, portMAX_DELAY);
// 停止WiFi驱动
esp_wifi_stop();
// 反初始化WiFi驱动,释放WiFi资源
esp_wifi_deinit();
// 删除事件组
vEventGroupDelete(periph_wifi->state_event);
// 释放WPA2企业级认证配置内存
if (periph_wifi->wpa2_e_cfg != NULL) {
audio_free(periph_wifi->wpa2_e_cfg);
periph_wifi->wpa2_e_cfg = NULL;
}
// 释放WiFi外设结构内存
audio_free(periph_wifi);
// 清除全局外设句柄
g_periph = NULL;
// 在ESP-IDF 4.4及以上版本中,删除默认事件循环和网络接口
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0))
esp_event_loop_delete_default();
esp_netif_destroy_default_wifi(sta);
#endif
return ESP_OK;
}
等待断开连接函数
WiFi销毁过程中使用periph_wifi_wait_for_disconnected
函数等待WiFi完全断开连接,确保资源可以安全释放:
// 文件:components/esp_peripherals/periph_wifi.c
esp_err_t periph_wifi_wait_for_disconnected(esp_periph_handle_t periph, TickType_t tick_to_wait)
{
// 验证WiFi外设句柄
VALIDATE_WIFI(periph, ESP_FAIL);
// 获取WiFi外设结构
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(periph);
// 等待断开连接标志位,最长等待时间由tick_to_wait指定
EventBits_t disconnected_bit = xEventGroupWaitBits(periph_wifi->state_event,
DISCONNECTED_BIT,
false, true, tick_to_wait);
// 检查是否成功获取到断开连接标志位
if (disconnected_bit & DISCONNECTED_BIT) {
return ESP_OK;
}
return ESP_FAIL;
}
WiFi外设销毁时序图
下图展示了WiFi外设销毁过程中的完整调用流程:
销毁流程的关键点
- 资源释放顺序:WiFi外设销毁过程遵循先断开连接、停止服务,再释放内存资源的原则
- 等待机制:使用事件组等待断开连接完成,确保资源安全释放
- 版本兼容:针对不同ESP-IDF版本提供不同的资源释放方式
- 防止重连:在销毁过程中禁用自动重连功能,避免资源冲突
通过这种完整的销毁流程,WiFi外设能够安全地释放所有资源,防止内存泄漏和资源残留问题。
WiFi外设事件处理机制
WiFi外设通过事件处理机制捕获并处理网络事件,将ESP-IDF底层的WiFi事件转换为ESP-ADF外设系统的事件,并进行相应处理。这种机制使应用程序能够方便地响应WiFi状态变化。
事件处理流程
WiFi外设的事件处理流程主要包括以下几个部分:
- 事件产生:WiFi驱动层产生原始事件(连接、断开、获取IP等)
- 事件捕获:通过
_wifi_event_callback
函数捕获WiFi事件 - 事件转换:将WiFi事件转换为ESP-ADF外设事件
- 事件分发:通过
esp_periph_send_event
函数将事件分发给应用程序 - 事件处理:应用程序通过注册的回调函数处理事件
运行时事件处理函数
WiFi外设的运行时事件处理通过_wifi_run
函数实现,该函数在外设接收到事件时被调用:
// 文件:components/esp_peripherals/periph_wifi.c
static esp_err_t _wifi_run(esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{
// 直接将接收到的事件转发出去
esp_periph_send_event(self, msg->cmd, NULL, 0);
return ESP_OK;
}
这个函数看似简单,但它在WiFi外设的事件处理流程中扮演着重要角色:
- 接收来自ESP-ADF外设系统的事件消息
- 通过
esp_periph_send_event
将事件转发给应用程序 - 实现事件的双向传递(从应用程序到外设,再从外设回到应用程序)
事件发送机制
事件发送通过esp_periph_send_event
函数实现,该函数位于esp_peripherals.c
:
// 文件:components/esp_peripherals/esp_peripherals.c
esp_err_t esp_periph_send_event(esp_periph_handle_t periph, int event_id, void *data, int data_len)
{
// 检查外设是否有注册事件接收器
if (periph->on_evt == NULL) {
return ESP_FAIL;
}
// 构造事件消息
audio_event_iface_msg_t msg;
msg.source_type = periph->periph_id; // 设置事件源类型为外设ID
msg.cmd = event_id; // 设置事件ID
msg.data = data; // 设置事件数据
msg.data_len = data_len; // 设置数据长度
msg.need_free_data = false; // 数据不需要自动释放
msg.source = periph; // 设置事件源为当前外设
// 如果注册了回调函数,则直接调用
if (periph->on_evt->cb) {
periph->on_evt->cb(&msg, periph->on_evt->user_ctx);
}
// 通过事件接口发送事件
return audio_event_iface_sendout(periph->on_evt->iface, &msg);
}
WiFi事件类型
WiFi外设定义了多种事件类型,用于表示不同的WiFi状态和操作结果:
事件ID | 描述 | 触发条件 |
---|---|---|
PERIPH_WIFI_CONNECTING | WiFi正在连接 | WiFi站点启动并开始连接 |
PERIPH_WIFI_CONNECTED | WiFi已连接 | 成功连接到AP并获取IP地址 |
PERIPH_WIFI_DISCONNECTED | WiFi已断开 | 与AP的连接断开 |
PERIPH_WIFI_CONFIG_DONE | WiFi配置完成 | 通过配网方式成功配置WiFi |
PERIPH_WIFI_CONFIG_ERROR | WiFi配置错误 | 配网过程中发生错误 |
事件处理流程图
下图展示了WiFi外设事件从产生到处理的完整流程:
事件处理状态图
WiFi外设的事件处理可以用以下状态图表示:
事件处理的关键作用
- 状态同步:通过事件机制保持应用程序与WiFi状态的同步
- 解耦合:将WiFi状态变化与应用程序逻辑解耦,提高代码可维护性
- 灵活配置:应用程序可以根据需要选择性地处理感兴趣的事件
- 异步处理:事件机制支持异步处理,避免阻塞主程序流程
通过这种完善的事件处理机制,ESP-ADF的WiFi外设能够与应用程序进行高效的通信,使应用程序能够及时响应网络状态变化,提供更好的用户体验。
WiFi外设服务函数
除了初始化、销毁和事件处理函数外,WiFi外设还提供了一系列辅助服务函数,用于查询状态、等待连接、配置参数和启动配网等操作。这些函数为应用程序提供了更灵活的WiFi管理能力。
连接状态查询与等待
查询WiFi连接状态
// 文件:components/esp_peripherals/periph_wifi.c
periph_wifi_state_t periph_wifi_is_connected(esp_periph_handle_t periph)
{
VALIDATE_WIFI(periph, PERIPH_WIFI_DISCONNECTED);
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(periph);
return periph_wifi->wifi_state;
}
该函数用于查询当前WiFi连接状态,返回值为periph_wifi_state_t
枚举类型,包括:
PERIPH_WIFI_UNCHANGE
:WiFi状态未改变PERIPH_WIFI_CONNECTING
:正在连接WiFiPERIPH_WIFI_CONNECTED
:已连接WiFiPERIPH_WIFI_DISCONNECTED
:已断开WiFi连接PERIPH_WIFI_SETTING
:正在设置WiFiPERIPH_WIFI_CONFIG_DONE
:WiFi配置完成PERIPH_WIFI_CONFIG_ERROR
:WiFi配置错误PERIPH_WIFI_ERROR
:WiFi发生错误
等待WiFi连接完成
// 文件:components/esp_peripherals/periph_wifi.c
esp_err_t periph_wifi_wait_for_connected(esp_periph_handle_t periph, TickType_t tick_to_wait)
{
VALIDATE_WIFI(periph, ESP_FAIL);
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(periph);
EventBits_t connected_bit = xEventGroupWaitBits(periph_wifi->state_event, CONNECTED_BIT, false, true, tick_to_wait);
if (connected_bit & CONNECTED_BIT) {
return ESP_OK;
}
return ESP_FAIL;
}
该函数用于阻塞等待WiFi连接完成,主要特点:
- 使用FreeRTOS事件组等待连接状态
- 参数
tick_to_wait
指定最长等待时间 - 当WiFi成功连接或超时时返回
- 返回值为
ESP_OK
表示连接成功,ESP_FAIL
表示等待超时
WiFi参数配置
设置监听间隔
// 文件:components/esp_peripherals/periph_wifi.c
esp_err_t esp_wifi_set_listen_interval(esp_periph_handle_t periph, int interval)
{
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(periph);
if (periph_wifi->wifi_config.sta.listen_interval != interval) {
periph_wifi->wifi_config.sta.listen_interval = interval;
} else {
ESP_LOGW(TAG, "Wifi listen interval %d is already set", interval);
}
return ESP_OK;
}
该函数用于设置WiFi站点模式下的监听间隔,主要作用:
- 设置ESP32接收AP信标的间隔时间
- 参数
interval
单位为AP信标间隔(默认100ms) - 较大的监听间隔可以降低功耗,但可能增加延迟
- 该设置在下次连接WiFi时生效
WiFi配网功能
启动WiFi配网
// 文件:components/esp_peripherals/periph_wifi.c
esp_err_t periph_wifi_config_start(esp_periph_handle_t periph, periph_wifi_config_mode_t mode)
{
VALIDATE_WIFI(periph, ESP_FAIL);
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(periph);
periph_wifi->wifi_state = PERIPH_WIFI_SETTING;
// 根据不同配网模式启动相应的配网方式
switch (mode) {
case WIFI_CONFIG_ESPTOUCH:
// 启动ESPTOUCH配网
// ...
break;
case WIFI_CONFIG_BLUEFI:
// 启动蓝牙配网
// ...
break;
default:
ESP_LOGE(TAG, "Not supported wifi config mode");
return ESP_FAIL;
}
return ESP_OK;
}
该函数用于启动WiFi配网过程,支持多种配网模式:
WIFI_CONFIG_ESPTOUCH
:使用ESP-Touch协议(手机App发送配网信息)WIFI_CONFIG_AIRKISS
:使用微信Airkiss协议WIFI_CONFIG_ESPTOUCH_AIRKISS
:同时支持ESP-Touch和AirkissWIFI_CONFIG_BLUEFI
:使用蓝牙BLE配网WIFI_CONFIG_WPS
:使用WPS配网(尚未支持)WIFI_CONFIG_WEB
:使用Web配网(尚未支持)
等待配网完成
// 文件:components/esp_peripherals/periph_wifi.c
esp_err_t periph_wifi_config_wait_done(esp_periph_handle_t periph, TickType_t tick_to_wait)
{
VALIDATE_WIFI(periph, ESP_FAIL);
periph_wifi_handle_t periph_wifi = (periph_wifi_handle_t)esp_periph_get_data(periph);
// 等待配网完成或超时
uint32_t start_ticks = xTaskGetTickCount();
while (1) {
if (periph_wifi->wifi_state == PERIPH_WIFI_CONFIG_DONE) {
return ESP_OK;
} else if (periph_wifi->wifi_state == PERIPH_WIFI_CONFIG_ERROR) {
return ESP_FAIL;
}
// 检查是否超时
if ((xTaskGetTickCount() - start_ticks) > tick_to_wait) {
return ESP_FAIL;
}
vTaskDelay(100 / portTICK_RATE_MS);
}
}
该函数用于阻塞等待WiFi配网过程完成,主要特点:
- 参数
tick_to_wait
指定最长等待时间 - 定期检查配网状态,直到成功、失败或超时
- 返回值为
ESP_OK
表示配网成功,ESP_FAIL
表示配网失败或超时
服务函数调用流程图
下图展示了WiFi外设服务函数的典型调用流程:
服务函数使用示例
以下是WiFi外设服务函数的典型使用示例:
// 初始化WiFi外设
periph_wifi_cfg_t wifi_cfg = {
.wifi_config = {
.sta = {
.ssid = "my_wifi_ssid",
.password = "my_wifi_password",
},
},
.disable_auto_reconnect = false
};
esp_periph_handle_t wifi_periph = periph_wifi_init(&wifi_cfg);
// 启动WiFi外设
esp_periph_start(wifi_periph);
// 等待WiFi连接完成(最多等待30秒)
if (periph_wifi_wait_for_connected(wifi_periph, 30000 / portTICK_RATE_MS) == ESP_OK) {
ESP_LOGI(TAG, "WiFi连接成功");
} else {
ESP_LOGE(TAG, "WiFi连接超时,启动配网");
// 启动蓝牙配网
periph_wifi_config_start(wifi_periph, WIFI_CONFIG_BLUEFI);
// 等待配网完成(最多等待120秒)
if (periph_wifi_config_wait_done(wifi_periph, 120000 / portTICK_RATE_MS) == ESP_OK) {
ESP_LOGI(TAG, "WiFi配网成功");
} else {
ESP_LOGE(TAG, "WiFi配网失败");
}
}
// 查询WiFi状态
periph_wifi_state_t state = periph_wifi_is_connected(wifi_periph);
if (state == PERIPH_WIFI_CONNECTED) {
ESP_LOGI(TAG, "WiFi已连接");
}
// 设置WiFi监听间隔(省电模式)
esp_wifi_set_listen_interval(wifi_periph, 5);
通过这些服务函数,应用程序可以灵活地管理WiFi连接、查询状态、配置参数和启动配网,为ESP-ADF应用提供完善的WiFi管理能力。