ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(配网外设之WIFI)

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驱动)与应用层之间,作为外设子系统的派生模块,负责对底层网络驱动的封装和统一管理。其架构位置如下图所示:

应用程序
ESP外设子系统
连接类外设
WiFi外设
BLUFI外设
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外设实现分为两个层次:

  1. 外设层:负责将WiFi集成到ESP-ADF外设系统中,处理事件分发和生命周期管理。

    • 头文件:components/esp_peripherals/include/periph_wifi.h
    • 实现文件:components/esp_peripherals/periph_wifi.c
  2. 底层驱动层:由ESP-IDF的WiFi和网络组件提供,负责实际的网络处理和协议实现。

    • ESP-IDF组件:esp_wifiesp_netifesp_event
WiFi外设层次架构图
底层驱动层 ESP-IDF WiFi
外设层 periph_wifi.c
调用
创建
设置
设置
设置
调用
调用
调用
调用
发送
触发
处理
发送
通知
WiFi驱动
esp_wifi_init
WiFi事件系统
esp_event_handler_register
_wifi_init
periph_wifi_init
_wifi_run
_wifi_destroy
ESP-ADF应用
esp_periph实例
esp_wifi_disconnect
esp_event_handler_unregister
PERIPH_WIFI_CONNECTING事件
WIFI_EVENT事件
_wifi_event_callback
PERIPH_WIFI_CONNECTED/DISCONNECTED事件

WiFi外设数据结构与API

外设层API

源文件components/esp_peripherals/include/periph_wifi.hcomponents/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是否禁用自动重连功能falsetrue
reconnect_timeout_msWiFi断开后重连的超时时间(毫秒)10005000
wifi_configWiFi配置参数,包括SSID、密码等见示例
wpa2_e_cfgWPA2企业级认证配置禁用见示例

WiFi外设初始化流程

WiFi外设的初始化流程主要关注ESP-ADF框架中的外设层实现,该层负责将WiFi功能集成到ESP-ADF的外设系统中。虽然WiFi外设最终会调用ESP-IDF提供的底层WiFi API,但本节主要分析ESP-ADF中的外设封装实现。

外设层初始化过程(periph_wifi.c)

外设层初始化主要通过periph_wifi_init函数(位于periph_wifi.c)完成,主要包括以下步骤:

  1. 创建外设句柄:调用esp_periph_create函数创建外设句柄
  2. 分配内部数据结构:分配periph_wifi_t结构体内存
  3. 创建事件组:创建状态事件组用于同步状态
  4. 设置配置参数:设置重连超时、自动重连标志等
  5. 配置WPA2企业级认证:如果需要,分配并配置WPA2企业级认证
  6. 注册回调函数:设置初始化、运行和销毁回调函数
// 文件: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函数完成,主要包括以下步骤:

  1. 验证初始化状态:确保WiFi尚未初始化
  2. 创建事件循环:根据ESP-IDF版本创建事件循环并注册事件处理程序
  3. 创建网络接口:创建默认WiFi站点接口
  4. 注册事件处理程序:注册WiFi和IP事件的回调函数
  5. 初始化WiFi驱动:使用默认配置初始化WiFi驱动
  6. 配置WiFi参数:设置WiFi工作模式、连接参数和电源管理模式
  7. 配置WPA2企业级认证:如果需要,设置证书、密钥和身份信息
  8. 启动WiFi:启动WiFi驱动并初始化状态标志
WiFi外设完整初始化时序图

下图展示了WiFi外设从应用程序调用到底层驱动完成初始化的完整流程:

