From f61671d60e0056b53679b342ab43a80cf8e0970c Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Mon, 28 Aug 2023 14:46:15 +0300 Subject: [PATCH] [ETH] Implement SPI support, multiple interfaces and more --- .../examples/ETH_LAN8720/ETH_LAN8720.ino | 29 +- .../examples/ETH_TLK110/ETH_TLK110.ino | 27 +- .../ETH_W5500_Arduino_SPI/.skip.esp32h2 | 0 .../ETH_W5500_Arduino_SPI.ino | 110 ++ .../examples/ETH_W5500_IDF_SPI/.skip.esp32h2 | 0 .../ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino | 107 ++ libraries/Ethernet/src/ETH.cpp | 1189 +++++++++++------ libraries/Ethernet/src/ETH.h | 209 ++- libraries/WiFi/src/WiFiGeneric.cpp | 8 +- libraries/WiFi/src/WiFiGeneric.h | 1 + 10 files changed, 1166 insertions(+), 514 deletions(-) create mode 100644 libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/.skip.esp32h2 create mode 100644 libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino create mode 100644 libraries/Ethernet/examples/ETH_W5500_IDF_SPI/.skip.esp32h2 create mode 100644 libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino diff --git a/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino b/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino index a3651d9ef98..862263973ee 100644 --- a/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino +++ b/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino @@ -3,11 +3,20 @@ */ +// Important to be defined BEFORE including ETH.h for ETH.begin() to work. +// Example RMII LAN8720 (Olimex, etc.) +#define ETH_PHY_TYPE ETH_PHY_LAN8720 +#define ETH_PHY_ADDR 0 +#define ETH_PHY_MDC 23 +#define ETH_PHY_MDIO 18 +#define ETH_PHY_POWER -1 +#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN + #include static bool eth_connected = false; -void WiFiEvent(WiFiEvent_t event) +void onEvent(arduino_event_id_t event, arduino_event_info_t info) { switch (event) { case ARDUINO_EVENT_ETH_START: @@ -19,18 +28,14 @@ void WiFiEvent(WiFiEvent_t event) Serial.println("ETH Connected"); break; case ARDUINO_EVENT_ETH_GOT_IP: - Serial.print("ETH MAC: "); - Serial.print(ETH.macAddress()); - Serial.print(", IPv4: "); - Serial.print(ETH.localIP()); - if (ETH.fullDuplex()) { - Serial.print(", FULL_DUPLEX"); - } - Serial.print(", "); - Serial.print(ETH.linkSpeed()); - Serial.println("Mbps"); + Serial.println("ETH Got IP"); + ETH.printInfo(Serial); eth_connected = true; break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; case ARDUINO_EVENT_ETH_DISCONNECTED: Serial.println("ETH Disconnected"); eth_connected = false; @@ -67,7 +72,7 @@ void testClient(const char * host, uint16_t port) void setup() { Serial.begin(115200); - WiFi.onEvent(WiFiEvent); + WiFi.onEvent(onEvent); ETH.begin(); } diff --git a/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino b/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino index c144b6eeb00..9558889fbd2 100644 --- a/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino +++ b/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino @@ -5,15 +5,16 @@ #include +#define ETH_TYPE ETH_PHY_TLK110 #define ETH_ADDR 31 -#define ETH_POWER_PIN 17 #define ETH_MDC_PIN 23 #define ETH_MDIO_PIN 18 -#define ETH_TYPE ETH_PHY_TLK110 +#define ETH_POWER_PIN 17 +#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN static bool eth_connected = false; -void WiFiEvent(WiFiEvent_t event) +void onEvent(arduino_event_id_t event, arduino_event_info_t info) { switch (event) { case ARDUINO_EVENT_ETH_START: @@ -25,18 +26,14 @@ void WiFiEvent(WiFiEvent_t event) Serial.println("ETH Connected"); break; case ARDUINO_EVENT_ETH_GOT_IP: - Serial.print("ETH MAC: "); - Serial.print(ETH.macAddress()); - Serial.print(", IPv4: "); - Serial.print(ETH.localIP()); - if (ETH.fullDuplex()) { - Serial.print(", FULL_DUPLEX"); - } - Serial.print(", "); - Serial.print(ETH.linkSpeed()); - Serial.println("Mbps"); + Serial.println("ETH Got IP"); + ETH.printInfo(Serial); eth_connected = true; break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; case ARDUINO_EVENT_ETH_DISCONNECTED: Serial.println("ETH Disconnected"); eth_connected = false; @@ -73,8 +70,8 @@ void testClient(const char * host, uint16_t port) void setup() { Serial.begin(115200); - WiFi.onEvent(WiFiEvent); - ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE); + WiFi.onEvent(onEvent); + ETH.begin(ETH_TYPE, ETH_ADDR, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_POWER_PIN, ETH_CLK_MODE); } diff --git a/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/.skip.esp32h2 b/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/.skip.esp32h2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino b/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino new file mode 100644 index 00000000000..0b7e3cf1342 --- /dev/null +++ b/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino @@ -0,0 +1,110 @@ +/* + This sketch shows the Ethernet event usage + +*/ + +#include +#include + +// Set this to 1 to enable dual Ethernet support +#define USE_TWO_ETH_PORTS 0 + +#define ETH_TYPE ETH_PHY_W5500 +#define ETH_ADDR 1 +#define ETH_CS 15 +#define ETH_IRQ 4 +#define ETH_RST 5 + +// SPI pins +#define ETH_SPI_SCK 14 +#define ETH_SPI_MISO 12 +#define ETH_SPI_MOSI 13 + +#if USE_TWO_ETH_PORTS +// Second port on shared SPI bus +#define ETH1_TYPE ETH_PHY_W5500 +#define ETH1_ADDR 1 +#define ETH1_CS 32 +#define ETH1_IRQ 33 +#define ETH1_RST 18 +ETHClass ETH1(1); +#endif + +static bool eth_connected = false; + +void onEvent(arduino_event_id_t event, arduino_event_info_t info) +{ + switch (event) { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + //set eth hostname here + ETH.setHostname("esp32-eth0"); + break; + case ARDUINO_EVENT_ETH_CONNECTED: + Serial.println("ETH Connected"); + break; + case ARDUINO_EVENT_ETH_GOT_IP: + Serial.printf("ETH Got IP: '%s'\n", esp_netif_get_desc(info.got_ip.esp_netif)); + ETH.printInfo(Serial); +#if USE_TWO_ETH_PORTS + ETH1.printInfo(Serial); +#endif + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } +} + +void testClient(const char * host, uint16_t port) +{ + Serial.print("\nconnecting to "); + Serial.println(host); + + WiFiClient client; + if (!client.connect(host, port)) { + Serial.println("connection failed"); + return; + } + client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); + while (client.connected() && !client.available()); + while (client.available()) { + Serial.write(client.read()); + } + + Serial.println("closing connection\n"); + client.stop(); +} + +void setup() +{ + Serial.begin(115200); + WiFi.onEvent(onEvent); + + SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI); + ETH.begin(ETH_TYPE, ETH_ADDR, ETH_CS, ETH_IRQ, ETH_RST, SPI); +#if USE_TWO_ETH_PORTS + ETH1.begin(ETH1_TYPE, ETH1_ADDR, ETH1_CS, ETH1_IRQ, ETH1_RST, SPI); +#endif +} + + +void loop() +{ + if (eth_connected) { + testClient("google.com", 80); + } + delay(10000); +} diff --git a/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/.skip.esp32h2 b/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/.skip.esp32h2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino b/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino new file mode 100644 index 00000000000..d68b3e1d162 --- /dev/null +++ b/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino @@ -0,0 +1,107 @@ +/* + This sketch shows the Ethernet event usage + +*/ + +#include + +// Set this to 1 to enable dual Ethernet support +#define USE_TWO_ETH_PORTS 0 + +#define ETH_TYPE ETH_PHY_W5500 +#define ETH_ADDR 1 +#define ETH_CS 15 +#define ETH_IRQ 4 +#define ETH_RST 5 +#define ETH_SPI_HOST SPI2_HOST +#define ETH_SPI_SCK 14 +#define ETH_SPI_MISO 12 +#define ETH_SPI_MOSI 13 + +#if USE_TWO_ETH_PORTS +// Second port on shared SPI bus +#define ETH1_TYPE ETH_PHY_W5500 +#define ETH1_ADDR 1 +#define ETH1_CS 32 +#define ETH1_IRQ 33 +#define ETH1_RST 18 +ETHClass ETH1(1); +#endif + +static bool eth_connected = false; + +void onEvent(arduino_event_id_t event, arduino_event_info_t info) +{ + switch (event) { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + //set eth hostname here + ETH.setHostname("esp32-eth0"); + break; + case ARDUINO_EVENT_ETH_CONNECTED: + Serial.println("ETH Connected"); + break; + case ARDUINO_EVENT_ETH_GOT_IP: + Serial.printf("ETH Got IP: '%s'\n", esp_netif_get_desc(info.got_ip.esp_netif)); + ETH.printInfo(Serial); +#if USE_TWO_ETH_PORTS + ETH1.printInfo(Serial); +#endif + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } +} + +void testClient(const char * host, uint16_t port) +{ + Serial.print("\nconnecting to "); + Serial.println(host); + + WiFiClient client; + if (!client.connect(host, port)) { + Serial.println("connection failed"); + return; + } + client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); + while (client.connected() && !client.available()); + while (client.available()) { + Serial.write(client.read()); + } + + Serial.println("closing connection\n"); + client.stop(); +} + +void setup() +{ + Serial.begin(115200); + WiFi.onEvent(onEvent); + ETH.begin(ETH_TYPE, ETH_ADDR, ETH_CS, ETH_IRQ, ETH_RST, ETH_SPI_HOST, ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI); +#if USE_TWO_ETH_PORTS + // Since SPI bus is shared, we should skip the SPI pins when calling ETH1.begin() + ETH1.begin(ETH1_TYPE, ETH1_ADDR, ETH1_CS, ETH1_IRQ, ETH1_RST, ETH_SPI_HOST); +#endif +} + + +void loop() +{ + if (eth_connected) { + testClient("google.com", 80); + } + delay(10000); +} diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index c50b3f3721e..ebc499f7857 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -20,23 +20,17 @@ #include "ETH.h" #include "esp_system.h" -#if ESP_IDF_VERSION_MAJOR > 3 - #include "esp_event.h" - #include "esp_eth.h" - #include "esp_eth_mac.h" - #include "esp_eth_com.h" -#if CONFIG_IDF_TARGET_ESP32 - #include "soc/emac_ext_struct.h" - #include "soc/rtc.h" - //#include "soc/io_mux_reg.h" - //#include "hal/gpio_hal.h" -#endif - #include "esp32-hal-periman.h" -#else - #include "eth_phy/phy.h" - #include "eth_phy/phy_tlk110.h" - #include "eth_phy/phy_lan8720.h" -#endif +#include "esp_event.h" +#include "esp_eth.h" +#include "esp_eth_mac.h" +#include "esp_eth_com.h" +#include "driver/gpio.h" +#include "driver/spi_master.h" +#if CONFIG_ETH_USE_ESP32_EMAC +#include "soc/emac_ext_struct.h" +#include "soc/rtc.h" +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ +#include "esp32-hal-periman.h" #include "lwip/err.h" #include "lwip/dns.h" #include "esp_mac.h" @@ -48,336 +42,167 @@ extern void tcpipInit(); extern void add_esp_interface_netif(esp_interface_t interface, esp_netif_t* esp_netif); /* from WiFiGeneric */ -#if ESP_IDF_VERSION_MAJOR > 3 - -/** -* @brief Callback function invoked when lowlevel initialization is finished -* -* @param[in] eth_handle: handle of Ethernet driver -* -* @return -* - ESP_OK: process extra lowlevel initialization successfully -* - ESP_FAIL: error occurred when processing extra lowlevel initialization -*/ - -static eth_clock_mode_t eth_clock_mode = ETH_CLK_MODE; - -#if CONFIG_ETH_RMII_CLK_INPUT -/* -static void emac_config_apll_clock(void) -{ - // apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) - rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get(); - switch (rtc_xtal_freq) { - case RTC_XTAL_FREQ_40M: // Recommended - // 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 - // sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 - rtc_clk_apll_enable(true, 0, 0, 6, 2); - break; - case RTC_XTAL_FREQ_26M: - // 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 - // sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 - rtc_clk_apll_enable(true, 39, 118, 15, 3); - break; - case RTC_XTAL_FREQ_24M: - // 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 - // sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 - rtc_clk_apll_enable(true, 255, 255, 12, 2); - break; - default: // Assume we have a 40M xtal - rtc_clk_apll_enable(true, 0, 0, 6, 2); - break; - } -} -*/ -#endif - -/* -static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){ -#if CONFIG_IDF_TARGET_ESP32 - if(eth_clock_mode > ETH_CLOCK_GPIO17_OUT){ - return ESP_FAIL; - } - // First deinit current config if different -#if CONFIG_ETH_RMII_CLK_INPUT - if(eth_clock_mode != ETH_CLOCK_GPIO0_IN && eth_clock_mode != ETH_CLOCK_GPIO0_OUT){ - pinMode(0, INPUT); - } -#endif - -#if CONFIG_ETH_RMII_CLK_OUTPUT -#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 - if(eth_clock_mode > ETH_CLOCK_GPIO0_OUT){ - pinMode(0, INPUT); - } -#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 16 - if(eth_clock_mode != ETH_CLOCK_GPIO16_OUT){ - pinMode(16, INPUT); - } -#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 17 - if(eth_clock_mode != ETH_CLOCK_GPIO17_OUT){ - pinMode(17, INPUT); - } -#endif -#endif - - // Setup interface for the correct pin -#if CONFIG_ETH_PHY_INTERFACE_MII - EMAC_EXT.ex_phyinf_conf.phy_intf_sel = 4; -#endif - - if(eth_clock_mode == ETH_CLOCK_GPIO0_IN){ -#ifndef CONFIG_ETH_RMII_CLK_INPUT - // RMII clock (50MHz) input to GPIO0 - //gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_EMAC_TX_CLK); - //PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]); - pinMode(0, INPUT); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[0], 5); - EMAC_EXT.ex_clk_ctrl.ext_en = 1; - EMAC_EXT.ex_clk_ctrl.int_en = 0; - EMAC_EXT.ex_oscclk_conf.clk_sel = 1; -#endif - } else { - if(eth_clock_mode == ETH_CLOCK_GPIO0_OUT){ -#ifndef CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 - // APLL clock output to GPIO0 (must be configured to 50MHz!) - //gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); - //PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]); - pinMode(0, OUTPUT); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[0], 1); - // Choose the APLL clock to output on GPIO - REG_WRITE(PIN_CTRL, 6); -#endif - } else if(eth_clock_mode == ETH_CLOCK_GPIO16_OUT){ -#if CONFIG_ETH_RMII_CLK_OUT_GPIO != 16 - // RMII CLK (50MHz) output to GPIO16 - //gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT); - //PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]); - pinMode(16, OUTPUT); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[16], 5); -#endif - } else if(eth_clock_mode == ETH_CLOCK_GPIO17_OUT){ -#if CONFIG_ETH_RMII_CLK_OUT_GPIO != 17 - // RMII CLK (50MHz) output to GPIO17 - //gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180); - //PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]); - pinMode(17, OUTPUT); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[17], 5); -#endif - } -#if CONFIG_ETH_RMII_CLK_INPUT - EMAC_EXT.ex_clk_ctrl.ext_en = 0; - EMAC_EXT.ex_clk_ctrl.int_en = 1; - EMAC_EXT.ex_oscclk_conf.clk_sel = 0; - emac_config_apll_clock(); - EMAC_EXT.ex_clkout_conf.div_num = 0; - EMAC_EXT.ex_clkout_conf.h_div_num = 0; -#endif - } -#endif - return ESP_OK; -} -*/ - - -/** -* @brief Callback function invoked when lowlevel deinitialization is finished -* -* @param[in] eth_handle: handle of Ethernet driver -* -* @return -* - ESP_OK: process extra lowlevel deinitialization successfully -* - ESP_FAIL: error occurred when processing extra lowlevel deinitialization -*/ -//static esp_err_t on_lowlevel_deinit_done(esp_eth_handle_t eth_handle){ -// return ESP_OK; -//} - - - -#else -static int _eth_phy_mdc_pin = -1; -static int _eth_phy_mdio_pin = -1; -static int _eth_phy_power_pin = -1; -static eth_phy_power_enable_func _eth_phy_power_enable_orig = NULL; - -static void _eth_phy_config_gpio(void) -{ - if(_eth_phy_mdc_pin < 0 || _eth_phy_mdio_pin < 0){ - log_e("MDC and MDIO pins are not configured!"); - return; - } - phy_rmii_configure_data_interface_pins(); - phy_rmii_smi_configure_pins(_eth_phy_mdc_pin, _eth_phy_mdio_pin); -} - -static void _eth_phy_power_enable(bool enable) -{ - pinMode(_eth_phy_power_pin, OUTPUT); - digitalWrite(_eth_phy_power_pin, enable); - delay(1); -} -#endif -ETHClass::ETHClass() - :initialized(false) - ,staticIP(false) -#if ESP_IDF_VERSION_MAJOR > 3 - ,eth_handle(NULL) +ETHClass::ETHClass(uint8_t eth_index) + :_eth_started(false) + ,_eth_handle(NULL) + ,_esp_netif(NULL) + ,_eth_index(eth_index) + ,_phy_type(ETH_PHY_MAX) +#if ETH_SPI_SUPPORTS_CUSTOM + ,_spi(NULL) #endif - ,_started(false) -{ -} + ,_spi_freq_mhz(20) + ,_pin_cs(-1) + ,_pin_irq(-1) + ,_pin_rst(-1) + ,_pin_sck(-1) + ,_pin_miso(-1) + ,_pin_mosi(-1) +#if CONFIG_ETH_USE_ESP32_EMAC + ,_pin_mcd(-1) + ,_pin_mdio(-1) + ,_pin_power(-1) + ,_pin_rmii_clock(-1) +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ +{} ETHClass::~ETHClass() {} bool ETHClass::ethDetachBus(void * bus_pointer){ ETHClass *bus = (ETHClass *) bus_pointer; - if(bus->_started) { + if(bus->_eth_started) { bus->end(); } return true; } -bool ETHClass::begin(uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_type_t type, eth_clock_mode_t clock_mode, bool use_mac_from_efuse) +#if CONFIG_ETH_USE_ESP32_EMAC +bool ETHClass::begin(eth_phy_type_t type, uint8_t phy_addr, int mdc, int mdio, int power, eth_clock_mode_t clock_mode) { -#if ESP_IDF_VERSION_MAJOR > 3 - if(esp_netif != NULL){ + esp_err_t ret = ESP_OK; + if(_esp_netif != NULL){ return true; } perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET, ETHClass::ethDetachBus); - eth_clock_mode = clock_mode; tcpipInit(); - if (use_mac_from_efuse) - { - uint8_t p[6] = { 0x00,0x00,0x00,0x00,0x00,0x00 }; - esp_efuse_mac_get_custom(p); - esp_base_mac_addr_set(p); - } + eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); + mac_config.clock_config.rmii.clock_mode = (clock_mode) ? EMAC_CLK_OUT : EMAC_CLK_EXT_IN; + mac_config.clock_config.rmii.clock_gpio = (1 == clock_mode) ? EMAC_APPL_CLK_OUT_GPIO : (2 == clock_mode) ? EMAC_CLK_OUT_GPIO : (3 == clock_mode) ? EMAC_CLK_OUT_180_GPIO : EMAC_CLK_IN_GPIO; + mac_config.smi_mdc_gpio_num = mdc; + mac_config.smi_mdio_gpio_num = mdio; - //tcpip_adapter_set_default_eth_handlers(); - - esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); - esp_netif = esp_netif_new(&cfg); + _pin_mcd = mdc; + _pin_mdio = mdio; + _pin_rmii_clock = mac_config.clock_config.rmii.clock_gpio; + _pin_power = power; - esp_eth_mac_t *eth_mac = NULL; -#if CONFIG_ETH_SPI_ETHERNET_DM9051 - if(type == ETH_PHY_DM9051){ - return false;//todo - } else { -#endif -#if CONFIG_ETH_USE_ESP32_EMAC - eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); - mac_config.clock_config.rmii.clock_mode = (eth_clock_mode) ? EMAC_CLK_OUT : EMAC_CLK_EXT_IN; - mac_config.clock_config.rmii.clock_gpio = (1 == eth_clock_mode) ? EMAC_APPL_CLK_OUT_GPIO : (2 == eth_clock_mode) ? EMAC_CLK_OUT_GPIO : (3 == eth_clock_mode) ? EMAC_CLK_OUT_180_GPIO : EMAC_CLK_IN_GPIO; - mac_config.smi_mdc_gpio_num = mdc; - mac_config.smi_mdio_gpio_num = mdio; - - _pin_mcd = mdc; - _pin_mdio = mdio; - _pin_rmii_clock = mac_config.clock_config.rmii.clock_gpio; - - if(!perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_INIT, NULL)){ return false; } - if(!perimanSetPinBus(_pin_mcd, ESP32_BUS_TYPE_INIT, NULL)){ return false; } - if(!perimanSetPinBus(_pin_mdio, ESP32_BUS_TYPE_INIT, NULL)){ return false; } - - eth_mac_config_t eth_mac_config = ETH_MAC_DEFAULT_CONFIG(); - eth_mac_config.sw_reset_timeout_ms = 1000; - - eth_mac = esp_eth_mac_new_esp32(&mac_config, ð_mac_config); - - if(!perimanSetPinBus(ETH_RMII_TX_EN, ESP32_BUS_TYPE_INIT, NULL)){ return false; } - if(!perimanSetPinBus(ETH_RMII_TX0, ESP32_BUS_TYPE_INIT, NULL)){ return false; } - if(!perimanSetPinBus(ETH_RMII_TX1, ESP32_BUS_TYPE_INIT, NULL)){ return false; } - if(!perimanSetPinBus(ETH_RMII_RX0, ESP32_BUS_TYPE_INIT, NULL)){ return false; } - if(!perimanSetPinBus(ETH_RMII_RX1_EN, ESP32_BUS_TYPE_INIT, NULL)){ return false; } - if(!perimanSetPinBus(ETH_RMII_CRS_DV, ESP32_BUS_TYPE_INIT, NULL)){ return false; } -#endif -#if CONFIG_ETH_SPI_ETHERNET_DM9051 + if(!perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(_pin_mcd, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(_pin_mdio, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(ETH_RMII_TX_EN, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(ETH_RMII_TX0, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(ETH_RMII_TX1, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(ETH_RMII_RX0, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(ETH_RMII_RX1_EN, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(ETH_RMII_CRS_DV, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(_pin_power != -1){ + if(!perimanSetPinBus(_pin_power, ESP32_BUS_TYPE_INIT, NULL)){ return false; } } -#endif - if(eth_mac == NULL){ + eth_mac_config_t eth_mac_config = ETH_MAC_DEFAULT_CONFIG(); + eth_mac_config.sw_reset_timeout_ms = 1000; + + esp_eth_mac_t * mac = esp_eth_mac_new_esp32(&mac_config, ð_mac_config); + if(mac == NULL){ log_e("esp_eth_mac_new_esp32 failed"); return false; } - _pin_power = power; - if(_pin_power != -1){ - if(!perimanSetPinBus(_pin_power, ESP32_BUS_TYPE_INIT, NULL)){ return false; } - } - eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); phy_config.phy_addr = phy_addr; phy_config.reset_gpio_num = power; - esp_eth_phy_t *eth_phy = NULL; + esp_eth_phy_t *phy = NULL; switch(type){ case ETH_PHY_LAN8720: - eth_phy = esp_eth_phy_new_lan87xx(&phy_config); + phy = esp_eth_phy_new_lan87xx(&phy_config); break; case ETH_PHY_TLK110: - eth_phy = esp_eth_phy_new_ip101(&phy_config); + phy = esp_eth_phy_new_ip101(&phy_config); break; case ETH_PHY_RTL8201: - eth_phy = esp_eth_phy_new_rtl8201(&phy_config); + phy = esp_eth_phy_new_rtl8201(&phy_config); break; case ETH_PHY_DP83848: - eth_phy = esp_eth_phy_new_dp83848(&phy_config); - break; -#if CONFIG_ETH_SPI_ETHERNET_DM9051 - case ETH_PHY_DM9051: - eth_phy = esp_eth_phy_new_dm9051(&phy_config); + phy = esp_eth_phy_new_dp83848(&phy_config); break; -#endif case ETH_PHY_KSZ8041: -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4,4,0) - eth_phy = esp_eth_phy_new_ksz80xx(&phy_config); -#else - log_e("unsupported ethernet type 'ETH_PHY_KSZ8041'"); -#endif + phy = esp_eth_phy_new_ksz80xx(&phy_config); break; case ETH_PHY_KSZ8081: -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4,4,0) - eth_phy = esp_eth_phy_new_ksz80xx(&phy_config); -#else - log_e("unsupported ethernet type 'ETH_PHY_KSZ8081'"); -#endif + phy = esp_eth_phy_new_ksz80xx(&phy_config); break; default: + log_e("Unsupported PHY %d", type); break; } - if(eth_phy == NULL){ + if(phy == NULL){ log_e("esp_eth_phy_new failed"); return false; } - eth_handle = NULL; - esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(eth_mac, eth_phy); - //eth_config.on_lowlevel_init_done = on_lowlevel_init_done; - //eth_config.on_lowlevel_deinit_done = on_lowlevel_deinit_done; - if(esp_eth_driver_install(ð_config, ð_handle) != ESP_OK || eth_handle == NULL){ - log_e("esp_eth_driver_install failed"); + _eth_handle = NULL; + esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); + ret = esp_eth_driver_install(ð_config, &_eth_handle); + if (ret != ESP_OK) { + log_e("SPI Ethernet driver install failed: %d", ret); + return false; + } + if(_eth_handle == NULL){ + log_e("esp_eth_driver_install failed! eth_handle is NULL"); return false; } + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); + + // Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are used and so you need to modify + // esp-netif configuration parameters for each interface (name, priority, etc.). + char if_key_str[10]; + char if_desc_str[10]; + char num_str[3]; + itoa(_eth_index, num_str, 10); + strcat(strcpy(if_key_str, "ETH_"), num_str); + strcat(strcpy(if_desc_str, "eth"), num_str); + + esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH(); + esp_netif_config.if_key = if_key_str; + esp_netif_config.if_desc = if_desc_str; + esp_netif_config.route_prio -= _eth_index*5; + + cfg.base = &esp_netif_config; + + _esp_netif = esp_netif_new(&cfg); + /* attach Ethernet driver to TCP/IP stack */ - if(esp_netif_attach(esp_netif, esp_eth_new_netif_glue(eth_handle)) != ESP_OK){ - log_e("esp_netif_attach failed"); + ret = esp_netif_attach(_esp_netif, esp_eth_new_netif_glue(_eth_handle)); + if(ret != ESP_OK){ + log_e("esp_netif_attach failed: %d", ret); return false; } /* attach to WiFiGeneric to receive events */ - add_esp_interface_netif(ESP_IF_ETH, esp_netif); + add_esp_interface_netif(ESP_IF_ETH, _esp_netif); - if(esp_eth_start(eth_handle) != ESP_OK){ - log_e("esp_eth_start failed"); + ret = esp_eth_start(_eth_handle); + if(ret != ESP_OK){ + log_e("esp_eth_start failed: %d", ret); return false; } - _started = true; + _eth_started = true; if(!perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_ETHERNET, (void *)(this))){ goto err; } if(!perimanSetPinBus(_pin_mcd, ESP32_BUS_TYPE_ETHERNET, (void *)(this))){ goto err; } @@ -393,70 +218,378 @@ bool ETHClass::begin(uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_typ if(_pin_power != -1){ if(!perimanSetPinBus(_pin_power, ESP32_BUS_TYPE_ETHERNET, (void *)(this))){ goto err; } } -#else - esp_err_t err; - if(initialized){ - err = esp_eth_enable(); - if(err){ - log_e("esp_eth_enable error: %d", err); - return false; + // holds a few milliseconds to let DHCP start and enter into a good state + // FIX ME -- adresses issue https://github.com/espressif/arduino-esp32/issues/5733 + delay(50); + + return true; + +err: + log_e("Failed to set all pins bus to ETHERNET"); + ETHClass::ethDetachBus((void *)(this)); + return false; +} +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ + +#if ETH_SPI_SUPPORTS_CUSTOM +static void *_eth_spi_init(const void *ctx){ + return (void*)ctx; +} + +static esp_err_t _eth_spi_deinit(void *ctx){ + return ESP_OK; +} + +esp_err_t ETHClass::_eth_spi_read(void *ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len){ + return ((ETHClass*)ctx)->eth_spi_read(cmd, addr, data, data_len); +} + +esp_err_t ETHClass::_eth_spi_write(void *ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len){ + return ((ETHClass*)ctx)->eth_spi_write(cmd, addr, data, data_len); +} + +esp_err_t ETHClass::eth_spi_read(uint32_t cmd, uint32_t addr, void *data, uint32_t data_len){ + if(_spi == NULL){ + return ESP_FAIL; + } + // log_i(" 0x%04lx 0x%04lx %lu", cmd, addr, data_len); + _spi->beginTransaction(SPISettings(_spi_freq_mhz * 1000 * 1000, MSBFIRST, SPI_MODE0)); + digitalWrite(_pin_cs, LOW); + +#if CONFIG_ETH_SPI_ETHERNET_DM9051 + if(_phy_type == ETH_PHY_DM9051){ + _spi->write(((cmd & 0x01) << 7) | (addr & 0x7F)); + } else +#endif +#if CONFIG_ETH_SPI_ETHERNET_W5500 + if(_phy_type == ETH_PHY_W5500){ + _spi->write16(cmd); + _spi->write(addr); + } else +#endif +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + if(_phy_type == ETH_PHY_KSZ8851){ + if(cmd > 1){ + _spi->write(cmd << 6 | addr); + } else { + _spi->write16(cmd << 14 | addr); } - _started = true; + } else +#endif + { + log_e("Unsupported PHY module: %d", _phy_type); + digitalWrite(_pin_cs, HIGH); + _spi->endTransaction(); + return ESP_FAIL; + } + _spi->transferBytes(NULL, (uint8_t *)data, data_len); + + digitalWrite(_pin_cs, HIGH); + _spi->endTransaction(); + return ESP_OK; +} + +esp_err_t ETHClass::eth_spi_write(uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len){ + if(_spi == NULL){ + return ESP_FAIL; + } + // log_i("0x%04lx 0x%04lx %lu", cmd, addr, data_len); + _spi->beginTransaction(SPISettings(_spi_freq_mhz * 1000 * 1000, MSBFIRST, SPI_MODE0)); + digitalWrite(_pin_cs, LOW); + +#if CONFIG_ETH_SPI_ETHERNET_DM9051 + if(_phy_type == ETH_PHY_DM9051){ + _spi->write(((cmd & 0x01) << 7) | (addr & 0x7F)); + } else +#endif +#if CONFIG_ETH_SPI_ETHERNET_W5500 + if(_phy_type == ETH_PHY_W5500){ + _spi->write16(cmd); + _spi->write(addr); + } else +#endif +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + if(_phy_type == ETH_PHY_KSZ8851){ + if(cmd > 1){ + _spi->write(cmd << 6 | addr); + } else { + _spi->write16(cmd << 14 | addr); + } + } else +#endif + { + log_e("Unsupported PHY module: %d", _phy_type); + digitalWrite(_pin_cs, HIGH); + _spi->endTransaction(); + return ESP_FAIL; + } + _spi->writeBytes((const uint8_t *)data, data_len); + + digitalWrite(_pin_cs, HIGH); + _spi->endTransaction(); + return ESP_OK; +} +#endif + +bool ETHClass::beginSPI(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, +#if ETH_SPI_SUPPORTS_CUSTOM + SPIClass *spi, +#endif + int sck, int miso, int mosi, spi_host_device_t spi_host, uint8_t spi_freq_mhz){ + esp_err_t ret = ESP_OK; + + if(_eth_started || _esp_netif != NULL || _eth_handle != NULL){ + log_w("ETH Already Started"); return true; } - _eth_phy_mdc_pin = mdc; - _eth_phy_mdio_pin = mdio; - _eth_phy_power_pin = power; - - if(type == ETH_PHY_LAN8720){ - eth_config_t config = phy_lan8720_default_ethernet_config; - memcpy(ð_config, &config, sizeof(eth_config_t)); - } else if(type == ETH_PHY_TLK110){ - eth_config_t config = phy_tlk110_default_ethernet_config; - memcpy(ð_config, &config, sizeof(eth_config_t)); - } else if(type == ETH_PHY_IP101) { - eth_config_t config = phy_ip101_default_ethernet_config; - memcpy(ð_config, &config, sizeof(eth_config_t)); - } else { - log_e("Bad ETH_PHY type: %u", (uint8_t)type); + if(cs < 0 || irq < 0){ + log_e("CS and IRQ pins must be defined!"); return false; } - eth_config.phy_addr = (eth_phy_base_t)phy_addr; - eth_config.clock_mode = clock_mode; - eth_config.gpio_config = _eth_phy_config_gpio; - eth_config.tcpip_input = tcpip_adapter_eth_input; - if(_eth_phy_power_pin >= 0){ - _eth_phy_power_enable_orig = eth_config.phy_power_enable; - eth_config.phy_power_enable = _eth_phy_power_enable; + perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET, ETHClass::ethDetachBus); + + if(_pin_cs != -1){ + if(!perimanSetPinBus(_pin_cs, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + } + if(_pin_rst != -1){ + if(!perimanSetPinBus(_pin_rst, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + } + if(_pin_irq != -1){ + if(!perimanSetPinBus(_pin_irq, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + } + if(_pin_sck != -1){ + if(!perimanSetPinBus(_pin_sck, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + } + if(_pin_miso != -1){ + if(!perimanSetPinBus(_pin_miso, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + } + if(_pin_mosi != -1){ + if(!perimanSetPinBus(_pin_mosi, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + } + +#if ETH_SPI_SUPPORTS_CUSTOM + _spi = spi; +#endif + if(spi_freq_mhz){ + _spi_freq_mhz = spi_freq_mhz; + } + _phy_type = type; + _pin_cs = cs; + _pin_irq = irq; + _pin_rst = rst; + _pin_sck = sck; + _pin_miso = miso; + _pin_mosi = mosi; + +#if ETH_SPI_SUPPORTS_CUSTOM + if(_spi != NULL){ + pinMode(_pin_cs, OUTPUT); + digitalWrite(_pin_cs, HIGH); + } +#endif + + // Init SPI bus + if(_pin_sck >= 0 && _pin_miso >= 0 && _pin_mosi >= 0){ + spi_bus_config_t buscfg = { + .mosi_io_num = _pin_mosi, + .miso_io_num = _pin_miso, + .sclk_io_num = _pin_sck, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + ret = spi_bus_initialize(spi_host, &buscfg, SPI_DMA_CH_AUTO); + if (ret != ESP_OK) { + log_e("SPI bus initialize failed: %d", ret); + return false; + } } tcpipInit(); - if (use_mac_from_efuse) - { - uint8_t p[6] = { 0x00,0x00,0x00,0x00,0x00,0x00 }; - esp_efuse_mac_get_custom(p); - esp_base_mac_addr_set(p); + // Install GPIO ISR handler to be able to service SPI Eth modules interrupts + ret = gpio_install_isr_service(0); + if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { + log_e("GPIO ISR handler install failed: %d", ret); + return false; } - err = esp_eth_init(ð_config); - if(!err){ - initialized = true; - err = esp_eth_enable(); - if(err){ - log_e("esp_eth_enable error: %d", err); - } else { - _started = true; - return true; + // Init common MAC and PHY configs to default + eth_mac_config_t eth_mac_config = ETH_MAC_DEFAULT_CONFIG(); + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + + // Update PHY config based on board specific configuration + phy_config.phy_addr = phy_addr; + phy_config.reset_gpio_num = _pin_rst; + + // Configure SPI interface for specific SPI module + spi_device_interface_config_t spi_devcfg = { + .mode = 0, + .clock_speed_hz = _spi_freq_mhz * 1000 * 1000, + .input_delay_ns = 20, + .spics_io_num = _pin_cs, + .queue_size = 20, + }; + + esp_eth_mac_t *mac = NULL; + esp_eth_phy_t *phy = NULL; +#if CONFIG_ETH_SPI_ETHERNET_W5500 + if(type == ETH_PHY_W5500){ + eth_w5500_config_t mac_config = ETH_W5500_DEFAULT_CONFIG(spi_host, &spi_devcfg); + mac_config.int_gpio_num = _pin_irq; +#if ETH_SPI_SUPPORTS_CUSTOM + if(_spi != NULL){ + mac_config.custom_spi_driver.config = this; + mac_config.custom_spi_driver.init = _eth_spi_init; + mac_config.custom_spi_driver.deinit = _eth_spi_deinit; + mac_config.custom_spi_driver.read = _eth_spi_read; + mac_config.custom_spi_driver.write = _eth_spi_write; } - } else { - log_e("esp_eth_init error: %d", err); +#endif + mac = esp_eth_mac_new_w5500(&mac_config, ð_mac_config); + phy = esp_eth_phy_new_w5500(&phy_config); + } else +#endif +#if CONFIG_ETH_SPI_ETHERNET_DM9051 + if(type == ETH_PHY_DM9051){ + eth_dm9051_config_t mac_config = ETH_DM9051_DEFAULT_CONFIG(spi_host, &spi_devcfg); + mac_config.int_gpio_num = _pin_irq; +#if ETH_SPI_SUPPORTS_CUSTOM + if(_spi != NULL){ + mac_config.custom_spi_driver.config = this; + mac_config.custom_spi_driver.init = _eth_spi_init; + mac_config.custom_spi_driver.deinit = _eth_spi_deinit; + mac_config.custom_spi_driver.read = _eth_spi_read; + mac_config.custom_spi_driver.write = _eth_spi_write; + } +#endif + mac = esp_eth_mac_new_dm9051(&mac_config, ð_mac_config); + phy = esp_eth_phy_new_dm9051(&phy_config); + } else +#endif +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + if(type == ETH_PHY_KSZ8851){ + eth_ksz8851snl_config_t mac_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_host, &spi_devcfg); + mac_config.int_gpio_num = _pin_irq; +#if ETH_SPI_SUPPORTS_CUSTOM + if(_spi != NULL){ + mac_config.custom_spi_driver.config = this; + mac_config.custom_spi_driver.init = _eth_spi_init; + mac_config.custom_spi_driver.deinit = _eth_spi_deinit; + mac_config.custom_spi_driver.read = _eth_spi_read; + mac_config.custom_spi_driver.write = _eth_spi_write; + } +#endif + mac = esp_eth_mac_new_ksz8851snl(&mac_config, ð_mac_config); + phy = esp_eth_phy_new_ksz8851snl(&phy_config); + } else +#endif + { + log_e("Unsupported PHY module: %d", (int)type); + return false; + } + + // Init Ethernet driver to default and install it + esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); + ret = esp_eth_driver_install(ð_config, &_eth_handle); + if (ret != ESP_OK) { + log_e("SPI Ethernet driver install failed: %d", ret); + return false; + } + if(_eth_handle == NULL){ + log_e("esp_eth_driver_install failed! eth_handle is NULL"); + return false; + } + + // Derive a new MAC address for this interface + uint8_t base_mac_addr[ETH_ADDR_LEN]; + ret = esp_efuse_mac_get_default(base_mac_addr); + if (ret != ESP_OK) { + log_e("Get EFUSE MAC failed: %d", ret); + return false; + } + uint8_t mac_addr[ETH_ADDR_LEN]; + base_mac_addr[ETH_ADDR_LEN - 1] += _eth_index; //Increment by the ETH number + esp_derive_local_mac(mac_addr, base_mac_addr); + + ret = esp_eth_ioctl(_eth_handle, ETH_CMD_S_MAC_ADDR, mac_addr); + if (ret != ESP_OK) { + log_e("SPI Ethernet MAC address config failed: %d", ret); + return false; + } + + // Use ESP_NETIF_DEFAULT_ETH when just one Ethernet interface is used and you don't need to modify + // default esp-netif configuration parameters. + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); + + // Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are used and so you need to modify + // esp-netif configuration parameters for each interface (name, priority, etc.). + char if_key_str[10]; + char if_desc_str[10]; + char num_str[3]; + itoa(_eth_index, num_str, 10); + strcat(strcpy(if_key_str, "ETH_"), num_str); + strcat(strcpy(if_desc_str, "eth"), num_str); + + esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH(); + esp_netif_config.if_key = if_key_str; + esp_netif_config.if_desc = if_desc_str; + esp_netif_config.route_prio -= _eth_index*5; + + cfg.base = &esp_netif_config; + + _esp_netif = esp_netif_new(&cfg); + if(_esp_netif == NULL){ + log_e("esp_netif_new failed"); + return false; + } + // Attach Ethernet driver to TCP/IP stack + esp_eth_netif_glue_handle_t new_netif_glue = esp_eth_new_netif_glue(_eth_handle); + if(new_netif_glue == NULL){ + log_e("esp_eth_new_netif_glue failed"); + return false; + } + + ret = esp_netif_attach(_esp_netif, new_netif_glue); + if (ret != ESP_OK) { + log_e("esp_netif_attach failed: %d", ret); + return false; + } + + // attach to WiFiGeneric to receive events + add_esp_interface_netif(ESP_IF_ETH, _esp_netif); + + // Start Ethernet driver state machine + ret = esp_eth_start(_eth_handle); + if (ret != ESP_OK) { + log_e("esp_eth_start failed: %d", ret); + return false; + } + + _eth_started = true; + + // If Arduino's SPI is used, cs pin is in GPIO mode +#if ETH_SPI_SUPPORTS_CUSTOM + if(_spi == NULL){ +#endif + if(!perimanSetPinBus(_pin_cs, ESP32_BUS_TYPE_ETHERNET, (void *)(this))){ goto err; } +#if ETH_SPI_SUPPORTS_CUSTOM } #endif - // holds a few milliseconds to let DHCP start and enter into a good state - // FIX ME -- adresses issue https://github.com/espressif/arduino-esp32/issues/5733 - delay(50); + if(!perimanSetPinBus(_pin_irq, ESP32_BUS_TYPE_ETHERNET, (void *)(this))){ goto err; } + + if(_pin_sck != -1){ + if(!perimanSetPinBus(_pin_sck, ESP32_BUS_TYPE_ETHERNET, (void *)(this))){ goto err; } + } + if(_pin_miso != -1){ + if(!perimanSetPinBus(_pin_miso, ESP32_BUS_TYPE_ETHERNET, (void *)(this))){ goto err; } + } + if(_pin_mosi != -1){ + if(!perimanSetPinBus(_pin_mosi, ESP32_BUS_TYPE_ETHERNET, (void *)(this))){ goto err; } + } + if(_pin_rst != -1){ + if(!perimanSetPinBus(_pin_rst, ESP32_BUS_TYPE_ETHERNET, (void *)(this))){ goto err; } + } return true; @@ -466,57 +599,158 @@ bool ETHClass::begin(uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_typ return false; } +#if ETH_SPI_SUPPORTS_CUSTOM +bool ETHClass::begin(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, SPIClass &spi, uint8_t spi_freq_mhz){ + + return beginSPI(type, phy_addr, cs, irq, rst, &spi, -1, -1, -1, SPI2_HOST, spi_freq_mhz); +} +#endif + +bool ETHClass::begin(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, spi_host_device_t spi_host, int sck, int miso, int mosi, uint8_t spi_freq_mhz){ + + return beginSPI(type, phy_addr, cs, irq, rst, +#if ETH_SPI_SUPPORTS_CUSTOM + NULL, +#endif + sck, miso, mosi, spi_host, spi_freq_mhz); +} + +void ETHClass::end(void) +{ + _eth_started = false; + + if(_esp_netif != NULL){ + esp_netif_destroy(_esp_netif); + _esp_netif = NULL; + } + + if(_eth_handle != NULL){ + if(esp_eth_stop(_eth_handle) != ESP_OK) { + log_e("Failed to stop Ethernet"); + return; + } + if(esp_eth_driver_uninstall(_eth_handle) != ESP_OK) { + log_e("Failed to stop Ethernet"); + return; + } + _eth_handle = NULL; + } + +#if ETH_SPI_SUPPORTS_CUSTOM + _spi = NULL; +#endif + +#if CONFIG_ETH_USE_ESP32_EMAC + if(_pin_rmii_clock != -1 && _pin_mcd != -1 && _pin_mdio != -1){ + perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(_pin_mcd, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(_pin_mdio, ESP32_BUS_TYPE_INIT, NULL); + + perimanSetPinBus(ETH_RMII_TX_EN, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_TX0, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_TX1, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_RX0, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_RX1_EN, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_CRS_DV, ESP32_BUS_TYPE_INIT, NULL); + + _pin_rmii_clock = -1; + _pin_mcd = -1; + _pin_mdio = -1; + } + + if(_pin_power != -1){ + perimanSetPinBus(_pin_power, ESP32_BUS_TYPE_INIT, NULL); + _pin_power = -1; + } +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ + if(_pin_cs != -1){ + perimanSetPinBus(_pin_cs, ESP32_BUS_TYPE_INIT, NULL); + _pin_cs = -1; + } + if(_pin_irq != -1){ + perimanSetPinBus(_pin_irq, ESP32_BUS_TYPE_INIT, NULL); + _pin_irq = -1; + } + if(_pin_sck != -1){ + perimanSetPinBus(_pin_sck, ESP32_BUS_TYPE_INIT, NULL); + _pin_sck = -1; + } + if(_pin_miso != -1){ + perimanSetPinBus(_pin_miso, ESP32_BUS_TYPE_INIT, NULL); + _pin_miso = -1; + } + if(_pin_mosi != -1){ + perimanSetPinBus(_pin_mosi, ESP32_BUS_TYPE_INIT, NULL); + _pin_mosi = -1; + } + if(_pin_rst != -1){ + perimanSetPinBus(_pin_rst, ESP32_BUS_TYPE_INIT, NULL); + _pin_rst = -1; + } +} + + + + + + + + + + bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) { + if(_esp_netif == NULL){ + return false; + } esp_err_t err = ESP_OK; esp_netif_ip_info_t info; + esp_netif_dns_info_t d1; + esp_netif_dns_info_t d2; + d1.ip.type = IPADDR_TYPE_V4; + d2.ip.type = IPADDR_TYPE_V4; if(static_cast(local_ip) != 0){ info.ip.addr = static_cast(local_ip); info.gw.addr = static_cast(gateway); info.netmask.addr = static_cast(subnet); + d1.ip.u_addr.ip4.addr = static_cast(dns1); + d2.ip.u_addr.ip4.addr = static_cast(dns2); } else { info.ip.addr = 0; info.gw.addr = 0; info.netmask.addr = 0; + d1.ip.u_addr.ip4.addr = 0; + d2.ip.u_addr.ip4.addr = 0; } - err = esp_netif_dhcpc_stop(esp_netif); + // Stop DHCPC + err = esp_netif_dhcpc_stop(_esp_netif); if(err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED){ log_e("DHCP could not be stopped! Error: %d", err); return false; } - err = esp_netif_set_ip_info(esp_netif, &info); + // Set IPv4, Netmask, Gateway + err = esp_netif_set_ip_info(_esp_netif, &info); if(err != ERR_OK){ log_e("ETH IP could not be configured! Error: %d", err); return false; } - if(info.ip.addr){ - staticIP = true; - } else { - err = esp_netif_dhcpc_start(esp_netif); + // Set DNS1-Server + esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_MAIN, &d1); + + // Set DNS2-Server + esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_BACKUP, &d2); + + // Start DHCPC if static IP was set + if(info.ip.addr == 0){ + err = esp_netif_dhcpc_start(_esp_netif); if(err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED){ log_w("DHCP could not be started! Error: %d", err); return false; } - staticIP = false; - } - - esp_netif_dns_info_t d; - d.ip.type = IPADDR_TYPE_V4; - - if(static_cast(dns1) != 0) { - // Set DNS1-Server - d.ip.u_addr.ip4.addr = static_cast(dns1); - esp_netif_set_dns_info(esp_netif, ESP_NETIF_DNS_MAIN, &d); - } - - if(static_cast(dns2) != 0) { - // Set DNS2-Server - d.ip.u_addr.ip4.addr = static_cast(dns2); - esp_netif_set_dns_info(esp_netif, ESP_NETIF_DNS_BACKUP, &d); } return true; @@ -524,8 +758,11 @@ bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, I IPAddress ETHClass::localIP() { + if(_esp_netif == NULL){ + return IPAddress(); + } esp_netif_ip_info_t ip; - if(esp_netif_get_ip_info(esp_netif, &ip)){ + if(esp_netif_get_ip_info(_esp_netif, &ip)){ return IPAddress(); } return IPAddress(ip.ip.addr); @@ -533,8 +770,11 @@ IPAddress ETHClass::localIP() IPAddress ETHClass::subnetMask() { + if(_esp_netif == NULL){ + return IPAddress(); + } esp_netif_ip_info_t ip; - if(esp_netif_get_ip_info(esp_netif, &ip)){ + if(esp_netif_get_ip_info(_esp_netif, &ip)){ return IPAddress(); } return IPAddress(ip.netmask.addr); @@ -542,8 +782,11 @@ IPAddress ETHClass::subnetMask() IPAddress ETHClass::gatewayIP() { + if(_esp_netif == NULL){ + return IPAddress(); + } esp_netif_ip_info_t ip; - if(esp_netif_get_ip_info(esp_netif, &ip)){ + if(esp_netif_get_ip_info(_esp_netif, &ip)){ return IPAddress(); } return IPAddress(ip.gw.addr); @@ -551,8 +794,11 @@ IPAddress ETHClass::gatewayIP() IPAddress ETHClass::dnsIP(uint8_t dns_no) { + if(_esp_netif == NULL){ + return IPAddress(); + } esp_netif_dns_info_t d; - if(esp_netif_get_dns_info(esp_netif, dns_no?ESP_NETIF_DNS_BACKUP:ESP_NETIF_DNS_MAIN, &d) != ESP_OK){ + if(esp_netif_get_dns_info(_esp_netif, dns_no?ESP_NETIF_DNS_BACKUP:ESP_NETIF_DNS_MAIN, &d) != ESP_OK){ return IPAddress(); } return IPAddress(d.ip.u_addr.ip4.addr); @@ -560,8 +806,11 @@ IPAddress ETHClass::dnsIP(uint8_t dns_no) IPAddress ETHClass::broadcastIP() { + if(_esp_netif == NULL){ + return IPAddress(); + } esp_netif_ip_info_t ip; - if(esp_netif_get_ip_info(esp_netif, &ip)){ + if(esp_netif_get_ip_info(_esp_netif, &ip)){ return IPAddress(); } return WiFiGenericClass::calculateBroadcast(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr)); @@ -569,8 +818,11 @@ IPAddress ETHClass::broadcastIP() IPAddress ETHClass::networkID() { + if(_esp_netif == NULL){ + return IPAddress(); + } esp_netif_ip_info_t ip; - if(esp_netif_get_ip_info(esp_netif, &ip)){ + if(esp_netif_get_ip_info(_esp_netif, &ip)){ return IPAddress(); } return WiFiGenericClass::calculateNetworkID(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr)); @@ -578,8 +830,11 @@ IPAddress ETHClass::networkID() uint8_t ETHClass::subnetCIDR() { + if(_esp_netif == NULL){ + return (uint8_t)0; + } esp_netif_ip_info_t ip; - if(esp_netif_get_ip_info(esp_netif, &ip)){ + if(esp_netif_get_ip_info(_esp_netif, &ip)){ return (uint8_t)0; } return WiFiGenericClass::calculateSubnetCIDR(IPAddress(ip.netmask.addr)); @@ -587,8 +842,11 @@ uint8_t ETHClass::subnetCIDR() const char * ETHClass::getHostname() { + if(_esp_netif == NULL){ + return ""; + } const char * hostname; - if(esp_netif_get_hostname(esp_netif, &hostname)){ + if(esp_netif_get_hostname(_esp_netif, &hostname)){ return NULL; } return hostname; @@ -596,64 +854,129 @@ const char * ETHClass::getHostname() bool ETHClass::setHostname(const char * hostname) { - return esp_netif_set_hostname(esp_netif, hostname) == 0; + if(_esp_netif == NULL){ + return false; + } + return esp_netif_set_hostname(_esp_netif, hostname) == 0; } -bool ETHClass::fullDuplex() +bool ETHClass::enableIpV6() { -#if ESP_IDF_VERSION_MAJOR > 3 - eth_duplex_t link_duplex; - esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &link_duplex); - return (link_duplex == ETH_DUPLEX_FULL); -#else - return eth_config.phy_get_duplex_mode(); -#endif + if(_esp_netif == NULL){ + return false; + } + return esp_netif_create_ip6_linklocal(_esp_netif) == 0; } -bool ETHClass::linkUp() +IPv6Address ETHClass::localIPv6() +{ + if(_esp_netif == NULL){ + return IPv6Address(); + } + static esp_ip6_addr_t addr; + if(esp_netif_get_ip6_linklocal(_esp_netif, &addr)){ + return IPv6Address(); + } + return IPv6Address(addr.addr); +} + +const char * ETHClass::ifkey(void) +{ + if(_esp_netif == NULL){ + return ""; + } + return esp_netif_get_ifkey(_esp_netif); +} + +const char * ETHClass::desc(void) +{ + if(_esp_netif == NULL){ + return ""; + } + return esp_netif_get_desc(_esp_netif); +} + +String ETHClass::impl_name(void) +{ + if(_esp_netif == NULL){ + return String(""); + } + char netif_name[8]; + esp_err_t err = esp_netif_get_netif_impl_name(_esp_netif, netif_name); + if(err != ESP_OK){ + log_e("Failed to get netif impl_name: %d", err); + return String(""); + } + return String(netif_name); +} + +bool ETHClass::connected() { -#if ESP_IDF_VERSION_MAJOR > 3 return WiFiGenericClass::getStatusBits() & ETH_CONNECTED_BIT; -#else - return eth_config.phy_check_link(); -#endif } -uint8_t ETHClass::linkSpeed() +bool ETHClass::hasIP() { -#if ESP_IDF_VERSION_MAJOR > 3 - eth_speed_t link_speed; - esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &link_speed); - return (link_speed == ETH_SPEED_10M)?10:100; -#else - return eth_config.phy_get_speed_mode()?100:10; -#endif + return WiFiGenericClass::getStatusBits() & ETH_HAS_IP_BIT; } -bool ETHClass::enableIpV6() +bool ETHClass::linkUp() { - return esp_netif_create_ip6_linklocal(esp_netif) == 0; + if(_esp_netif == NULL){ + return false; + } + return esp_netif_is_netif_up(_esp_netif); } -IPv6Address ETHClass::localIPv6() +bool ETHClass::fullDuplex() { - static esp_ip6_addr_t addr; - if(esp_netif_get_ip6_linklocal(esp_netif, &addr)){ - return IPv6Address(); + if(_eth_handle == NULL){ + return false; } - return IPv6Address(addr.addr); + eth_duplex_t link_duplex; + esp_eth_ioctl(_eth_handle, ETH_CMD_G_DUPLEX_MODE, &link_duplex); + return (link_duplex == ETH_DUPLEX_FULL); +} + +bool ETHClass::autoNegotiation() +{ + if(_eth_handle == NULL){ + return false; + } + bool auto_nego; + esp_eth_ioctl(_eth_handle, ETH_CMD_G_AUTONEGO, &auto_nego); + return auto_nego; +} + +uint32_t ETHClass::phyAddr() +{ + if(_eth_handle == NULL){ + return 0; + } + uint32_t phy_addr; + esp_eth_ioctl(_eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr); + return phy_addr; +} + +uint8_t ETHClass::linkSpeed() +{ + if(_eth_handle == NULL){ + return 0; + } + eth_speed_t link_speed; + esp_eth_ioctl(_eth_handle, ETH_CMD_G_SPEED, &link_speed); + return (link_speed == ETH_SPEED_10M)?10:100; } uint8_t * ETHClass::macAddress(uint8_t* mac) { + if(_eth_handle == NULL){ + return NULL; + } if(!mac){ return NULL; } -#ifdef ESP_IDF_VERSION_MAJOR - esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac); -#else - esp_eth_get_mac(mac); -#endif + esp_eth_ioctl(_eth_handle, ETH_CMD_G_MAC_ADDR, mac); return mac; } @@ -666,36 +989,48 @@ String ETHClass::macAddress(void) return String(macStr); } -#if ESP_IDF_VERSION_MAJOR > 3 - -void ETHClass::end(void) -{ - if(esp_eth_stop(eth_handle) != ESP_OK) { - log_e("Failed to stop Ehternet"); - return; - } - if(esp_eth_driver_uninstall(eth_handle) != ESP_OK) { - log_e("Failed to stop Ethernet"); - return; - } - _started = false; - - perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_INIT, NULL); - perimanSetPinBus(_pin_mcd, ESP32_BUS_TYPE_INIT, NULL); - perimanSetPinBus(_pin_mdio, ESP32_BUS_TYPE_INIT, NULL); - - perimanSetPinBus(ETH_RMII_TX_EN, ESP32_BUS_TYPE_INIT, NULL); - perimanSetPinBus(ETH_RMII_TX0, ESP32_BUS_TYPE_INIT, NULL); - perimanSetPinBus(ETH_RMII_TX1, ESP32_BUS_TYPE_INIT, NULL); - perimanSetPinBus(ETH_RMII_RX0, ESP32_BUS_TYPE_INIT, NULL); - perimanSetPinBus(ETH_RMII_RX1_EN, ESP32_BUS_TYPE_INIT, NULL); - perimanSetPinBus(ETH_RMII_CRS_DV, ESP32_BUS_TYPE_INIT, NULL); - - if(_pin_power != -1){ - perimanSetPinBus(_pin_power, ESP32_BUS_TYPE_INIT, NULL); - } +void ETHClass::printInfo(Print & out){ + out.print(desc()); + out.print(":"); + if (linkUp()) { + out.print(" "); + + out.print(" "); + out.print("ether "); + out.print(macAddress()); + out.printf(" phy 0x%lX", phyAddr()); + out.println(); + + out.print(" "); + out.print("inet "); + out.print(localIP()); + out.print(" netmask "); + out.print(subnetMask()); + out.print(" broadcast "); + out.print(broadcastIP()); + out.println(); + + out.print(" "); + out.print("gateway "); + out.print(gatewayIP()); + out.print(" dns "); + out.print(dnsIP()); + out.println(); + + out.println(); } -#endif - ETHClass ETH; diff --git a/libraries/Ethernet/src/ETH.h b/libraries/Ethernet/src/ETH.h index 31981ec2198..7ef39ef561f 100644 --- a/libraries/Ethernet/src/ETH.h +++ b/libraries/Ethernet/src/ETH.h @@ -21,11 +21,59 @@ #ifndef _ETH_H_ #define _ETH_H_ +// +// Example configurations for pins_arduino.h to allow starting with ETH.begin(); +// + +// // Example RMII LAN8720 (Olimex, etc.) +// #define ETH_PHY_TYPE ETH_PHY_LAN8720 +// #define ETH_PHY_ADDR 0 +// #define ETH_PHY_MDC 23 +// #define ETH_PHY_MDIO 18 +// #define ETH_PHY_POWER -1 +// #define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN + +// // Example RMII ESP32_Ethernet_V4 +// #define ETH_PHY_TYPE ETH_PHY_TLK110 +// #define ETH_PHY_ADDR 1 +// #define ETH_PHY_MDC 23 +// #define ETH_PHY_MDIO 18 +// #define ETH_PHY_POWER -1 +// #define ETH_CLK_MODE ETH_CLOCK_GPIO0_OUT + +// // Example SPI using ESP-IDF's driver +// #define ETH_PHY_TYPE ETH_PHY_W5500 +// #define ETH_PHY_ADDR 1 +// #define ETH_PHY_CS 15 +// #define ETH_PHY_IRQ 4 +// #define ETH_PHY_RST 5 +// #define ETH_PHY_SPI_HOST SPI2_HOST +// #define ETH_PHY_SPI_SCK 14 +// #define ETH_PHY_SPI_MISO 12 +// #define ETH_PHY_SPI_MOSI 13 + +// // Example SPI using Arduino's driver +// #define ETH_PHY_TYPE ETH_PHY_W5500 +// #define ETH_PHY_ADDR 1 +// #define ETH_PHY_CS 15 +// #define ETH_PHY_IRQ 4 +// #define ETH_PHY_RST 5 +// #define ETH_PHY_SPI SPI + +// This will be uncommented once custom SPI support is available in ESP-IDF +#define ETH_SPI_SUPPORTS_CUSTOM 1 + #include "WiFi.h" +#if ETH_SPI_SUPPORTS_CUSTOM +#include "SPI.h" +#endif #include "esp_system.h" #include "esp_eth.h" #include "esp_netif.h" +#if CONFIG_ETH_USE_ESP32_EMAC +#define ETH_PHY_IP101 ETH_PHY_TLK110 +typedef enum { ETH_CLOCK_GPIO0_IN, ETH_CLOCK_GPIO0_OUT, ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT } eth_clock_mode_t; //Dedicated GPIOs for RMII #define ETH_RMII_TX_EN 21 #define ETH_RMII_TX0 19 @@ -33,94 +81,137 @@ #define ETH_RMII_RX0 25 #define ETH_RMII_RX1_EN 26 #define ETH_RMII_CRS_DV 27 - -#ifndef ETH_PHY_ADDR -#define ETH_PHY_ADDR 0 -#endif - -#ifndef ETH_PHY_TYPE -#define ETH_PHY_TYPE ETH_PHY_LAN8720 -#endif - -#ifndef ETH_PHY_POWER -#define ETH_PHY_POWER -1 -#endif - -#ifndef ETH_PHY_MDC -#define ETH_PHY_MDC 23 -#endif - -#ifndef ETH_PHY_MDIO -#define ETH_PHY_MDIO 18 +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ + +#ifndef ETH_PHY_SPI_FREQ_MHZ +#define ETH_PHY_SPI_FREQ_MHZ 20 +#endif /* ETH_PHY_SPI_FREQ_MHZ */ + +typedef enum { +#if CONFIG_ETH_USE_ESP32_EMAC + ETH_PHY_LAN8720, ETH_PHY_TLK110, ETH_PHY_RTL8201, ETH_PHY_DP83848, ETH_PHY_KSZ8041, ETH_PHY_KSZ8081, +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ +#if CONFIG_ETH_SPI_ETHERNET_DM9051 + ETH_PHY_DM9051, #endif - -#ifndef ETH_CLK_MODE -#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN +#if CONFIG_ETH_SPI_ETHERNET_W5500 + ETH_PHY_W5500, #endif - -#if ESP_IDF_VERSION_MAJOR > 3 -typedef enum { ETH_CLOCK_GPIO0_IN, ETH_CLOCK_GPIO0_OUT, ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT } eth_clock_mode_t; +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + ETH_PHY_KSZ8851, #endif - -typedef enum { ETH_PHY_LAN8720, ETH_PHY_TLK110, ETH_PHY_RTL8201, ETH_PHY_DP83848, ETH_PHY_DM9051, ETH_PHY_KSZ8041, ETH_PHY_KSZ8081, ETH_PHY_MAX } eth_phy_type_t; -#define ETH_PHY_IP101 ETH_PHY_TLK110 + ETH_PHY_MAX +} eth_phy_type_t; class ETHClass { - private: - bool initialized; - bool staticIP; -#if ESP_IDF_VERSION_MAJOR > 3 - esp_eth_handle_t eth_handle; - esp_netif_t *esp_netif; - - protected: - bool _started; - int8_t _pin_mcd = -1; - int8_t _pin_mdio = -1; - int8_t _pin_power = -1; - int8_t _pin_rmii_clock = -1; - static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); -#else - bool _started; - eth_config_t eth_config; -#endif public: - ETHClass(); + ETHClass(uint8_t eth_index=0); ~ETHClass(); - bool begin(uint8_t phy_addr=ETH_PHY_ADDR, int power=ETH_PHY_POWER, int mdc=ETH_PHY_MDC, int mdio=ETH_PHY_MDIO, eth_phy_type_t type=ETH_PHY_TYPE, eth_clock_mode_t clk_mode=ETH_CLK_MODE, bool use_mac_from_efuse=false); +#if CONFIG_ETH_USE_ESP32_EMAC + bool begin(eth_phy_type_t type, uint8_t phy_addr, int mdc, int mdio, int power, eth_clock_mode_t clk_mode); +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ +#if ETH_SPI_SUPPORTS_CUSTOM + bool begin(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, SPIClass &spi, uint8_t spi_freq_mhz=ETH_PHY_SPI_FREQ_MHZ); +#endif + bool begin(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, spi_host_device_t spi_host, int sck=-1, int miso=-1, int mosi=-1, uint8_t spi_freq_mhz=ETH_PHY_SPI_FREQ_MHZ); + + bool begin(){ +#if defined(ETH_PHY_TYPE) && defined(ETH_PHY_ADDR) + #if defined(CONFIG_ETH_USE_ESP32_EMAC) && defined(ETH_PHY_POWER) && defined(ETH_PHY_MDC) && defined(ETH_PHY_MDIO) && defined(ETH_CLK_MODE) + return begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_POWER, ETH_CLK_MODE); + #elif defined(ETH_PHY_CS) && defined(ETH_PHY_IRQ) && defined(ETH_PHY_RST) + #if ETH_SPI_SUPPORTS_CUSTOM && defined(ETH_PHY_SPI) + return begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, ETH_PHY_SPI, ETH_PHY_SPI_FREQ_MHZ); + #elif defined(ETH_PHY_SPI_HOST) && defined(ETH_PHY_SPI_SCK) && defined(ETH_PHY_SPI_MISO) && defined(ETH_PHY_SPI_MOSI) + return begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, ETH_PHY_SPI_HOST, ETH_PHY_SPI_SCK, ETH_PHY_SPI_MISO, ETH_PHY_SPI_MOSI, ETH_PHY_SPI_FREQ_MHZ); + #endif + #endif +#endif + return false; + } - bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000); + void end(); + // Netif APIs + esp_netif_t * netif(void){ return _esp_netif; } + bool config(IPAddress local_ip = (uint32_t)0x00000000, IPAddress gateway = (uint32_t)0x00000000, IPAddress subnet = (uint32_t)0x00000000, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000); const char * getHostname(); bool setHostname(const char * hostname); - - bool fullDuplex(); - bool linkUp(); - uint8_t linkSpeed(); - - bool enableIpV6(); - IPv6Address localIPv6(); - IPAddress localIP(); IPAddress subnetMask(); IPAddress gatewayIP(); IPAddress dnsIP(uint8_t dns_no = 0); - IPAddress broadcastIP(); IPAddress networkID(); uint8_t subnetCIDR(); + bool enableIpV6(); + IPv6Address localIPv6(); + const char * ifkey(void); + const char * desc(void); + String impl_name(void); + + // Event based getters + bool connected(); + bool hasIP(); + // ETH Handle APIs uint8_t * macAddress(uint8_t* mac); String macAddress(); + bool fullDuplex(); + bool linkUp(); + uint8_t linkSpeed(); + bool autoNegotiation(); + uint32_t phyAddr(); - void end(); + // Info APIs + void printInfo(Print & out); friend class WiFiClient; friend class WiFiServer; +#if ETH_SPI_SUPPORTS_CUSTOM + static esp_err_t _eth_spi_read(void *ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len); + static esp_err_t _eth_spi_write(void *ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); +#endif + + protected: +#if ETH_SPI_SUPPORTS_CUSTOM + esp_err_t eth_spi_read(uint32_t cmd, uint32_t addr, void *data, uint32_t data_len); + esp_err_t eth_spi_write(uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); +#endif + + static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); + private: + bool _eth_started; + esp_eth_handle_t _eth_handle; + esp_netif_t *_esp_netif; + uint8_t _eth_index; + eth_phy_type_t _phy_type; +#if ETH_SPI_SUPPORTS_CUSTOM + SPIClass * _spi; +#endif + uint8_t _spi_freq_mhz; + int8_t _pin_cs; + int8_t _pin_irq; + int8_t _pin_rst; + int8_t _pin_sck; + int8_t _pin_miso; + int8_t _pin_mosi; +#if CONFIG_ETH_USE_ESP32_EMAC + int8_t _pin_mcd; + int8_t _pin_mdio; + int8_t _pin_power; + int8_t _pin_rmii_clock; +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ + static bool ethDetachBus(void * bus_pointer); + bool beginSPI(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, +#if ETH_SPI_SUPPORTS_CUSTOM + SPIClass * spi, +#endif + int sck, int miso, int mosi, spi_host_device_t spi_host, uint8_t spi_freq_mhz); }; extern ETHClass ETH; diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index 7c8629b3c45..733b90ad525 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -444,10 +444,13 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev } else if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP) { #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; - log_v("Ethernet got %sip:" IPSTR, event->ip_changed?"new":"", IP2STR(&event->ip_info.ip)); + log_v("Ethernet got %sip:" IPSTR, event->ip_changed?"new ":"", IP2STR(&event->ip_info.ip)); #endif arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP; memcpy(&arduino_event.event_info.got_ip, event_data, sizeof(ip_event_got_ip_t)); + } else if (event_base == ETH_EVENT && event_id == IP_EVENT_ETH_LOST_IP) { + log_v("Ethernet Lost IP"); + arduino_event.event_id = ARDUINO_EVENT_ETH_LOST_IP; /* * IPv6 @@ -870,6 +873,7 @@ const char * WiFiGenericClass::eventName(arduino_event_id_t id) { case ARDUINO_EVENT_ETH_CONNECTED: return "ETH_CONNECTED"; case ARDUINO_EVENT_ETH_DISCONNECTED: return "ETH_DISCONNECTED"; case ARDUINO_EVENT_ETH_GOT_IP: return "ETH_GOT_IP"; + case ARDUINO_EVENT_ETH_LOST_IP: return "ETH_LOST_IP"; case ARDUINO_EVENT_ETH_GOT_IP6: return "ETH_GOT_IP6"; case ARDUINO_EVENT_WPS_ER_SUCCESS: return "WPS_ER_SUCCESS"; case ARDUINO_EVENT_WPS_ER_FAILED: return "WPS_ER_FAILED"; @@ -1137,6 +1141,8 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event) gw[0], gw[1], gw[2], gw[3]); #endif setStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP_BIT); + } else if(event->event_id == ARDUINO_EVENT_ETH_LOST_IP) { + clearStatusBits(ETH_HAS_IP_BIT); } else if(event->event_id == ARDUINO_EVENT_WIFI_STA_GOT_IP6) { setStatusBits(STA_CONNECTED_BIT | STA_HAS_IP6_BIT); diff --git a/libraries/WiFi/src/WiFiGeneric.h b/libraries/WiFi/src/WiFiGeneric.h index 25fa1b2937e..38396f5a72e 100644 --- a/libraries/WiFi/src/WiFiGeneric.h +++ b/libraries/WiFi/src/WiFiGeneric.h @@ -59,6 +59,7 @@ typedef enum { ARDUINO_EVENT_ETH_CONNECTED, ARDUINO_EVENT_ETH_DISCONNECTED, ARDUINO_EVENT_ETH_GOT_IP, + ARDUINO_EVENT_ETH_LOST_IP, ARDUINO_EVENT_ETH_GOT_IP6, ARDUINO_EVENT_WPS_ER_SUCCESS, ARDUINO_EVENT_WPS_ER_FAILED,