feat: Implement Ethernet and Wi-Fi network connectivity with LED status indication and configuration.
This commit is contained in:
27
Provider/main/Kconfig.projbuild
Normal file
27
Provider/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
menu "CalendarInk Network Configuration"
|
||||||
|
|
||||||
|
config CALENDINK_WIFI_SSID
|
||||||
|
string "WiFi SSID"
|
||||||
|
default ""
|
||||||
|
help
|
||||||
|
SSID (network name) for the WiFi connection.
|
||||||
|
|
||||||
|
config CALENDINK_WIFI_PASSWORD
|
||||||
|
string "WiFi Password"
|
||||||
|
default ""
|
||||||
|
help
|
||||||
|
Password for the WiFi connection.
|
||||||
|
|
||||||
|
config CALENDINK_ETH_RETRIES
|
||||||
|
int "Maximum Ethernet Connection Retries"
|
||||||
|
default 5
|
||||||
|
help
|
||||||
|
Number of times to retry the Ethernet connection before falling back to WiFi.
|
||||||
|
|
||||||
|
config CALENDINK_WIFI_RETRIES
|
||||||
|
int "Maximum WiFi Connection Retries"
|
||||||
|
default 5
|
||||||
|
help
|
||||||
|
Number of times to retry the WiFi connection before failing completely.
|
||||||
|
|
||||||
|
endmenu
|
||||||
@@ -6,11 +6,16 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_netif.h"
|
#include "esp_netif.h"
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
|
#include "esp_wifi.h"
|
||||||
#include "ethernet_init.h"
|
#include "ethernet_init.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
// Project includes
|
// Project includes
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
|
|
||||||
|
// === Ethernet ===
|
||||||
|
|
||||||
internal constexpr char kLogEthernet[] = "ETH";
|
internal constexpr char kLogEthernet[] = "ETH";
|
||||||
internal constexpr char kNetifDescEth[] = "eth0";
|
internal constexpr char kNetifDescEth[] = "eth0";
|
||||||
|
|
||||||
@@ -19,6 +24,9 @@ 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;
|
||||||
|
#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 eth_on_got_ip(void *arg, esp_event_base_t event_base, int32_t event_id,
|
||||||
void *event_data) {
|
void *event_data) {
|
||||||
@@ -59,6 +67,12 @@ void teardown_ethernet() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal esp_err_t connect_ethernet(bool blockUntilIPAcquired) {
|
internal esp_err_t connect_ethernet(bool blockUntilIPAcquired) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert(!s_ethernet_connected &&
|
||||||
|
"Ethernet connect called but already connected!");
|
||||||
|
s_ethernet_connected = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
s_semph_get_ip_addrs = xSemaphoreCreateBinary();
|
s_semph_get_ip_addrs = xSemaphoreCreateBinary();
|
||||||
if (s_semph_get_ip_addrs == NULL) {
|
if (s_semph_get_ip_addrs == NULL) {
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
@@ -101,6 +115,12 @@ internal esp_err_t connect_ethernet(bool blockUntilIPAcquired) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void disconnect_ethernet() {
|
void disconnect_ethernet() {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert(s_ethernet_connected &&
|
||||||
|
"Ethernet disconnect called but not connected!");
|
||||||
|
s_ethernet_connected = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
teardown_ethernet();
|
teardown_ethernet();
|
||||||
ESP_ERROR_CHECK(esp_unregister_shutdown_handler(&teardown_ethernet));
|
ESP_ERROR_CHECK(esp_unregister_shutdown_handler(&teardown_ethernet));
|
||||||
}
|
}
|
||||||
@@ -114,4 +134,113 @@ internal esp_err_t check_ethernet_connection(uint32_t timeoutSeconds) {
|
|||||||
} else {
|
} else {
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === WiFi ===
|
||||||
|
|
||||||
|
internal constexpr char kLogWifi[] = "WIFI";
|
||||||
|
internal esp_netif_t *s_wifi_netif = nullptr;
|
||||||
|
internal SemaphoreHandle_t s_semph_get_wifi_ip_addrs = nullptr;
|
||||||
|
#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();
|
||||||
|
} 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;
|
||||||
|
ESP_LOGI(kLogWifi, "Got IPv4 event: Interface \"%s\" address: " IPSTR,
|
||||||
|
esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip));
|
||||||
|
xSemaphoreGive(s_semph_get_wifi_ip_addrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void teardown_wifi() {
|
||||||
|
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_DISCONNECTED,
|
||||||
|
&wifi_event_handler);
|
||||||
|
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
||||||
|
&wifi_event_handler);
|
||||||
|
|
||||||
|
if (s_wifi_netif) {
|
||||||
|
esp_wifi_disconnect();
|
||||||
|
esp_wifi_stop();
|
||||||
|
esp_wifi_deinit();
|
||||||
|
esp_netif_destroy(s_wifi_netif);
|
||||||
|
s_wifi_netif = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal esp_err_t connect_wifi(const char *ssid, const char *password,
|
||||||
|
bool blockUntilIPAcquired) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert(!s_wifi_connected && "WiFi connect called but already connected!");
|
||||||
|
s_wifi_connected = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s_semph_get_wifi_ip_addrs = xSemaphoreCreateBinary();
|
||||||
|
if (s_semph_get_wifi_ip_addrs == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// esp_netif_init() is already called by Ethernet, but safe to call multiple
|
||||||
|
// times or we can assume it's initialized.
|
||||||
|
s_wifi_netif = esp_netif_create_default_wifi_sta();
|
||||||
|
|
||||||
|
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_DISCONNECTED, &wifi_event_handler, NULL));
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
||||||
|
&wifi_event_handler, NULL));
|
||||||
|
|
||||||
|
wifi_config_t wifi_config = {};
|
||||||
|
strncpy((char *)wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid) - 1);
|
||||||
|
strncpy((char *)wifi_config.sta.password, password,
|
||||||
|
sizeof(wifi_config.sta.password) - 1);
|
||||||
|
// Setting a default auth mode if password is provided
|
||||||
|
wifi_config.sta.threshold.authmode =
|
||||||
|
password[0] != '\0' ? WIFI_AUTH_WPA2_PSK : WIFI_AUTH_OPEN;
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_start());
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_connect());
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_register_shutdown_handler(&teardown_wifi));
|
||||||
|
|
||||||
|
if (blockUntilIPAcquired) {
|
||||||
|
ESP_LOGI(kLogWifi, "Waiting for IP address.");
|
||||||
|
xSemaphoreTake(s_semph_get_wifi_ip_addrs, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnect_wifi() {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert(s_wifi_connected && "WiFi disconnect called but not connected!");
|
||||||
|
s_wifi_connected = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
teardown_wifi();
|
||||||
|
ESP_ERROR_CHECK(esp_unregister_shutdown_handler(&teardown_wifi));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal esp_err_t check_wifi_connection(uint32_t timeoutSeconds) {
|
||||||
|
ESP_LOGI(kLogWifi, "Waiting for IP address for %d seconds.", timeoutSeconds);
|
||||||
|
if (xSemaphoreTake(s_semph_get_wifi_ip_addrs,
|
||||||
|
pdMS_TO_TICKS(timeoutSeconds * 1000))) {
|
||||||
|
return ESP_OK;
|
||||||
|
} else {
|
||||||
|
return ESP_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,13 @@
|
|||||||
// Could be a config but its the GPIO on my ESP32-S3-ETH
|
// Could be a config but its the GPIO on my ESP32-S3-ETH
|
||||||
#define LED_GPIO GPIO_NUM_21
|
#define LED_GPIO GPIO_NUM_21
|
||||||
|
|
||||||
enum class led_status : uint8 { Connecting, Ready, Failed };
|
enum class led_status : uint8 {
|
||||||
|
ConnectingEthernet,
|
||||||
|
ConnectingWifi,
|
||||||
|
ReadyEthernet,
|
||||||
|
ReadyWifi,
|
||||||
|
Failed
|
||||||
|
};
|
||||||
|
|
||||||
internal led_strip_handle_t led_strip;
|
internal led_strip_handle_t led_strip;
|
||||||
|
|
||||||
@@ -30,11 +36,17 @@ internal void destroy_led(void) { led_strip_clear(led_strip); }
|
|||||||
|
|
||||||
internal void set_led_status(led_status status) {
|
internal void set_led_status(led_status status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case led_status::Connecting:
|
case led_status::ConnectingEthernet:
|
||||||
led_strip_set_pixel(led_strip, 0, 255, 255, 0);
|
led_strip_set_pixel(led_strip, 0, 255, 165, 0);
|
||||||
break;
|
break;
|
||||||
case led_status::Ready:
|
case led_status::ConnectingWifi:
|
||||||
led_strip_set_pixel(led_strip, 0, 0, 255, 0);
|
led_strip_set_pixel(led_strip, 0, 148, 0, 211);
|
||||||
|
break;
|
||||||
|
case led_status::ReadyEthernet:
|
||||||
|
led_strip_set_pixel(led_strip, 0, 0, 255, 0); // Green
|
||||||
|
break;
|
||||||
|
case led_status::ReadyWifi:
|
||||||
|
led_strip_set_pixel(led_strip, 0, 0, 0, 255); // Blue
|
||||||
break;
|
break;
|
||||||
case led_status::Failed:
|
case led_status::Failed:
|
||||||
led_strip_set_pixel(led_strip, 0, 255, 0, 0);
|
led_strip_set_pixel(led_strip, 0, 255, 0, 0);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "soc/gpio_num.h"
|
#include "soc/gpio_num.h"
|
||||||
|
|
||||||
@@ -15,16 +16,19 @@
|
|||||||
|
|
||||||
// TODO : Make it configurable
|
// TODO : Make it configurable
|
||||||
internal constexpr bool blockUntilEthernetEstablished = false;
|
internal constexpr bool blockUntilEthernetEstablished = false;
|
||||||
internal constexpr uint8_t maxEthernetRetries = 5;
|
internal bool ethernetInitialized = false;
|
||||||
|
internal bool wifiInitialized = false;
|
||||||
|
|
||||||
extern "C" void app_main() {
|
extern "C" void app_main() {
|
||||||
printf("Hello, Worldi!\n");
|
printf("Hello, Worldi!\n");
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
setup_led();
|
setup_led();
|
||||||
|
|
||||||
set_led_status(led_status::Connecting);
|
set_led_status(led_status::ConnectingEthernet);
|
||||||
|
ethernetInitialized = true;
|
||||||
esp_err_t result = connect_ethernet(blockUntilEthernetEstablished);
|
esp_err_t result = connect_ethernet(blockUntilEthernetEstablished);
|
||||||
if (result != ESP_OK) {
|
if (result != ESP_OK) {
|
||||||
set_led_status(led_status::Failed);
|
set_led_status(led_status::Failed);
|
||||||
@@ -36,7 +40,7 @@ extern "C" void app_main() {
|
|||||||
if (!blockUntilEthernetEstablished) {
|
if (!blockUntilEthernetEstablished) {
|
||||||
uint8 retries = 1;
|
uint8 retries = 1;
|
||||||
do {
|
do {
|
||||||
set_led_status(led_status::Connecting);
|
set_led_status(led_status::ConnectingEthernet);
|
||||||
result = check_ethernet_connection(retries);
|
result = check_ethernet_connection(retries);
|
||||||
|
|
||||||
if (result != ESP_OK) {
|
if (result != ESP_OK) {
|
||||||
@@ -45,25 +49,73 @@ extern "C" void app_main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
retries++;
|
retries++;
|
||||||
} while (result == ESP_ERR_TIMEOUT && retries <= maxEthernetRetries);
|
} while (result == ESP_ERR_TIMEOUT &&
|
||||||
|
retries <= CONFIG_CALENDINK_ETH_RETRIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != ESP_OK) {
|
if (result != ESP_OK) {
|
||||||
// TODO : Wifi connection
|
printf("Ethernet failed, trying wifi\n");
|
||||||
// Needs to disconnect ethernet at that point if we go wifi
|
disconnect_ethernet();
|
||||||
// If wifi failes -> total shutdown
|
ethernetInitialized = false;
|
||||||
goto shutdown;
|
|
||||||
|
set_led_status(led_status::ConnectingWifi);
|
||||||
|
wifiInitialized = true;
|
||||||
|
result =
|
||||||
|
connect_wifi(CONFIG_CALENDINK_WIFI_SSID, CONFIG_CALENDINK_WIFI_PASSWORD,
|
||||||
|
blockUntilEthernetEstablished);
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
set_led_status(led_status::Failed);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blockUntilEthernetEstablished) {
|
||||||
|
uint8 retries = 1;
|
||||||
|
do {
|
||||||
|
set_led_status(led_status::ConnectingWifi);
|
||||||
|
result = check_wifi_connection(retries);
|
||||||
|
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
set_led_status(led_status::Failed);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
retries++;
|
||||||
|
} while (result == ESP_ERR_TIMEOUT &&
|
||||||
|
retries <= CONFIG_CALENDINK_WIFI_RETRIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
printf("Wifi failed.\n");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_led_status(led_status::ReadyWifi);
|
||||||
|
printf("Will use Wifi!\n");
|
||||||
|
} else {
|
||||||
|
set_led_status(led_status::ReadyEthernet);
|
||||||
|
printf("Will use Ethernet!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
set_led_status(led_status::Ready);
|
printf("Connected!\n");
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||||
|
|
||||||
// TODO Main loop
|
// TODO Main loop
|
||||||
|
|
||||||
shutdown:
|
shutdown:
|
||||||
disconnect_ethernet();
|
printf("Shutting down.\n");
|
||||||
|
|
||||||
|
if (ethernetInitialized) {
|
||||||
|
disconnect_ethernet();
|
||||||
|
ethernetInitialized = false;
|
||||||
|
}
|
||||||
|
if (wifiInitialized) {
|
||||||
|
disconnect_wifi();
|
||||||
|
wifiInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
destroy_led();
|
destroy_led();
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_event_loop_delete_default());
|
ESP_ERROR_CHECK(esp_event_loop_delete_default());
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_deinit());
|
||||||
}
|
}
|
||||||
|
|||||||
0
Provider/sdkconfig.defaults
Normal file
0
Provider/sdkconfig.defaults
Normal file
Reference in New Issue
Block a user