应用程序 periph_wifi_init (periph_wifi.c) esp_periph库 _wifi_init (periph_wifi.c) esp_wifi驱动 事件系统 periph_wifi_init(config) esp_periph_create(PERIPH_ID_WIFI, "periph_wifi") periph 分配 periph_wifi_t 结构体 创建状态事件组 设置重连超时、自动重连标志等 配置WPA2企业级认证 esp_periph_set_data(periph, periph_wifi) esp_periph_set_function(periph, _wifi_init, _wifi_run, _wifi_destroy) periph 当外设被添加到外设集合并启动时 _wifi_init(self) esp_periph_get_data(self) periph_wifi esp_event_loop_create_default() esp_netif_create_default_wifi_sta() esp_event_handler_register(WIFI_EVENT, ...) esp_event_handler_register(IP_EVENT, ...) esp_wifi_init(&cfg) esp_wifi_set_storage(WIFI_STORAGE_RAM) esp_wifi_set_mode(WIFI_MODE_STA) esp_wifi_set_config(WIFI_IF_STA, &periph_wifi->>wifi_config) esp_wifi_sta_wpa2_ent_set_ca_cert(...) esp_wifi_sta_wpa2_ent_set_cert_key(...) esp_wifi_sta_wpa2_ent_set_identity(...) esp_wifi_sta_wpa2_ent_enable() alt [启用WPA2企业级认证] esp_wifi_start() 初始化状态标志 ESP_OK 应用程序 periph_wifi_init (periph_wifi.c) esp_periph库 _wifi_init (periph_wifi.c) esp_wifi驱动 事件系统
WiFi事件回调函数

WiFi事件回调函数(_wifi_event_callback)是WiFi外设实现的核心部分,负责处理WiFi连接过程中的各种事件,并触发相应的状态变化和通知。该函数根据ESP-IDF版本有两种不同的实现方式,但功能基本相同。

事件回调函数的主要功能
  1. 处理WiFi站点启动事件:当WiFi站点启动时,自动发起连接请求
  2. 处理IP获取事件:当成功获取IP地址时,更新连接状态并发送连接成功事件
  3. 处理断开连接事件:当WiFi断开连接时,更新状态并根据配置决定是否自动重连
  4. 维护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事件处理流程图
站点启动
获取IP
断开连接
其他事件
WiFi事件发生
事件类型?
发起WiFi连接
更新状态为已连接
清除断开标志位
设置连接标志位
发送连接成功事件
保存当前WiFi配置
更新状态为已断开
清除连接标志位
设置断开标志位
发送断开连接事件
是否启用自动重连?
启动重连定时器
结束处理
记录未处理事件
WiFi事件回调的关键作用
  1. 状态管理:通过事件组和状态变量维护WiFi连接状态,使应用程序可以查询当前状态
  2. 事件通知:通过esp_periph_send_event向应用程序发送WiFi状态变化事件
  3. 自动重连:在断开连接时,根据配置自动启动重连定时器
  4. 版本兼容:针对不同ESP-IDF版本提供不同的实现,保证代码兼容性

通过这个事件回调函数,WiFi外设能够自动处理连接、断开和重连过程,为应用程序提供稳定的WiFi连接服务。

WiFi外设销毁流程

WiFi外设的销毁流程主要通过_wifi_destroy函数(位于periph_wifi.c)完成,主要包括以下步骤:

  1. 停止定时器:停止可能正在运行的重连定时器
  2. 禁用自动重连:设置标志位禁止自动重连
  3. 断开WiFi连接:主动断开当前WiFi连接
  4. 等待断开完成:等待WiFi完全断开连接
  5. 停止WiFi驱动:停止并反初始化WiFi驱动
  6. 释放资源:删除事件组、释放内存等
销毁函数实现
// 文件: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外设销毁过程中的完整调用流程:

应用程序 esp_periph库 _wifi_destroy (periph_wifi.c) periph_wifi_wait_for_disconnected (periph_wifi.c) esp_wifi驱动 事件系统 esp_periph_destroy(periph) _wifi_destroy(self) esp_periph_stop_timer(self) 禁用自动重连 esp_wifi_disconnect() periph_wifi_wait_for_disconnected(self, portMAX_DELAY) 等待DISCONNECTED_BIT事件标志 ESP_OK esp_wifi_stop() esp_wifi_deinit() 删除事件组 释放WPA2企业级认证配置内存 释放WiFi外设结构内存 esp_event_loop_delete_default() esp_netif_destroy_default_wifi(sta) alt [ESP-IDF 4.4及以上版本] ESP_OK ESP_OK 应用程序 esp_periph库 _wifi_destroy (periph_wifi.c) periph_wifi_wait_for_disconnected (periph_wifi.c) esp_wifi驱动 事件系统
销毁流程的关键点
  1. 资源释放顺序:WiFi外设销毁过程遵循先断开连接、停止服务,再释放内存资源的原则
  2. 等待机制:使用事件组等待断开连接完成,确保资源安全释放
  3. 版本兼容:针对不同ESP-IDF版本提供不同的资源释放方式
  4. 防止重连:在销毁过程中禁用自动重连功能,避免资源冲突

