#include "wifi/wifi.h" #include #include #include "esp_event_base.h" #include "esp_netif.h" #include "esp_netif_ip_addr.h" #include "esp_netif_types.h" #include "esp_wifi.h" #include "esp_wifi_types.h" #include namespace { esp_netif_t* gSoftApNetif; esp_netif_t* gStationNetif; inplace_function, uint8_t)> gAPConnectCallback = [](auto...) {}; inplace_function, uint8_t)> gAPDisconnectCallback = [](auto...) {}; inplace_function gStationStartCallback = [] {}; inplace_function gStationDisconnectCallback = [] {}; inplace_function)> gStationGotIpCallback = [](auto...) {}; void wifi_event_handler(void*, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_base == WIFI_EVENT) { if (event_id == WIFI_EVENT_STA_START) { gStationStartCallback(); } else if (event_id == WIFI_EVENT_STA_DISCONNECTED) { gStationDisconnectCallback(); } else if (event_id == WIFI_EVENT_AP_STACONNECTED) { auto disconnectEvent = reinterpret_cast(event_data); std::array macStr = {0}; std::snprintf(macStr.data(), macStr.size(), "%02x:%02x:%02x:%02x:%02x:%02x", disconnectEvent->mac[0], disconnectEvent->mac[1], disconnectEvent->mac[2], disconnectEvent->mac[3], disconnectEvent->mac[4], disconnectEvent->mac[5]); gAPConnectCallback(macStr, disconnectEvent->aid); } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { auto disconnectEvent = reinterpret_cast(event_data); std::array macStr = {0}; std::snprintf(macStr.data(), macStr.size(), "%02x:%02x:%02x:%02x:%02x:%02x", disconnectEvent->mac[0], disconnectEvent->mac[1], disconnectEvent->mac[2], disconnectEvent->mac[3], disconnectEvent->mac[4], disconnectEvent->mac[5]); gAPDisconnectCallback(macStr, disconnectEvent->aid); } } else if (event_base == IP_EVENT) { if (event_id == IP_EVENT_STA_GOT_IP) { auto event = reinterpret_cast(event_data); auto ipAddr = &event->ip_info.ip; std::array ipStr = {0}; std::snprintf(ipStr.data(), ipStr.size(), "%d.%d.%d.%d", esp_ip4_addr1_16(ipAddr), esp_ip4_addr2_16(ipAddr), esp_ip4_addr3_16(ipAddr), esp_ip4_addr4_16(ipAddr)); gStationGotIpCallback(ipStr); } } } } // namespace namespace wifi { void init() { if (esp_netif_init() != ESP_OK) throw std::runtime_error("Failed to initialize netif"); if (esp_event_loop_create_default() != ESP_OK) throw std::runtime_error("Failed to create event loop"); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); if (esp_wifi_init(&cfg) != ESP_OK) throw std::runtime_error("Failed to initialize wifi"); if (esp_event_handler_instance_register( ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL) != ESP_OK) throw std::runtime_error("Failed to register wifi event handler"); } void deinit() { if (esp_wifi_deinit() != ESP_OK) throw std::runtime_error("Failed to deinitialize wifi"); if (esp_event_loop_delete_default() != ESP_OK) throw std::runtime_error("Failed to delete event loop"); // Apparently, this is not implemented in the esp idf yet // esp_netif_deinit(); } void set_mode(Mode mode) { wifi_mode_t esp_mode = WIFI_MODE_NULL; switch (mode) { case Mode::station: esp_mode = WIFI_MODE_STA; break; case Mode::soft_ap: esp_mode = WIFI_MODE_AP; break; // case Mode::station_and_soft_ap: // esp_mode = WIFI_MODE_APSTA; // break; } if (esp_wifi_set_mode(esp_mode) != ESP_OK) throw std::runtime_error("Failed to set wifi mode"); } void configure_soft_ap(std::string_view ssid, std::string_view password, soft_ap_settings_t settings) { // Create network interface if (gSoftApNetif != nullptr) esp_netif_destroy_default_wifi(gSoftApNetif); gSoftApNetif = esp_netif_create_default_wifi_ap(); // Configure wifi wifi_config_t wifi_config = { .ap = { .ssid_len = static_cast(ssid.size()), .channel = settings.channel, .authmode = password.size() != 0 ? WIFI_AUTH_WPA3_PSK : WIFI_AUTH_OPEN, .max_connection = settings.max_connections, .pmf_cfg = { .required = true, }, .sae_pwe_h2e = WPA3_SAE_PWE_BOTH, }, }; std::copy(ssid.begin(), ssid.end(), wifi_config.ap.ssid); std::copy(password.begin(), password.end(), wifi_config.ap.password); if (esp_wifi_set_config(WIFI_IF_AP, &wifi_config) != ESP_OK) throw std::runtime_error("Failed to set wifi config"); // Register event handlers gAPConnectCallback = settings.connected; gAPDisconnectCallback = settings.disconnected; } void configure_station(std::string_view ssid, std::string_view password, station_settings_t settings) { // Create network interface if (gStationNetif != nullptr) esp_netif_destroy_default_wifi(gStationNetif); gStationNetif = esp_netif_create_default_wifi_sta(); // Configure wifi // TODO: Are there really no other settings necessary? wifi_config_t wifi_config = {}; std::copy(ssid.begin(), ssid.end(), wifi_config.sta.ssid); std::copy(password.begin(), password.end(), wifi_config.sta.password); if (esp_wifi_set_config(WIFI_IF_STA, &wifi_config) != ESP_OK) throw std::runtime_error("Failed to configure wifi station"); // Set event handlers gStationStartCallback = settings.stationStarted; gStationDisconnectCallback = settings.disconnected; gStationGotIpCallback = settings.gotIp; } void clear_callbacks() { gAPConnectCallback = [](auto...) {}; gAPDisconnectCallback = [](auto...) {}; gStationStartCallback = [] {}; gStationGotIpCallback = [](auto...) {}; gStationDisconnectCallback = [] {}; } void station_connect() { if (esp_wifi_connect() != ESP_OK) throw std::runtime_error("Failed to connect to wifi"); } void station_disconnect() { if (esp_wifi_disconnect() != ESP_OK) throw std::runtime_error("Failed to disconnect from wifi"); } void start() { if (esp_wifi_start() != ESP_OK) throw std::runtime_error("Failed to start wifi"); } void stop() { if (esp_wifi_stop() != ESP_OK) throw std::runtime_error("Failed to stop wifi"); } std::span scan(std::span memory) { uint16_t number = memory.size(); wifi_ap_record_t ap_info[number]; esp_err_t err; if ((err = esp_wifi_scan_start(NULL, true)) != ESP_OK) { throw std::runtime_error("Failed to start scan"); } if (esp_wifi_scan_get_ap_records(&number, ap_info) != ESP_OK) throw std::runtime_error("Failed to get wifi ap records"); std::transform(&ap_info[0], &ap_info[0] + number, memory.begin(), [](const wifi_ap_record_t& record) { scanned_ap_t result; std::copy(&record.ssid[0], &record.ssid[0] + 32, result.ssid.begin()); result.rssi = record.rssi; return result; }); return std::span{memory.begin(), number}; } } // namespace wifi