/* 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 #include #include #include #include #include #include #include #include #include #include #if SOC_WIFI_SUPPORTED #include #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 #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 *)¤t_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 *)¤t_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 */