1. esp32的esp_wifi(wifi驱动库),esp_netif(网络接口) ,lwip(轻量级TCP/IP网络协议栈)是什么?三者之间有什么关系?
esp_wifi驱动库用户控制wifi硬件单元;
lwip是一层纯软件,轻量级TCP/IP协议栈;
esp_netif是esp官方提供的操作TCP/IP协议栈的API。
从上面的ESP32功能框图中可以看出wifi是单片机中的一个独立的硬件,实现了通过无线发送数据目的。同理蓝牙,以太网等等都是单片机中一块独立的硬件。所以既然是硬件,我们在使用wifi收发数据前就需要进行初始化配置等操作。
以上是一张ESP32官方文档中描述esp_wifi(wifi驱动库),esp_netif(网络接口) ,lwip(轻量级TCP/IP网络协议栈)之间的操作关系图。
ESP-NETIF是ESP32官方在TCP/IP协议栈之上封装的一层供应用程序访问协议栈的便携的接口,也就是说IP协议栈在这里是不需要被用户应用程序直接访问的。
从(A)开始看,用户应用程序调用esp_netif中的API接口初始化TCP/IP协议栈,之后调用esp_wifi中的API接口初始化wifi硬件,接下来就是数据的收发过程,用户程序发送的数据经过TCP/IP协议栈的处理打包后到达wifi驱动,最后经过物理硬件电磁波发送出去,总的来说就是用户层 -》TCP/IP协议栈-》wifi硬件-》对端。
2. ESP-NETIF interaction解读。文档连接:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/network/esp_netif.html
ESP-NETIF library 有两方面的作用。
(1). 在TCP/IP协议栈之上提供了一个抽象层,允许用户在未来可能的情况下选择使用的IP栈;
(2). 这个抽象层的API是线程安全的,即使底层的TCP/IP协议栈接口不是线程安全的。
目前,ESP-IDF框架只为轻量级的TCP/IP协议栈实现了ESP-NETIF抽象层,然而适配器(指前面说的ESP-NETIF抽象层)本身TCP/IP的实现是不可见的即使不同的是实现也是可能的。
一些ESP-NETIF抽象层的API接口函数可以被应用程序调用,比如获取和设置IP地址,配置DHCP。其他的接口函数被网络驱动层调用(在这里我觉得是wifi驱动层)。
在很多情况下,应用程序不需要调用ESP-NETIF抽象层的API接口,因为他们会被默认的网络事件调用。
ESP-NETIF组件是tcpip适配器的继承者,从IDF v4.1开始废弃了tcpip适配器。请参考 TCP/IP 适配器迁移指南 用ESP-NETIF替代tcpip适配器。
(3). ESP-NETIF interaction
A) User code, boiler plate。
A.初始化代码
- 总的来说,使用IO驱动作为通信媒介和配置TCP/IP协议栈的应用程序在使用ESP-NETIF APIs 时是抽象的,看下面描述。
- 初始化IO驱动。
- 创建一个新的ESP-NETIF实例,进行配置。
- 连接IO驱动到ESP-NETIF实例 (这里我的理解是wifi硬件单元通过IO驱动和ESP-NETIF网络接口建立连接)。
- 配置事件处理函数(处理wifi硬件单元事件和tcp/ip协议栈事件)。
B.使用ESP-NETIF API的网络接口交互。
- 获取TCP/IP下相关参数。
- 接收IP事件(连接/断开)。
- 控制应用程序的生命周期(设置接口的开和关)。
B) 通讯驱动, IO 驱动, 媒介驱动。
- 与ESP-NETIF有关的通讯驱动扮演着两种重要角色:以后补充。
C) ESP-NETIF, former tcpip_adapter
- 以后补充。
D) Network stack
- 以后补充。
3. ESP32 wifi相关代码解读。
最简单的联网代码
#include "esp_wifi.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "string.h"
static const char* TAG = "test esp_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);
if(event_base == WIFI_EVENT) {
switch(event_id) {
case WIFI_EVENT_STA_START:
ESP_LOGI(TAG, "----> %s", "WIFI_EVENT_STA_START");
break;
case WIFI_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "----> %s", "WIFI_EVENT_STA_DISCONNECTED");
break;
default:
break;
}
}else if(event_base == IP_EVENT) {
ip_event_got_ip_t *event = (ip_event_got_ip_t*)event_data;
switch(event_id) {
case IP_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "----> IP_EVENT_STA_GOT_IP ip:");
ESP_LOGI(TAG, "----> sta ip:"IPSTR, IP2STR(&event->ip_info.ip));
ESP_LOGI(TAG, "----> mask:"IPSTR, IP2STR(&event->ip_info.netmask));
ESP_LOGI(TAG, "----> gw:"IPSTR, IP2STR(&event->ip_info.gw));
break;
default:
break;
}
}else {
ESP_LOGI(TAG, "----> %s", "unknown event_base");
}
return;
}
void app_main()
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
esp_event_loop_create_default();
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL);
esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL);
//网络接口初始化
esp_netif_init();
esp_netif_create_default_wifi_sta();
//wifi初始化
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
wifi_config_t wifi_config = {
.sta.ssid = "WX-JGGY",
.sta.password = "juguogongyudb"
};
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_start(); //启动wifi
esp_wifi_connect(); //启动连接到ap
while(1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("hello world\n");
}
}