diff --git a/Provider/dependencies.lock b/Provider/dependencies.lock index 732a10f..c54b014 100644 --- a/Provider/dependencies.lock +++ b/Provider/dependencies.lock @@ -1,4 +1,116 @@ dependencies: + espressif/ethernet_init: + component_hash: 9f7d29acf5fe32315579ddb6247388291cda555aa529409108c0ada0aa7cd99d + dependencies: + - matches: + - if: $CONFIG{ETHERNET_SPI_USE_CH390} == 1 + name: espressif/ch390 + registry_url: https://components.espressif.com + require: private + version: '*' + - matches: + - if: $CONFIG{ETHERNET_SPI_USE_DM9051} == 1 + name: espressif/dm9051 + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=6.0 + version: ^1.0.0 + version: '*' + - matches: + - if: idf_version >=6.0 + version: ^1.0.0 + name: espressif/dp83848 + registry_url: https://components.espressif.com + require: private + rules: + - if: target in [esp32, esp32p4] + - if: $CONFIG{ETHERNET_PHY_USE_DP83848} == 1 + version: '*' + - matches: + - if: $CONFIG{ETHERNET_SPI_USE_ENC28J60} == 1 + name: espressif/enc28j60 + registry_url: https://components.espressif.com + require: private + version: '*' + - matches: + - if: idf_version >=6.0 + version: ^1.0.0 + name: espressif/ip101 + registry_url: https://components.espressif.com + require: private + rules: + - if: target in [esp32, esp32p4] + - if: $CONFIG{ETHERNET_PHY_USE_IP101} == 1 + version: '*' + - matches: + - if: idf_version >=6.0 + version: ^1.0.0 + name: espressif/ksz80xx + registry_url: https://components.espressif.com + require: private + rules: + - if: target in [esp32, esp32p4] + - if: $CONFIG{ETHERNET_PHY_USE_KSZ80XX} == 1 + version: '*' + - matches: + - if: $CONFIG{ETHERNET_SPI_USE_KSZ8851SNL} == 1 + name: espressif/ksz8851snl + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=6.0 + version: ^1.0.0 + version: '*' + - matches: + - if: $CONFIG{ETHERNET_SPI_USE_LAN865X} == 1 + name: espressif/lan865x + registry_url: https://components.espressif.com + require: private + version: ^0.1.1 + - name: espressif/lan867x + registry_url: https://components.espressif.com + require: private + rules: + - if: target in [esp32, esp32p4] + - if: $CONFIG{ETHERNET_PHY_USE_LAN867X} == 1 + version: '>=2.0.0' + - matches: + - if: idf_version >=6.0 + version: ^1.0.0 + name: espressif/lan87xx + registry_url: https://components.espressif.com + require: private + rules: + - if: target in [esp32, esp32p4] + - if: $CONFIG{ETHERNET_PHY_USE_LAN87XX} == 1 + version: '*' + - matches: + - if: idf_version >=6.0 + version: ^1.0.0 + name: espressif/rtl8201 + registry_url: https://components.espressif.com + require: private + rules: + - if: target in [esp32, esp32p4] + - if: $CONFIG{ETHERNET_PHY_USE_RTL8201} == 1 + version: '*' + - matches: + - if: $CONFIG{ETHERNET_SPI_USE_W5500} == 1 + name: espressif/w5500 + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=6.0 + version: ^1.0.0 + version: '*' + - name: idf + require: private + version: '>=5.4.3,!=5.5.0,!=5.5.1' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.3.0 espressif/led_strip: component_hash: 28621486f77229aaf81c71f5e15d6fbf36c2949cf11094e07090593e659e7639 dependencies: @@ -14,8 +126,9 @@ dependencies: type: idf version: 5.5.3 direct_dependencies: +- espressif/ethernet_init - espressif/led_strip - idf -manifest_hash: f9f27a7bfd490a8f252ea50084db6f87c986509746a1f4fe61b5ce5bb0e44fcb +manifest_hash: ca3e63d48140ce7f8993b19863499b13d6162b34a6fa4d0557513b244fc7a7e3 target: esp32s3 version: 2.0.0 diff --git a/Provider/main/connect.cpp b/Provider/main/connect.cpp index e69de29..c50bd20 100644 --- a/Provider/main/connect.cpp +++ b/Provider/main/connect.cpp @@ -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; + } +} \ No newline at end of file diff --git a/Provider/main/idf_component.yml b/Provider/main/idf_component.yml index 88e3292..0a60f25 100644 --- a/Provider/main/idf_component.yml +++ b/Provider/main/idf_component.yml @@ -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 diff --git a/Provider/main/led_status.cpp b/Provider/main/led_status.cpp index de9b7dc..4a4039f 100644 --- a/Provider/main/led_status.cpp +++ b/Provider/main/led_status.cpp @@ -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); diff --git a/Provider/main/main.cpp b/Provider/main/main.cpp index 73b8e2e..0d7ffcd 100644 --- a/Provider/main/main.cpp +++ b/Provider/main/main.cpp @@ -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()); } diff --git a/Provider/main/types.hpp b/Provider/main/types.hpp index 587036e..519a159 100644 --- a/Provider/main/types.hpp +++ b/Provider/main/types.hpp @@ -10,4 +10,6 @@ using uint64 = uint64_t; using int8 = int8_t; using int16 = int16_t; using int32 = int32_t; -using int64 = int64_t; \ No newline at end of file +using int64 = int64_t; + +#define internal static \ No newline at end of file