天天看點

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 吞吐量可能會下降。

繼續閱讀