// SDK #include "esp_err.h" #include "esp_eth.h" #include "esp_eth_driver.h" #include "esp_event.h" #include "esp_log.h" #include "esp_netif.h" #include "esp_system.h" #include "ethernet_init.h" // Project includes #include "types.hpp" internal constexpr char kLogEthernet[] = "ETH"; internal constexpr char kNetifDescEth[] = "eth0"; internal esp_eth_handle_t *s_eth_handles = nullptr; internal uint8_t s_eth_count = 0; internal esp_eth_netif_glue_handle_t s_eth_glue = nullptr; internal esp_netif_t *s_eth_netif = nullptr; internal SemaphoreHandle_t s_semph_get_ip_addrs = nullptr; void eth_on_got_ip(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; bool isEthernetNetif = strncmp(kNetifDescEth, esp_netif_get_desc(event->esp_netif), strlen(kNetifDescEth) - 1) == 0; if (!isEthernetNetif) { return; } ESP_LOGI(kLogEthernet, "Got IPv4 event: Interface \"%s\" address: " IPSTR, esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip)); xSemaphoreGive(s_semph_get_ip_addrs); } void teardown_ethernet() { if (s_semph_get_ip_addrs != nullptr) { vSemaphoreDelete(s_semph_get_ip_addrs); s_semph_get_ip_addrs = nullptr; } if (s_eth_netif) { ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, ð_on_got_ip)); ESP_ERROR_CHECK(esp_eth_stop(s_eth_handles[0])); ESP_ERROR_CHECK(esp_eth_del_netif_glue(s_eth_glue)); esp_netif_destroy(s_eth_netif); ethernet_deinit_all(s_eth_handles); } s_eth_glue = nullptr; s_eth_netif = nullptr; s_eth_handles = nullptr; s_eth_count = 0; esp_netif_deinit(); } internal esp_err_t connect_ethernet(bool blockUntilIPAcquired) { s_semph_get_ip_addrs = xSemaphoreCreateBinary(); if (s_semph_get_ip_addrs == NULL) { return ESP_ERR_NO_MEM; } // Connection is split in two steps. First we open the connection and ask for // an ip. Second a semaphor will block until the ip is acquired. If we dont // block then the user have to verify the semaphore before continuing. ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(ethernet_init_all(&s_eth_handles, &s_eth_count)); esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH(); // Warning: the interface desc is used in tests to capture actual connection // details (IP, gw, mask) esp_netif_config.if_desc = kNetifDescEth; esp_netif_config.route_prio = 64; esp_netif_config_t netif_config = {.base = &esp_netif_config, .driver = nullptr, .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH}; s_eth_netif = esp_netif_new(&netif_config); s_eth_glue = esp_eth_new_netif_glue(s_eth_handles[0]); esp_netif_attach(s_eth_netif, s_eth_glue); // Register user defined event handlers ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, ð_on_got_ip, NULL)); ESP_ERROR_CHECK(esp_eth_start(s_eth_handles[0])); // Will teardown connection properly on shutdown ESP_ERROR_CHECK(esp_register_shutdown_handler(&teardown_ethernet)); if (blockUntilIPAcquired) { ESP_LOGI(kLogEthernet, "Waiting for IP address."); xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY); } return ESP_OK; } void disconnect_ethernet() { teardown_ethernet(); ESP_ERROR_CHECK(esp_unregister_shutdown_handler(&teardown_ethernet)); } internal esp_err_t check_ethernet_connection(uint32_t timeoutSeconds) { ESP_LOGI(kLogEthernet, "Waiting for IP address for %d seconds.", timeoutSeconds); if (xSemaphoreTake(s_semph_get_ip_addrs, pdMS_TO_TICKS(timeoutSeconds * 1000))) { return ESP_OK; } else { return ESP_ERR_TIMEOUT; } }