Fixing ethernet and wifi connection to be more robust
This commit is contained in:
1 parent
bdf4a73cf2
commit
8b24d9ed83
4 files changed
+100
-29
No files matched your search
+93
-27
@@ -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 led_blink_number(int n, uint8_t r, uint8_t g, uint8_t b);
|
||||||
internal void blink_last_ip_octet();
|
internal void blink_last_ip_octet();
|
||||||
|
|
||||||
|
// Internal states
|
||||||
|
internal esp_netif_ip_info_t s_current_ip_info = {};
|
||||||
|
|
||||||
// === Ethernet ===
|
// === Ethernet ===
|
||||||
|
|
||||||
internal constexpr char kLogEthernet[] = "ETH";
|
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_eth_netif_glue_handle_t s_eth_glue = nullptr;
|
||||||
internal esp_netif_t *s_eth_netif = nullptr;
|
internal esp_netif_t *s_eth_netif = nullptr;
|
||||||
internal SemaphoreHandle_t s_semph_get_ip_addrs = 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
|
#ifndef NDEBUG
|
||||||
internal bool s_ethernet_connected = false;
|
internal bool s_ethernet_connected = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void eth_on_got_ip(void *arg, esp_event_base_t event_base, int32_t event_id,
|
void ethernet_event_handler(void *arg, esp_event_base_t event_base,
|
||||||
void *event_data) {
|
int32_t event_id, void *event_data) {
|
||||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP) {
|
||||||
bool isEthernetNetif =
|
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||||
strncmp(kNetifDescEth, esp_netif_get_desc(event->esp_netif),
|
if (event->esp_netif != s_eth_netif) {
|
||||||
strlen(kNetifDescEth) - 1) == 0;
|
return;
|
||||||
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));
|
||||||
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() {
|
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) {
|
if (s_semph_get_ip_addrs != nullptr) {
|
||||||
vSemaphoreDelete(s_semph_get_ip_addrs);
|
vSemaphoreDelete(s_semph_get_ip_addrs);
|
||||||
s_semph_get_ip_addrs = nullptr;
|
s_semph_get_ip_addrs = nullptr;
|
||||||
@@ -59,7 +79,9 @@ void teardown_ethernet() {
|
|||||||
if (s_eth_netif) {
|
if (s_eth_netif) {
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP,
|
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_stop(s_eth_handles[0]));
|
||||||
ESP_ERROR_CHECK(esp_eth_del_netif_glue(s_eth_glue));
|
ESP_ERROR_CHECK(esp_eth_del_netif_glue(s_eth_glue));
|
||||||
esp_netif_destroy(s_eth_netif);
|
esp_netif_destroy(s_eth_netif);
|
||||||
@@ -82,7 +104,8 @@ internal esp_err_t connect_ethernet(bool blockUntilIPAcquired) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
s_semph_get_ip_addrs = xSemaphoreCreateBinary();
|
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;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
// Connection is split in two steps. First we open the connection and ask for
|
// 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
|
// Register user defined event handlers
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP,
|
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]));
|
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) {
|
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.",
|
ESP_LOGI(kLogEthernet, "Waiting for IP address for %d seconds.",
|
||||||
timeoutSeconds);
|
timeoutSeconds);
|
||||||
if (xSemaphoreTake(s_semph_get_ip_addrs,
|
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 constexpr char kLogWifi[] = "WIFI";
|
||||||
internal esp_netif_t *s_wifi_netif = nullptr;
|
internal esp_netif_t *s_wifi_netif = nullptr;
|
||||||
internal SemaphoreHandle_t s_semph_get_wifi_ip_addrs = 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
|
#ifndef NDEBUG
|
||||||
internal bool s_wifi_connected = false;
|
internal bool s_wifi_connected = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
||||||
int32_t event_id, void *event_data) {
|
int32_t event_id, void *event_data) {
|
||||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
|
||||||
ESP_LOGI(kLogWifi, "WiFi disconnected, retrying...");
|
ESP_LOGI(kLogWifi, "WiFi associated with AP.");
|
||||||
esp_wifi_connect();
|
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) {
|
} 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;
|
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_LOGI(kLogWifi, "Got IPv4 event: Interface \"%s\" address: " IPSTR,
|
||||||
esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip));
|
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);
|
xSemaphoreGive(s_semph_get_wifi_ip_addrs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void teardown_wifi() {
|
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) {
|
if (s_semph_get_wifi_ip_addrs != nullptr) {
|
||||||
vSemaphoreDelete(s_semph_get_wifi_ip_addrs);
|
vSemaphoreDelete(s_semph_get_wifi_ip_addrs);
|
||||||
s_semph_get_wifi_ip_addrs = nullptr;
|
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,
|
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
|
||||||
&wifi_event_handler);
|
&wifi_event_handler);
|
||||||
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
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
|
#endif
|
||||||
|
|
||||||
s_semph_get_wifi_ip_addrs = xSemaphoreCreateBinary();
|
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;
|
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();
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
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(
|
ESP_ERROR_CHECK(esp_event_handler_register(
|
||||||
WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &wifi_event_handler, NULL));
|
WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &wifi_event_handler, NULL));
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
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) {
|
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);
|
ESP_LOGI(kLogWifi, "Waiting for IP address for %d seconds.", timeoutSeconds);
|
||||||
if (xSemaphoreTake(s_semph_get_wifi_ip_addrs,
|
if (xSemaphoreTake(s_semph_get_wifi_ip_addrs,
|
||||||
pdMS_TO_TICKS(timeoutSeconds * 1000))) {
|
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) {
|
internal esp_err_t get_ip_info(esp_netif_ip_info_t *ip_info) {
|
||||||
if (s_eth_netif) {
|
*ip_info = s_current_ip_info;
|
||||||
return esp_netif_get_ip_info(s_eth_netif, ip_info);
|
return ESP_OK;
|
||||||
} else if (s_wifi_netif) {
|
|
||||||
return esp_netif_get_ip_info(s_wifi_netif, ip_info);
|
|
||||||
}
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void led_blink_number(int n, uint8_t r, uint8_t g, uint8_t b);
|
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 t = (last_octet / 10) % 10;
|
||||||
int u = last_octet % 10;
|
int u = last_octet % 10;
|
||||||
|
|
||||||
led_blink_number(h, 255, 255, 255);
|
if (h > 0) {
|
||||||
led_blink_number(t, 255, 255, 255);
|
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);
|
led_blink_number(u, 255, 255, 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ internal esp_err_t static_file_handler(httpd_req_t *req) {
|
|||||||
struct stat file_stat;
|
struct stat file_stat;
|
||||||
if (stat(filepath, &file_stat) == -1) {
|
if (stat(filepath, &file_stat) == -1) {
|
||||||
// Try gzipped first, then fallback to index.html
|
// 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);
|
snprintf(filepath_gz, sizeof(filepath_gz), "%s.gz", filepath);
|
||||||
if (stat(filepath_gz, &file_stat) == 0) {
|
if (stat(filepath_gz, &file_stat) == 0) {
|
||||||
strlcpy(filepath, filepath_gz, sizeof(filepath));
|
strlcpy(filepath, filepath_gz, sizeof(filepath));
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ extern "C" void app_main() {
|
|||||||
set_led_status(led_status::ConnectingEthernet);
|
set_led_status(led_status::ConnectingEthernet);
|
||||||
result = check_ethernet_connection(retries);
|
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) {
|
if (result != ESP_OK) {
|
||||||
set_led_status(led_status::Failed);
|
set_led_status(led_status::Failed);
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
nvs, data, nvs, 0x9000, 0x6000,
|
nvs, data, nvs, 0x9000, 0x6000,
|
||||||
phy_init, data, phy, 0xf000, 0x1000,
|
phy_init, data, phy, 0xf000, 0x1000,
|
||||||
factory, app, factory, 0x10000, 1M,
|
factory, app, factory, 0x10000, 1M,
|
||||||
www, data, littlefs, , 64K,
|
www, data, littlefs, , 128K,
|
||||||
|
Reference in new issue
Block a user