#include "ethernet_manager.h" #include "config.h" #include "esp_log.h" #include "esp_event.h" #include "esp_eth_driver.h" #include "esp_eth_mac.h" #include "esp_eth_phy.h" #include "esp_netif.h" #include "driver/spi_master.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "lwip/ip_addr.h" #include "esp_eth_phy_w5500.h" #include "esp_eth_mac_w5500.h" #include static const char *TAG = TAG_ETH; // Ethernet handles static esp_eth_handle_t eth_handle = NULL; static esp_eth_mac_t *eth_mac = NULL; static esp_eth_phy_t *eth_phy = NULL; static esp_netif_t *eth_netif = NULL; // State tracking static bool eth_initialized = false; static bool eth_connected = false; static bool eth_has_ip = false; static SemaphoreHandle_t eth_mutex = NULL; // Event callback static eth_event_callback_t event_callback = NULL; // Current configuration static bmc_eth_config_t current_config = { .use_dhcp = true, .static_ip = BMC_STATIC_IP, .netmask = BMC_NETMASK, .gateway = BMC_GATEWAY, }; // ============================================================================ // Event Handler // ============================================================================ static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { switch (event_id) { case ETHERNET_EVENT_CONNECTED: ESP_LOGI(TAG, "Ethernet link up"); eth_connected = true; if (event_callback) { event_callback(ETH_EVENT_CONNECTED); } break; case ETHERNET_EVENT_DISCONNECTED: ESP_LOGI(TAG, "Ethernet link down"); eth_connected = false; eth_has_ip = false; if (event_callback) { event_callback(ETH_EVENT_DISCONNECTED); } break; case ETHERNET_EVENT_START: ESP_LOGI(TAG, "Ethernet started"); break; case ETHERNET_EVENT_STOP: ESP_LOGI(TAG, "Ethernet stopped"); break; case IP_EVENT_ETH_GOT_IP: { ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; ESP_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip)); ESP_LOGI(TAG, "Netmask: " IPSTR, IP2STR(&event->ip_info.netmask)); ESP_LOGI(TAG, "Gateway: " IPSTR, IP2STR(&event->ip_info.gw)); eth_has_ip = true; if (event_callback) { event_callback(ETH_EVENT_GOT_IP); } } break; default: break; } } // ============================================================================ // SPI Configuration for W5500 // ============================================================================ static esp_err_t init_spi_for_ethernet(void) { spi_bus_config_t buscfg = { .miso_io_num = ETH_SPI_MISO_GPIO, .mosi_io_num = ETH_SPI_MOSI_GPIO, .sclk_io_num = ETH_SPI_SCLK_GPIO, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 4096, }; esp_err_t ret = spi_bus_initialize(ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret)); return ret; } ESP_LOGI(TAG, "SPI bus initialized for W5500"); return ESP_OK; } // ============================================================================ // Public Functions // ============================================================================ esp_err_t ethernet_manager_init(void) { if (eth_initialized) { ESP_LOGW(TAG, "Ethernet manager already initialized"); return ESP_OK; } ESP_LOGI(TAG, "Initializing Ethernet manager (W5500 SPI)"); // Create mutex eth_mutex = xSemaphoreCreateMutex(); if (!eth_mutex) { ESP_LOGE(TAG, "Failed to create mutex"); return ESP_ERR_NO_MEM; } // Initialize TCP/IP stack ESP_ERROR_CHECK(esp_netif_init()); // Create default event loop if not already created esp_err_t loop_ret = esp_event_loop_create_default(); if (loop_ret != ESP_OK && loop_ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "Failed to create event loop: %s", esp_err_to_name(loop_ret)); return loop_ret; } // Create default ETH netif esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); eth_netif = esp_netif_new(&netif_cfg); // Register event handlers ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, ð_event_handler, NULL)); // Initialize SPI bus esp_err_t ret = init_spi_for_ethernet(); if (ret != ESP_OK) { return ret; } // Configure W5500 MAC address uint8_t mac_addr[6] = ETH_MAC_ADDR; // Create SPI device configuration for W5500 spi_device_interface_config_t devcfg = { .mode = 0, .clock_speed_hz = 36 * 1000 * 1000, // 36 MHz .queue_size = 20, .spics_io_num = ETH_SPI_CS_GPIO, }; // Create W5500 MAC instance using SPI (new API uses spi_host and device config pointer) eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(ETH_SPI_HOST, &devcfg); w5500_config.int_gpio_num = ETH_SPI_INT_GPIO; eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); mac_config.rx_task_stack_size = 4096; mac_config.rx_task_prio = 15; eth_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config); if (!eth_mac) { ESP_LOGE(TAG, "Failed to create W5500 MAC"); return ESP_FAIL; } // Create W5500 PHY instance eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); phy_config.phy_addr = 1; // W5500 uses address 1 phy_config.reset_gpio_num = ETH_SPI_RST_GPIO; phy_config.reset_timeout_ms = 1000; eth_phy = esp_eth_phy_new_w5500(&phy_config); if (!eth_phy) { ESP_LOGE(TAG, "Failed to create W5500 PHY"); return ESP_FAIL; } // Create Ethernet driver esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(eth_mac, eth_phy); ret = esp_eth_driver_install(ð_config, ð_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to install Ethernet driver: %s", esp_err_to_name(ret)); return ret; } // Set MAC address ret = esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, mac_addr); if (ret != ESP_OK) { ESP_LOGW(TAG, "Failed to set MAC address: %s", esp_err_to_name(ret)); } // Attach Ethernet driver to TCP/IP stack ret = esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to attach Ethernet to netif: %s", esp_err_to_name(ret)); esp_eth_driver_uninstall(eth_handle); return ret; } // Start Ethernet driver ret = esp_eth_start(eth_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to start Ethernet: %s", esp_err_to_name(ret)); return ret; } eth_initialized = true; ESP_LOGI(TAG, "Ethernet manager initialized successfully"); return ESP_OK; } bool ethernet_is_connected(void) { return eth_connected && eth_has_ip; } esp_err_t ethernet_get_ip(char *ip_str) { if (!eth_initialized || !ip_str) { return ESP_ERR_INVALID_STATE; } esp_netif_ip_info_t ip_info; esp_err_t ret = esp_netif_get_ip_info(eth_netif, &ip_info); if (ret == ESP_OK) { snprintf(ip_str, 16, IPSTR, IP2STR(&ip_info.ip)); } return ret; } esp_err_t ethernet_get_network_info(char *ip, char *netmask, char *gateway) { if (!eth_initialized) { return ESP_ERR_INVALID_STATE; } esp_netif_ip_info_t ip_info; esp_err_t ret = esp_netif_get_ip_info(eth_netif, &ip_info); if (ret == ESP_OK) { if (ip) snprintf(ip, 16, IPSTR, IP2STR(&ip_info.ip)); if (netmask) snprintf(netmask, 16, IPSTR, IP2STR(&ip_info.netmask)); if (gateway) snprintf(gateway, 16, IPSTR, IP2STR(&ip_info.gw)); } return ret; } esp_err_t ethernet_get_mac(char *mac_str) { if (!eth_initialized || !mac_str) { return ESP_ERR_INVALID_STATE; } uint8_t mac[6]; esp_err_t ret = esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac); if (ret == ESP_OK) { snprintf(mac_str, 18, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } return ret; } esp_err_t ethernet_set_static_ip(const bmc_eth_config_t *config) { if (!eth_initialized || !config) { return ESP_ERR_INVALID_STATE; } xSemaphoreTake(eth_mutex, portMAX_DELAY); // Stop DHCP esp_netif_dhcpc_stop(eth_netif); // Set static IP esp_netif_ip_info_t ip_info; ip_info.ip.addr = ipaddr_addr(config->static_ip); ip_info.netmask.addr = ipaddr_addr(config->netmask); ip_info.gw.addr = ipaddr_addr(config->gateway); esp_err_t ret = esp_netif_set_ip_info(eth_netif, &ip_info); if (ret == ESP_OK) { memcpy(¤t_config, config, sizeof(bmc_eth_config_t)); current_config.use_dhcp = false; ESP_LOGI(TAG, "Static IP configured: %s", config->static_ip); } else { ESP_LOGE(TAG, "Failed to set static IP: %s", esp_err_to_name(ret)); } xSemaphoreGive(eth_mutex); return ret; } esp_err_t ethernet_enable_dhcp(void) { if (!eth_initialized) { return ESP_ERR_INVALID_STATE; } xSemaphoreTake(eth_mutex, portMAX_DELAY); esp_err_t ret = esp_netif_dhcpc_start(eth_netif); if (ret == ESP_OK) { current_config.use_dhcp = true; ESP_LOGI(TAG, "DHCP enabled"); } else { ESP_LOGE(TAG, "Failed to enable DHCP: %s", esp_err_to_name(ret)); } xSemaphoreGive(eth_mutex); return ret; } int ethernet_get_link_speed(void) { if (!eth_initialized || !eth_connected) { return 0; } eth_speed_t speed; esp_err_t ret = esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &speed); if (ret == ESP_OK) { return (speed == ETH_SPEED_100M) ? 100 : 10; } return 0; } bool ethernet_is_full_duplex(void) { if (!eth_initialized || !eth_connected) { return false; } eth_duplex_t duplex; esp_err_t ret = esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &duplex); return (ret == ESP_OK && duplex == ETH_DUPLEX_FULL); } esp_err_t ethernet_register_event_callback(eth_event_callback_t callback) { event_callback = callback; return ESP_OK; }