#include "wifi_manager.h" #include "config.h" #include "esp_log.h" #include "esp_event.h" #include "esp_netif.h" #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" #include #include // Private state static struct { wifi_status_t status; EventGroupHandle_t event_group; esp_netif_t* netif; char current_ssid[33]; char current_password[65]; uint8_t max_retries; uint8_t retry_count; uint32_t connect_start_time; bool auto_reconnect; bool initialized; // Statistics uint32_t total_attempts; uint32_t successful_connections; esp_err_t last_error; } wifi_state = { .status = WIFI_STATUS_DISCONNECTED, .event_group = NULL, .netif = NULL, .current_ssid = "", .current_password = "", .max_retries = WIFI_MAXIMUM_RETRY, .retry_count = 0, .connect_start_time = 0, .auto_reconnect = true, .initialized = false, .total_attempts = 0, .successful_connections = 0, .last_error = ESP_OK }; // Private function declarations static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); static esp_err_t start_connection_attempt(void); // Private function implementations static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_base == WIFI_EVENT) { switch (event_id) { case WIFI_EVENT_STA_START: ESP_LOGI(SYSTEM_TAG, "WiFi station started"); break; case WIFI_EVENT_STA_CONNECTED: ESP_LOGI(SYSTEM_TAG, "Connected to WiFi network: %s", wifi_state.current_ssid); wifi_state.status = WIFI_STATUS_CONNECTED; break; case WIFI_EVENT_STA_DISCONNECTED: { wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data; ESP_LOGW(SYSTEM_TAG, "WiFi disconnected, reason: %d", disconnected->reason); if (wifi_state.status == WIFI_STATUS_CONNECTED) { // We were connected, so this is a disconnection if (wifi_state.auto_reconnect) { wifi_state.status = WIFI_STATUS_RECONNECTING; wifi_state.retry_count = 0; ESP_LOGI(SYSTEM_TAG, "Auto-reconnect enabled, attempting to reconnect..."); esp_wifi_connect(); } else { wifi_state.status = WIFI_STATUS_DISCONNECTED; } } else { // Connection attempt failed wifi_state.retry_count++; wifi_state.last_error = ESP_ERR_WIFI_NOT_CONNECT; if (wifi_state.max_retries == 0 || wifi_state.retry_count < wifi_state.max_retries) { wifi_state.status = WIFI_STATUS_CONNECTING; ESP_LOGI(SYSTEM_TAG, "Retry %d/%d connecting to WiFi...", wifi_state.retry_count, wifi_state.max_retries); esp_wifi_connect(); } else { wifi_state.status = WIFI_STATUS_FAILED; ESP_LOGE(SYSTEM_TAG, "Failed to connect to WiFi after %d attempts", wifi_state.retry_count); xEventGroupSetBits(wifi_state.event_group, WIFI_FAIL_BIT); } } break; } default: break; } } 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(SYSTEM_TAG, "Got IP address: " IPSTR, IP2STR(&event->ip_info.ip)); wifi_state.status = WIFI_STATUS_CONNECTED; wifi_state.successful_connections++; wifi_state.retry_count = 0; wifi_state.last_error = ESP_OK; xEventGroupSetBits(wifi_state.event_group, WIFI_CONNECTED_BIT); } } static void update_connection_time(void) { if (wifi_state.connect_start_time > 0) { wifi_state.connect_start_time = xTaskGetTickCount() * portTICK_PERIOD_MS; } } static esp_err_t start_connection_attempt(void) { wifi_state.total_attempts++; wifi_state.connect_start_time = xTaskGetTickCount() * portTICK_PERIOD_MS; wifi_state.retry_count = 0; wifi_state.status = WIFI_STATUS_CONNECTING; // Clear event bits xEventGroupClearBits(wifi_state.event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT); return esp_wifi_connect(); } // Public API implementation esp_err_t wifi_manager_init(void) { if (wifi_state.initialized) { ESP_LOGW(SYSTEM_TAG, "WiFi manager already initialized"); return ESP_OK; } ESP_LOGI(SYSTEM_TAG, "Initializing WiFi manager..."); // Create event group wifi_state.event_group = xEventGroupCreate(); if (!wifi_state.event_group) { ESP_LOGE(SYSTEM_TAG, "Failed to create WiFi event group"); return ESP_FAIL; } // Initialize network interface esp_err_t ret = esp_netif_init(); if (ret != ESP_OK) { ESP_LOGE(SYSTEM_TAG, "Failed to initialize netif: %s", esp_err_to_name(ret)); return ret; } ret = esp_event_loop_create_default(); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(SYSTEM_TAG, "Failed to create event loop: %s", esp_err_to_name(ret)); return ret; } wifi_state.netif = esp_netif_create_default_wifi_sta(); if (!wifi_state.netif) { ESP_LOGE(SYSTEM_TAG, "Failed to create default WiFi STA netif"); return ESP_FAIL; } // Initialize WiFi wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ret = esp_wifi_init(&cfg); if (ret != ESP_OK) { ESP_LOGE(SYSTEM_TAG, "Failed to initialize WiFi: %s", esp_err_to_name(ret)); return ret; } // Register event handlers ret = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL); if (ret != ESP_OK) { ESP_LOGE(SYSTEM_TAG, "Failed to register WiFi event handler: %s", esp_err_to_name(ret)); return ret; } ret = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL); if (ret != ESP_OK) { ESP_LOGE(SYSTEM_TAG, "Failed to register IP event handler: %s", esp_err_to_name(ret)); return ret; } // Set WiFi mode ret = esp_wifi_set_mode(WIFI_MODE_STA); if (ret != ESP_OK) { ESP_LOGE(SYSTEM_TAG, "Failed to set WiFi mode: %s", esp_err_to_name(ret)); return ret; } // Start WiFi ret = esp_wifi_start(); if (ret != ESP_OK) { ESP_LOGE(SYSTEM_TAG, "Failed to start WiFi: %s", esp_err_to_name(ret)); return ret; } wifi_state.initialized = true; wifi_state.status = WIFI_STATUS_DISCONNECTED; ESP_LOGI(SYSTEM_TAG, "WiFi manager initialized successfully"); return ESP_OK; } esp_err_t wifi_manager_connect(const char* ssid, const char* password, uint8_t max_retries) { if (!wifi_state.initialized) { ESP_LOGE(SYSTEM_TAG, "WiFi manager not initialized"); return ESP_FAIL; } if (!ssid || strlen(ssid) == 0 || strlen(ssid) > 32) { ESP_LOGE(SYSTEM_TAG, "Invalid SSID"); return ESP_ERR_INVALID_ARG; } if (!password || strlen(password) > 64) { ESP_LOGE(SYSTEM_TAG, "Invalid password"); return ESP_ERR_INVALID_ARG; } // Store connection parameters strncpy(wifi_state.current_ssid, ssid, sizeof(wifi_state.current_ssid) - 1); wifi_state.current_ssid[sizeof(wifi_state.current_ssid) - 1] = '\0'; strncpy(wifi_state.current_password, password, sizeof(wifi_state.current_password) - 1); wifi_state.current_password[sizeof(wifi_state.current_password) - 1] = '\0'; wifi_state.max_retries = max_retries; // Configure WiFi wifi_config_t wifi_config = {0}; 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); wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; wifi_config.sta.pmf_cfg.capable = true; wifi_config.sta.pmf_cfg.required = false; esp_err_t ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_config); if (ret != ESP_OK) { ESP_LOGE(SYSTEM_TAG, "Failed to set WiFi config: %s", esp_err_to_name(ret)); return ret; } ESP_LOGI(SYSTEM_TAG, "Connecting to WiFi SSID: %s", ssid); return start_connection_attempt(); } esp_err_t wifi_manager_connect_default(void) { return wifi_manager_connect(WIFI_SSID, WIFI_PASS, WIFI_MAXIMUM_RETRY); } esp_err_t wifi_manager_disconnect(void) { if (!wifi_state.initialized) { return ESP_FAIL; } wifi_state.auto_reconnect = false; wifi_state.status = WIFI_STATUS_DISCONNECTED; esp_err_t ret = esp_wifi_disconnect(); if (ret != ESP_OK) { ESP_LOGE(SYSTEM_TAG, "Failed to disconnect WiFi: %s", esp_err_to_name(ret)); } return ret; } wifi_status_t wifi_manager_get_status(void) { return wifi_state.status; } esp_err_t wifi_manager_get_info(wifi_info_t* info) { if (!info) { return ESP_ERR_INVALID_ARG; } info->status = wifi_state.status; strncpy(info->ssid, wifi_state.current_ssid, sizeof(info->ssid) - 1); info->ssid[sizeof(info->ssid) - 1] = '\0'; info->ip_address = wifi_manager_get_ip(); info->rssi = wifi_manager_get_rssi(); info->retry_count = wifi_state.retry_count; info->auto_reconnect = wifi_state.auto_reconnect; if (wifi_state.connect_start_time > 0) { uint32_t current_time = xTaskGetTickCount() * portTICK_PERIOD_MS; info->connect_time_ms = current_time - wifi_state.connect_start_time; } else { info->connect_time_ms = 0; } return ESP_OK; } bool wifi_manager_is_connected(void) { return wifi_state.status == WIFI_STATUS_CONNECTED; } uint32_t wifi_manager_get_ip(void) { if (!wifi_state.initialized || !wifi_manager_is_connected()) { return 0; } esp_netif_ip_info_t ip_info; if (esp_netif_get_ip_info(wifi_state.netif, &ip_info) == ESP_OK) { return ip_info.ip.addr; } return 0; } esp_err_t wifi_manager_get_ip_string(char* ip_str, size_t max_len) { if (!ip_str || max_len < 16) { return ESP_ERR_INVALID_ARG; } uint32_t ip = wifi_manager_get_ip(); if (ip == 0) { strncpy(ip_str, "0.0.0.0", max_len - 1); ip_str[max_len - 1] = '\0'; return ESP_FAIL; } // Convert uint32_t IP to string manually uint8_t* ip_bytes = (uint8_t*)&ip; snprintf(ip_str, max_len, "%d.%d.%d.%d", ip_bytes[0], ip_bytes[1], ip_bytes[2], ip_bytes[3]); return ESP_OK; } int8_t wifi_manager_get_rssi(void) { if (!wifi_state.initialized || !wifi_manager_is_connected()) { return 0; } wifi_ap_record_t ap_info; if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) { return ap_info.rssi; } return 0; } esp_err_t wifi_manager_set_auto_reconnect(bool enable) { wifi_state.auto_reconnect = enable; ESP_LOGI(SYSTEM_TAG, "Auto-reconnect %s", enable ? "enabled" : "disabled"); return ESP_OK; } esp_err_t wifi_manager_wait_for_connection(uint32_t timeout_ms) { if (!wifi_state.initialized) { return ESP_FAIL; } if (wifi_manager_is_connected()) { return ESP_OK; } TickType_t timeout_ticks = (timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); EventBits_t bits = xEventGroupWaitBits(wifi_state.event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, timeout_ticks); if (bits & WIFI_CONNECTED_BIT) { return ESP_OK; } else if (bits & WIFI_FAIL_BIT) { return ESP_FAIL; } else { return ESP_ERR_TIMEOUT; } } const char* wifi_manager_status_to_string(wifi_status_t status) { switch (status) { case WIFI_STATUS_DISCONNECTED: return "DISCONNECTED"; case WIFI_STATUS_CONNECTING: return "CONNECTING"; case WIFI_STATUS_CONNECTED: return "CONNECTED"; case WIFI_STATUS_FAILED: return "FAILED"; case WIFI_STATUS_RECONNECTING: return "RECONNECTING"; default: return "UNKNOWN"; } } esp_err_t wifi_manager_start_scan(void) { if (!wifi_state.initialized) { return ESP_FAIL; } wifi_scan_config_t scan_config = { .ssid = NULL, .bssid = NULL, .channel = 0, .show_hidden = false, .scan_type = WIFI_SCAN_TYPE_ACTIVE, .scan_time.active.min = 100, .scan_time.active.max = 300 }; return esp_wifi_scan_start(&scan_config, false); } esp_err_t wifi_manager_get_scan_results(wifi_ap_record_t* ap_info, uint16_t max_aps, uint16_t* num_aps) { if (!ap_info || !num_aps) { return ESP_ERR_INVALID_ARG; } return esp_wifi_scan_get_ap_records(&max_aps, ap_info); } esp_err_t wifi_manager_reconnect(void) { if (!wifi_state.initialized) { return ESP_FAIL; } ESP_LOGI(SYSTEM_TAG, "Forcing WiFi reconnection..."); wifi_state.retry_count = 0; return start_connection_attempt(); } esp_err_t wifi_manager_get_stats(uint32_t* total_attempts, uint32_t* successful_connections, esp_err_t* last_error) { if (total_attempts) *total_attempts = wifi_state.total_attempts; if (successful_connections) *successful_connections = wifi_state.successful_connections; if (last_error) *last_error = wifi_state.last_error; return ESP_OK; } esp_err_t wifi_manager_reset_stats(void) { wifi_state.total_attempts = 0; wifi_state.successful_connections = 0; wifi_state.last_error = ESP_OK; ESP_LOGI(SYSTEM_TAG, "WiFi statistics reset"); return ESP_OK; }