252 lines
8.0 KiB
C++
252 lines
8.0 KiB
C++
#include "wifi/wifi.h"
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
|
|
#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 <util/inplace_function.h>
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
esp_netif_t* gSoftApNetif;
|
|
esp_netif_t* gStationNetif;
|
|
|
|
inplace_function<void(std::array<char, 18>, uint8_t)> gAPConnectCallback =
|
|
[](auto...) {};
|
|
inplace_function<void(std::array<char, 18>, uint8_t)> gAPDisconnectCallback =
|
|
[](auto...) {};
|
|
|
|
inplace_function<void()> gStationStartCallback = [] {};
|
|
inplace_function<void()> gStationDisconnectCallback = [] {};
|
|
inplace_function<void(std::array<char, 17>)> 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<wifi_event_ap_stadisconnected_t*>(event_data);
|
|
|
|
std::array<char, 18> 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<wifi_event_ap_stadisconnected_t*>(event_data);
|
|
|
|
std::array<char, 18> 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<ip_event_got_ip_t*>(event_data);
|
|
|
|
auto ipAddr = &event->ip_info.ip;
|
|
|
|
std::array<char, 17> 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<uint8_t>(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<scanned_ap_t> scan(std::span<scanned_ap_t> 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
|