天天看点

ESP32 应用实践:ethernet 转 WiFi 实现

一:简介

Ethernet 转 WiFi 用于实现以太网口的设备通过 WiFi 进行无线互联。将从设备 发出的 802.3 帧数据转化为 802.11 帧数据发送出去,接收到的 802.11 帧数据转换为 802.3 帧数据发送给设备,其跳过了 ESP32 的 lwip,直接在物理层进行了数据的转发,提高了数据转发的效率。

ESP32 应用实践:ethernet 转 WiFi 实现

在本 Demo 中,Ethernet 转 WiFi 主要有两种使用方式:STATION 模式和 SOFTAP 模式,

二:硬件准备

实现 Ethernet 转 WiFi 需使用带有 phy 功能的 ESP32 开发板,本 Demo 使用的是 ESP32_Ethernet_v3。对于普通的 ESP32 开发板,想要实现本 Demo 需外接 PHY,目前 ESP32 Ethernt driver 支持的 phy 有 TLK110 和 LAN8720,而在 ESP32_Ethernet_v3 中集成的是 TLK110 。

ESP32 应用实践:ethernet 转 WiFi 实现
ESP32 应用实践:ethernet 转 WiFi 实现

三:配置说明

3.1 PHY 配置

用户可以在

make menuconfig

中对 PHY 进行配置。如果使用 ESP32_Ethernet_v3 开发板,只需要使用默认配置即可;对于外接 phy 的用户,可以参照 Ethernet Demo 中的要求对 phy 进行修改。

3.2 WiFi 配置

WiFi 的配置主要是为了提高数据的吞吐率,在本 Demo 中,增加了 WiFi RX 和 TX 的 buffer 数量,并调整了 ESP32 的 CPU 时钟,具体优化信息请参照默认配置项 sdkconfig.defaults。

Note: 用户可以根据自己需要通过

make menuconfig

调整相关参数,但是 STATIC_RX_BUFFER_NUM和 TX/RX BA Window(the size of WiFi Block Ack TX window) 均不要超过 16 ,否则可能会因为内存问题引起 crash,其中这些参数位于 Component config -> Wi-Fi 下。

四:Demo 使用步骤

通过如下方式获取此 Demo

$ git clone  https://github.com/espressif/esp-iot-solution
$ cd esp-iot-solution
$ git submodule update --init --recursive
           

本 Demo 位于 esp-iot-solution/examples/eth2wifi 下,Demo 提供了 ethernet 转 WiFi 的两种模式:ESP32 作为 STATION 模式和 ESP32 作为 SOFTAP 模式。

4.1 STATION 模式

STATION 模式是设备将 Ethernet 帧数据转化为 WiFi station 帧数据,然后将 WiFi station 数据无线发送给 AP ,从而实现类似于无线网卡的功能。

a) 使用 USB 转串口线将开发板连接到 PC 上

b) 进入 esp-iot-solution/examples/eth2wifi 所在目录

c) 选择配置

$ make menuconfig
           
  • 在 Serial flasher config - Default serial port 中,配置需要下载的串口
  • 在 Component config - IoT Example - Ethernet to WiFi Demo Configuration - The SSID for demo 中设置 SSID
  • 在 Component config - IoT Example - Ethernet to WiFi Demo Configuration - The PASSWORD for demo 中设置 WiFi 密码
  • 在 Component config - IoT Example - Ethernet to WiFi Demo Configuration - WiFi station mode 中,输入 y,选择 STA 模式(默认即为 Y )
ESP32 应用实践:ethernet 转 WiFi 实现

d) 编译并烧录程序

$ make flash
           

e) 运行

  1. 烧录成功后,打开串口工具,此时会打印 log,根据 SSID 连接 AP,然后 PC 会发起 DHCP 请求
  2. 查看是否拿到 IP,并尝试 ping 网关来测试是否正常
ESP32 应用实践:ethernet 转 WiFi 实现

4.2 SOFTAP 模式

