版本信息: v2.7-65-gcf908721
本章节分析的源码位于
/components/wifi_service/src/esp_wifi_setting.c
文件
ESP-ADF的esp_wifi_setting模块内部定义了一个核心结构体,用于封装WiFi配网接口的实现:
struct esp_wifi_setting {
wifi_setting_func start; /*!< 启动配网的函数指针 */
wifi_setting_func stop; /*!< 停止配网的函数指针 */
wifi_setting_teardown_func teardown; /*!< 清理配网资源的函数指针 */
bool running; /*!< 配网是否正在运行 */
char *tag; /*!< 配网方式的标签名称 */
void *user_data; /*!< 用户自定义数据 */
void *notify_handle; /*!< 通知句柄(通常是WiFi服务句柄) */
};
这个结构体设计体现了ESP-ADF中插件式架构的思想:
start
、stop
、teardown
)实现多态行为running
标志跟踪配网状态user_data
指针支持自定义数据扩展notify_handle
实现配网结果的回传tag
标签支持日志输出下面的图表展示了esp_wifi_setting
结构与函数指针和外部组件的关系:
这个图表展示了esp_wifi_setting
结构体如何通过函数指针关联具体配网实现,以及如何通过notify_handle
与WiFi服务交互。这种设计模式实现了高度的解耦和可扩展性。
esp_wifi_setting_create
函数用于创建一个新的WiFi配置接口实例:
/**
* @brief 创建WiFi配置接口实例
*
* 该函数完成以下主要操作:
* 1. 分配esp_wifi_setting结构体内存
* 2. 设置配置实例的标签名
* 3. 初始化结构体其他成员为默认值
*
* @param tag 配置接口实例的标签名,用于调试输出识别
* @return 成功返回esp_wifi_setting_handle_t句柄,失败返回NULL
*/
esp_wifi_setting_handle_t esp_wifi_setting_create(const char *tag)
{
// 分配内存并初始化为全0
esp_wifi_setting_handle_t new_entry = audio_calloc(1, sizeof(struct esp_wifi_setting));
AUDIO_MEM_CHECK(TAG, new_entry, return NULL);
// 设置标签名,如果未提供则使用默认标签"wifi_setting"
if (tag) {
new_entry->tag = audio_strdup(tag);
} else {
new_entry->tag = audio_strdup("wifi_setting");
}
// 检查标签名内存分配是否成功
AUDIO_MEM_CHECK(TAG, new_entry->tag, {
audio_free(new_entry);
return NULL;
})
// 返回创建的实例句柄
return new_entry;
}
audio_calloc
分配并清零内存,确保所有字段初始值为0或NULLAUDIO_MEM_CHECK
宏检查内存分配,失败时执行清理并返回NULLcalloc
,其他字段自动初始化为零值函数使用ESP-ADF的内存管理API进行内存操作:
audio_calloc
:分配并清零内存audio_strdup
:复制字符串并分配新内存audio_free
:释放分配的内存这种方式使得内存管理更一致,并便于调试内存问题。
esp_wifi_setting_destroy
函数用于销毁WiFi配置接口实例并释放相关资源:
/**
* @brief 销毁WiFi配置接口实例
*
* 该函数完成以下主要操作:
* 1. 验证传入的句柄参数
* 2. 释放句柄占用的内存资源
*
* @param handle 要销毁的WiFi配置接口实例句柄
* @return
* - ESP_OK 成功
* - ESP_ERR_INVALID_ARG 参数无效
*/
esp_err_t esp_wifi_setting_destroy(esp_wifi_setting_handle_t handle)
{
// 参数检查,确保句柄有效
AUDIO_NULL_CHECK(TAG, handle, return ESP_ERR_INVALID_ARG);
// 释放实例内存
audio_free(handle);
// 返回操作成功
return ESP_OK;
}
AUDIO_NULL_CHECK
宏检查句柄是否为NULL需要注意的是,当前实现中有一个潜在问题:函数仅释放了handle
本身,但没有释放handle->tag
等内部分配的内存,这可能导致内存泄漏。完整的实现应该先释放内部资源,再释放句柄本身。
esp_wifi_setting_register_function
函数用于注册WiFi配置接口的三个核心函数:
/**
* @brief 注册WiFi配置接口函数
*
* 该函数完成以下主要操作:
* 1. 注册启动配网的函数
* 2. 注册停止配网的函数
* 3. 注册清理配网资源的函数
*
* @param handle 配置接口实例句柄
* @param start 启动配网的函数指针
* @param stop 停止配网的函数指针
* @param teardown 清理配网资源的函数指针
* @return ESP_OK表示成功
*/
esp_err_t esp_wifi_setting_register_function(esp_wifi_setting_handle_t handle,
wifi_setting_func start,
wifi_setting_func stop,
wifi_setting_teardown_func teardown)
{
// 设置启动配网函数
handle->start = start;
// 设置停止配网函数
handle->stop = stop;
// 设置清理资源函数
handle->teardown = teardown;
// 返回操作成功
return ESP_OK;
}
这个函数是配网接口的核心部分,通过它可以将具体配网方式的实现函数注册到接口框架中,实现了接口与实现的分离。
以下是一个完整的配网接口创建、注册和使用流程示例:
// 定义配网实现函数
static esp_err_t my_config_start(esp_wifi_setting_handle_t handle)
{
ESP_LOGI(TAG, "启动自定义配网");
// 实现启动配网的逻辑...
return ESP_OK;
}
static esp_err_t my_config_stop(esp_wifi_setting_handle_t handle)
{
ESP_LOGI(TAG, "停止自定义配网");
// 实现停止配网的逻辑...
return ESP_OK;
}
static esp_err_t my_config_teardown(esp_wifi_setting_handle_t handle, wifi_config_t *info)
{
ESP_LOGI(TAG, "清理自定义配网资源");
// 实现清理资源的逻辑...
return ESP_OK;
}
// 创建和注册配网接口
esp_wifi_setting_handle_t create_my_config(void)
{
// 1. 创建配网接口实例
esp_wifi_setting_handle_t handle = esp_wifi_setting_create("my_config");
if (handle == NULL) {
ESP_LOGE(TAG, "创建配网接口失败");
return NULL;
}
// 2. 注册配网实现函数
esp_wifi_setting_register_function(handle,
my_config_start,
my_config_stop,
my_config_teardown);
// 3. 设置用户自定义数据(可选)
my_config_t *config = audio_calloc(1, sizeof(my_config_t));
if (config) {
// 设置配置参数...
esp_wifi_setting_set_data(handle, config);
}
return handle;
}
// 使用配网接口
void use_wifi_config(void)
{
// 1. 创建WiFi服务
periph_service_handle_t wifi_service = wifi_service_create(&wifi_cfg);
// 2. 创建配网接口
esp_wifi_setting_handle_t my_config = create_my_config();
// 3. 注册配网接口到WiFi服务
int index = 0;
wifi_service_register_setting_handle(wifi_service, my_config, &index);
// 4. 设置通知句柄
esp_wifi_setting_register_notify_handle(my_config, wifi_service);
// 5. 启动配网
wifi_service_setting_start(wifi_service, index);
// ... 其他代码 ...
// 6. 销毁资源
wifi_service_destroy(wifi_service); // 会自动清理关联的配网接口
}
下面的时序图展示了配网接口的创建、注册和使用流程:
ESP-ADF的wifi_service模块中的esp_wifi_setting配网接口管理函数遵循了以下设计原则:
当前实现中存在一些可改进的地方:
esp_wifi_setting_register_function
函数没有检查参数有效性esp_wifi_setting_destroy
函数未释放tag
等内部分配的内存running
标志的统一管理在使用这些配网接口管理函数时,建议遵循以下最佳实践:
create
调用都有对应的destroy
调用