MeshTalos-Client/managed_components/espressif__arduino-esp32/libraries/WiFi/src/WiFiGeneric.cpp
2025-12-03 14:20:11 +08:00

1019 lines
31 KiB
C++

/*
ESP8266WiFiGeneric.cpp - WiFi library for esp8266
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Reworked on 28 Dec 2015 by Markus Sattler
*/
#include "WiFi.h"
#include "WiFiGeneric.h"
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
extern "C" {
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <esp_err.h>
#include <esp_wifi.h>
#include <esp_event.h>
#include <esp_mac.h>
#include <esp_netif.h>
#if SOC_WIFI_SUPPORTED
#include <esp_phy.h>
#endif
#include "lwip/ip_addr.h"
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/dns.h"
#include "lwip/netif.h"
#include "dhcpserver/dhcpserver.h"
#include "dhcpserver/dhcpserver_options.h"
} //extern "C"
#include "esp32-hal.h"
#include <vector>
#include "sdkconfig.h"
ESP_EVENT_DEFINE_BASE(ARDUINO_EVENTS);
static esp_netif_t *esp_netifs[ESP_IF_MAX] = {NULL, NULL, NULL};
esp_netif_t *get_esp_interface_netif(esp_interface_t interface) {
if (interface < ESP_IF_MAX) {
return esp_netifs[interface];
}
return NULL;
}
static void _arduino_event_cb(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
arduino_event_t arduino_event;
arduino_event.event_id = ARDUINO_EVENT_MAX;
/*
* SCAN
* */
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_event_sta_scan_done_t *event = (wifi_event_sta_scan_done_t *)event_data;
log_v("SCAN Done: ID: %u, Status: %u, Results: %u", event->scan_id, event->status, event->number);
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_SCAN_DONE;
memcpy(&arduino_event.event_info.wifi_scan_done, event_data, sizeof(wifi_event_sta_scan_done_t));
/*
* WPS
* */
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_SUCCESS) {
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_SUCCESS;
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_FAILED) {
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_FAILED;
memcpy(&arduino_event.event_info.wps_fail_reason, event_data, sizeof(wifi_event_sta_wps_fail_reason_t));
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_TIMEOUT) {
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_TIMEOUT;
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_PIN) {
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_PIN;
memcpy(&arduino_event.event_info.wps_er_pin, event_data, sizeof(wifi_event_sta_wps_er_pin_t));
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_PBC_OVERLAP) {
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_PBC_OVERLAP;
/*
* FTM
* */
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_FTM_REPORT) {
arduino_event.event_id = ARDUINO_EVENT_WIFI_FTM_REPORT;
memcpy(&arduino_event.event_info.wifi_ftm_report, event_data, sizeof(wifi_event_ftm_report_t));
#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
/*
* SMART CONFIG
* */
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
log_v("SC Scan Done");
arduino_event.event_id = ARDUINO_EVENT_SC_SCAN_DONE;
} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
log_v("SC Found Channel");
arduino_event.event_id = ARDUINO_EVENT_SC_FOUND_CHANNEL;
} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
smartconfig_event_got_ssid_pswd_t *event = (smartconfig_event_got_ssid_pswd_t *)event_data;
log_v("SC: SSID: %s, Password: %s", (const char *)event->ssid, (const char *)event->password);
#endif
arduino_event.event_id = ARDUINO_EVENT_SC_GOT_SSID_PSWD;
memcpy(&arduino_event.event_info.sc_got_ssid_pswd, event_data, sizeof(smartconfig_event_got_ssid_pswd_t));
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
log_v("SC Send Ack Done");
arduino_event.event_id = ARDUINO_EVENT_SC_SEND_ACK_DONE;
#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
/*
* Provisioning
* */
} else if (event_base == NETWORK_PROV_EVENT && event_id == NETWORK_PROV_INIT) {
log_v("Provisioning Initialized!");
arduino_event.event_id = ARDUINO_EVENT_PROV_INIT;
} else if (event_base == NETWORK_PROV_EVENT && event_id == NETWORK_PROV_DEINIT) {
log_v("Provisioning Uninitialized!");
arduino_event.event_id = ARDUINO_EVENT_PROV_DEINIT;
} else if (event_base == NETWORK_PROV_EVENT && event_id == NETWORK_PROV_START) {
log_v("Provisioning Start!");
arduino_event.event_id = ARDUINO_EVENT_PROV_START;
} else if (event_base == NETWORK_PROV_EVENT && event_id == NETWORK_PROV_END) {
log_v("Provisioning End!");
network_prov_mgr_deinit();
arduino_event.event_id = ARDUINO_EVENT_PROV_END;
} else if (event_base == NETWORK_PROV_EVENT && event_id == NETWORK_PROV_WIFI_CRED_RECV) {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_sta_config_t *event = (wifi_sta_config_t *)event_data;
log_v("Provisioned Credentials: SSID: %s, Password: %s", (const char *)event->ssid, (const char *)event->password);
#endif
arduino_event.event_id = ARDUINO_EVENT_PROV_CRED_RECV;
memcpy(&arduino_event.event_info.prov_cred_recv, event_data, sizeof(wifi_sta_config_t));
} else if (event_base == NETWORK_PROV_EVENT && event_id == NETWORK_PROV_WIFI_CRED_FAIL) {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
network_prov_wifi_sta_fail_reason_t *reason = (network_prov_wifi_sta_fail_reason_t *)event_data;
log_e("Provisioning Failed: Reason : %s", (*reason == NETWORK_PROV_WIFI_STA_AUTH_ERROR) ? "Authentication Failed" : "AP Not Found");
#endif
arduino_event.event_id = ARDUINO_EVENT_PROV_CRED_FAIL;
memcpy(&arduino_event.event_info.prov_fail_reason, event_data, sizeof(network_prov_wifi_sta_fail_reason_t));
} else if (event_base == NETWORK_PROV_EVENT && event_id == NETWORK_PROV_WIFI_CRED_SUCCESS) {
log_v("Provisioning Success!");
arduino_event.event_id = ARDUINO_EVENT_PROV_CRED_SUCCESS;
#endif
#endif
}
if (arduino_event.event_id < ARDUINO_EVENT_MAX) {
Network.postEvent(&arduino_event);
}
}
static bool initWiFiEvents() {
if (esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb, NULL, NULL)) {
log_e("event_handler_instance_register for WIFI_EVENT Failed!");
return false;
}
#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
if (esp_event_handler_instance_register(SC_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb, NULL, NULL)) {
log_e("event_handler_instance_register for SC_EVENT Failed!");
return false;
}
#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
if (esp_event_handler_instance_register(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb, NULL, NULL)) {
log_e("event_handler_instance_register for NETWORK_PROV_EVENT Failed!");
return false;
}
#endif
#endif
return true;
}
static bool deinitWiFiEvents() {
if (esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb)) {
log_e("esp_event_handler_unregister for WIFI_EVENT Failed!");
return false;
}
#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
if (esp_event_handler_unregister(SC_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb)) {
log_e("esp_event_handler_unregister for SC_EVENT Failed!");
return false;
}
#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
if (esp_event_handler_unregister(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb)) {
log_e("esp_event_handler_unregister for NETWORK_PROV_EVENT Failed!");
return false;
}
#endif
#endif
return true;
}
/*
* WiFi INIT
* */
static bool lowLevelInitDone = false;
bool WiFiGenericClass::_wifiUseStaticBuffers = false;
bool WiFiGenericClass::useStaticBuffers() {
return _wifiUseStaticBuffers;
}
void WiFiGenericClass::useStaticBuffers(bool bufferMode) {
if (lowLevelInitDone) {
log_w("WiFi already started. Call WiFi.mode(WIFI_MODE_NULL) before setting Static Buffer Mode.");
}
_wifiUseStaticBuffers = bufferMode;
}
// Temporary fix to ensure that CDC+JTAG stay on on ESP32-C3
#if CONFIG_IDF_TARGET_ESP32C3
extern "C" void phy_bbpll_en_usb(bool en);
#endif
#if CONFIG_ESP_WIFI_REMOTE_ENABLED
bool WiFiGenericClass::setPins(int8_t clk, int8_t cmd, int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t rst) {
return hostedSetPins(clk, cmd, d0, d1, d2, d3, rst);
}
#endif
bool wifiLowLevelInit(bool persistent) {
if (!lowLevelInitDone) {
lowLevelInitDone = true;
#if CONFIG_ESP_WIFI_REMOTE_ENABLED
if (!hostedInitWiFi()) {
lowLevelInitDone = false;
return lowLevelInitDone;
}
#endif
if (!Network.begin()) {
lowLevelInitDone = false;
return lowLevelInitDone;
}
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
if (!WiFiGenericClass::useStaticBuffers()) {
cfg.static_tx_buf_num = 0;
cfg.dynamic_tx_buf_num = 32;
cfg.tx_buf_type = 1;
cfg.cache_tx_buf_num = 4; // can't be zero!
cfg.static_rx_buf_num = 4;
cfg.dynamic_rx_buf_num = 32;
}
esp_err_t err = esp_wifi_init(&cfg);
if (err) {
log_e("esp_wifi_init 0x%x: %s", err, esp_err_to_name(err));
lowLevelInitDone = false;
return lowLevelInitDone;
}
// Temporary fix to ensure that CDC+JTAG stay on on ESP32-C3
#if CONFIG_IDF_TARGET_ESP32C3
phy_bbpll_en_usb(true);
#endif
if (!persistent) {
lowLevelInitDone = esp_wifi_set_storage(WIFI_STORAGE_RAM) == ESP_OK;
}
if (lowLevelInitDone) {
initWiFiEvents();
if (esp_netifs[ESP_IF_WIFI_AP] == NULL) {
esp_netifs[ESP_IF_WIFI_AP] = esp_netif_create_default_wifi_ap();
}
if (esp_netifs[ESP_IF_WIFI_STA] == NULL) {
esp_netifs[ESP_IF_WIFI_STA] = esp_netif_create_default_wifi_sta();
}
arduino_event_t arduino_event;
arduino_event.event_id = ARDUINO_EVENT_WIFI_READY;
Network.postEvent(&arduino_event);
}
}
return lowLevelInitDone;
}
static bool wifiLowLevelDeinit() {
if (lowLevelInitDone) {
lowLevelInitDone = false;
deinitWiFiEvents();
if (esp_netifs[ESP_IF_WIFI_AP] != NULL) {
esp_netif_destroy_default_wifi(esp_netifs[ESP_IF_WIFI_AP]);
esp_netifs[ESP_IF_WIFI_AP] = NULL;
}
if (esp_netifs[ESP_IF_WIFI_STA] != NULL) {
esp_netif_destroy_default_wifi(esp_netifs[ESP_IF_WIFI_STA]);
esp_netifs[ESP_IF_WIFI_STA] = NULL;
}
lowLevelInitDone = !(esp_wifi_deinit() == ESP_OK);
if (!lowLevelInitDone) {
arduino_event_t arduino_event;
arduino_event.event_id = ARDUINO_EVENT_WIFI_OFF;
Network.postEvent(&arduino_event);
#if CONFIG_ESP_WIFI_REMOTE_ENABLED
hostedDeinitWiFi();
#endif
}
}
return !lowLevelInitDone;
}
static bool _esp_wifi_started = false;
static bool espWiFiStart() {
if (_esp_wifi_started) {
return true;
}
_esp_wifi_started = true;
esp_err_t err = esp_wifi_start();
if (err != ESP_OK) {
_esp_wifi_started = false;
log_e("esp_wifi_start 0x%x: %s", err, esp_err_to_name(err));
return _esp_wifi_started;
}
#if SOC_WIFI_SUPPORT_5G
log_v("Setting Band Mode to AUTO");
esp_wifi_set_band_mode(WIFI_BAND_MODE_AUTO);
#endif
return _esp_wifi_started;
}
static bool espWiFiStop() {
esp_err_t err;
if (!_esp_wifi_started) {
return true;
}
_esp_wifi_started = false;
err = esp_wifi_stop();
if (err) {
log_e("Could not stop WiFi! 0x%x: %s", err, esp_err_to_name(err));
_esp_wifi_started = true;
return false;
}
return wifiLowLevelDeinit();
}
// -----------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------- Generic WiFi function -----------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
bool WiFiGenericClass::_persistent = true;
bool WiFiGenericClass::_long_range = false;
wifi_mode_t WiFiGenericClass::_forceSleepLastMode = WIFI_MODE_NULL;
#if CONFIG_IDF_TARGET_ESP32S2
wifi_ps_type_t WiFiGenericClass::_sleepEnabled = WIFI_PS_NONE;
#else
wifi_ps_type_t WiFiGenericClass::_sleepEnabled = WIFI_PS_MIN_MODEM;
#endif
WiFiGenericClass::WiFiGenericClass() {}
const char *WiFiGenericClass::disconnectReasonName(wifi_err_reason_t reason) {
return WiFi.STA.disconnectReasonName(reason);
}
const char *WiFiGenericClass::eventName(arduino_event_id_t id) {
return Network.eventName(id);
}
const char *WiFiGenericClass::getHostname() {
return NetworkManager::getHostname();
}
bool WiFiGenericClass::setHostname(const char *hostname) {
return NetworkManager::setHostname(hostname);
}
/**
* callback for WiFi events
* @param arg
*/
void WiFiGenericClass::_eventCallback(arduino_event_t *event) {
if (!event) {
return; //Null would crash this function
}
// log_d("Arduino Event: %d - %s", event->event_id, WiFi.eventName(event->event_id));
if (event->event_id == ARDUINO_EVENT_WIFI_SCAN_DONE) {
WiFiScanClass::_scanDone();
#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
} else if (event->event_id == ARDUINO_EVENT_SC_GOT_SSID_PSWD) {
WiFi.begin(
(const char *)event->event_info.sc_got_ssid_pswd.ssid, (const char *)event->event_info.sc_got_ssid_pswd.password, 0,
((event->event_info.sc_got_ssid_pswd.bssid_set == true) ? event->event_info.sc_got_ssid_pswd.bssid : NULL)
);
} else if (event->event_id == ARDUINO_EVENT_SC_SEND_ACK_DONE) {
esp_smartconfig_stop();
WiFiSTAClass::_smartConfigDone = true;
#endif
}
}
/**
* Return the current channel associated with the network
* @return channel (1-13)
*/
int32_t WiFiGenericClass::channel(void) {
uint8_t primaryChan = 0;
wifi_second_chan_t secondChan = WIFI_SECOND_CHAN_NONE;
if (!lowLevelInitDone) {
return primaryChan;
}
esp_wifi_get_channel(&primaryChan, &secondChan);
return primaryChan;
}
/**
* Set the WiFi channel configuration
* @param primary primary channel. Depending on the region, not all channels may be available.
* @param secondary secondary channel (WIFI_SECOND_CHAN_NONE, WIFI_SECOND_CHAN_ABOVE, WIFI_SECOND_CHAN_BELOW)
* @return 0 on success, otherwise error
*/
int WiFiGenericClass::setChannel(uint8_t primary, wifi_second_chan_t secondary) {
wifi_country_t country;
esp_err_t ret;
ret = esp_wifi_get_country(&country);
if (ret != ESP_OK) {
log_e("Failed to get country info 0x%x: %s", ret, esp_err_to_name(ret));
return ret;
}
uint8_t min_chan = country.schan;
uint8_t max_chan = min_chan + country.nchan - 1;
if (primary < min_chan || primary > max_chan) {
log_e("Invalid primary channel: %d. Valid range is %d-%d for country %s", primary, min_chan, max_chan, country.cc);
return ESP_ERR_INVALID_ARG;
}
ret = esp_wifi_set_channel(primary, secondary);
if (ret != ESP_OK) {
log_e("Failed to set channel 0x%x: %s", ret, esp_err_to_name(ret));
return ret;
}
return ESP_OK;
}
/**
* store WiFi config in SDK flash area
* @param persistent
*/
void WiFiGenericClass::persistent(bool persistent) {
_persistent = persistent;
}
/**
* enable WiFi long range mode
* @param enable
*/
void WiFiGenericClass::enableLongRange(bool enable) {
_long_range = enable;
}
/**
* set new mode
* @param m WiFiMode_t
*/
bool WiFiGenericClass::mode(wifi_mode_t m) {
wifi_mode_t cm = getMode();
if (cm == m) {
return true;
}
if (!cm && m) {
// Turn ON WiFi
if (!wifiLowLevelInit(_persistent)) {
return false;
}
Network.onSysEvent(_eventCallback);
}
if (((m & WIFI_MODE_STA) != 0) && ((cm & WIFI_MODE_STA) == 0)) {
// we are enabling STA interface
WiFi.STA.onEnable();
}
if (((m & WIFI_MODE_AP) != 0) && ((cm & WIFI_MODE_AP) == 0)) {
// we are enabling AP interface
WiFi.AP.onEnable();
}
if (cm && !m) {
// Turn OFF WiFi
if (!espWiFiStop()) {
return false;
}
if ((cm & WIFI_MODE_STA) != 0) {
// we are disabling STA interface
WiFi.STA.onDisable();
}
if ((cm & WIFI_MODE_AP) != 0) {
// we are disabling AP interface
WiFi.AP.onDisable();
}
Network.removeEvent(_eventCallback);
return true;
}
esp_err_t err;
if (((m & WIFI_MODE_STA) != 0) && ((cm & WIFI_MODE_STA) == 0)) {
err = esp_netif_set_hostname(esp_netifs[ESP_IF_WIFI_STA], NetworkManager::getHostname());
if (err) {
log_e("Could not set hostname! 0x%x: %s", err, esp_err_to_name(err));
return false;
}
}
err = esp_wifi_set_mode(m);
if (err) {
log_e("Could not set mode! 0x%x: %s", err, esp_err_to_name(err));
return false;
}
if (((m & WIFI_MODE_STA) == 0) && ((cm & WIFI_MODE_STA) != 0)) {
// we are disabling STA interface (but AP is ON)
WiFi.STA.onDisable();
}
if (((m & WIFI_MODE_AP) == 0) && ((cm & WIFI_MODE_AP) != 0)) {
// we are disabling AP interface (but STA is ON)
WiFi.AP.onDisable();
}
if (_long_range) {
if (m & WIFI_MODE_STA) {
err = esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_LR);
if (err != ESP_OK) {
log_e("Could not enable long range on STA! 0x%x: %s", err, esp_err_to_name(err));
return false;
}
}
if (m & WIFI_MODE_AP) {
err = esp_wifi_set_protocol(WIFI_IF_AP, WIFI_PROTOCOL_LR);
if (err != ESP_OK) {
log_e("Could not enable long range on AP! 0x%x: %s", err, esp_err_to_name(err));
return false;
}
}
} else {
#if CONFIG_SOC_WIFI_HE_SUPPORT
#define WIFI_PROTOCOL_DEFAULT (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_11AX)
#else
#define WIFI_PROTOCOL_DEFAULT (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N)
#endif
uint32_t current_protocol = 0;
if (m & WIFI_MODE_STA) {
err = esp_wifi_get_protocol(WIFI_IF_STA, (uint8_t *)&current_protocol);
if (err == ESP_OK && current_protocol == WIFI_PROTOCOL_LR) {
log_v("Disabling long range on STA");
err = esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_DEFAULT);
if (err != ESP_OK) {
log_e("Could not disable long range on STA! 0x%x: %s", err, esp_err_to_name(err));
}
}
}
if (m & WIFI_MODE_AP) {
err = esp_wifi_get_protocol(WIFI_IF_AP, (uint8_t *)&current_protocol);
if (err == ESP_OK && current_protocol == WIFI_PROTOCOL_LR) {
log_v("Disabling long range on AP");
err = esp_wifi_set_protocol(WIFI_IF_AP, WIFI_PROTOCOL_DEFAULT);
if (err != ESP_OK) {
log_e("Could not disable long range on AP! 0x%x: %s", err, esp_err_to_name(err));
}
}
}
}
if (!espWiFiStart()) {
return false;
}
#ifdef BOARD_HAS_DUAL_ANTENNA
if (!setDualAntennaConfig(ANT1, ANT2, WIFI_RX_ANT_AUTO, WIFI_TX_ANT_AUTO)) {
log_e("Dual Antenna Config failed!");
return false;
}
#endif
return true;
}
/**
* get WiFi mode
* @return WiFiMode
*/
wifi_mode_t WiFiGenericClass::getMode() {
if (!lowLevelInitDone || !_esp_wifi_started) {
return WIFI_MODE_NULL;
}
wifi_mode_t mode;
if (esp_wifi_get_mode(&mode) != ESP_OK) {
log_w("WiFi not started");
return WIFI_MODE_NULL;
}
return mode;
}
/**
* control STA mode
* @param enable bool
* @return ok
*/
bool WiFiGenericClass::enableSTA(bool enable) {
wifi_mode_t currentMode = getMode();
bool isEnabled = ((currentMode & WIFI_MODE_STA) != 0);
if (isEnabled != enable) {
if (enable) {
return mode((wifi_mode_t)(currentMode | WIFI_MODE_STA));
}
return mode((wifi_mode_t)(currentMode & (~WIFI_MODE_STA)));
}
return true;
}
/**
* control AP mode
* @param enable bool
* @return ok
*/
bool WiFiGenericClass::enableAP(bool enable) {
wifi_mode_t currentMode = getMode();
bool isEnabled = ((currentMode & WIFI_MODE_AP) != 0);
if (isEnabled != enable) {
if (enable) {
return mode((wifi_mode_t)(currentMode | WIFI_MODE_AP));
}
return mode((wifi_mode_t)(currentMode & (~WIFI_MODE_AP)));
}
return true;
}
/**
* control modem sleep when only in STA mode
* @param enable bool
* @return ok
*/
bool WiFiGenericClass::setSleep(bool enabled) {
return setSleep(enabled ? WIFI_PS_MIN_MODEM : WIFI_PS_NONE);
}
/**
* control modem sleep when only in STA mode
* @param mode wifi_ps_type_t
* @return ok
*/
bool WiFiGenericClass::setSleep(wifi_ps_type_t sleepType) {
if (sleepType != _sleepEnabled) {
_sleepEnabled = sleepType;
if (WiFi.STA.started()) {
esp_err_t err = esp_wifi_set_ps(_sleepEnabled);
if (err != ESP_OK) {
log_e("esp_wifi_set_ps failed!: 0x%x: %s", err, esp_err_to_name(err));
return false;
}
}
return true;
}
return false;
}
/**
* get modem sleep enabled
* @return true if modem sleep is enabled
*/
wifi_ps_type_t WiFiGenericClass::getSleep() {
return _sleepEnabled;
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 2)
/**
* control wifi band mode
* @param band_mode enum possible band modes
* @return ok
*/
bool WiFiGenericClass::setBandMode(wifi_band_mode_t band_mode) {
#if SOC_WIFI_SUPPORT_5G
if (!WiFi.STA.started() && !WiFi.AP.started()) {
log_e("You need to start WiFi first");
return false;
}
wifi_band_mode_t bm = WIFI_BAND_MODE_AUTO;
esp_err_t err = esp_wifi_get_band_mode(&bm);
if (err != ESP_OK) {
log_e("Failed to get Current Band Mode: 0x%x: %s", err, esp_err_to_name(err));
return false;
} else if (bm == band_mode) {
log_d("No change in Band Mode");
return true;
} else {
log_d("Switching Band Mode from %d to %d", bm, band_mode);
}
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
if (WiFi.STA.connected() || WiFi.AP.connected()) {
log_e("Your network will get disconnected!");
}
#endif
err = esp_wifi_set_band_mode(band_mode);
if (err != ESP_OK) {
log_e("Failed to set Band Mode: 0x%x: %s", err, esp_err_to_name(err));
return false;
}
delay(100);
return true;
#else
if (band_mode == WIFI_BAND_MODE_5G_ONLY) {
log_e("This chip supports only 2.4GHz WiFi");
}
return band_mode != WIFI_BAND_MODE_5G_ONLY;
#endif
}
/**
* get the current enabled wifi band mode
* @return enum band mode
*/
wifi_band_mode_t WiFiGenericClass::getBandMode() {
#if SOC_WIFI_SUPPORT_5G
wifi_band_mode_t band_mode = WIFI_BAND_MODE_AUTO;
if (!WiFi.STA.started() && !WiFi.AP.started()) {
log_e("You need to start WiFi first");
return band_mode;
}
esp_err_t err = esp_wifi_get_band_mode(&band_mode);
if (err != ESP_OK) {
log_e("Failed to get Band Mode: 0x%x: %s", err, esp_err_to_name(err));
}
return band_mode;
#else
return WIFI_BAND_MODE_2G_ONLY;
#endif
}
#endif
/**
* get the current active wifi band
* @return enum band
*/
wifi_band_t WiFiGenericClass::getBand() {
#if SOC_WIFI_SUPPORT_5G
wifi_band_t band = WIFI_BAND_2G;
if (!WiFi.STA.started() && !WiFi.AP.started()) {
log_e("You need to start WiFi first");
return band;
}
esp_err_t err = esp_wifi_get_band(&band);
if (err != ESP_OK) {
log_e("Failed to get Band: 0x%x: %s", err, esp_err_to_name(err));
}
return band;
#else
return WIFI_BAND_2G;
#endif
}
/**
* control wifi tx power
* @param power enum maximum wifi tx power
* @return ok
*/
bool WiFiGenericClass::setTxPower(wifi_power_t power) {
if (!WiFi.STA.started() && !WiFi.AP.started()) {
log_w("Neither AP or STA has been started");
return false;
}
esp_err_t err = esp_wifi_set_max_tx_power(power);
if (err != ESP_OK) {
log_e("Failed to set TX Power: 0x%x: %s", err, esp_err_to_name(err));
}
return err == ESP_OK;
}
wifi_power_t WiFiGenericClass::getTxPower() {
int8_t power;
if (!WiFi.STA.started() && !WiFi.AP.started()) {
log_w("Neither AP or STA has been started");
return WIFI_POWER_19_5dBm;
}
esp_err_t err = esp_wifi_get_max_tx_power(&power);
if (err != ESP_OK) {
log_e("Failed to get TX Power: 0x%x: %s", err, esp_err_to_name(err));
return WIFI_POWER_19_5dBm;
}
return (wifi_power_t)power;
}
/**
* Initiate FTM Session.
* @param frm_count Number of FTM frames requested in terms of 4 or 8 bursts (allowed values - 0(No pref), 16, 24, 32, 64)
* @param burst_period Requested time period between consecutive FTM bursts in 100's of milliseconds (allowed values - 0(No pref), 2 - 255)
* @param channel Primary channel of the FTM Responder
* @param mac MAC address of the FTM Responder
* @return true on success
*/
bool WiFiGenericClass::initiateFTM(uint8_t frm_count, uint16_t burst_period, uint8_t channel, const uint8_t *mac) {
wifi_ftm_initiator_cfg_t ftmi_cfg = {
.resp_mac = {0, 0, 0, 0, 0, 0}, .channel = channel, .frm_count = frm_count, .burst_period = burst_period, .use_get_report_api = true
};
if (mac != NULL) {
memcpy(ftmi_cfg.resp_mac, mac, 6);
}
// Request FTM session with the Responder
esp_err_t err = esp_wifi_ftm_initiate_session(&ftmi_cfg);
if (ESP_OK != err) {
log_e("Failed to initiate FTM session: 0x%x: %s", err, esp_err_to_name(err));
return false;
}
return true;
}
/**
* Configure Dual antenna.
* @param gpio_ant1 Configure the GPIO number for the antenna 1 connected to the RF switch (default GPIO2 on ESP32-WROOM-DA)
* @param gpio_ant2 Configure the GPIO number for the antenna 2 connected to the RF switch (default GPIO25 on ESP32-WROOM-DA)
* @param rx_mode Set the RX antenna mode. See wifi_rx_ant_t for the options.
* @param tx_mode Set the TX antenna mode. See wifi_tx_ant_t for the options.
* @return true on success
*/
bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2, wifi_rx_ant_t rx_mode, wifi_tx_ant_t tx_mode) {
#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
esp_phy_ant_gpio_config_t wifi_ant_io;
esp_err_t err = esp_phy_get_ant_gpio(&wifi_ant_io);
if (ESP_OK != err) {
log_e("Failed to get antenna configuration: 0x%x: %s", err, esp_err_to_name(err));
return false;
}
wifi_ant_io.gpio_cfg[0].gpio_num = gpio_ant1;
wifi_ant_io.gpio_cfg[0].gpio_select = 1;
wifi_ant_io.gpio_cfg[1].gpio_num = gpio_ant2;
wifi_ant_io.gpio_cfg[1].gpio_select = 1;
err = esp_phy_set_ant_gpio(&wifi_ant_io);
if (ESP_OK != err) {
log_e("Failed to set antenna GPIO configuration: 0x%x: %s", err, esp_err_to_name(err));
return false;
}
// Set antenna default configuration
esp_phy_ant_config_t ant_config = {
.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO,
.rx_ant_default = ESP_PHY_ANT_MAX, // Ignored in AUTO mode
.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO,
.enabled_ant0 = 1,
.enabled_ant1 = 2,
};
switch (rx_mode) {
case WIFI_RX_ANT0: ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_ANT0; break;
case WIFI_RX_ANT1: ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_ANT1; break;
case WIFI_RX_ANT_AUTO:
log_i("TX Antenna will be automatically selected");
ant_config.rx_ant_default = ESP_PHY_ANT_ANT0;
ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
// Force TX for AUTO if RX is AUTO
ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
goto set_ant;
break;
default:
log_e("Invalid default antenna! Falling back to AUTO");
ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
break;
}
switch (tx_mode) {
case WIFI_TX_ANT0: ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_ANT0; break;
case WIFI_TX_ANT1: ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_ANT1; break;
case WIFI_TX_ANT_AUTO:
log_i("RX Antenna will be automatically selected");
ant_config.rx_ant_default = ESP_PHY_ANT_ANT0;
ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
// Force RX for AUTO if RX is AUTO
ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
break;
default:
log_e("Invalid default antenna! Falling back to AUTO");
ant_config.rx_ant_default = ESP_PHY_ANT_ANT0;
ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
break;
}
set_ant:
err = esp_phy_set_ant(&ant_config);
if (ESP_OK != err) {
log_e("Failed to set antenna configuration: 0x%x: %s", err, esp_err_to_name(err));
return false;
}
#endif
return true;
}
// -----------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------ Generic Network function ---------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
/*
* Deprecated Methods
*/
int WiFiGenericClass::hostByName(const char *aHostname, IPAddress &aResult) {
return Network.hostByName(aHostname, aResult);
}
IPAddress WiFiGenericClass::calculateNetworkID(IPAddress ip, IPAddress subnet) {
IPAddress networkID;
for (size_t i = 0; i < 4; i++) {
networkID[i] = subnet[i] & ip[i];
}
return networkID;
}
IPAddress WiFiGenericClass::calculateBroadcast(IPAddress ip, IPAddress subnet) {
IPAddress broadcastIp;
for (int i = 0; i < 4; i++) {
broadcastIp[i] = ~subnet[i] | ip[i];
}
return broadcastIp;
}
uint8_t WiFiGenericClass::calculateSubnetCIDR(IPAddress subnetMask) {
uint8_t CIDR = 0;
for (uint8_t i = 0; i < 4; i++) {
if (subnetMask[i] == 0x80) { // 128
CIDR += 1;
} else if (subnetMask[i] == 0xC0) { // 192
CIDR += 2;
} else if (subnetMask[i] == 0xE0) { // 224
CIDR += 3;
} else if (subnetMask[i] == 0xF0) { // 242
CIDR += 4;
} else if (subnetMask[i] == 0xF8) { // 248
CIDR += 5;
} else if (subnetMask[i] == 0xFC) { // 252
CIDR += 6;
} else if (subnetMask[i] == 0xFE) { // 254
CIDR += 7;
} else if (subnetMask[i] == 0xFF) { // 255
CIDR += 8;
}
}
return CIDR;
}
wifi_event_id_t WiFiGenericClass::onEvent(WiFiEventCb cbEvent, arduino_event_id_t event) {
return Network.onEvent(cbEvent, event);
}
wifi_event_id_t WiFiGenericClass::onEvent(WiFiEventFuncCb cbEvent, arduino_event_id_t event) {
return Network.onEvent(cbEvent, event);
}
wifi_event_id_t WiFiGenericClass::onEvent(WiFiEventSysCb cbEvent, arduino_event_id_t event) {
return Network.onEvent(cbEvent, event);
}
void WiFiGenericClass::removeEvent(WiFiEventCb cbEvent, arduino_event_id_t event) {
Network.removeEvent(cbEvent, event);
}
void WiFiGenericClass::removeEvent(WiFiEventSysCb cbEvent, arduino_event_id_t event) {
Network.removeEvent(cbEvent, event);
}
void WiFiGenericClass::removeEvent(wifi_event_id_t id) {
Network.removeEvent(id);
}
int WiFiGenericClass::setStatusBits(int bits) {
return Network.setStatusBits(bits);
}
int WiFiGenericClass::clearStatusBits(int bits) {
return Network.clearStatusBits(bits);
}
int WiFiGenericClass::getStatusBits() {
return Network.getStatusBits();
}
int WiFiGenericClass::waitStatusBits(int bits, uint32_t timeout_ms) {
return Network.waitStatusBits(bits, timeout_ms);
}
#endif /* SOC_WIFI_SUPPORTED */