diff --git a/Provider/main/connect.cpp b/Provider/main/connect.cpp index 757f9aa..20a4b3e 100644 --- a/Provider/main/connect.cpp +++ b/Provider/main/connect.cpp @@ -21,6 +21,9 @@ internal esp_err_t get_ip_info(esp_netif_ip_info_t *ip_info); internal void led_blink_number(int n, uint8_t r, uint8_t g, uint8_t b); internal void blink_last_ip_octet(); +// Internal states +internal esp_netif_ip_info_t s_current_ip_info = {}; + // === Ethernet === internal constexpr char kLogEthernet[] = "ETH"; @@ -31,26 +34,43 @@ 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; +internal SemaphoreHandle_t s_semph_eth_link = nullptr; +internal volatile bool s_eth_link_up = false; #ifndef NDEBUG internal bool s_ethernet_connected = false; #endif -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)); +void ethernet_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) { + if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP) { + ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; + if (event->esp_netif != s_eth_netif) { + 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); + s_current_ip_info = event->ip_info; + xSemaphoreGive(s_semph_get_ip_addrs); + } else if (event_base == ETH_EVENT && event_id == ETHERNET_EVENT_CONNECTED) { + ESP_LOGI(kLogEthernet, "Ethernet Link Up"); + s_eth_link_up = true; + if (s_semph_eth_link) { + xSemaphoreGive(s_semph_eth_link); + } + } else if (event_base == ETH_EVENT && + event_id == ETHERNET_EVENT_DISCONNECTED) { + ESP_LOGI(kLogEthernet, "Ethernet Link Down"); + s_eth_link_up = false; + } } void teardown_ethernet() { + if (s_semph_eth_link != nullptr) { + vSemaphoreDelete(s_semph_eth_link); + s_semph_eth_link = nullptr; + } + if (s_semph_get_ip_addrs != nullptr) { vSemaphoreDelete(s_semph_get_ip_addrs); s_semph_get_ip_addrs = nullptr; @@ -59,7 +79,9 @@ void teardown_ethernet() { if (s_eth_netif) { ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, - ð_on_got_ip)); + ðernet_event_handler)); + ESP_ERROR_CHECK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, + ðernet_event_handler)); 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); @@ -82,7 +104,8 @@ internal esp_err_t connect_ethernet(bool blockUntilIPAcquired) { #endif s_semph_get_ip_addrs = xSemaphoreCreateBinary(); - if (s_semph_get_ip_addrs == NULL) { + s_semph_eth_link = xSemaphoreCreateBinary(); + if (s_semph_get_ip_addrs == NULL || s_semph_eth_link == NULL) { return ESP_ERR_NO_MEM; } // Connection is split in two steps. First we open the connection and ask for @@ -107,7 +130,9 @@ internal esp_err_t connect_ethernet(bool blockUntilIPAcquired) { // Register user defined event handlers ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, - ð_on_got_ip, NULL)); + ðernet_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, + ðernet_event_handler, NULL)); ESP_ERROR_CHECK(esp_eth_start(s_eth_handles[0])); @@ -135,6 +160,15 @@ void disconnect_ethernet() { } internal esp_err_t check_ethernet_connection(uint32_t timeoutSeconds) { + // Wait up to 5000ms for the physical link to negotiate + if (!s_eth_link_up) { + if (!xSemaphoreTake(s_semph_eth_link, pdMS_TO_TICKS(5000))) { + ESP_LOGE(kLogEthernet, + "No physical Ethernet link detected. Skipping DHCP wait."); + return ESP_ERR_INVALID_STATE; // Special error to skip retries + } + } + ESP_LOGI(kLogEthernet, "Waiting for IP address for %d seconds.", timeoutSeconds); if (xSemaphoreTake(s_semph_get_ip_addrs, @@ -151,30 +185,50 @@ internal esp_err_t check_ethernet_connection(uint32_t timeoutSeconds) { internal constexpr char kLogWifi[] = "WIFI"; internal esp_netif_t *s_wifi_netif = nullptr; internal SemaphoreHandle_t s_semph_get_wifi_ip_addrs = nullptr; +internal SemaphoreHandle_t s_semph_wifi_link = nullptr; +internal volatile bool s_wifi_link_up = false; #ifndef NDEBUG internal bool s_wifi_connected = false; #endif void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { - if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { - ESP_LOGI(kLogWifi, "WiFi disconnected, retrying..."); - esp_wifi_connect(); + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) { + ESP_LOGI(kLogWifi, "WiFi associated with AP."); + s_wifi_link_up = true; + if (s_semph_wifi_link) { + xSemaphoreGive(s_semph_wifi_link); + } + } else if (event_base == WIFI_EVENT && + event_id == WIFI_EVENT_STA_DISCONNECTED) { + ESP_LOGI(kLogWifi, "WiFi disconnected."); + s_wifi_link_up = false; } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; + if (event->esp_netif != s_wifi_netif) { + return; + } ESP_LOGI(kLogWifi, "Got IPv4 event: Interface \"%s\" address: " IPSTR, esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip)); + s_current_ip_info = event->ip_info; xSemaphoreGive(s_semph_get_wifi_ip_addrs); } } void teardown_wifi() { + if (s_semph_wifi_link != nullptr) { + vSemaphoreDelete(s_semph_wifi_link); + s_semph_wifi_link = nullptr; + } + if (s_semph_get_wifi_ip_addrs != nullptr) { vSemaphoreDelete(s_semph_get_wifi_ip_addrs); s_semph_get_wifi_ip_addrs = nullptr; } + esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, + &wifi_event_handler); esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &wifi_event_handler); esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, @@ -197,7 +251,8 @@ internal esp_err_t connect_wifi(const char *ssid, const char *password, #endif s_semph_get_wifi_ip_addrs = xSemaphoreCreateBinary(); - if (s_semph_get_wifi_ip_addrs == NULL) { + s_semph_wifi_link = xSemaphoreCreateBinary(); + if (s_semph_get_wifi_ip_addrs == NULL || s_semph_wifi_link == NULL) { return ESP_ERR_NO_MEM; } @@ -208,6 +263,8 @@ internal esp_err_t connect_wifi(const char *ssid, const char *password, wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_event_handler_register( + WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &wifi_event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register( WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &wifi_event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, @@ -248,6 +305,15 @@ void disconnect_wifi() { } internal esp_err_t check_wifi_connection(uint32_t timeoutSeconds) { + // Wait up to 10000ms for the physical link to associate with the AP + if (!s_wifi_link_up) { + if (!xSemaphoreTake(s_semph_wifi_link, pdMS_TO_TICKS(10000))) { + ESP_LOGE(kLogWifi, + "Failed to associate with WiFi AP. Skipping DHCP wait."); + return ESP_ERR_INVALID_STATE; // Special error to skip retries + } + } + ESP_LOGI(kLogWifi, "Waiting for IP address for %d seconds.", timeoutSeconds); if (xSemaphoreTake(s_semph_get_wifi_ip_addrs, pdMS_TO_TICKS(timeoutSeconds * 1000))) { @@ -259,12 +325,8 @@ internal esp_err_t check_wifi_connection(uint32_t timeoutSeconds) { } internal esp_err_t get_ip_info(esp_netif_ip_info_t *ip_info) { - if (s_eth_netif) { - return esp_netif_get_ip_info(s_eth_netif, ip_info); - } else if (s_wifi_netif) { - return esp_netif_get_ip_info(s_wifi_netif, ip_info); - } - return ESP_FAIL; + *ip_info = s_current_ip_info; + return ESP_OK; } internal void led_blink_number(int n, uint8_t r, uint8_t g, uint8_t b); @@ -280,8 +342,12 @@ internal void blink_last_ip_octet() { int t = (last_octet / 10) % 10; int u = last_octet % 10; - led_blink_number(h, 255, 255, 255); - led_blink_number(t, 255, 255, 255); + if (h > 0) { + led_blink_number(h, 255, 255, 255); + } + if (h > 0 || t > 0) { + led_blink_number(t, 255, 255, 255); + } led_blink_number(u, 255, 255, 255); } } diff --git a/Provider/main/http_server.cpp b/Provider/main/http_server.cpp index e930950..f2b756a 100644 --- a/Provider/main/http_server.cpp +++ b/Provider/main/http_server.cpp @@ -58,7 +58,7 @@ internal esp_err_t static_file_handler(httpd_req_t *req) { struct stat file_stat; if (stat(filepath, &file_stat) == -1) { // Try gzipped first, then fallback to index.html - char filepath_gz[FILE_PATH_MAX]; + char filepath_gz[FILE_PATH_MAX + 16]; snprintf(filepath_gz, sizeof(filepath_gz), "%s.gz", filepath); if (stat(filepath_gz, &file_stat) == 0) { strlcpy(filepath, filepath_gz, sizeof(filepath)); diff --git a/Provider/main/main.cpp b/Provider/main/main.cpp index 6f72050..7366c17 100644 --- a/Provider/main/main.cpp +++ b/Provider/main/main.cpp @@ -48,6 +48,11 @@ extern "C" void app_main() { set_led_status(led_status::ConnectingEthernet); result = check_ethernet_connection(retries); + if (result == ESP_ERR_INVALID_STATE) { + printf("Ethernet cable not plugged in, skipping retries.\n"); + break; + } + if (result != ESP_OK) { set_led_status(led_status::Failed); vTaskDelay(pdMS_TO_TICKS(1000)); diff --git a/Provider/partitions.csv b/Provider/partitions.csv index 2a02adf..707d6df 100644 --- a/Provider/partitions.csv +++ b/Provider/partitions.csv @@ -2,4 +2,4 @@ nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, -www, data, littlefs, , 64K, +www, data, littlefs, , 128K,