esp32-sip-client-with-headset/main/wifi/wifi_manager.c

346 lines
11 KiB
C

/**
* WiFi Manager - Verwaltet WiFi AP und Station Mode
*
* - Hotspot-Modus wenn keine WLAN-Daten konfiguriert
* - Station-Modus wenn WLAN konfiguriert
* - Automatischer Fallback zu Hotspot bei Verbindungsproblemen
*/
#include <string.h>
#include "wifi_manager.h"
#include "config/config_manager.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_mac.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "lwip/err.h"
#include "lwip/sys.h"
static const char* TAG = "WIFI_MGR";
// Event Bits
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
// Maximale Wiederholungsversuche
#define MAX_RETRY_COUNT 5
// State
static wifi_state_t s_state = WIFI_STATE_IDLE;
static EventGroupHandle_t s_wifi_event_group;
static esp_netif_t* s_netif_ap = NULL;
static esp_netif_t* s_netif_sta = NULL;
static int s_retry_count = 0;
static wifi_event_callback_t s_callback = NULL;
static bool s_initialized = false;
// Forward Declarations
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data);
static void ip_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data);
static void notify_callback(wifi_state_t state, void* data)
{
s_state = state;
if (s_callback) {
s_callback(state, data);
}
}
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_AP_START:
ESP_LOGI(TAG, "AP gestartet");
notify_callback(WIFI_STATE_AP_STARTED, NULL);
break;
case WIFI_EVENT_AP_STOP:
ESP_LOGI(TAG, "AP gestoppt");
break;
case WIFI_EVENT_AP_STACONNECTED: {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*)event_data;
ESP_LOGI(TAG, "Client verbunden: %02x:%02x:%02x:%02x:%02x:%02x",
event->mac[0], event->mac[1], event->mac[2],
event->mac[3], event->mac[4], event->mac[5]);
break;
}
case WIFI_EVENT_AP_STADISCONNECTED: {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*)event_data;
ESP_LOGI(TAG, "Client getrennt: %02x:%02x:%02x:%02x:%02x:%02x",
event->mac[0], event->mac[1], event->mac[2],
event->mac[3], event->mac[4], event->mac[5]);
break;
}
case WIFI_EVENT_STA_START:
ESP_LOGI(TAG, "STA gestartet, verbinde...");
esp_wifi_connect();
notify_callback(WIFI_STATE_STA_CONNECTING, NULL);
break;
case WIFI_EVENT_STA_DISCONNECTED: {
wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*)event_data;
ESP_LOGW(TAG, "Verbindung getrennt (Grund: %d)", event->reason);
if (s_retry_count < MAX_RETRY_COUNT) {
s_retry_count++;
ESP_LOGI(TAG, "Wiederverbinden... (Versuch %d/%d)", s_retry_count, MAX_RETRY_COUNT);
vTaskDelay(pdMS_TO_TICKS(2000));
esp_wifi_connect();
notify_callback(WIFI_STATE_STA_DISCONNECTED, NULL);
} else {
ESP_LOGE(TAG, "Max. Versuche erreicht - Fallback zu AP");
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
notify_callback(WIFI_STATE_STA_FAILED, NULL);
// Starte AP
wifi_manager_start_ap();
}
break;
}
case WIFI_EVENT_STA_CONNECTED:
ESP_LOGI(TAG, "Mit AP verbunden");
s_retry_count = 0;
break;
default:
break;
}
}
}
static void ip_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_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
ESP_LOGI(TAG, "IP erhalten: " IPSTR, IP2STR(&event->ip_info.ip));
s_retry_count = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
notify_callback(WIFI_STATE_STA_CONNECTED, NULL);
}
}
esp_err_t wifi_manager_init(void)
{
if (s_initialized) {
return ESP_OK;
}
ESP_LOGI(TAG, "Initialisiere WiFi Manager");
s_wifi_event_group = xEventGroupCreate();
// TCP/IP Stack initialisieren
ESP_ERROR_CHECK(esp_netif_init());
// Netif für AP und STA erstellen
s_netif_ap = esp_netif_create_default_wifi_ap();
s_netif_sta = esp_netif_create_default_wifi_sta();
// WiFi mit Standardkonfiguration initialisieren
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// Event Handler registrieren
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
&wifi_event_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
&ip_event_handler, NULL, NULL));
// WiFi Storage
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
s_initialized = true;
return ESP_OK;
}
esp_err_t wifi_manager_start(void)
{
ESP_LOGI(TAG, "Starte WiFi...");
const device_config_t* config = config_get();
if (config->wifi.configured) {
// Station Mode - mit konfiguriertem WLAN verbinden
return wifi_manager_connect(&config->wifi);
} else {
// AP Mode - Hotspot starten
return wifi_manager_start_ap();
}
}
esp_err_t wifi_manager_stop(void)
{
ESP_LOGI(TAG, "Stoppe WiFi");
return esp_wifi_stop();
}
esp_err_t wifi_manager_start_ap(void)
{
ESP_LOGI(TAG, "Starte Hotspot: %s", CONFIG_BSC_DEFAULT_AP_SSID);
// Stoppen falls bereits aktiv
esp_wifi_stop();
// AP-IP konfigurieren
esp_netif_ip_info_t ip_info;
ip_info.ip.addr = esp_ip4addr_aton("192.168.4.1");
ip_info.gw.addr = esp_ip4addr_aton("192.168.4.1");
ip_info.netmask.addr = esp_ip4addr_aton("255.255.255.0");
esp_netif_dhcps_stop(s_netif_ap);
esp_netif_set_ip_info(s_netif_ap, &ip_info);
esp_netif_dhcps_start(s_netif_ap);
// WiFi AP Konfiguration
wifi_config_t wifi_config = {
.ap = {
.ssid_len = strlen(CONFIG_BSC_DEFAULT_AP_SSID),
.channel = 1,
.max_connection = 4,
.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.required = false,
},
},
};
strncpy((char*)wifi_config.ap.ssid, CONFIG_BSC_DEFAULT_AP_SSID, sizeof(wifi_config.ap.ssid));
strncpy((char*)wifi_config.ap.password, CONFIG_BSC_DEFAULT_AP_PASSWORD, sizeof(wifi_config.ap.password));
if (strlen(CONFIG_BSC_DEFAULT_AP_PASSWORD) < 8) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Hotspot gestartet. SSID: %s, Passwort: %s",
CONFIG_BSC_DEFAULT_AP_SSID, CONFIG_BSC_DEFAULT_AP_PASSWORD);
return ESP_OK;
}
esp_err_t wifi_manager_connect(const wifi_config_data_t* config)
{
if (!config || strlen(config->ssid) == 0) {
ESP_LOGE(TAG, "Ungültige WiFi-Konfiguration");
return ESP_ERR_INVALID_ARG;
}
ESP_LOGI(TAG, "Verbinde mit WLAN: %s", config->ssid);
// Stoppen falls bereits aktiv
esp_wifi_stop();
// Static IP konfigurieren wenn gewünscht
if (config->ip_mode == IP_MODE_STATIC && strlen(config->static_ip) > 0) {
ESP_LOGI(TAG, "Verwende statische IP: %s", config->static_ip);
esp_netif_dhcpc_stop(s_netif_sta);
esp_netif_ip_info_t ip_info;
memset(&ip_info, 0, sizeof(ip_info));
ip_info.ip.addr = esp_ip4addr_aton(config->static_ip);
ip_info.gw.addr = esp_ip4addr_aton(config->gateway);
ip_info.netmask.addr = esp_ip4addr_aton(config->netmask);
esp_netif_set_ip_info(s_netif_sta, &ip_info);
// DNS konfigurieren wenn vorhanden
if (strlen(config->dns) > 0) {
esp_netif_dns_info_t dns;
dns.ip.u_addr.ip4.addr = esp_ip4addr_aton(config->dns);
dns.ip.type = ESP_IPADDR_TYPE_V4;
esp_netif_set_dns_info(s_netif_sta, ESP_NETIF_DNS_MAIN, &dns);
}
} else {
esp_netif_dhcpc_start(s_netif_sta);
}
// WiFi STA Konfiguration
wifi_config_t wifi_config = {
.sta = {
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
},
};
strncpy((char*)wifi_config.sta.ssid, config->ssid, sizeof(wifi_config.sta.ssid));
strncpy((char*)wifi_config.sta.password, config->password, sizeof(wifi_config.sta.password));
s_retry_count = 0;
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());
return ESP_OK;
}
esp_err_t wifi_manager_disconnect(void)
{
ESP_LOGI(TAG, "Trenne WiFi-Verbindung");
esp_wifi_disconnect();
return wifi_manager_start_ap();
}
wifi_state_t wifi_manager_get_state(void)
{
return s_state;
}
esp_err_t wifi_manager_get_ip(char* ip_str, size_t len)
{
esp_netif_ip_info_t ip_info;
esp_netif_t* netif = (s_state == WIFI_STATE_AP_STARTED) ? s_netif_ap : s_netif_sta;
esp_err_t err = esp_netif_get_ip_info(netif, &ip_info);
if (err != ESP_OK) return err;
snprintf(ip_str, len, IPSTR, IP2STR(&ip_info.ip));
return ESP_OK;
}
esp_err_t wifi_manager_scan(void)
{
ESP_LOGI(TAG, "Starte WLAN-Scan...");
// Scan-Konfiguration
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_register_callback(wifi_event_callback_t callback)
{
s_callback = callback;
return ESP_OK;
}
esp_netif_t* wifi_manager_get_netif(void)
{
return (s_state == WIFI_STATE_AP_STARTED) ? s_netif_ap : s_netif_sta;
}