SOFTAP 模式是利用 ESP32 所属的设备作为一个 AP,从而可以组建一个小型的局域网,因为交互需要 IP 信息,所以需要设备具备 DHCP Server 的能力,在本 Demo 中,使用 PC 来作为 DHCP Server。

4.2.1 Ubuntu DHCP server 配置

Ubuntu 配置 dhcp 服务器需要:计算机设置静态 ip ,(充当 dhcp 服务器的计算机的 ip 需要是静态 ip,不可以是通过动态获得,设置静态 ip 需要设置在对应的网卡:如 eth0 )设置子网掩码,默认网关,以及配置 dhcp。

a) PC 设置静态 ip/子网掩码/网关

静态 ip 的配置:

设置–>系统设置–>网络–>选项–> ipv4 –>方法:手动;添加–> address, subnet, netmask.

我设置的静态ip地址:192.168.5.0,子网掩码:255.255.255.0,网关:192.168.5.1。

$ sudo vim /etc/network/interfaces
           

设置成如下内容:

auto lo
 iface lo inet loopback
 auto eth0
 iface eth0 inet static
 address .5.0
 gateway .5.1
 netmask .255.0
           

Note: eth0 是测试 PC 上的网卡名称,不同的电脑网卡名称不同,可通过 ipconfig 查看,替换成自己的网卡名称即可

配置完成后重启网络服务:

sudo /etc/init.d/networking restart

b) 配置 DHCP 服务器

  • 首先安装 DHCP 服务器
  • 配置 DHCP 的网卡

设置使用网卡(我的是 eth0 )作为 DHCP Server

  • 编辑当前配置
$ sudo vim /etc/dhcp/dhcpd.conf
           

在文件末尾添加如下几项

subnet   netmask  {
  range  ;
#  option domain-name-servers ;
#  option domain-name "internal.example.org";
#  option routers ;
  option broadcast-address ;
  default-lease-time ;
  max-lease-time ;  
}
           
  • 配置完成后,重启 dhcp 服务:
$ sudo /etc/init.d/isc-dhcpd-server restart
           

Note: /etc/dhcp/dhcpd.conf中的 subnet 一定要包含 server 本机的 ip 在内,否则启动不了

最后可以通过 ifconfig eth0 查看是否静态 IP 设置成功

c) 烧写步骤

烧写 softap 的步骤与 STA 基本相同,只需要在第 4 步时将 Ethernet to wifi station forwarding data 设置为 n 即为 softap 模式。

d) 运行

  1. 将 ESP32 连接到 PC 设备上,确保 PC 设备已经开启了 DHCP Server,配置方法请参照前文 Ubuntu 配置 DHCP server
  2. 给 ESP32 上电,并打开 PC 上的串口工具,此时串口会打印 log
  3. 用手机连接 ESP32 的 SSID(默认为 DEMO_TEST),成功后会在步骤 2 中打印 STA 连接成功的 Log
  4. 尝试 ping 手机拿到的 IP 地址测试是否正常
ESP32 应用实践:ethernet 转 WiFi 实现

五:核心代码分析

5.1 事件处理

ESP32 代码中将网络中的各种状态全部封装成了事件,所以 Ethernet 转 WiFi 的核心是网络事件( Event )的处理;在本次 Demo 中,主要做了如下事件的处理:

static esp_err_t event_handler(void* ctx, system_event_t* event)
{
    switch (event->event_id) {
        case SYSTEM_EVENT_STA_START:
            printf("SYSTEM_EVENT_STA_START\r\n");
            break;

        case SYSTEM_EVENT_STA_CONNECTED:
            printf("SYSTEM_EVENT_STA_CONNECTED\r\n");
            wifi_is_connected = true;

            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, (wifi_rxcb_t)tcpip_adapter_sta_input_eth_output);
           

对于 SYSTEM_EVENT_STA_START 事件,我们并没有进行常见的 esp_wifi_connect() 操作,而是放在 Ethernet task 中进行,这么做主要是为了获取 PC 的 MAC 地址,然后将 sta 的 MAC 替换为 PC 的 MAC。

对于 SYSTEM_EVENT_STA_CONNECTED 事件,ESP32 连接上 AP 后,会进入此事件,在一般的网络交互中,此时开始进行 DHCP 请求操作,但因为此时 ESP32 只是作为一个管道,所以在这里我们并不是将数据抛给 lwip 而是将数据“窃取”并转发 给 Ethernet。

case SYSTEM_EVENT_STA_GOT_IP:
            printf("SYSTEM_EVENT_STA_GOT_IP\r\n");
            break;

        case SYSTEM_EVENT_STA_DISCONNECTED:
            printf("SlYSTEM_EVENT_STA_DISCONNECTED\r\n");
            wifi_is_connected = false;
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, NULL);
            esp_wifi_connect();
            break;
           

