├── .gitignore ├── main ├── CMakeLists.txt ├── Kconfig.projbuild └── main.c ├── CMakeLists.txt ├── docker-compose.yaml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /sdkconfig* 3 | -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register(SRCS "main.c" INCLUDE_DIRS ".") 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 4 | project(eth2wlan) 5 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | idf: 3 | image: espressif/idf:latest 4 | environment: 5 | - ESPPORT=/dev/ttyAMA0 6 | - ESPBAUD=115200 7 | volumes: 8 | - .:/app 9 | - /dev/ttyAMA0:/dev/ttyAMA0 10 | working_dir: /app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eth2wlan 2 | The project enables ethernet to Wi-Fi data forwarding function (Ethernet to Wi-Fi bridge). It supports both station and access point mode. 3 | 4 | ## Overview 5 | The similarities on MAC layer between Ethernet and Wi-Fi make it easy to forward packets from Ethernet to Wi-Fi and vice versa. This example illustrates how to implement a simple "router" which only supports forwarding packets between Ethernet port and Wi-Fi interface. 6 | 7 | In this example, ESP32 works like a *bridge* between Ethernet and Wi-Fi, and it won't perform any actions on Layer3 and higher layer, which means there's no need to initialize the TCP/IP stack. 8 | 9 | ## Hardware 10 | To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. 11 | 12 | Besides that, `esp_eth` component can drive third-party Ethernet module which integrates MAC and PHY and provides common communication interface (e.g. SPI, USB, etc). This example will take the **DM9051** as an example, illustrating how to install the Ethernet driver in the same manner. 13 | 14 | ### Common Pin Assignments 15 | See [here](https://github.com/espressif/esp-idf/blob/release/v4.4/examples/ethernet/README.md#common-pin-assignments) the common pin assignments for Ethernet examples. 16 | 17 | ### Common Boards 18 | * wESP32 19 | | Parameter | Value | 20 | | --------- | ------- | 21 | | type | LAN87XX | 22 | | MDC | 16 | 23 | | MDIO | 17 | 24 | | PHY Address | 0 | 25 | 26 | * Olimex ESP32-POE 27 | | Parameter | Value | 28 | | --------- | ------- | 29 | | type | LAN87XX | 30 | | MDC | 23 | 31 | | MDIO | 18 | 32 | | PHY Address | 0 | 33 | | Power PIN | 12 | 34 | 35 | * Olimex ESP32-EVB 36 | | Parameter | Value | 37 | | --------- | ------- | 38 | | type | LAN87XX | 39 | | MDC | 23 | 40 | | MDIO | 18 | 41 | | PHY Address | 0 | 42 | 43 | * LILYGO TTGO T-Internet-POE ESP32-WROOM LAN8270A Chip 44 | | Parameter | Value | 45 | | --------- | ------- | 46 | | type | LAN87XX | 47 | | MDC | 23 | 48 | | MDIO | 18 | 49 | | PHY Address | 0 | 50 | 51 | * OpenHacks LAN8720 52 | | Parameter | Value | 53 | | --------- | ------- | 54 | | type | LAN87XX | 55 | | MDC | 23 | 56 | | MDIO | 18 | 57 | | PHY Address | 1 | 58 | 59 | * Wireless Tag WT32-ETH01 60 | | Parameter | Value | 61 | | --------- | ------- | 62 | | type | LAN87XX | 63 | | MDC | 23 | 64 | | MDIO | 18 | 65 | | PHY Address | 1 | 66 | | Power PIN | 16 | 67 | 68 | ## Configuration 69 | ```bash 70 | docker-compose run --rm idf idf.py menuconfig 71 | ``` 72 | 73 | In addition to the common configurations, you might need to update the default values of following configuration: 74 | 75 | In the `Ethernet to WLAN Configuration` menu: 76 | * Set the SSID and passphrase for Wi-Fi interface under `Wi-Fi SSID` and `Wi-Fi Password`. 77 | 78 | ## Build and Flash 79 | 80 | Build the project and flash it to the board, then run monitor tool to view serial output: 81 | 82 | ```bash 83 | docker-compose run --rm idf idf.py build flash monitor 84 | ``` 85 | 86 | To exit the serial monitor, type ``Ctrl-]``. 87 | 88 | See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. 89 | 90 | ## Troubleshooting 91 | 92 | See [here](https://github.com/espressif/esp-idf/blob/release/v4.4/examples/ethernet/README.md#common-troubleshooting) the common troubleshooting for Ethernet examples. 93 | 94 | * If you got error message like `WiFi send packet failed` when running the example, you may need to enlarge the value of `FLOW_CONTROL_WIFI_SEND_DELAY_MS` in "ethernet_example_main.c", because Ethernet process packets faster than Wi-Fi on ESP32. 95 | * If you got error message like `send flow control message failed or timeout` when running the example, you may need to enlarge the value of `FLOW_CONTROL_QUEUE_LENGTH` in "ethernet_example_main". 96 | -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Ethernet to WLAN Configuration" 2 | 3 | config GPIO_RANGE_MIN 4 | int 5 | default 0 6 | 7 | config GPIO_RANGE_MAX 8 | int 9 | default 33 if IDF_TARGET_ESP32 10 | default 46 if IDF_TARGET_ESP32S2 11 | default 19 if IDF_TARGET_ESP32C3 12 | default 48 if IDF_TARGET_ESP32S3 13 | 14 | config USE_SPI_ETHERNET 15 | bool 16 | 17 | choice ETHERNET_TYPE 18 | prompt "Ethernet Type" 19 | default USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 20 | default USE_W5500 21 | help 22 | Select which kind of Ethernet will be used in the example. 23 | 24 | config USE_INTERNAL_ETHERNET 25 | depends on IDF_TARGET_ESP32 26 | select ETH_USE_ESP32_EMAC 27 | bool "Internal EMAC" 28 | help 29 | Select internal Ethernet MAC controller. 30 | 31 | config USE_DM9051 32 | bool "DM9051 Module" 33 | select USE_SPI_ETHERNET 34 | select ETH_USE_SPI_ETHERNET 35 | select ETH_SPI_ETHERNET_DM9051 36 | help 37 | Select external SPI-Ethernet module (DM9051). 38 | 39 | config USE_W5500 40 | bool "W5500 Module" 41 | select USE_SPI_ETHERNET 42 | select ETH_USE_SPI_ETHERNET 43 | select ETH_SPI_ETHERNET_W5500 44 | help 45 | Select external SPI-Ethernet module (W5500). 46 | 47 | config USE_KSZ8851SNL 48 | bool "KSZ8851SNL Module" 49 | select USE_SPI_ETHERNET 50 | select ETH_USE_SPI_ETHERNET 51 | select ETH_SPI_ETHERNET_KSZ8851SNL 52 | help 53 | Select external SPI-Ethernet module (KSZ8851SNL). 54 | endchoice # ETHERNET_TYPE 55 | 56 | if USE_INTERNAL_ETHERNET 57 | choice ETH_PHY_MODEL 58 | prompt "Ethernet PHY Device" 59 | default ETH_PHY_LAN87XX 60 | help 61 | Select the Ethernet PHY device to use in the example. 62 | 63 | config ETH_PHY_IP101 64 | bool "IP101" 65 | help 66 | IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver. 67 | Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it. 68 | 69 | config ETH_PHY_RTL8201 70 | bool "RTL8201/SR8201" 71 | help 72 | RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX. 73 | Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it. 74 | 75 | config ETH_PHY_LAN87XX 76 | bool "LAN87xx" 77 | help 78 | Below chips are supported: 79 | LAN8710A is a small footprint MII/RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and 80 | flexPWR® Technology. 81 | LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support. 82 | LAN8740A/LAN8741A is a small footprint MII/RMII 10/100 Energy Efficient Ethernet Transceiver 83 | with HP Auto-MDIX and flexPWR® Technology. 84 | LAN8742A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and 85 | flexPWR® Technology. 86 | Goto https://www.microchip.com for more information about them. 87 | 88 | config ETH_PHY_DP83848 89 | bool "DP83848" 90 | help 91 | DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. 92 | Goto http://www.ti.com/product/DP83848J for more information about it. 93 | 94 | config ETH_PHY_KSZ80XX 95 | bool "KSZ80xx" 96 | help 97 | With the KSZ80xx series, Microchip offers single-chip 10BASE-T/100BASE-TX 98 | Ethernet Physical Layer Tranceivers (PHY). 99 | The following chips are supported: KSZ8001, KSZ8021, KSZ8031, KSZ8041, 100 | KSZ8051, KSZ8061, KSZ8081, KSZ8091 101 | Goto https://www.microchip.com for more information about them. 102 | endchoice # ETH_PHY_MODEL 103 | 104 | config ETH_MDC_GPIO 105 | int "SMI MDC GPIO number" 106 | range GPIO_RANGE_MIN GPIO_RANGE_MAX 107 | default 23 108 | help 109 | Set the GPIO number used by SMI MDC. 110 | 111 | config ETH_MDIO_GPIO 112 | int "SMI MDIO GPIO number" 113 | range GPIO_RANGE_MIN GPIO_RANGE_MAX 114 | default 18 115 | help 116 | Set the GPIO number used by SMI MDIO. 117 | endif # USE_INTERNAL_ETHERNET 118 | 119 | if USE_SPI_ETHERNET 120 | config ETH_SPI_HOST 121 | int "SPI Host Number" 122 | range 0 2 123 | default 1 124 | help 125 | Set the SPI host used to communicate with the SPI Ethernet Controller. 126 | 127 | config ETH_SPI_SCLK_GPIO 128 | int "SPI SCLK GPIO number" 129 | range GPIO_RANGE_MIN GPIO_RANGE_MAX 130 | default 14 if IDF_TARGET_ESP32 131 | default 12 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 132 | default 6 if IDF_TARGET_ESP32C3 133 | help 134 | Set the GPIO number used by SPI SCLK. 135 | 136 | config ETH_SPI_MOSI_GPIO 137 | int "SPI MOSI GPIO number" 138 | range GPIO_RANGE_MIN GPIO_RANGE_MAX 139 | default 13 if IDF_TARGET_ESP32 140 | default 11 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 141 | default 7 if IDF_TARGET_ESP32C3 142 | help 143 | Set the GPIO number used by SPI MOSI. 144 | 145 | config ETH_SPI_MISO_GPIO 146 | int "SPI MISO GPIO number" 147 | range GPIO_RANGE_MIN GPIO_RANGE_MAX 148 | default 12 if IDF_TARGET_ESP32 149 | default 13 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 150 | default 2 if IDF_TARGET_ESP32C3 151 | help 152 | Set the GPIO number used by SPI MISO. 153 | 154 | config ETH_SPI_CS_GPIO 155 | int "SPI CS GPIO number" 156 | range GPIO_RANGE_MIN GPIO_RANGE_MAX 157 | default 15 if IDF_TARGET_ESP32 158 | default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 159 | help 160 | Set the GPIO number used by SPI CS. 161 | 162 | config ETH_SPI_CLOCK_MHZ 163 | int "SPI clock speed (MHz)" 164 | range 5 80 165 | default 12 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C3 166 | default 36 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 167 | help 168 | Set the clock speed (MHz) of SPI interface. 169 | 170 | config ETH_SPI_INT_GPIO 171 | int "Interrupt GPIO number" 172 | range GPIO_RANGE_MIN GPIO_RANGE_MAX 173 | default 4 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 174 | help 175 | Set the GPIO number used by the SPI Ethernet module interrupt line. 176 | endif # USE_SPI_ETHERNET 177 | 178 | config ETH_PHY_RST_GPIO 179 | int "PHY Reset GPIO number" 180 | range -1 GPIO_RANGE_MAX 181 | default 16 182 | help 183 | Set the GPIO number used to reset PHY chip. 184 | Set to -1 to disable PHY chip hardware reset. 185 | 186 | config ETH_PHY_ADDR 187 | int "PHY Address" 188 | range 0 31 189 | default 1 190 | help 191 | Set PHY address according your board schematic. 192 | 193 | config WLAN_AP_MODE 194 | bool "Wi-Fi Access Point" 195 | default n 196 | help 197 | If set, it is ethernet to wifi softap forwarding data. 198 | 199 | config WLAN_SSID 200 | string "Wi-Fi SSID" 201 | default "ap" 202 | help 203 | Set the SSID of Wi-Fi ap interface. 204 | 205 | config WLAN_PASSPHRASE 206 | string "Wi-Fi Password" 207 | default "12345678" 208 | help 209 | Set the password of Wi-Fi ap interface. 210 | 211 | if WLAN_AP_MODE 212 | config WLAN_CHANNEL 213 | int "WiFi channel" 214 | range 1 13 215 | default 1 216 | help 217 | Set the channel of Wi-Fi ap. 218 | 219 | config MAX_STA_CONN 220 | int "Maximum STA connections" 221 | default 4 222 | help 223 | Maximum number of the station that allowed to connect to current Wi-Fi hotspot. 224 | endif # WLAN_AP_MODE 225 | 226 | endmenu 227 | -------------------------------------------------------------------------------- /main/main.c: -------------------------------------------------------------------------------- 1 | /* eth2wlan (Ethernet to Wi-Fi packet forwarding) 2 | 3 | This example code is in the Public Domain (or CC0 licensed, at your option.) 4 | 5 | Unless required by applicable law or agreed to in writing, this 6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | CONDITIONS OF ANY KIND, either express or implied. 8 | */ 9 | #include 10 | #include 11 | #include "sdkconfig.h" 12 | #include "freertos/FreeRTOS.h" 13 | #include "freertos/task.h" 14 | #include "freertos/queue.h" 15 | #include "esp_event.h" 16 | #include "esp_log.h" 17 | #include "esp_eth.h" 18 | #include "esp_wifi.h" 19 | #include "nvs_flash.h" 20 | #include "esp_private/wifi.h" 21 | #include "driver/gpio.h" 22 | #if CONFIG_ETH_USE_SPI_ETHERNET 23 | #include "driver/spi_master.h" 24 | #endif 25 | 26 | static const char *TAG = "eth2wlan"; 27 | static esp_eth_handle_t s_eth_handle = NULL; 28 | static QueueHandle_t flow_control_queue = NULL; 29 | static bool s_sta_is_connected = false; 30 | static bool s_ethernet_is_connected = false; 31 | static bool s_mac_is_set = false; 32 | static uint8_t s_eth_mac[6]; 33 | 34 | #define FLOW_CONTROL_QUEUE_TIMEOUT_MS (100) 35 | #define FLOW_CONTROL_QUEUE_LENGTH (40) 36 | #define FLOW_CONTROL_WIFI_SEND_TIMEOUT_MS (100) 37 | 38 | typedef struct { 39 | void *packet; 40 | uint16_t length; 41 | } flow_control_msg_t; 42 | 43 | // Forward packets from Wi-Fi to Ethernet 44 | static esp_err_t pkt_wifi2eth(void *buffer, uint16_t len, void *eb) 45 | { 46 | if (s_ethernet_is_connected) { 47 | if (esp_eth_transmit(s_eth_handle, buffer, len) != ESP_OK) { 48 | ESP_LOGE(TAG, "Ethernet send packet failed"); 49 | } 50 | } 51 | esp_wifi_internal_free_rx_buffer(eb); 52 | return ESP_OK; 53 | } 54 | 55 | // Forward packets from Ethernet to Wi-Fi 56 | // Note that, Ethernet works faster than Wi-Fi on ESP32, 57 | // so we need to add an extra queue to balance their speed difference. 58 | static esp_err_t pkt_eth2wifi(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t len, void *priv) 59 | { 60 | esp_err_t ret = ESP_OK; 61 | flow_control_msg_t msg = { 62 | .packet = buffer, 63 | .length = len 64 | }; 65 | if (xQueueSend(flow_control_queue, &msg, pdMS_TO_TICKS(FLOW_CONTROL_QUEUE_TIMEOUT_MS)) != pdTRUE) { 66 | ESP_LOGE(TAG, "send flow control message failed or timeout"); 67 | free(buffer); 68 | ret = ESP_FAIL; 69 | } 70 | return ret; 71 | } 72 | 73 | // This task will fetch the packet from the queue, and then send out through Wi-Fi. 74 | // Wi-Fi handles packets slower than Ethernet, we might add some delay between each transmitting. 75 | static void eth2wifi_flow_control_task(void *args) 76 | { 77 | flow_control_msg_t msg; 78 | int res = 0; 79 | uint32_t timeout = 0; 80 | while (1) { 81 | if (xQueueReceive(flow_control_queue, &msg, pdMS_TO_TICKS(FLOW_CONTROL_QUEUE_TIMEOUT_MS)) == pdTRUE) { 82 | timeout = 0; 83 | if (msg.length) { 84 | do { 85 | if (!s_mac_is_set) { 86 | memcpy(s_eth_mac, (uint8_t*)msg.packet + 6, sizeof(s_eth_mac)); 87 | ESP_ERROR_CHECK(esp_wifi_start()); 88 | #if CONFIG_WLAN_AP_MODE 89 | esp_wifi_set_mac(WIFI_IF_AP, s_eth_mac); 90 | #else 91 | esp_wifi_set_mac(WIFI_IF_STA, s_eth_mac); 92 | esp_wifi_connect(); 93 | #endif 94 | s_mac_is_set = true; 95 | } 96 | vTaskDelay(pdMS_TO_TICKS(timeout)); 97 | timeout += 2; 98 | if (s_sta_is_connected) { 99 | #if CONFIG_WLAN_AP_MODE 100 | res = esp_wifi_internal_tx(WIFI_IF_AP, msg.packet, msg.length); 101 | #else 102 | res = esp_wifi_internal_tx(WIFI_IF_STA, msg.packet, msg.length); 103 | #endif 104 | } 105 | } while (res && timeout < FLOW_CONTROL_WIFI_SEND_TIMEOUT_MS); 106 | if (res != ESP_OK) { 107 | ESP_LOGE(TAG, "WiFi send packet failed: %d", res); 108 | } 109 | } 110 | free(msg.packet); 111 | } 112 | } 113 | vTaskDelete(NULL); 114 | } 115 | 116 | // Event handler for Ethernet 117 | static void eth_event_handler(void *arg, esp_event_base_t event_base, 118 | int32_t event_id, void *event_data) 119 | { 120 | switch (event_id) { 121 | case ETHERNET_EVENT_CONNECTED: 122 | ESP_LOGI(TAG, "Ethernet Link Up"); 123 | s_ethernet_is_connected = true; 124 | esp_eth_ioctl(s_eth_handle, ETH_CMD_G_MAC_ADDR, s_eth_mac); 125 | break; 126 | case ETHERNET_EVENT_DISCONNECTED: 127 | ESP_LOGI(TAG, "Ethernet Link Down"); 128 | s_ethernet_is_connected = false; 129 | ESP_ERROR_CHECK(esp_wifi_stop()); 130 | break; 131 | case ETHERNET_EVENT_START: 132 | ESP_LOGI(TAG, "Ethernet Started"); 133 | break; 134 | case ETHERNET_EVENT_STOP: 135 | ESP_LOGI(TAG, "Ethernet Stopped"); 136 | break; 137 | default: 138 | break; 139 | } 140 | } 141 | 142 | // Event handler for Wi-Fi 143 | static void wifi_event_handler(void *arg, esp_event_base_t event_base, 144 | int32_t event_id, void *event_data) 145 | { 146 | static uint8_t s_con_cnt = 0; 147 | switch (event_id) { 148 | case WIFI_EVENT_AP_STACONNECTED: 149 | ESP_LOGI(TAG, "Wi-Fi AP got a station connected"); 150 | if (!s_con_cnt) { 151 | s_sta_is_connected = true; 152 | esp_wifi_internal_reg_rxcb(WIFI_IF_AP, pkt_wifi2eth); 153 | } 154 | s_con_cnt++; 155 | break; 156 | case WIFI_EVENT_AP_STADISCONNECTED: 157 | ESP_LOGI(TAG, "Wi-Fi AP got a station disconnected"); 158 | s_con_cnt--; 159 | if (!s_con_cnt) { 160 | s_sta_is_connected = false; 161 | esp_wifi_internal_reg_rxcb(WIFI_IF_AP, NULL); 162 | } 163 | break; 164 | case WIFI_EVENT_STA_CONNECTED: 165 | ESP_LOGI(TAG, "Wi-Fi station connected"); 166 | s_sta_is_connected = true; 167 | esp_wifi_internal_reg_rxcb(WIFI_IF_STA, pkt_wifi2eth); 168 | break; 169 | case WIFI_EVENT_STA_DISCONNECTED: 170 | ESP_LOGI(TAG, "Wi-Fi station disconnected"); 171 | s_sta_is_connected = false; 172 | esp_wifi_internal_reg_rxcb(WIFI_IF_STA, NULL); 173 | esp_wifi_connect(); 174 | break; 175 | default: 176 | break; 177 | } 178 | } 179 | 180 | static void initialize_ethernet(void) 181 | { 182 | ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler, NULL)); 183 | eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); 184 | eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); 185 | phy_config.phy_addr = CONFIG_ETH_PHY_ADDR; 186 | phy_config.reset_gpio_num = CONFIG_ETH_PHY_RST_GPIO; 187 | #if CONFIG_USE_INTERNAL_ETHERNET 188 | eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); 189 | esp32_emac_config.smi_mdc_gpio_num = CONFIG_ETH_MDC_GPIO; 190 | esp32_emac_config.smi_mdio_gpio_num = CONFIG_ETH_MDIO_GPIO; 191 | esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); 192 | #if CONFIG_ETH_PHY_IP101 193 | esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); 194 | #elif CONFIG_ETH_PHY_RTL8201 195 | esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config); 196 | #elif CONFIG_ETH_PHY_LAN87XX 197 | esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config); 198 | #elif CONFIG_ETH_PHY_DP83848 199 | esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config); 200 | #elif CONFIG_ETH_PHY_KSZ80XX 201 | esp_eth_phy_t *phy = esp_eth_phy_new_ksz80xx(&phy_config); 202 | #endif 203 | #elif CONFIG_ETH_USE_SPI_ETHERNET 204 | gpio_install_isr_service(0); 205 | spi_device_handle_t spi_handle = NULL; 206 | spi_bus_config_t buscfg = { 207 | .miso_io_num = CONFIG_ETH_SPI_MISO_GPIO, 208 | .mosi_io_num = CONFIG_ETH_SPI_MOSI_GPIO, 209 | .sclk_io_num = CONFIG_ETH_SPI_SCLK_GPIO, 210 | .quadwp_io_num = -1, 211 | .quadhd_io_num = -1, 212 | }; 213 | ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO)); 214 | 215 | #if CONFIG_USE_KSZ8851SNL 216 | spi_device_interface_config_t devcfg = { 217 | .mode = 0, 218 | .clock_speed_hz = CONFIG_ETH_SPI_CLOCK_MHZ * 1000 * 1000, 219 | .spics_io_num = CONFIG_ETH_SPI_CS_GPIO, 220 | .queue_size = 20 221 | }; 222 | ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_ETH_SPI_HOST, &devcfg, &spi_handle)); 223 | /* KSZ8851SNL ethernet driver is based on spi driver */ 224 | eth_ksz8851snl_config_t ksz8851snl_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_handle); 225 | ksz8851snl_config.int_gpio_num = CONFIG_ETH_SPI_INT_GPIO; 226 | esp_eth_mac_t *mac = esp_eth_mac_new_ksz8851snl(&ksz8851snl_config, &mac_config); 227 | esp_eth_phy_t *phy = esp_eth_phy_new_ksz8851snl(&phy_config); 228 | #elif CONFIG_USE_DM9051 229 | spi_device_interface_config_t devcfg = { 230 | .command_bits = 1, 231 | .address_bits = 7, 232 | .mode = 0, 233 | .clock_speed_hz = CONFIG_ETH_SPI_CLOCK_MHZ * 1000 * 1000, 234 | .spics_io_num = CONFIG_ETH_SPI_CS_GPIO, 235 | .queue_size = 20 236 | }; 237 | ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_ETH_SPI_HOST, &devcfg, &spi_handle)); 238 | /* dm9051 ethernet driver is based on spi driver */ 239 | eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); 240 | dm9051_config.int_gpio_num = CONFIG_ETH_SPI_INT_GPIO; 241 | esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config); 242 | esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); 243 | #elif CONFIG_USE_W5500 244 | spi_device_interface_config_t devcfg = { 245 | .command_bits = 16, // Actually it's the address phase in W5500 SPI frame 246 | .address_bits = 8, // Actually it's the control phase in W5500 SPI frame 247 | .mode = 0, 248 | .clock_speed_hz = CONFIG_ETH_SPI_CLOCK_MHZ * 1000 * 1000, 249 | .spics_io_num = CONFIG_ETH_SPI_CS_GPIO, 250 | .queue_size = 20 251 | }; 252 | ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_ETH_SPI_HOST, &devcfg, &spi_handle)); 253 | /* w5500 ethernet driver is based on spi driver */ 254 | eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); 255 | w5500_config.int_gpio_num = CONFIG_ETH_SPI_INT_GPIO; 256 | esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config); 257 | esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config); 258 | #endif 259 | #endif // CONFIG_ETH_USE_SPI_ETHERNET 260 | esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); 261 | config.stack_input = pkt_eth2wifi; 262 | ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle)); 263 | #if !CONFIG_USE_INTERNAL_ETHERNET 264 | /* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually. 265 | 02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control. 266 | */ 267 | ESP_ERROR_CHECK(esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) { 268 | 0x02, 0x00, 0x00, 0x12, 0x34, 0x56 269 | })); 270 | #endif 271 | bool eth_promiscuous = true; 272 | esp_eth_ioctl(s_eth_handle, ETH_CMD_S_PROMISCUOUS, ð_promiscuous); 273 | esp_eth_start(s_eth_handle); 274 | } 275 | 276 | static void initialize_wifi(void) 277 | { 278 | ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL)); 279 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 280 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 281 | ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); 282 | 283 | #ifdef CONFIG_WLAN_AP_MODE 284 | wifi_config_t wifi_config = { 285 | .ap = { 286 | .ssid = CONFIG_WLAN_SSID, 287 | .ssid_len = strlen(CONFIG_WLAN_SSID), 288 | .password = CONFIG_WLAN_PASSPHRASE, 289 | .max_connection = CONFIG_MAX_STA_CONN, 290 | .authmode = WIFI_AUTH_WPA_WPA2_PSK, 291 | .channel = CONFIG_WLAN_CHANNEL // default: channel 1 292 | }, 293 | }; 294 | if (strlen(CONFIG_WLAN_PASSPHRASE) == 0) { 295 | wifi_config.ap.authmode = WIFI_AUTH_OPEN; 296 | } 297 | 298 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); 299 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config)); 300 | #else 301 | wifi_config_t wifi_config = { 302 | .sta = { 303 | .ssid = CONFIG_WLAN_SSID, 304 | .password = CONFIG_WLAN_PASSPHRASE, 305 | }, 306 | }; 307 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); 308 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); 309 | #endif 310 | } 311 | 312 | static esp_err_t initialize_flow_control(void) 313 | { 314 | flow_control_queue = xQueueCreate(FLOW_CONTROL_QUEUE_LENGTH, sizeof(flow_control_msg_t)); 315 | if (!flow_control_queue) { 316 | ESP_LOGE(TAG, "create flow control queue failed"); 317 | return ESP_FAIL; 318 | } 319 | BaseType_t ret = xTaskCreate(eth2wifi_flow_control_task, "flow_ctl", 2048, NULL, (tskIDLE_PRIORITY + 2), NULL); 320 | if (ret != pdTRUE) { 321 | ESP_LOGE(TAG, "create flow control task failed"); 322 | return ESP_FAIL; 323 | } 324 | return ESP_OK; 325 | } 326 | 327 | void app_main(void) 328 | { 329 | esp_err_t ret = nvs_flash_init(); 330 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { 331 | ESP_ERROR_CHECK(nvs_flash_erase()); 332 | ret = nvs_flash_init(); 333 | } 334 | ESP_ERROR_CHECK(ret); 335 | ESP_ERROR_CHECK(esp_event_loop_create_default()); 336 | ESP_ERROR_CHECK(initialize_flow_control()); 337 | initialize_wifi(); 338 | initialize_ethernet(); 339 | } 340 | --------------------------------------------------------------------------------