警告
This document is not updated for ESP32C61 yet, so some of the content may not be correct.
This warning was automatically inserted due to the source file being in the add_warnings_pages list.
ESP-NETIF 开发者指南
如 ESP-NETIF 架构 所示,ESP-NETIF 实际上是 I/O 驱动和 TCP/IP 协议栈之间的中介。本指南用以说明如何自定义这二者,即如何实现 ESP-NETIF 自定义 I/O 驱动程序 和 ESP-NETIF 自定义 TCP/IP 协议栈。
ESP-NETIF 自定义 I/O 驱动程序
本节概述了如何配置具有 ESP-NETIF 连接功能的新 I/O 驱动程序。
通常情况下,I/O 驱动程序须注册为 ESP-NETIF 驱动程序。因此,它依赖于 ESP-NETIF 组件,并负责提供数据路径函数、后附回调函数,并在多数情况下用于设置默认事件处理程序,根据驱动程序的生命周期转换来定义网络接口操作。
数据包 Input/Output
根据 ESP-NETIF 架构 章节提供的图表可以看出,须定义以下三个数据路径函数 API 以连接 ESP-NETIF:
前两个函数可以传输和释放 RX 缓冲区,用作回调。它们由 ESP-NETIF(及其底层 TCP/IP 堆栈)调用,并由 I/O 驱动实现。
另一方面,接收函数由 I/O 驱动程序调用,因此驱动的代码只需在接收到新数据时调用 esp_netif_receive()
函数。
后附回调
网络接口初始化的最后一步是调用以下 API,将 ESP-NETIF 实例附加到 I/O 驱动程序上:
esp_err_t esp_netif_attach(esp_netif_t *esp_netif, esp_netif_iodriver_handle driver_handle);
假设 esp_netif_iodriver_handle
是指向驱动程序对象的指针,该对象是从 struct esp_netif_driver_base_s
衍生的结构体,那么 I/O 驱动结构体的第一个成员必须是此基础结构,并指向:
后附函数回调
相关的 ESP-NETIF 实例
因此,I/O 驱动程序须创建以下结构体的实例:
typedef struct my_netif_driver_s {
esp_netif_driver_base_t base; /*!< 保留基本结构体作为 esp-netif 驱动 */
driver_impl *h; /*!< 驱动实现 */
} my_netif_driver_t;
此实例中包含 my_netif_driver_t::base.post_attach
的真实值和实际的驱动处理程序 my_netif_driver_t::h
。
从初始化代码调用 esp_netif_attach()
时,将执行 I/O 驱动程序代码的后附回调,以在 ESP-NETIF 和 I/O 驱动程序实例之间相互注册回调。通常,后附回调中也会启动驱动程序。以下为一个简单的后附回调示例:
static esp_err_t my_post_attach_start(esp_netif_t * esp_netif, void * args)
{
my_netif_driver_t *driver = args;
const esp_netif_driver_ifconfig_t driver_ifconfig = {
.driver_free_rx_buffer = my_free_rx_buf,
.transmit = my_transmit,
.handle = driver->driver_impl
};
driver->base.netif = esp_netif;
ESP_ERROR_CHECK(esp_netif_set_driver_config(esp_netif, &driver_ifconfig));
my_driver_start(driver->driver_impl);
return ESP_OK;
}
默认处理程序
I/O 驱动程序通常还会根据 I/O 驱动程序的状态转换,为相关网络接口的生命周期行为提供默认定义,例如 driver start ->
network start 等。
以下是此类默认处理程序的一个示例:
esp_err_t my_driver_netif_set_default_handlers(my_netif_driver_t *driver, esp_netif_t * esp_netif)
{
driver_set_event_handler(driver->driver_impl, esp_netif_action_start, MY_DRV_EVENT_START, esp_netif);
driver_set_event_handler(driver->driver_impl, esp_netif_action_stop, MY_DRV_EVENT_STOP, esp_netif);
return ESP_OK;
}
网络堆栈连接
用于传输和释放 RX 缓冲区的数据路径函数(在 I/O 驱动中定义)由 ESP-NETIF 的 TCP/IP 堆栈连接层调用。
注意,ESP-IDF 为最常见的网络接口(如 Wi-Fi station 或以太网)提供了几种网络堆栈配置。这些配置在 esp_netif/include/esp_netif_defaults.h 中定义,能够满足大多数网络驱动程序的需求。
有时可能需要定义一个基于 lwIP 的自定义接口,例如当您需要使用特定的数据包池更新 esp_netif/lwip/netif/wlanif.c 文件时。在这种情况下,您需要显式定义对 lwIP 的依赖关系,并包含 esp_netif/include/lwip/esp_netif_net_stack.h 文件以获取相关的 lwIP 配置结构体。
ESP-NETIF 自定义 TCP/IP 协议栈
若实现了 BSD API,则可以借助 ESP-IDF 使用自定义的 TCP/IP 协议栈。除了使用一般性的 ESP-NETIF 功能,还可以支持自定义的 TCP/IP 协议栈,这样应用代码就能和使用 lwIP 时保持一致。
要想实现这一点,请在 ESP-NETIF 组件配置菜单中选择 ESP_NETIF_PROVIDE_CUSTOM_IMPLEMENTATION
。此选项将禁用 ESP-NETIF 功能的 lwIP 实现,只提供带有数据声明和 API 声明的头文件,因此要在自定义组件中提供必要的实现。有关以上功能的 dummy 实现示例,请参考 esp_netif/loopback/esp_netif_loopback.c。
也可以不借助 lwIP 构建 ESP-IDF,请参考 components/esp_netif_stack/README.md。
API 参考
以下参考 API 概述了这些网络堆栈和 ESP-NETIF 的交互:
Header File
This header file can be included with:
#include "esp_netif_net_stack.h"
This header file is a part of the API provided by the
esp_netif
component. To declare that your component depends onesp_netif
, add the following to your CMakeLists.txt:REQUIRES esp_netif
or
PRIV_REQUIRES esp_netif
Functions
-
esp_netif_t *esp_netif_get_handle_from_netif_impl(void *dev)
Returns esp-netif handle.
- 参数
dev -- [in] opaque ptr to network interface of specific TCP/IP stack
- 返回
handle to related esp-netif instance
-
void *esp_netif_get_netif_impl(esp_netif_t *esp_netif)
Returns network stack specific implementation handle.
- 参数
esp_netif -- [in] Handle to esp-netif instance
- 返回
handle to related network stack netif handle
-
esp_err_t esp_netif_set_link_speed(esp_netif_t *esp_netif, uint32_t speed)
Set link-speed for the specified network interface.
- 参数
esp_netif -- [in] Handle to esp-netif instance
speed -- [in] Link speed in bit/s
- 返回
ESP_OK on success
-
esp_err_t esp_netif_transmit(esp_netif_t *esp_netif, void *data, size_t len)
Outputs packets from the TCP/IP stack to the media to be transmitted.
This function gets called from network stack to output packets to IO driver.
- 参数
esp_netif -- [in] Handle to esp-netif instance
data -- [in] Data to be transmitted
len -- [in] Length of the data frame
- 返回
ESP_OK on success, an error passed from the I/O driver otherwise
-
esp_err_t esp_netif_transmit_wrap(esp_netif_t *esp_netif, void *data, size_t len, void *netstack_buf)
Outputs packets from the TCP/IP stack to the media to be transmitted.
This function gets called from network stack to output packets to IO driver.
- 参数
esp_netif -- [in] Handle to esp-netif instance
data -- [in] Data to be transmitted
len -- [in] Length of the data frame
netstack_buf -- [in] net stack buffer
- 返回
ESP_OK on success, an error passed from the I/O driver otherwise
-
void esp_netif_free_rx_buffer(void *esp_netif, void *buffer)
Free the rx buffer allocated by the media driver.
This function gets called from network stack when the rx buffer to be freed in IO driver context, i.e. to deallocate a buffer owned by io driver (when data packets were passed to higher levels to avoid copying)
- 参数
esp_netif -- [in] Handle to esp-netif instance
buffer -- [in] Rx buffer pointer