对于事件 SYSTEM_EVENT_STA_GOT_IP ,好吧,这个事件在这个 Demo 是不会被触发了,因为我们没使用 lwip 中的 DHCP client 功能。

当事件 SYSTEM_EVENT_STA_DISCONNECTED 被触发,我们要做的是让 Ethernet 收到的数据将不会通过 WiFi 进行转发,同时重连网络。

case SYSTEM_EVENT_AP_STACONNECTED:
            printf("SYSTEM_EVENT_AP_STACONNECTED\r\n");
            wifi_is_connected = true;

            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP, (wifi_rxcb_t)tcpip_adapter_ap_input_eth_output);
            break;

        case SYSTEM_EVENT_AP_STADISCONNECTED:
            printf("SYSTEM_EVENT_AP_STADISCONNECTED\r\n");
            wifi_is_connected = false;
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP, NULL);
            break;
           

作为 AP 时事件处理和 STA 相同,区别是这里设置为 AP 模式,而不是 STA 模式。

case SYSTEM_EVENT_ETH_CONNECTED:
            printf("SYSTEM_EVENT_ETH_CONNECTED\r\n");
            ethernet_is_connected = true;
            break;

        case SYSTEM_EVENT_ETH_DISCONNECTED:
            printf("SYSTEM_EVENT_ETH_DISCONNECTED\r\n");
            ethernet2wifi_mac_status_set(false);
            ethernet_is_connected = false;
            break;

           

Ethernet 事件的处理主要是探测以太网是否连接或者断开,同时在断开时,ethernet2wifi_mac_status_set 还要置为 false,以保证下次重新连接时重新替换 sta 的 mac 地址。

5.2 MAC地址设置

因为 Ethernet 转 WiFi 牵涉到 3 个 MAC(PC、Etherner 和 STA/AP ),而网络很多操作需要校验 MAC,为了确保在网络交互时 MAC 还能保持 PC 的 MAC,在本 Demo 中将 STA 的 MAC 设置为 PC 的 MAC。

if (!ethernet2wifi_mac_status_get()) {
   memcpy(eth_mac, (uint8_t*)msg.buffer + 6, sizeof(eth_mac));
   ESP_ERROR_CHECK(esp_wifi_start());
#ifdef CONFIG_ETH_TO_STATION_MODE
   esp_wifi_set_mac(WIFI_IF_STA, eth_mac);
   esp_wifi_connect();
#else
   esp_wifi_set_mac(WIFI_IF_AP, eth_mac);
#endif
   ethernet2wifi_mac_status_set(true);
 }
           

在 SYSTEM_EVENT_ETH_CONNECTED 事件被触发之后,PC 开始发送包含 MAC 地址的网络数据,如下图所示:

ESP32 应用实践:ethernet 转 WiFi 实现

我们截取之后将 STA 的 MAC 地址设置为 PC 的 MAC 地址,此时再连接 AP,并将状态置为 true,以避免下次 PC 发送数据时重复设置 MAC。

在连接到 AP 之后,PC 再进行 DHCP 请求时,sta 就会使用 PC的 MAC 地址和 AP 进行交互,以此保证正常通讯。

六:性能指标分析

我们使用了 iperf 对吞吐率进行了简单的测试,在开放工作环境下,其 TCP 吞吐量稳定在 45Mbps 左右。但周围环境会对 WiFi 吞吐量造成较大影响,在环境较差时,WiFi 吞吐量可能会下降。

继续阅读