通过这种完整的销毁流程,WiFi外设能够安全地释放所有资源,防止内存泄漏和资源残留问题。

WiFi外设事件处理机制

WiFi外设通过事件处理机制捕获并处理网络事件,将ESP-IDF底层的WiFi事件转换为ESP-ADF外设系统的事件,并进行相应处理。这种机制使应用程序能够方便地响应WiFi状态变化。

事件处理流程

WiFi外设的事件处理流程主要包括以下几个部分:

  1. 事件产生:WiFi驱动层产生原始事件(连接、断开、获取IP等)
  2. 事件捕获:通过_wifi_event_callback函数捕获WiFi事件
  3. 事件转换:将WiFi事件转换为ESP-ADF外设事件
  4. 事件分发:通过esp_periph_send_event函数将事件分发给应用程序
  5. 事件处理:应用程序通过注册的回调函数处理事件
运行时事件处理函数

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外设的事件处理流程中扮演着重要角色:

  1. 接收来自ESP-ADF外设系统的事件消息
  2. 通过esp_periph_send_event将事件转发给应用程序
  3. 实现事件的双向传递(从应用程序到外设,再从外设回到应用程序)
事件发送机制

事件发送通过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_CONNECTINGWiFi正在连接WiFi站点启动并开始连接
PERIPH_WIFI_CONNECTEDWiFi已连接成功连接到AP并获取IP地址
PERIPH_WIFI_DISCONNECTEDWiFi已断开与AP的连接断开
PERIPH_WIFI_CONFIG_DONEWiFi配置完成通过配网方式成功配置WiFi
PERIPH_WIFI_CONFIG_ERRORWiFi配置错误配网过程中发生错误
事件处理流程图

下图展示了WiFi外设事件从产生到处理的完整流程:

ESP-IDF WiFi驱动 _wifi_event_callback _wifi_run esp_periph_send_event 应用程序回调 WiFi事件(连接、断开、IP等) 更新WiFi状态 esp_periph_send_event(PERIPH_WIFI_*) 调用应用程序注册的回调 发送命令到WiFi外设 esp_periph_send_event(msg->>cmd) 转发事件回应用程序 ESP-IDF WiFi驱动 _wifi_event_callback _wifi_run esp_periph_send_event 应用程序回调
事件处理状态图

WiFi外设的事件处理可以用以下状态图表示:

_wifi_init完成
WIFI_EVENT_STA_START
IP_EVENT_STA_GOT_IP
WIFI_EVENT_STA_DISCONNECTED
WIFI_EVENT_STA_DISCONNECTED
自动重连定时器触发
初始化
已断开
连接中
已连接
事件处理的关键作用
  1. 状态同步:通过事件机制保持应用程序与WiFi状态的同步
  2. 解耦合:将WiFi状态变化与应用程序逻辑解耦,提高代码可维护性
  3. 灵活配置:应用程序可以根据需要选择性地处理感兴趣的事件
  4. 异步处理:事件机制支持异步处理,避免阻塞主程序流程

通过这种完善的事件处理机制,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:正在连接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发生错误
等待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和Airkiss
  • WIFI_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外设服务函数的典型调用流程:

应用程序 periph_wifi_is_connected periph_wifi_wait_for_connected periph_wifi_config_start periph_wifi_config_wait_done periph_wifi_is_connected(periph) 返回当前WiFi状态 alt [查询连接状态] periph_wifi_wait_for_connected(periph, timeout) 等待CONNECTED_BIT事件标志 ESP_OK或ESP_FAIL alt [等待连接完成] periph_wifi_config_start(periph, mode) 根据mode启动相应配网方式 ESP_OK或ESP_FAIL periph_wifi_config_wait_done(periph, timeout) 轮询检查配网状态 ESP_OK或ESP_FAIL alt [启动WiFi配网] 应用程序 periph_wifi_is_connected periph_wifi_wait_for_connected periph_wifi_config_start periph_wifi_config_wait_done
服务函数使用示例

以下是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管理能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

omnibots

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值