feat: Add initial Ethernet connectivity and LED status indication.
This commit is contained in:
@@ -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,
|
||||
ð_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;
|
||||
}
|
||||
}
|
||||
@@ -15,3 +15,4 @@ dependencies:
|
||||
# # All dependencies of `main` are public by default.
|
||||
# public: true
|
||||
espressif/led_strip: ^3.0.3
|
||||
espressif/ethernet_init: ^1.3.0
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
// SDK Includes
|
||||
#include "led_strip.h"
|
||||
|
||||
enum class led_status : uint8 { Connecting, Ready, Failed };
|
||||
|
||||
// Could be a config but its the GPIO on my ESP32-S3-ETH
|
||||
#define LED_GPIO GPIO_NUM_21
|
||||
|
||||
static led_strip_handle_t led_strip;
|
||||
enum class led_status : uint8 { Connecting, Ready, Failed };
|
||||
|
||||
static void setup_led(void) {
|
||||
internal led_strip_handle_t led_strip;
|
||||
|
||||
internal void setup_led(void) {
|
||||
/* LED strip initialization with the GPIO and pixels number*/
|
||||
led_strip_config_t strip_config = {};
|
||||
strip_config.strip_gpio_num = LED_GPIO;
|
||||
@@ -26,12 +26,12 @@ static void setup_led(void) {
|
||||
led_strip_clear(led_strip);
|
||||
}
|
||||
|
||||
static void destroy_led(void) { led_strip_clear(led_strip); }
|
||||
internal void destroy_led(void) { led_strip_clear(led_strip); }
|
||||
|
||||
void set_led_status(led_status status) {
|
||||
internal void set_led_status(led_status status) {
|
||||
switch (status) {
|
||||
case led_status::Connecting:
|
||||
led_strip_set_pixel(led_strip, 0, 0, 0, 255);
|
||||
led_strip_set_pixel(led_strip, 0, 255, 255, 0);
|
||||
break;
|
||||
case led_status::Ready:
|
||||
led_strip_set_pixel(led_strip, 0, 0, 255, 0);
|
||||
|
||||
@@ -13,20 +13,57 @@
|
||||
#include "connect.cpp"
|
||||
#include "led_status.cpp"
|
||||
|
||||
extern "C" void app_main() {
|
||||
setup_led();
|
||||
printf("Hello, Worldi!\n");
|
||||
set_led_status(led_status::Connecting);
|
||||
// TODO : Make it configurable
|
||||
internal constexpr bool blockUntilEthernetEstablished = false;
|
||||
internal constexpr uint8_t maxEthernetRetries = 5;
|
||||
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
extern "C" void app_main() {
|
||||
printf("Hello, Worldi!\n");
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
setup_led();
|
||||
|
||||
set_led_status(led_status::Connecting);
|
||||
esp_err_t result = connect_ethernet(blockUntilEthernetEstablished);
|
||||
if (result != ESP_OK) {
|
||||
set_led_status(led_status::Failed);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
// Check for ethernet connection until its made
|
||||
if (!blockUntilEthernetEstablished) {
|
||||
uint8 retries = 1;
|
||||
do {
|
||||
set_led_status(led_status::Connecting);
|
||||
result = check_ethernet_connection(retries);
|
||||
|
||||
if (result != ESP_OK) {
|
||||
set_led_status(led_status::Failed);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
retries++;
|
||||
} while (result == ESP_ERR_TIMEOUT && retries <= maxEthernetRetries);
|
||||
}
|
||||
|
||||
if (result != ESP_OK) {
|
||||
// TODO : Wifi connection
|
||||
// Needs to disconnect ethernet at that point if we go wifi
|
||||
// If wifi failes -> total shutdown
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
set_led_status(led_status::Ready);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
// TODO Main loop
|
||||
|
||||
set_led_status(led_status::Failed);
|
||||
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
shutdown:
|
||||
disconnect_ethernet();
|
||||
|
||||
destroy_led();
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_loop_delete_default());
|
||||
}
|
||||
|
||||
@@ -10,4 +10,6 @@ using uint64 = uint64_t;
|
||||
using int8 = int8_t;
|
||||
using int16 = int16_t;
|
||||
using int32 = int32_t;
|
||||
using int64 = int64_t;
|
||||
using int64 = int64_t;
|
||||
|
||||
#define internal static
|
||||
Reference in New Issue
Block a user