From e97d6849d275ffeb083776e3e3cd411fe6ec84e7 Mon Sep 17 00:00:00 2001 From: Piero Andreini Date: Mon, 30 Mar 2026 02:07:17 +0200 Subject: [PATCH] Add ETHClass2 lib, board definition and ETH companion radio support --- boards/t_eth_elite.json | 51 + examples/companion_radio/main.cpp | 9 +- lib/ETHClass2/library.properties | 9 + lib/ETHClass2/src/ETHClass2.cpp | 1075 +++++++++++++++++++++ lib/ETHClass2/src/ETHClass2.h | 219 +++++ src/helpers/esp32/SerialWifiInterface.cpp | 8 +- 6 files changed, 1364 insertions(+), 7 deletions(-) create mode 100644 boards/t_eth_elite.json create mode 100644 lib/ETHClass2/library.properties create mode 100644 lib/ETHClass2/src/ETHClass2.cpp create mode 100644 lib/ETHClass2/src/ETHClass2.h diff --git a/boards/t_eth_elite.json b/boards/t_eth_elite.json new file mode 100644 index 00000000..e2b039d1 --- /dev/null +++ b/boards/t_eth_elite.json @@ -0,0 +1,51 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32s3_out.ld", + "partitions": "default.csv", + "memory_type": "qio_qspi" + }, + "core": "esp32", + "extra_flags": [ + "-DARDUINO_USB_MODE=1", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "hwids": [ + [ + "0x303A", + "0x1001" + ] + ], + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": [ + "wifi" + ], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "LilyGo T-ETH-ELite (16MB Flash 8MB PSRAM)", + "upload": { + "flash_size": "16MB", + "maximum_ram_size": 8388608, + "maximum_size": 16777216, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://lilygo.cc/products/t-eth-elite-1", + "vendor": "LilyGo" + } \ No newline at end of file diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 876dc9c3..6bf09022 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -35,7 +35,7 @@ static uint32_t _atoi(const char* sp) { #endif #ifdef ESP32 - #ifdef WIFI_SSID + #if defined(WIFI_SSID) || defined(USE_ETHERNET) #include SerialWifiInterface serial_interface; #ifndef TCP_PORT @@ -122,7 +122,7 @@ void setup() { disp->endFrame(); } #endif - + if (!radio_init()) { halt(); } fast_rng.begin(radio_get_rng_seed()); @@ -194,9 +194,12 @@ void setup() { ); #ifdef WIFI_SSID - board.setInhibitSleep(true); // prevent sleep when WiFi is active + board.setInhibitSleep(true); WiFi.begin(WIFI_SSID, WIFI_PWD); serial_interface.begin(TCP_PORT); +#elif defined(USE_ETHERNET) + serial_interface.begin(TCP_PORT); + Serial.printf("TCP server started on port %d\n", TCP_PORT); #elif defined(BLE_PIN_CODE) serial_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin()); #elif defined(SERIAL_RX) diff --git a/lib/ETHClass2/library.properties b/lib/ETHClass2/library.properties new file mode 100644 index 00000000..73e9002a --- /dev/null +++ b/lib/ETHClass2/library.properties @@ -0,0 +1,9 @@ +name=ETHClass2 +version=1.0.0 +author=Lewis He +maintainer=Lewis He +sentence=Enables network connection (local and Internet) using the ESP32/ESP32S3 Ethernet. +paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through Ethernet. The IP address can be assigned statically or through a DHCP. The library can also manage DNS. +category=Communication +url= +architectures=esp32 diff --git a/lib/ETHClass2/src/ETHClass2.cpp b/lib/ETHClass2/src/ETHClass2.cpp new file mode 100644 index 00000000..57c2cb7e --- /dev/null +++ b/lib/ETHClass2/src/ETHClass2.cpp @@ -0,0 +1,1075 @@ +/* + ETH.h - espre ETH PHY support. + Based on WiFi.h from Arduino WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// Disable the automatic pin remapping of the API calls in this file +#define ARDUINO_CORE_BUILD + +#include "ETHClass2.h" +#include "esp_system.h" +#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" +#include "esp_netif.h" +#include "esp_netif_types.h" +#include "esp_netif_defaults.h" +#include "esp_eth_phy.h" + +#ifndef ETH_ADDR_LEN +#define ETH_ADDR_LEN 6 +#endif + + +#undef CONFIG_ETH_SPI_ETHERNET_DM9051 + +extern void tcpipInit(); +extern void add_esp_interface_netif(esp_interface_t interface, esp_netif_t *esp_netif); /* from WiFiGeneric */ + + +ETHClass2::ETHClass2(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 + , _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 */ +{} + +ETHClass2::~ETHClass2() +{} + +bool ETHClass2::ethDetachBus(void *bus_pointer) +{ + ETHClass2 *bus = (ETHClass2 *) bus_pointer; + if (bus->_eth_started) { + bus->end(); + } + return true; +} + +#if CONFIG_ETH_USE_ESP32_EMAC +bool ETHClass2::begin(eth_phy_type_t type, uint8_t phy_addr, int mdc, int mdio, int power, eth_clock_mode_t clock_mode) +{ + esp_err_t ret = ESP_OK; + if (_esp_netif != NULL) { + return true; + } + + // perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_RMII, ETHClass2::ethDetachBus); + // perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_CLK, ETHClass2::ethDetachBus); + // perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_MCD, ETHClass2::ethDetachBus); + // perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_MDIO, ETHClass2::ethDetachBus); + // if(power != -1){ + // perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_PWR, ETHClass2::ethDetachBus); + // } + + tcpipInit(); + + eth_mac_config_t mac_config = ETH_MAC_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 = digitalPinToGPIONumber(mdc); + mac_config.smi_mdio_gpio_num = digitalPinToGPIONumber(mdio); + + _pin_mcd = digitalPinToGPIONumber(mdc); + _pin_mdio = digitalPinToGPIONumber(mdio); + _pin_rmii_clock = mac_config.clock_config.rmii.clock_gpio; + _pin_power = digitalPinToGPIONumber(power); + + // if(!perimanClearPinBus(_pin_rmii_clock)){ return false; } + // if(!perimanClearPinBus(_pin_mcd)){ return false; } + // if(!perimanClearPinBus(_pin_mdio)){ return false; } + // if(!perimanClearPinBus(ETH_RMII_TX_EN)){ return false; } + // if(!perimanClearPinBus(ETH_RMII_TX0)){ return false; } + // if(!perimanClearPinBus(ETH_RMII_TX1)){ return false; } + // if(!perimanClearPinBus(ETH_RMII_RX0)){ return false; } + // if(!perimanClearPinBus(ETH_RMII_RX1_EN)){ return false; } + // if(!perimanClearPinBus(ETH_RMII_CRS_DV)){ return false; } + // if(_pin_power != -1){ + // if(!perimanClearPinBus(_pin_power)){ return false; } + // } + + 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); + if (mac == NULL) { + log_e("esp_eth_mac_new_esp32 failed"); + return false; + } + + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.phy_addr = phy_addr; + phy_config.reset_gpio_num = _pin_power; + + esp_eth_phy_t *phy = NULL; + switch (type) { + case ETH_PHY_LAN8720: + phy = esp_eth_phy_new_lan87xx(&phy_config); + break; + case ETH_PHY_TLK110: + // phy = esp_eth_phy_new_ip101(&phy_config); + break; + case ETH_PHY_RTL8201: + phy = esp_eth_phy_new_rtl8201(&phy_config); + break; + case ETH_PHY_DP83848: + // phy = esp_eth_phy_new_dp83848(&phy_config); + break; + case ETH_PHY_KSZ8041: + // phy = esp_eth_phy_new_ksz80xx(&phy_config); + break; + case ETH_PHY_KSZ8081: + // phy = esp_eth_phy_new_ksz80xx(&phy_config); + break; + default: + log_e("Unsupported PHY %d", type); + break; + } + if (phy == NULL) { + log_e("esp_eth_phy_new failed"); + return false; + } + + _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]; + if (_eth_index == 0) { + strcpy(if_key_str, "ETH_DEF"); + strcpy(if_desc_str, "eth"); + } else { + 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 */ + 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); + + ret = esp_eth_start(_eth_handle); + if (ret != ESP_OK) { + log_e("esp_eth_start failed: %d", ret); + return false; + } + _eth_started = true; + + // if(!perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_ETHERNET_CLK, (void *)(this), -1, -1)){ goto err; } + // if(!perimanSetPinBus(_pin_mcd, ESP32_BUS_TYPE_ETHERNET_MCD, (void *)(this), -1, -1)){ goto err; } + // if(!perimanSetPinBus(_pin_mdio, ESP32_BUS_TYPE_ETHERNET_MDIO, (void *)(this), -1, -1)){ goto err; } + + // if(!perimanSetPinBus(ETH_RMII_TX_EN, ESP32_BUS_TYPE_ETHERNET_RMII, (void *)(this), -1, -1)){ goto err; } + // if(!perimanSetPinBus(ETH_RMII_TX0, ESP32_BUS_TYPE_ETHERNET_RMII, (void *)(this), -1, -1)){ goto err; } + // if(!perimanSetPinBus(ETH_RMII_TX1, ESP32_BUS_TYPE_ETHERNET_RMII, (void *)(this), -1, -1)){ goto err; } + // if(!perimanSetPinBus(ETH_RMII_RX0, ESP32_BUS_TYPE_ETHERNET_RMII, (void *)(this), -1, -1)){ goto err; } + // if(!perimanSetPinBus(ETH_RMII_RX1_EN, ESP32_BUS_TYPE_ETHERNET_RMII, (void *)(this), -1, -1)){ goto err; } + // if(!perimanSetPinBus(ETH_RMII_CRS_DV, ESP32_BUS_TYPE_ETHERNET_RMII, (void *)(this), -1, -1)){ goto err; } + + // if(_pin_power != -1){ + // if(!perimanSetPinBus(_pin_power, ESP32_BUS_TYPE_ETHERNET_PWR, (void *)(this), -1, -1)){ goto err; } + // } + // 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"); + ETHClass2::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 ETHClass2::_eth_spi_read(void *ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len) +{ + return ((ETHClass2 *)ctx)->eth_spi_read(cmd, addr, data, data_len); +} + +esp_err_t ETHClass2::_eth_spi_write(void *ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len) +{ + return ((ETHClass2 *)ctx)->eth_spi_write(cmd, addr, data, data_len); +} + +esp_err_t ETHClass2::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); + } + } 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 ETHClass2::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 ETHClass2::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; + } + if (cs < 0 || irq < 0) { + log_e("CS and IRQ pins must be defined!"); + return false; + } + + // perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_SPI, ETHClass2::ethDetachBus); + + // if(_pin_cs != -1){ + // if(!perimanClearPinBus(_pin_cs)){ return false; } + // } + // if(_pin_rst != -1){ + // if(!perimanClearPinBus(_pin_rst)){ return false; } + // } + // if(_pin_irq != -1){ + // if(!perimanClearPinBus(_pin_irq)){ return false; } + // } + // if(_pin_sck != -1){ + // if(!perimanClearPinBus(_pin_sck)){ return false; } + // } + // if(_pin_miso != -1){ + // if(!perimanClearPinBus(_pin_miso)){ return false; } + // } + // if(_pin_mosi != -1){ + // if(!perimanClearPinBus(_pin_mosi)){ 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 = digitalPinToGPIONumber(cs); + _pin_irq = digitalPinToGPIONumber(irq); + _pin_rst = digitalPinToGPIONumber(rst); + _pin_sck = digitalPinToGPIONumber(sck); + _pin_miso = digitalPinToGPIONumber(miso); + _pin_mosi = digitalPinToGPIONumber(mosi); + +#if ETH_SPI_SUPPORTS_CUSTOM + if (_spi != NULL) { + pinMode(_pin_cs, OUTPUT); + digitalWrite(_pin_cs, HIGH); + // perimanSetPinBusExtraType(_pin_cs, "ETH_CS"); + } +#endif + + + tcpipInit(); + + // 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; + } + + // 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; + + // Init SPI bus + spi_device_handle_t spi_handle = {0}; + spi_bus_config_t buscfg = {0}; + buscfg.miso_io_num = _pin_miso; + buscfg.mosi_io_num = _pin_mosi; + buscfg.sclk_io_num = _pin_sck; + buscfg.quadwp_io_num = -1; + buscfg.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"); + return false; + } + + // Configure SPI interface for specific SPI module + spi_device_interface_config_t spi_devcfg = { + .command_bits = 16, // Actually it's the address phase in W5500 SPI frame + .address_bits = 8, // Actually it's the control phase in W5500 SPI frame + .mode = 0, + .clock_speed_hz = _spi_freq_mhz * 1000 * 1000, + .queue_size = 20 + }; + // Set SPI module Chip Select GPIO + spi_devcfg.spics_io_num = _pin_cs; + + ret = spi_bus_add_device(spi_host, &spi_devcfg, &spi_handle); + if (ret != ESP_OK) { + log_e("spi_bus_add_device failed"); + return false; + } + + 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_handle); + + 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_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+1; // Increment by the ETH number, and we start at 0 so add 1 more + 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]; + if (_eth_index == 0) { + strcpy(if_key_str, "ETH_DEF"); + strcpy(if_desc_str, "eth"); + } else { + 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_SPI, (void *)(this), -1, -1)){ goto err; } +#if ETH_SPI_SUPPORTS_CUSTOM + } +#endif + // if(!perimanSetPinBus(_pin_irq, ESP32_BUS_TYPE_ETHERNET_SPI, (void *)(this), -1, -1)){ goto err; } + + // if(_pin_sck != -1){ + // if(!perimanSetPinBus(_pin_sck, ESP32_BUS_TYPE_ETHERNET_SPI, (void *)(this), -1, -1)){ goto err; } + // } + // if(_pin_miso != -1){ + // if(!perimanSetPinBus(_pin_miso, ESP32_BUS_TYPE_ETHERNET_SPI, (void *)(this), -1, -1)){ goto err; } + // } + // if(_pin_mosi != -1){ + // if(!perimanSetPinBus(_pin_mosi, ESP32_BUS_TYPE_ETHERNET_SPI, (void *)(this), -1, -1)){ goto err; } + // } + // if(_pin_rst != -1){ + // if(!perimanSetPinBus(_pin_rst, ESP32_BUS_TYPE_ETHERNET_SPI, (void *)(this), -1, -1)){ goto err; } + // } + + return true; + +err: + log_e("Failed to set all pins bus to ETHERNET"); + ETHClass2::ethDetachBus((void *)(this)); + return false; +} + +#if ETH_SPI_SUPPORTS_CUSTOM +bool ETHClass2::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 ETHClass2::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 ETHClass2::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) { + // perimanClearPinBus(_pin_rmii_clock); + // perimanClearPinBus(_pin_mcd); + // perimanClearPinBus(_pin_mdio); + + // perimanClearPinBus(ETH_RMII_TX_EN); + // perimanClearPinBus(ETH_RMII_TX0); + // perimanClearPinBus(ETH_RMII_TX1); + // perimanClearPinBus(ETH_RMII_RX0); + // perimanClearPinBus(ETH_RMII_RX1_EN); + // perimanClearPinBus(ETH_RMII_CRS_DV); + + _pin_rmii_clock = -1; + _pin_mcd = -1; + _pin_mdio = -1; + } + + if (_pin_power != -1) { + // perimanClearPinBus(_pin_power); + _pin_power = -1; + } +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ + if (_pin_cs != -1) { + // perimanClearPinBus(_pin_cs); + _pin_cs = -1; + } + if (_pin_irq != -1) { + // perimanClearPinBus(_pin_irq); + _pin_irq = -1; + } + if (_pin_sck != -1) { + // perimanClearPinBus(_pin_sck); + _pin_sck = -1; + } + if (_pin_miso != -1) { + // perimanClearPinBus(_pin_miso); + _pin_miso = -1; + } + if (_pin_mosi != -1) { + // perimanClearPinBus(_pin_mosi); + _pin_mosi = -1; + } + if (_pin_rst != -1) { + // perimanClearPinBus(_pin_rst); + _pin_rst = -1; + } +} + +bool ETHClass2::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; + } + + // 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; + } + + // 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; + } + + // 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; + } + } + + return true; +} + +IPAddress ETHClass2::localIP() +{ + if (_esp_netif == NULL) { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) { + return IPAddress(); + } + return IPAddress(ip.ip.addr); +} + +IPAddress ETHClass2::subnetMask() +{ + if (_esp_netif == NULL) { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) { + return IPAddress(); + } + return IPAddress(ip.netmask.addr); +} + +IPAddress ETHClass2::gatewayIP() +{ + if (_esp_netif == NULL) { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) { + return IPAddress(); + } + return IPAddress(ip.gw.addr); +} + +IPAddress ETHClass2::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) { + return IPAddress(); + } + return IPAddress(d.ip.u_addr.ip4.addr); +} + +IPAddress ETHClass2::broadcastIP() +{ + if (_esp_netif == NULL) { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) { + return IPAddress(); + } + return WiFiGenericClass::calculateBroadcast(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr)); +} + +IPAddress ETHClass2::networkID() +{ + if (_esp_netif == NULL) { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) { + return IPAddress(); + } + return WiFiGenericClass::calculateNetworkID(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr)); +} + +uint8_t ETHClass2::subnetCIDR() +{ + if (_esp_netif == NULL) { + return (uint8_t)0; + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) { + return (uint8_t)0; + } + return WiFiGenericClass::calculateSubnetCIDR(IPAddress(ip.netmask.addr)); +} + +const char *ETHClass2::getHostname() +{ + if (_esp_netif == NULL) { + return ""; + } + const char *hostname; + if (esp_netif_get_hostname(_esp_netif, &hostname)) { + return NULL; + } + return hostname; +} + +bool ETHClass2::setHostname(const char *hostname) +{ + if (_esp_netif == NULL) { + return false; + } + return esp_netif_set_hostname(_esp_netif, hostname) == 0; +} + +bool ETHClass2::enableIpV6() +{ + if (_esp_netif == NULL) { + return false; + } + return esp_netif_create_ip6_linklocal(_esp_netif) == 0; +} + +IPv6Address ETHClass2::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 *ETHClass2::ifkey(void) +{ + if (_esp_netif == NULL) { + return ""; + } + return esp_netif_get_ifkey(_esp_netif); +} + +const char *ETHClass2::desc(void) +{ + if (_esp_netif == NULL) { + return ""; + } + return esp_netif_get_desc(_esp_netif); +} + +String ETHClass2::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 ETHClass2::connected() +{ + return WiFiGenericClass::getStatusBits() & ETH_CONNECTED_BIT; +} + +bool ETHClass2::hasIP() +{ + return WiFiGenericClass::getStatusBits() & ETH_HAS_IP_BIT; +} + +bool ETHClass2::linkUp() +{ + if (_esp_netif == NULL) { + return false; + } + return esp_netif_is_netif_up(_esp_netif); +} + +bool ETHClass2::fullDuplex() +{ + if (_eth_handle == NULL) { + return false; + } + eth_duplex_t link_duplex; + esp_eth_ioctl(_eth_handle, ETH_CMD_G_DUPLEX_MODE, &link_duplex); + return (link_duplex == ETH_DUPLEX_FULL); +} + +bool ETHClass2::autoNegotiation() +{ + if (_eth_handle == NULL) { + return false; + } + bool auto_nego = false;; + // esp_eth_ioctl(_eth_handle, ETH_CMD_G_AUTONEGO, &auto_nego); + return auto_nego; +} + +uint32_t ETHClass2::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 ETHClass2::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 *ETHClass2::macAddress(uint8_t *mac) +{ + if (_eth_handle == NULL) { + return NULL; + } + if (!mac) { + return NULL; + } + esp_eth_ioctl(_eth_handle, ETH_CMD_G_MAC_ADDR, mac); + return mac; +} + +String ETHClass2::macAddress(void) +{ + uint8_t mac[6] = {0, 0, 0, 0, 0, 0}; + char macStr[18] = { 0 }; + macAddress(mac); + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(macStr); +} + +void ETHClass2::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(); +} + +ETHClass2 ETH2; diff --git a/lib/ETHClass2/src/ETHClass2.h b/lib/ETHClass2/src/ETHClass2.h new file mode 100644 index 00000000..8c4685fb --- /dev/null +++ b/lib/ETHClass2/src/ETHClass2.h @@ -0,0 +1,219 @@ +/* + ETH.h - espre ETH PHY support. + Based on WiFi.h from Ardiono WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#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 0 +#include "WiFi.h" +#if ETH_SPI_SUPPORTS_CUSTOM +#include "SPI.h" +#endif +#include "esp_system.h" +#include "esp_eth.h" +#include "esp_netif.h" +#include "hal/spi_types.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 +#define ETH_RMII_TX1 22 +#define ETH_RMII_RX0 25 +#define ETH_RMII_RX1_EN 26 +#define ETH_RMII_CRS_DV 27 +#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 +#if CONFIG_ETH_SPI_ETHERNET_W5500 + ETH_PHY_W5500, +#endif +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + ETH_PHY_KSZ8851, +#endif + ETH_PHY_MAX +} eth_phy_type_t; + +class ETHClass2 { + public: + ETHClass2(uint8_t eth_index=0); + ~ETHClass2(); + +#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; + } + + 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); + 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(); + + // 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 ETHClass2 ETH2; + +#endif /* _ETH_H_ */ diff --git a/src/helpers/esp32/SerialWifiInterface.cpp b/src/helpers/esp32/SerialWifiInterface.cpp index 462e3ecc..eb62457a 100644 --- a/src/helpers/esp32/SerialWifiInterface.cpp +++ b/src/helpers/esp32/SerialWifiInterface.cpp @@ -2,10 +2,9 @@ #include void SerialWifiInterface::begin(int port) { - // wifi setup is handled outside of this class, only starts the server - server.begin(port); + server = WiFiServer(port); + server.begin(); } - // ---------- public methods void SerialWifiInterface::enable() { if (_isEnabled) return; @@ -169,4 +168,5 @@ size_t SerialWifiInterface::checkRecvFrame(uint8_t dest[]) { bool SerialWifiInterface::isConnected() const { return deviceConnected; //pServer != NULL && pServer->getConnectedCount() > 0; -} \ No newline at end of file +} +