feat: Add initial Ethernet connectivity and LED status indication.

This commit is contained in:
2026-03-01 22:20:35 -05:00
parent 886eaf77ce
commit 056c86644f
6 changed files with 288 additions and 18 deletions

View File

@@ -0,0 +1,117 @@
// 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,
&eth_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,
&eth_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;
}
}