From c731223456a6a030ff0f802f670de0e9821eacf0 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 26 Oct 2024 18:15:22 +0200 Subject: [PATCH 001/564] [WiFi] Split WiFi code specific for ESP8266 and ESP32 --- ...FiEvent.cpp => ESPEasyWiFiEvent_ESP32.cpp} | 409 ++++++++---------- src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h | 40 ++ .../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp | 115 +++++ ...WiFiEvent.h => ESPEasyWiFiEvent_ESP8266.h} | 34 +- src/src/ESPEasyCore/ESPEasyWifi.cpp | 314 +------------- src/src/ESPEasyCore/ESPEasyWifi.h | 4 - .../ESPEasyWifi_abstracted_ESP32.cpp | 219 ++++++++++ .../ESPEasyWifi_abstracted_ESP8266.cpp | 196 +++++++++ src/src/ESPEasyCore/ESPEasyWifi_abstrated.h | 48 ++ 9 files changed, 815 insertions(+), 564 deletions(-) rename src/src/ESPEasyCore/{ESPEasyWiFiEvent.cpp => ESPEasyWiFiEvent_ESP32.cpp} (50%) create mode 100644 src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h create mode 100644 src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp rename src/src/ESPEasyCore/{ESPEasyWiFiEvent.h => ESPEasyWiFiEvent_ESP8266.h} (70%) create mode 100644 src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp create mode 100644 src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp create mode 100644 src/src/ESPEasyCore/ESPEasyWifi_abstrated.h diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp similarity index 50% rename from src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp rename to src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp index ea4d769fd..9d414fa6d 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp @@ -1,161 +1,158 @@ -#include "../ESPEasyCore/ESPEasyWiFiEvent.h" - -#if FEATURE_ETHERNET -#include -#endif - -#include "../DataStructs/RTCStruct.h" - -#include "../DataTypes/ESPEasyTimeSource.h" - -#include "../ESPEasyCore/ESPEasyEth.h" -#include "../ESPEasyCore/ESPEasy_Log.h" -#include "../ESPEasyCore/ESPEasyNetwork.h" -#include "../ESPEasyCore/ESPEasyWifi.h" -#include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" - -#include "../Globals/ESPEasyWiFiEvent.h" -#include "../Globals/NetworkState.h" -#include "../Globals/RTC.h" -#include "../Globals/WiFi_AP_Candidates.h" - -#include "../Helpers/ESPEasy_time_calc.h" - - -#if FEATURE_ETHERNET -#include "../Globals/ESPEasyEthEvent.h" -#endif - +#include "../ESPEasyCore/ESPEasyWiFiEvent_ESP32.h" #ifdef ESP32 +# if FEATURE_ETHERNET +# include +# endif // if FEATURE_ETHERNET + +# include "../DataStructs/RTCStruct.h" + +# include "../DataTypes/ESPEasyTimeSource.h" + +# include "../ESPEasyCore/ESPEasyEth.h" +# include "../ESPEasyCore/ESPEasy_Log.h" +# include "../ESPEasyCore/ESPEasyNetwork.h" +# include "../ESPEasyCore/ESPEasyWifi.h" +# include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" + +# include "../Globals/ESPEasyWiFiEvent.h" +# include "../Globals/NetworkState.h" +# include "../Globals/RTC.h" +# include "../Globals/WiFi_AP_Candidates.h" + +# include "../Helpers/ESPEasy_time_calc.h" + + +# if FEATURE_ETHERNET +# include "../Globals/ESPEasyEthEvent.h" +# endif // if FEATURE_ETHERNET + + void setUseStaticIP(bool enabled) { } -#endif // ifdef ESP32 -#ifdef ESP8266 -void WiFi_Access_Static_IP::set_use_static_ip(bool enabled) { - _useStaticIp = enabled; -} -void setUseStaticIP(bool enabled) { - WiFi_Access_Static_IP tmp_wifi; - - tmp_wifi.set_use_static_ip(enabled); -} - -#endif // ifdef ESP8266 - - - - // ******************************************************************************** // Functions called on events. // Make sure not to call anything in these functions that result in delay() or yield() // ******************************************************************************** -#ifdef ESP32 -#include +# include static bool ignoreDisconnectEvent = false; -#if ESP_IDF_VERSION_MAJOR > 3 +# if ESP_IDF_VERSION_MAJOR > 3 void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { switch (event) { case ARDUINO_EVENT_WIFI_READY: // ESP32 WiFi ready break; case ARDUINO_EVENT_WIFI_STA_START: - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_STA_STOP: - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_AP_START: - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_AP_STOP: - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0 - #if FEATURE_ETHERNET + # if FEATURE_ETHERNET + if (active_network_medium == NetworkMedium_t::Ethernet) { // DNS records are shared among WiFi and Ethernet (very bad design!) // So we must restore the DNS records for Ethernet in case we started with WiFi and then plugged in Ethernet. // As soon as WiFi is turned off, the DNS entry for Ethernet is cleared. EthEventData.markLostIP(); } - #endif // if FEATURE_ETHERNET + # endif // if FEATURE_ETHERNET WiFiEventData.markLostIP(); - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, + /* - active_network_medium == NetworkMedium_t::Ethernet ? - F("ETH : Event Lost IP") : - */ -// F("WiFi : Event Lost IP")); - #endif + active_network_medium == NetworkMedium_t::Ethernet ? + F("ETH : Event Lost IP") : + */ + + // F("WiFi : Event Lost IP")); + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: // Receive probe request packet in soft-AP interface // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.setAuthMode(info.wifi_sta_authmode_change.new_mode); - #else + # else // if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.setAuthMode(info.auth_change.new_mode); - #endif + # endif // if ESP_IDF_VERSION_MAJOR > 3 break; case ARDUINO_EVENT_WIFI_STA_CONNECTED: { char ssid_copy[33]; // Ensure space for maximum len SSID (32) plus trailing 0 - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 memcpy(ssid_copy, info.wifi_sta_connected.ssid, info.wifi_sta_connected.ssid_len); - ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier - WiFiEventData.markConnected((const char*) ssid_copy, info.wifi_sta_connected.bssid, info.wifi_sta_connected.channel); + ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier + WiFiEventData.markConnected((const char *)ssid_copy, info.wifi_sta_connected.bssid, info.wifi_sta_connected.channel); WiFiEventData.setAuthMode(info.wifi_sta_connected.authmode); - //addLog(LOG_LEVEL_INFO, F("WiFi : Event WIFI_STA_CONNECTED")); - #else + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event WIFI_STA_CONNECTED")); + # else // if ESP_IDF_VERSION_MAJOR > 3 memcpy(ssid_copy, info.connected.ssid, info.connected.ssid_len); ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier - WiFiEventData.markConnected((const char*) ssid_copy, info.connected.bssid, info.connected.channel); - #endif + WiFiEventData.markConnected((const char *)ssid_copy, info.connected.bssid, info.connected.channel); + # endif // if ESP_IDF_VERSION_MAJOR > 3 break; } case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: + if (!ignoreDisconnectEvent) { ignoreDisconnectEvent = true; - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnect(static_cast(info.wifi_sta_disconnected.reason)); + if (info.wifi_sta_disconnected.reason == WIFI_REASON_AUTH_EXPIRE) { // See: https://github.com/espressif/arduino-esp32/issues/8877#issuecomment-1807677897 - #if ESP_IDF_VERSION_MAJOR >= 5 + # if ESP_IDF_VERSION_MAJOR >= 5 + // FIXME TD-er: Should no longer be needed. WiFi.STA._setStatus(WL_CONNECTION_LOST); - #else + # else // if ESP_IDF_VERSION_MAJOR >= 5 WiFiSTAClass::_setStatus(WL_CONNECTION_LOST); - #endif + # endif // if ESP_IDF_VERSION_MAJOR >= 5 } - #else + # else // if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnect(static_cast(info.disconnected.reason)); + if (info.disconnected.reason == WIFI_REASON_AUTH_EXPIRE) { // See: https://github.com/espressif/arduino-esp32/issues/8877#issuecomment-1807677897 WiFiSTAClass::_setStatus(WL_CONNECTION_LOST); } - #endif + # endif // if ESP_IDF_VERSION_MAJOR > 3 WiFi.persistent(false); WiFi.disconnect(true); } @@ -164,139 +161,148 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { ignoreDisconnectEvent = false; WiFiEventData.markGotIP(); break; - #if FEATURE_USE_IPV6 + # if FEATURE_USE_IPV6 case ARDUINO_EVENT_WIFI_STA_GOT_IP6: { - ip_event_got_ip6_t * event = static_cast(&info.got_ip6); - const IPAddress ip(IPv6, (const uint8_t*)event->ip6_info.ip.addr, event->ip6_info.ip.zone); + ip_event_got_ip6_t *event = static_cast(&info.got_ip6); + const IPAddress ip(IPv6, (const uint8_t *)event->ip6_info.ip.addr, event->ip6_info.ip.zone); WiFiEventData.markGotIPv6(ip); break; } case ARDUINO_EVENT_WIFI_AP_GOT_IP6: addLog(LOG_LEVEL_INFO, F("WIFI : AP got IP6")); break; - #endif + # endif // if FEATURE_USE_IPV6 case ARDUINO_EVENT_WIFI_AP_STACONNECTED: - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markConnectedAPmode(info.wifi_ap_staconnected.mac); - #else + # else // if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markConnectedAPmode(info.sta_connected.mac); - #endif + # endif // if ESP_IDF_VERSION_MAJOR > 3 break; case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnectedAPmode(info.wifi_ap_stadisconnected.mac); - #else + # else // if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnectedAPmode(info.sta_disconnected.mac); - #endif + # endif // if ESP_IDF_VERSION_MAJOR > 3 break; case ARDUINO_EVENT_WIFI_SCAN_DONE: WiFiEventData.processedScanDone = false; break; -#if FEATURE_ETHERNET +# if FEATURE_ETHERNET case ARDUINO_EVENT_ETH_START: case ARDUINO_EVENT_ETH_CONNECTED: case ARDUINO_EVENT_ETH_GOT_IP: case ARDUINO_EVENT_ETH_DISCONNECTED: case ARDUINO_EVENT_ETH_STOP: - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 case ARDUINO_EVENT_ETH_GOT_IP6: - #else + # else // if ESP_IDF_VERSION_MAJOR > 3 case ARDUINO_EVENT_GOT_IP6: - #endif + # endif // if ESP_IDF_VERSION_MAJOR > 3 + // Handled in EthEvent break; -#endif //FEATURE_ETHERNET +# endif // FEATURE_ETHERNET default: - { - - // addLogMove(LOG_LEVEL_ERROR, concat(F("UNKNOWN WIFI/ETH EVENT: "), event)); - } + { + // addLogMove(LOG_LEVEL_ERROR, concat(F("UNKNOWN WIFI/ETH EVENT: "), event)); break; + } } } -#else + +# else // if ESP_IDF_VERSION_MAJOR > 3 void WiFiEvent(system_event_id_t event, system_event_info_t info) { switch (event) { case SYSTEM_EVENT_WIFI_READY: // ESP32 WiFi ready break; case SYSTEM_EVENT_STA_START: - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); + # endif // ifndef BUILD_NO_DEBUG break; case SYSTEM_EVENT_STA_STOP: - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); + # endif // ifndef BUILD_NO_DEBUG break; case SYSTEM_EVENT_AP_START: - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); + # endif // ifndef BUILD_NO_DEBUG break; case SYSTEM_EVENT_AP_STOP: - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); + # endif // ifndef BUILD_NO_DEBUG break; case SYSTEM_EVENT_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0 - #if FEATURE_ETHERNET + # if FEATURE_ETHERNET + if (active_network_medium == NetworkMedium_t::Ethernet) { EthEventData.markLostIP(); } else - #endif // if FEATURE_ETHERNET + # endif // if FEATURE_ETHERNET WiFiEventData.markLostIP(); - # ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG + /* - addLog(LOG_LEVEL_INFO, - active_network_medium == NetworkMedium_t::Ethernet ? - F("ETH : Event Lost IP") : F("WiFi : Event Lost IP")); - */ - #endif + addLog(LOG_LEVEL_INFO, + active_network_medium == NetworkMedium_t::Ethernet ? + F("ETH : Event Lost IP") : F("WiFi : Event Lost IP")); + */ + # endif // ifndef BUILD_NO_DEBUG break; case SYSTEM_EVENT_AP_PROBEREQRECVED: // Receive probe request packet in soft-AP interface // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 - # ifndef BUILD_NO_DEBUG - //addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); - #endif + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); + # endif // ifndef BUILD_NO_DEBUG break; case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.setAuthMode(info.wifi_sta_authmode_change.new_mode); - #else + # else // if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.setAuthMode(info.auth_change.new_mode); - #endif + # endif // if ESP_IDF_VERSION_MAJOR > 3 break; case SYSTEM_EVENT_STA_CONNECTED: { char ssid_copy[33] = { 0 }; // Ensure space for maximum len SSID (32) plus trailing 0 - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 memcpy(ssid_copy, info.wifi_sta_connected.ssid, info.wifi_sta_connected.ssid_len); - ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier - WiFiEventData.markConnected((const char*) ssid_copy, info.wifi_sta_connected.bssid, info.wifi_sta_connected.channel); - #else + ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier + WiFiEventData.markConnected((const char *)ssid_copy, info.wifi_sta_connected.bssid, info.wifi_sta_connected.channel); + # else // if ESP_IDF_VERSION_MAJOR > 3 memcpy(ssid_copy, info.connected.ssid, info.connected.ssid_len); ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier - WiFiEventData.markConnected((const char*) ssid_copy, info.connected.bssid, info.connected.channel); - #endif + WiFiEventData.markConnected((const char *)ssid_copy, info.connected.bssid, info.connected.channel); + # endif // if ESP_IDF_VERSION_MAJOR > 3 break; } case SYSTEM_EVENT_STA_DISCONNECTED: + if (!ignoreDisconnectEvent) { ignoreDisconnectEvent = true; - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnect(static_cast(info.wifi_sta_disconnected.reason)); - #else + # else // if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnect(static_cast(info.disconnected.reason)); - #endif + # endif // if ESP_IDF_VERSION_MAJOR > 3 WiFi.persistent(false); WiFi.disconnect(true); } @@ -306,135 +312,58 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { WiFiEventData.markGotIP(); break; case SYSTEM_EVENT_AP_STACONNECTED: - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markConnectedAPmode(info.wifi_ap_staconnected.mac); - #else + # else // if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markConnectedAPmode(info.sta_connected.mac); - #endif + # endif // if ESP_IDF_VERSION_MAJOR > 3 break; case SYSTEM_EVENT_AP_STADISCONNECTED: - #if ESP_IDF_VERSION_MAJOR > 3 + # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnectedAPmode(info.wifi_ap_stadisconnected.mac); - #else + # else // if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnectedAPmode(info.sta_disconnected.mac); - #endif + # endif // if ESP_IDF_VERSION_MAJOR > 3 break; case SYSTEM_EVENT_SCAN_DONE: WiFiEventData.processedScanDone = false; break; -#if FEATURE_ETHERNET +# if FEATURE_ETHERNET case SYSTEM_EVENT_ETH_START: + if (ethPrepare()) { - //addLog(LOG_LEVEL_INFO, F("ETH event: Started")); + // addLog(LOG_LEVEL_INFO, F("ETH event: Started")); } else { - //addLog(LOG_LEVEL_ERROR, F("ETH event: Could not prepare ETH!")); + // addLog(LOG_LEVEL_ERROR, F("ETH event: Could not prepare ETH!")); } break; case SYSTEM_EVENT_ETH_CONNECTED: - //addLog(LOG_LEVEL_INFO, F("ETH event: Connected")); + // addLog(LOG_LEVEL_INFO, F("ETH event: Connected")); EthEventData.markConnected(); break; case SYSTEM_EVENT_ETH_GOT_IP: EthEventData.markGotIP(); - //addLog(LOG_LEVEL_INFO, F("ETH event: Got IP")); + + // addLog(LOG_LEVEL_INFO, F("ETH event: Got IP")); break; case SYSTEM_EVENT_ETH_DISCONNECTED: - //addLog(LOG_LEVEL_ERROR, F("ETH event: Disconnected")); + // addLog(LOG_LEVEL_ERROR, F("ETH event: Disconnected")); EthEventData.markDisconnect(); break; case SYSTEM_EVENT_ETH_STOP: - //addLog(LOG_LEVEL_INFO, F("ETH event: Stopped")); + // addLog(LOG_LEVEL_INFO, F("ETH event: Stopped")); break; case SYSTEM_EVENT_GOT_IP6: - //addLog(LOG_LEVEL_INFO, F("ETH event: Got IP6")); + // addLog(LOG_LEVEL_INFO, F("ETH event: Got IP6")); break; -#endif //FEATURE_ETHERNET +# endif // FEATURE_ETHERNET default: - { - //addLogMove(LOG_LEVEL_ERROR, concat(F("UNKNOWN WIFI/ETH EVENT: "), event)); - } + { + // addLogMove(LOG_LEVEL_ERROR, concat(F("UNKNOWN WIFI/ETH EVENT: "), event)); break; + } } } -#endif - +# endif // if ESP_IDF_VERSION_MAJOR > 3 #endif // ifdef ESP32 - -#ifdef ESP8266 - -void onConnected(const WiFiEventStationModeConnected& event) { - WiFiEventData.markConnected(event.ssid, event.bssid, event.channel); -} - -void onDisconnect(const WiFiEventStationModeDisconnected& event) { - WiFiEventData.markDisconnect(event.reason); - if (WiFi.status() == WL_CONNECTED) { - // See https://github.com/esp8266/Arduino/issues/5912 - WiFi.persistent(false); - WiFi.disconnect(false); - delay(0); - } -} - -void onGotIP(const WiFiEventStationModeGotIP& event) { - WiFiEventData.markGotIP(); -} - -void onDHCPTimeout() { - WiFiEventData.processedDHCPTimeout = false; -} - -void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) { - WiFiEventData.markConnectedAPmode(event.mac); -} - -void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { - WiFiEventData.markDisconnectedAPmode(event.mac); -} - -void onStationModeAuthModeChanged(const WiFiEventStationModeAuthModeChanged& event) { - WiFiEventData.setAuthMode(event.newMode); -} - -#if FEATURE_ESP8266_DIRECT_WIFI_SCAN -void onWiFiScanDone(void *arg, STATUS status) { - if (status == OK) { - auto *head = reinterpret_cast(arg); - int scanCount = 0; - for (bss_info *it = head; it != nullptr; it = STAILQ_NEXT(it, next)) { - WiFi_AP_Candidates.process_WiFiscan(*it); - ++scanCount; - } - WiFi_AP_Candidates.after_process_WiFiscan(); - WiFiEventData.lastGetScanMoment.setNow(); -// WiFiEventData.processedScanDone = true; -# ifndef BUILD_NO_DEBUG -/* - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, concat(F("WiFi : Scan finished (ESP8266), found: "), scanCount)); - } -*/ -#endif - WiFi_AP_Candidates.load_knownCredentials(); - if (WiFi_AP_Candidates.addedKnownCandidate() || !NetworkConnected()) { - WiFiEventData.wifiConnectAttemptNeeded = true; - # ifndef BUILD_NO_DEBUG - if (WiFi_AP_Candidates.addedKnownCandidate()) { - //addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); - } - #endif - NetworkConnectRelaxed(); - } - - } - - WiFiMode_t mode = WiFi.getMode(); - setWifiMode(WIFI_OFF); - delay(1); - setWifiMode(mode); - delay(1); -} -#endif - -#endif // ifdef ESP8266 diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h new file mode 100644 index 000000000..9f7d6b904 --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h @@ -0,0 +1,40 @@ +#ifndef ESPEASY_WIFI_EVENT_ESP32_H +#define ESPEASY_WIFI_EVENT_ESP32_H + +#ifdef ESP32 + +#include "../../ESPEasy_common.h" + +#include + +// ******************************************************************************** + +// Work-around for setting _useStaticIP +// See reported issue: https://github.com/esp8266/Arduino/issues/4114 +// ******************************************************************************** +#include +#include +#include +class WiFi_Access_Static_IP : public WiFiSTAClass { +public: + + void set_use_static_ip(bool enabled); +}; + +void setUseStaticIP(bool enabled); + + +// ******************************************************************************** +// Functions called on events. +// Make sure not to call anything in these functions that result in delay() or yield() +// ******************************************************************************** + #if ESP_IDF_VERSION_MAJOR > 3 + #include + void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info); + #else + void WiFiEvent(system_event_id_t event, system_event_info_t info); + #endif + +#endif + +#endif \ No newline at end of file diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp new file mode 100644 index 000000000..b96282116 --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp @@ -0,0 +1,115 @@ +#include "../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h" + +#ifdef ESP8266 + +#include "../DataStructs/RTCStruct.h" + +#include "../DataTypes/ESPEasyTimeSource.h" + +#include "../ESPEasyCore/ESPEasyEth.h" +#include "../ESPEasyCore/ESPEasy_Log.h" +#include "../ESPEasyCore/ESPEasyNetwork.h" +#include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" + +#include "../Globals/ESPEasyWiFiEvent.h" +#include "../Globals/NetworkState.h" +#include "../Globals/RTC.h" +#include "../Globals/WiFi_AP_Candidates.h" + +#include "../Helpers/ESPEasy_time_calc.h" + + +void WiFi_Access_Static_IP::set_use_static_ip(bool enabled) { + _useStaticIp = enabled; +} +void setUseStaticIP(bool enabled) { + WiFi_Access_Static_IP tmp_wifi; + + tmp_wifi.set_use_static_ip(enabled); +} + + + + + +// ******************************************************************************** +// Functions called on events. +// Make sure not to call anything in these functions that result in delay() or yield() +// ******************************************************************************** +void onConnected(const WiFiEventStationModeConnected& event) { + WiFiEventData.markConnected(event.ssid, event.bssid, event.channel); +} + +void onDisconnect(const WiFiEventStationModeDisconnected& event) { + WiFiEventData.markDisconnect(event.reason); + if (WiFi.status() == WL_CONNECTED) { + // See https://github.com/esp8266/Arduino/issues/5912 + WiFi.persistent(false); + WiFi.disconnect(false); + delay(0); + } +} + +void onGotIP(const WiFiEventStationModeGotIP& event) { + WiFiEventData.markGotIP(); +} + +void onDHCPTimeout() { + WiFiEventData.processedDHCPTimeout = false; +} + +void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) { + WiFiEventData.markConnectedAPmode(event.mac); +} + +void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { + WiFiEventData.markDisconnectedAPmode(event.mac); +} + +void onStationModeAuthModeChanged(const WiFiEventStationModeAuthModeChanged& event) { + WiFiEventData.setAuthMode(event.newMode); +} + +#if FEATURE_ESP8266_DIRECT_WIFI_SCAN +void onWiFiScanDone(void *arg, STATUS status) { + if (status == OK) { + auto *head = reinterpret_cast(arg); + int scanCount = 0; + for (bss_info *it = head; it != nullptr; it = STAILQ_NEXT(it, next)) { + WiFi_AP_Candidates.process_WiFiscan(*it); + ++scanCount; + } + WiFi_AP_Candidates.after_process_WiFiscan(); + WiFiEventData.lastGetScanMoment.setNow(); +// WiFiEventData.processedScanDone = true; +# ifndef BUILD_NO_DEBUG +/* + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("WiFi : Scan finished (ESP8266), found: "), scanCount)); + } +*/ +#endif + WiFi_AP_Candidates.load_knownCredentials(); + if (WiFi_AP_Candidates.addedKnownCandidate() || !NetworkConnected()) { + WiFiEventData.wifiConnectAttemptNeeded = true; + # ifndef BUILD_NO_DEBUG + if (WiFi_AP_Candidates.addedKnownCandidate()) { + //addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); + } + #endif + NetworkConnectRelaxed(); + } + + } + + WiFiMode_t mode = WiFi.getMode(); + setWifiMode(WIFI_OFF); + delay(1); + setWifiMode(mode); + delay(1); +} + +#endif + +#endif diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.h b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h similarity index 70% rename from src/src/ESPEasyCore/ESPEasyWiFiEvent.h rename to src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h index 996692c62..aed20ebb8 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.h +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h @@ -1,5 +1,8 @@ -#ifndef ESPEASY_WIFI_EVENT_H -#define ESPEASY_WIFI_EVENT_H +#ifndef ESPEASY_WIFI_EVENT_ESP8266_H +#define ESPEASY_WIFI_EVENT_ESP8266_H + +#ifdef ESP8266 + #include "../../ESPEasy_common.h" @@ -10,18 +13,7 @@ // Work-around for setting _useStaticIP // See reported issue: https://github.com/esp8266/Arduino/issues/4114 // ******************************************************************************** -#ifdef ESP32 -#include -#include -#include -class WiFi_Access_Static_IP : public WiFiSTAClass { -public: - void set_use_static_ip(bool enabled); -}; -#endif - -#ifdef ESP8266 #include #include class WiFi_Access_Static_IP : public ESP8266WiFiSTAClass { @@ -29,8 +21,6 @@ public: void set_use_static_ip(bool enabled); }; -#endif - void setUseStaticIP(bool enabled); @@ -39,17 +29,6 @@ void setUseStaticIP(bool enabled); // Functions called on events. // Make sure not to call anything in these functions that result in delay() or yield() // ******************************************************************************** -#ifdef ESP32 - #if ESP_IDF_VERSION_MAJOR > 3 - #include - void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info); - #else - void WiFiEvent(system_event_id_t event, system_event_info_t info); - #endif -#endif - -#ifdef ESP8266 - void onConnected(const WiFiEventStationModeConnected& event); void onDisconnect(const WiFiEventStationModeDisconnected& event); @@ -70,5 +49,4 @@ void onWiFiScanDone(void *arg, STATUS status); #endif - -#endif // ESPEASY_WIFI_EVENT_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 8f5ea6c31..2245649dd 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -3,7 +3,6 @@ #include "../../ESPEasy-Globals.h" #include "../DataStructs/TimingStats.h" #include "../ESPEasyCore/ESPEasyNetwork.h" -#include "../ESPEasyCore/ESPEasyWiFiEvent.h" #include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/Serial.h" @@ -24,6 +23,11 @@ #include "../Helpers/StringGenerator_WiFi.h" #include "../Helpers/StringProvider.h" + + +#include "../ESPEasyCore/ESPEasyWifi_abstrated.h" + + #ifdef ESP32 #include #include // Needed to call ESP-IDF functions like esp_wifi_.... @@ -261,28 +265,7 @@ bool WiFiConnected() { if (WiFiEventData.unprocessedWifiEvents()) { return false; } - bool wifi_isconnected = WiFi.isConnected(); - #ifdef ESP8266 - // Perform check on SDK function, see: https://github.com/esp8266/Arduino/issues/7432 - station_status_t status = wifi_station_get_connect_status(); - switch(status) { - case STATION_GOT_IP: - wifi_isconnected = true; - break; - case STATION_NO_AP_FOUND: - case STATION_CONNECT_FAIL: - case STATION_WRONG_PASSWORD: - wifi_isconnected = false; - break; - case STATION_IDLE: - case STATION_CONNECTING: - break; - - default: - wifi_isconnected = false; - break; - } - #endif + bool wifi_isconnected = ESPEasy_WiFi_abstraction::WiFiConnected(); if (recursiveCall) return wifi_isconnected; recursiveCall = true; @@ -566,9 +549,7 @@ void AttemptWiFiConnect() { // Set Wifi config // ******************************************************************************** bool prepareWiFi() { - #if defined(ESP32) - registerWiFiEventHandler(); - #endif + ESPEasy_WiFi_abstraction::registerWiFiEventHandler(); if (!WiFi_AP_Candidates.hasCandidateCredentials()) { if (!WiFiEventData.warnedNoValidWiFiSettings) { @@ -677,21 +658,6 @@ void resetWiFi() { initWiFi(); } -#ifdef ESP32 -void removeWiFiEventHandler() -{ - WiFi.removeEvent(WiFiEventData.wm_event_id); - WiFiEventData.wm_event_id = 0; -} - -void registerWiFiEventHandler() -{ - if (WiFiEventData.wm_event_id != 0) { - removeWiFiEventHandler(); - } - WiFiEventData.wm_event_id = WiFi.onEvent(WiFiEvent); -} -#endif void initWiFi() @@ -704,7 +670,7 @@ void initWiFi() // WiFi = ESP8266WiFiClass(); #endif // ifdef ESP8266 #ifdef ESP32 - removeWiFiEventHandler(); + ESPEasy_WiFi_abstraction::removeWiFiEventHandler(); #endif @@ -719,23 +685,7 @@ void initWiFi() } setWifiMode(WIFI_OFF); -#if defined(ESP32) - registerWiFiEventHandler(); -#endif -#ifdef ESP8266 - // WiFi event handlers - static bool handlers_initialized = false; - if (!handlers_initialized) { - stationConnectedHandler = WiFi.onStationModeConnected(onConnected); - stationDisconnectedHandler = WiFi.onStationModeDisconnected(onDisconnect); - stationGotIpHandler = WiFi.onStationModeGotIP(onGotIP); - stationModeDHCPTimeoutHandler = WiFi.onStationModeDHCPTimeout(onDHCPTimeout); - stationModeAuthModeChangeHandler = WiFi.onStationModeAuthModeChanged(onStationModeAuthModeChanged); - APModeStationConnectedHandler = WiFi.onSoftAPModeStationConnected(onConnectedAPmode); - APModeStationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(onDisconnectedAPmode); - handlers_initialized = true; - } -#endif + ESPEasy_WiFi_abstraction::registerWiFiEventHandler(); delay(100); } @@ -791,18 +741,7 @@ void SetWiFiTXpower(float dBm, float rssi) { dBm = minTXpwr; } - #ifdef ESP32 - int8_t power = dBm * 4; - if (esp_wifi_set_max_tx_power(power) == ESP_OK) { - if (esp_wifi_get_max_tx_power(&power) == ESP_OK) { - dBm = static_cast(power) / 4.0f; - } - } - #endif - - #ifdef ESP8266 - WiFi.setOutputPower(dBm); - #endif +ESPEasy_WiFi_abstraction::SetWiFiTXpower(dBm); if (WiFiEventData.wifi_TX_pwr < dBm) { // Will increase the TX power, give power supply of the unit some rest @@ -840,39 +779,7 @@ void SetWiFiTXpower(float dBm, float rssi) { float GetRSSIthreshold(float& maxTXpwr) { maxTXpwr = Settings.getWiFi_TX_power(); - float threshold = WIFI_SENSITIVITY_n; - switch (getConnectionProtocol()) { - case WiFiConnectionProtocol::WiFi_Protocol_11b: - threshold = WIFI_SENSITIVITY_11b; - if (maxTXpwr > MAX_TX_PWR_DBM_11b) maxTXpwr = MAX_TX_PWR_DBM_11b; - break; - case WiFiConnectionProtocol::WiFi_Protocol_11g: - threshold = WIFI_SENSITIVITY_54g; - if (maxTXpwr > MAX_TX_PWR_DBM_54g) maxTXpwr = MAX_TX_PWR_DBM_54g; - break; -#ifdef ESP8266 - case WiFiConnectionProtocol::WiFi_Protocol_11n: -#else - case WiFiConnectionProtocol::WiFi_Protocol_HT20: - case WiFiConnectionProtocol::WiFi_Protocol_HT40: - case WiFiConnectionProtocol::WiFi_Protocol_HE20: -#endif - - threshold = WIFI_SENSITIVITY_n; - if (maxTXpwr > MAX_TX_PWR_DBM_n) maxTXpwr = MAX_TX_PWR_DBM_n; - break; -#ifdef ESP32 -#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) - case WiFiConnectionProtocol::WiFi_Protocol_11a: - case WiFiConnectionProtocol::WiFi_Protocol_VHT20: - // FIXME TD-er: Must determine max. TX power for these 5 GHz modi -#endif - case WiFiConnectionProtocol::WiFi_Protocol_LR: -#endif - case WiFiConnectionProtocol::Unknown: - break; - } - return threshold; + return ESPEasy_WiFi_abstraction::GetRSSIthreshold(maxTXpwr); } int GetRSSI_quality() { @@ -886,37 +793,7 @@ int GetRSSI_quality() { } WiFiConnectionProtocol getConnectionProtocol() { - if (WiFi.RSSI() < 0) { - #ifdef ESP8266 - switch (wifi_get_phy_mode()) { - case PHY_MODE_11B: - return WiFiConnectionProtocol::WiFi_Protocol_11b; - case PHY_MODE_11G: - return WiFiConnectionProtocol::WiFi_Protocol_11g; - case PHY_MODE_11N: - return WiFiConnectionProtocol::WiFi_Protocol_11n; - } - #endif - #ifdef ESP32 - - wifi_phy_mode_t phymode; - esp_wifi_sta_get_negotiated_phymode(&phymode); - switch (phymode) { - case WIFI_PHY_MODE_11B: return WiFiConnectionProtocol::WiFi_Protocol_11b; - case WIFI_PHY_MODE_11G: return WiFiConnectionProtocol::WiFi_Protocol_11g; - case WIFI_PHY_MODE_HT20: return WiFiConnectionProtocol::WiFi_Protocol_HT20; - case WIFI_PHY_MODE_HT40: return WiFiConnectionProtocol::WiFi_Protocol_HT40; - case WIFI_PHY_MODE_HE20: return WiFiConnectionProtocol::WiFi_Protocol_HE20; - case WIFI_PHY_MODE_LR: return WiFiConnectionProtocol::WiFi_Protocol_LR; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) - // 5 GHz - case WIFI_PHY_MODE_11A: return WiFiConnectionProtocol::WiFi_Protocol_11a; - case WIFI_PHY_MODE_VHT20: return WiFiConnectionProtocol::WiFi_Protocol_VHT20; -#endif - } - #endif - } - return WiFiConnectionProtocol::Unknown; + return ESPEasy_WiFi_abstraction::getConnectionProtocol(); } #ifdef ESP32 @@ -947,29 +824,7 @@ void WifiDisconnect() # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : WifiDisconnect()")); #endif - #ifdef ESP32 - removeWiFiEventHandler(); - WiFi.disconnect(); - delay(100); - { - const IPAddress ip; - const IPAddress gw; - const IPAddress subnet; - const IPAddress dns; - WiFi.config(ip, gw, subnet, dns); - } - #endif - #ifdef ESP8266 - // Only call disconnect when STA is active - if (WifiIsSTA(WiFi.getMode())) { - wifi_station_disconnect(); - } - station_config conf{}; - memset(&conf, 0, sizeof(conf)); - ETS_UART_INTR_DISABLE(); - wifi_station_set_config_current(&conf); - ETS_UART_INTR_ENABLE(); - #endif + ESPEasy_WiFi_abstraction::WiFiDisconnect(); WiFiEventData.setWiFiDisconnected(); WiFiEventData.markDisconnect(WIFI_DISCONNECT_REASON_UNSPECIFIED); /* @@ -1395,6 +1250,8 @@ void setWifiMode(WiFiMode_t new_mode) { if (new_mode == WIFI_OFF) { + + // FIXME TD-er: Is this correct to mark Turn ON ???? WiFiEventData.markWiFiTurnOn(); #if defined(ESP32) // Needs to be set while WiFi is off @@ -1410,42 +1267,19 @@ void setWifiMode(WiFiMode_t new_mode) { #endif // ifdef ESP8266 delay(1); } else { - #ifdef ESP32 if (cur_mode == WIFI_OFF) { - registerWiFiEventHandler(); + ESPEasy_WiFi_abstraction::registerWiFiEventHandler(); } - #endif // Only set power mode when AP is not enabled // When AP is enabled, the sleep mode is already set to WIFI_NONE_SLEEP if (!WifiIsAP(new_mode)) { if (Settings.WifiNoneSleep()) { - #ifdef ESP8266 - WiFi.setSleepMode(WIFI_NONE_SLEEP); - #endif - #ifdef ESP32 - WiFi.setSleep(WIFI_PS_NONE); - #endif + ESPEasy_WiFi_abstraction::setWiFiNoneSleep(); } else if (Settings.EcoPowerMode()) { - // Allow light sleep during idle times - #ifdef ESP8266 - WiFi.setSleepMode(WIFI_LIGHT_SLEEP); - #endif - #ifdef ESP32 - // Maximum modem power saving. - // In this mode, interval to receive beacons is determined by the listen_interval parameter in wifi_sta_config_t - // FIXME TD-er: Must test if this is desired behavior in ESP32. - WiFi.setSleep(WIFI_PS_MAX_MODEM); - #endif + ESPEasy_WiFi_abstraction::setWiFiEcoPowerMode(); } else { // Default - #ifdef ESP8266 - WiFi.setSleepMode(WIFI_MODEM_SLEEP); - #endif - #ifdef ESP32 - // Minimum modem power saving. - // In this mode, station wakes up to receive beacon every DTIM period - WiFi.setSleep(WIFI_PS_MIN_MODEM); - #endif + ESPEasy_WiFi_abstraction::setWiFiDefaultPowerMode(); } } #if FEATURE_SET_WIFI_TX_PWR @@ -1477,20 +1311,12 @@ void setWifiMode(WiFiMode_t new_mode) { bool WifiIsAP(WiFiMode_t wifimode) { - #if defined(ESP32) - return (wifimode == WIFI_MODE_AP) || (wifimode == WIFI_MODE_APSTA); - #else // if defined(ESP32) - return (wifimode == WIFI_AP) || (wifimode == WIFI_AP_STA); - #endif // if defined(ESP32) + return ESPEasy_WiFi_abstraction::WifiIsAP(wifimode); } bool WifiIsSTA(WiFiMode_t wifimode) { - #if defined(ESP32) - return (wifimode & WIFI_MODE_STA) != 0; - #else // if defined(ESP32) - return (wifimode & WIFI_STA) != 0; - #endif // if defined(ESP32) + return ESPEasy_WiFi_abstraction::WifiIsSTA(wifimode); } bool WiFiUseStaticIP() { @@ -1510,103 +1336,7 @@ bool wifiAPmodeActivelyUsed() } void setConnectionSpeed() { - #ifdef ESP8266 - // ESP8266 only supports 802.11g mode when running in STA+AP - const bool forcedByAPmode = WifiIsAP(WiFi.getMode()); - WiFiPhyMode_t phyMode = (Settings.ForceWiFi_bg_mode() || forcedByAPmode) ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N; - if (!forcedByAPmode) { - const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); - if (candidate.phy_known() && (candidate.bits.phy_11g != candidate.bits.phy_11n)) { - if ((WIFI_PHY_MODE_11G == phyMode) && !candidate.bits.phy_11g) { - phyMode = WIFI_PHY_MODE_11N; - addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11n only")); - } else if ((WIFI_PHY_MODE_11N == phyMode) && !candidate.bits.phy_11n) { - phyMode = WIFI_PHY_MODE_11G; - addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11g only")); - } - } else { - bool useAlternate = WiFiEventData.connectionFailures > 10; - if (useAlternate) { - phyMode = (WIFI_PHY_MODE_11G == phyMode) ? WIFI_PHY_MODE_11N : WIFI_PHY_MODE_11G; - } - } - } else { - // No need to perform a next attempt. - WiFi_AP_Candidates.markAttempt(); - } - - if (WiFi.getPhyMode() == phyMode) { - return; - } - #ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = concat(F("WIFI : Set to 802.11"), (WIFI_PHY_MODE_11G == phyMode) ? 'g' : 'n'); - if (forcedByAPmode) { - log += (F(" (AP+STA mode)")); - } - if (Settings.ForceWiFi_bg_mode()) { - log += F(" Force B/G mode"); - } - addLogMove(LOG_LEVEL_INFO, log); - } - #endif - WiFi.setPhyMode(phyMode); - #endif // ifdef ESP8266 - - // Does not (yet) work, so commented out. - #ifdef ESP32 - - // HT20 = 20 MHz channel width. - // HT40 = 40 MHz channel width. - // In theory, HT40 can offer upto 150 Mbps connection speed. - // However since HT40 is using nearly all channels on 2.4 GHz WiFi, - // Thus you are more likely to experience disturbances. - // The response speed and stability is better at HT20 for ESP units. - esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT20); - - uint8_t protocol = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G; // Default to BG - - if (!Settings.ForceWiFi_bg_mode() || (WiFiEventData.connectionFailures > 10)) { - // Set to use BGN - protocol |= WIFI_PROTOCOL_11N; - #ifdef ESP32C6 - protocol |= WIFI_PROTOCOL_11AX; - #endif - } - - const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); - if (candidate.phy_known()) { - // Check to see if the access point is set to "N-only" - if ((protocol & WIFI_PROTOCOL_11N) == 0) { - if (!candidate.bits.phy_11b && !candidate.bits.phy_11g && candidate.bits.phy_11n) { - if (candidate.bits.phy_11n) { - // Set to use BGN - protocol |= WIFI_PROTOCOL_11N; - addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11n only")); - } -#ifdef ESP32C6 - if (candidate.bits.phy_11ax) { - // Set to use WiFi6 - protocol |= WIFI_PROTOCOL_11AX; - addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11ax")); - } -#endif - } - } - } - - - if (WifiIsSTA(WiFi.getMode())) { - // Set to use "Long GI" making it more resilliant to reflections - // See: https://www.tp-link.com/us/configuration-guides/q_a_basic_wireless_concepts/?configurationId=2958#_idTextAnchor038 - esp_wifi_config_80211_tx_rate(WIFI_IF_STA, WIFI_PHY_RATE_MCS3_LGI); - esp_wifi_set_protocol(WIFI_IF_STA, protocol); - } - - if (WifiIsAP(WiFi.getMode())) { - esp_wifi_set_protocol(WIFI_IF_AP, protocol); - } - #endif // ifdef ESP32 + ESPEasy_WiFi_abstraction::setConnectionSpeed(Settings.ForceWiFi_bg_mode()); } void setupStaticIPconfig() { diff --git a/src/src/ESPEasyCore/ESPEasyWifi.h b/src/src/ESPEasyCore/ESPEasyWifi.h index 9b680a4fb..393c335d1 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.h +++ b/src/src/ESPEasyCore/ESPEasyWifi.h @@ -112,10 +112,6 @@ bool checkAndResetWiFi(); void resetWiFi(); void initWiFi(); -#ifdef ESP32 -void removeWiFiEventHandler(); -void registerWiFiEventHandler(); -#endif #if FEATURE_SET_WIFI_TX_PWR void SetWiFiTXpower(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp new file mode 100644 index 000000000..a7d463427 --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -0,0 +1,219 @@ +#include "../ESPEasyCore/ESPEasyWifi_abstrated.h" + +#ifdef ESP32 + +# include "../Globals/ESPEasyWiFiEvent.h" +# include "../Globals/WiFi_AP_Candidates.h" +# include "../ESPEasyCore/ESPEasyWiFiEvent_ESP32.h" + + +# include +# include // Needed to call ESP-IDF functions like esp_wifi_.... + +# include + + +namespace ESPEasy_WiFi_abstraction { +bool WiFiConnected() { + return WiFi.isConnected(); +} + +void WiFiDisconnect() { + removeWiFiEventHandler(); + WiFi.disconnect(); + delay(100); + { + const IPAddress ip; + const IPAddress gw; + const IPAddress subnet; + const IPAddress dns; + WiFi.config(ip, gw, subnet, dns); + } +} + +bool WifiIsAP(WiFiMode_t wifimode) +{ + return (wifimode == WIFI_MODE_AP) || (wifimode == WIFI_MODE_APSTA); +} + +bool WifiIsSTA(WiFiMode_t wifimode) +{ + return (wifimode & WIFI_MODE_STA) != 0; +} + +void removeWiFiEventHandler() +{ + WiFi.removeEvent(WiFiEventData.wm_event_id); + WiFiEventData.wm_event_id = 0; +} + +void registerWiFiEventHandler() +{ + if (WiFiEventData.wm_event_id != 0) { + removeWiFiEventHandler(); + } + WiFiEventData.wm_event_id = WiFi.onEvent(WiFiEvent); +} + +float GetRSSIthreshold(float& maxTXpwr) { + float threshold = WIFI_SENSITIVITY_n; + + switch (getConnectionProtocol()) { + case WiFiConnectionProtocol::WiFi_Protocol_11b: + threshold = WIFI_SENSITIVITY_11b; + + if (maxTXpwr > MAX_TX_PWR_DBM_11b) { maxTXpwr = MAX_TX_PWR_DBM_11b; } + break; + case WiFiConnectionProtocol::WiFi_Protocol_11g: + threshold = WIFI_SENSITIVITY_54g; + + if (maxTXpwr > MAX_TX_PWR_DBM_54g) { maxTXpwr = MAX_TX_PWR_DBM_54g; } + break; + case WiFiConnectionProtocol::WiFi_Protocol_HT20: + case WiFiConnectionProtocol::WiFi_Protocol_HT40: + case WiFiConnectionProtocol::WiFi_Protocol_HE20: + + threshold = WIFI_SENSITIVITY_n; + + if (maxTXpwr > MAX_TX_PWR_DBM_n) { maxTXpwr = MAX_TX_PWR_DBM_n; } + break; +# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) + case WiFiConnectionProtocol::WiFi_Protocol_11a: + case WiFiConnectionProtocol::WiFi_Protocol_VHT20: + // FIXME TD-er: Must determine max. TX power for these 5 GHz modi +# endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) + case WiFiConnectionProtocol::WiFi_Protocol_LR: + case WiFiConnectionProtocol::Unknown: + break; + } + return threshold; +} + +WiFiConnectionProtocol getConnectionProtocol() +{ + if (WiFi.RSSI() < 0) { + wifi_phy_mode_t phymode; + esp_wifi_sta_get_negotiated_phymode(&phymode); + + switch (phymode) { + case WIFI_PHY_MODE_11B: return WiFiConnectionProtocol::WiFi_Protocol_11b; + case WIFI_PHY_MODE_11G: return WiFiConnectionProtocol::WiFi_Protocol_11g; + case WIFI_PHY_MODE_HT20: return WiFiConnectionProtocol::WiFi_Protocol_HT20; + case WIFI_PHY_MODE_HT40: return WiFiConnectionProtocol::WiFi_Protocol_HT40; + case WIFI_PHY_MODE_HE20: return WiFiConnectionProtocol::WiFi_Protocol_HE20; + case WIFI_PHY_MODE_LR: return WiFiConnectionProtocol::WiFi_Protocol_LR; +# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + + // 5 GHz + case WIFI_PHY_MODE_11A: return WiFiConnectionProtocol::WiFi_Protocol_11a; + case WIFI_PHY_MODE_VHT20: return WiFiConnectionProtocol::WiFi_Protocol_VHT20; +# endif // if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) + } + } + return WiFiConnectionProtocol::Unknown; +} + +# if FEATURE_SET_WIFI_TX_PWR +void SetWiFiTXpower(float& dBm) +{ + int8_t power = dBm * 4; + + if (esp_wifi_set_max_tx_power(power) == ESP_OK) { + if (esp_wifi_get_max_tx_power(&power) == ESP_OK) { + dBm = static_cast(power) / 4.0f; + } + } +} + +# endif // if FEATURE_SET_WIFI_TX_PWR + +void setConnectionSpeed(bool ForceWiFi_bg_mode) { + // Does not (yet) work, so commented out. + + // HT20 = 20 MHz channel width. + // HT40 = 40 MHz channel width. + // In theory, HT40 can offer upto 150 Mbps connection speed. + // However since HT40 is using nearly all channels on 2.4 GHz WiFi, + // Thus you are more likely to experience disturbances. + // The response speed and stability is better at HT20 for ESP units. + esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT20); + + uint8_t protocol = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G; // Default to BG + + if (!ForceWiFi_bg_mode || (WiFiEventData.connectionFailures > 10)) { + // Set to use BGN + protocol |= WIFI_PROTOCOL_11N; + #ifdef ESP32C6 + protocol |= WIFI_PROTOCOL_11AX; + #endif + } + + const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); + if (candidate.phy_known()) { + // Check to see if the access point is set to "N-only" + if ((protocol & WIFI_PROTOCOL_11N) == 0) { + if (!candidate.bits.phy_11b && !candidate.bits.phy_11g && candidate.bits.phy_11n) { + if (candidate.bits.phy_11n) { + // Set to use BGN + protocol |= WIFI_PROTOCOL_11N; + addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11n only")); + } +#ifdef ESP32C6 + if (candidate.bits.phy_11ax) { + // Set to use WiFi6 + protocol |= WIFI_PROTOCOL_11AX; + addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11ax")); + } +#endif + } + } + } + + + if (ESPEasy_WiFi_abstraction::WifiIsSTA(WiFi.getMode())) { + // Set to use "Long GI" making it more resilliant to reflections + // See: https://www.tp-link.com/us/configuration-guides/q_a_basic_wireless_concepts/?configurationId=2958#_idTextAnchor038 + esp_wifi_config_80211_tx_rate(WIFI_IF_STA, WIFI_PHY_RATE_MCS3_LGI); + esp_wifi_set_protocol(WIFI_IF_STA, protocol); + } + + if (ESPEasy_WiFi_abstraction::WifiIsAP(WiFi.getMode())) { + esp_wifi_set_protocol(WIFI_IF_AP, protocol); + } +} + +void setWiFiNoneSleep() +{ + WiFi.setSleep(WIFI_PS_NONE); +} + +void setWiFiEcoPowerMode() +{ + // Allow light sleep during idle times +# ifdef ESP8266 + WiFi.setSleepMode(WIFI_LIGHT_SLEEP); +# endif // ifdef ESP8266 +# ifdef ESP32 + + // Maximum modem power saving. + // In this mode, interval to receive beacons is determined by the listen_interval parameter in wifi_sta_config_t + // FIXME TD-er: Must test if this is desired behavior in ESP32. + WiFi.setSleep(WIFI_PS_MAX_MODEM); +# endif // ifdef ESP32 +} + +void setWiFiDefaultPowerMode() +{ + // Minimum modem power saving. + // In this mode, station wakes up to receive beacon every DTIM period + WiFi.setSleep(WIFI_PS_MIN_MODEM); +} + + + + + +} // namespace ESPEasy_WiFi_abstraction + + +#endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp new file mode 100644 index 000000000..26b19eebd --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp @@ -0,0 +1,196 @@ +#include "../ESPEasyCore/ESPEasyWifi_abstrated.h" + +#ifdef ESP8266 + +# include "../Globals/ESPEasyWiFiEvent.h" +# include "../Globals/WiFi_AP_Candidates.h" + +# include "../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h" + +namespace ESPEasy_WiFi_abstraction { +bool WiFiConnected() +{ + bool wifi_isconnected = WiFi.isConnected(); + + // Perform check on SDK function, see: https://github.com/esp8266/Arduino/issues/7432 + station_status_t status = wifi_station_get_connect_status(); + + switch (status) { + case STATION_GOT_IP: + wifi_isconnected = true; + break; + case STATION_NO_AP_FOUND: + case STATION_CONNECT_FAIL: + case STATION_WRONG_PASSWORD: + wifi_isconnected = false; + break; + case STATION_IDLE: + case STATION_CONNECTING: + break; + + default: + wifi_isconnected = false; + break; + } + return wifi_isconnected; +} + +void WiFiDisconnect() { + // Only call disconnect when STA is active + if (ESPEasy_WiFi_abstraction::WifiIsSTA(WiFi.getMode())) { + wifi_station_disconnect(); + } + station_config conf{}; + memset(&conf, 0, sizeof(conf)); + ETS_UART_INTR_DISABLE(); + wifi_station_set_config_current(&conf); + ETS_UART_INTR_ENABLE(); +} + +bool WifiIsAP(WiFiMode_t wifimode) +{ + return (wifimode == WIFI_AP) || (wifimode == WIFI_AP_STA); +} + +bool WifiIsSTA(WiFiMode_t wifimode) +{ + return (wifimode & WIFI_STA) != 0; +} + +void removeWiFiEventHandler() { + // Not needed for ESP8266 +} + +void registerWiFiEventHandler() +{ + // WiFi event handlers + static bool handlers_initialized = false; + + if (!handlers_initialized) { + stationConnectedHandler = WiFi.onStationModeConnected(onConnected); + stationDisconnectedHandler = WiFi.onStationModeDisconnected(onDisconnect); + stationGotIpHandler = WiFi.onStationModeGotIP(onGotIP); + stationModeDHCPTimeoutHandler = WiFi.onStationModeDHCPTimeout(onDHCPTimeout); + stationModeAuthModeChangeHandler = WiFi.onStationModeAuthModeChanged(onStationModeAuthModeChanged); + APModeStationConnectedHandler = WiFi.onSoftAPModeStationConnected(onConnectedAPmode); + APModeStationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(onDisconnectedAPmode); + handlers_initialized = true; + } +} + +float GetRSSIthreshold(float& maxTXpwr) { + float threshold = WIFI_SENSITIVITY_n; + + switch (getConnectionProtocol()) { + case WiFiConnectionProtocol::WiFi_Protocol_11b: + threshold = WIFI_SENSITIVITY_11b; + + if (maxTXpwr > MAX_TX_PWR_DBM_11b) { maxTXpwr = MAX_TX_PWR_DBM_11b; } + break; + case WiFiConnectionProtocol::WiFi_Protocol_11g: + threshold = WIFI_SENSITIVITY_54g; + + if (maxTXpwr > MAX_TX_PWR_DBM_54g) { maxTXpwr = MAX_TX_PWR_DBM_54g; } + break; + case WiFiConnectionProtocol::WiFi_Protocol_11n: + threshold = WIFI_SENSITIVITY_n; + + if (maxTXpwr > MAX_TX_PWR_DBM_n) { maxTXpwr = MAX_TX_PWR_DBM_n; } + break; + case WiFiConnectionProtocol::Unknown: + break; + } + return threshold; +} + +WiFiConnectionProtocol getConnectionProtocol() +{ + if (WiFi.RSSI() < 0) { + switch (wifi_get_phy_mode()) { + case PHY_MODE_11B: + return WiFiConnectionProtocol::WiFi_Protocol_11b; + case PHY_MODE_11G: + return WiFiConnectionProtocol::WiFi_Protocol_11g; + case PHY_MODE_11N: + return WiFiConnectionProtocol::WiFi_Protocol_11n; + } + } + return WiFiConnectionProtocol::Unknown; +} + +# if FEATURE_SET_WIFI_TX_PWR +void SetWiFiTXpower(float& dBm) +{ + WiFi.setOutputPower(dBm); +} + +# endif // if FEATURE_SET_WIFI_TX_PWR + +void setConnectionSpeed(bool ForceWiFi_bg_mode) { + // ESP8266 only supports 802.11g mode when running in STA+AP + const bool forcedByAPmode = ESPEasy_WiFi_abstraction::WifiIsAP(WiFi.getMode()); + WiFiPhyMode_t phyMode = (ForceWiFi_bg_mode || forcedByAPmode) ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N; + if (!forcedByAPmode) { + const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); + if (candidate.phy_known() && (candidate.bits.phy_11g != candidate.bits.phy_11n)) { + if ((WIFI_PHY_MODE_11G == phyMode) && !candidate.bits.phy_11g) { + phyMode = WIFI_PHY_MODE_11N; + addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11n only")); + } else if ((WIFI_PHY_MODE_11N == phyMode) && !candidate.bits.phy_11n) { + phyMode = WIFI_PHY_MODE_11G; + addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11g only")); + } + } else { + bool useAlternate = WiFiEventData.connectionFailures > 10; + if (useAlternate) { + phyMode = (WIFI_PHY_MODE_11G == phyMode) ? WIFI_PHY_MODE_11N : WIFI_PHY_MODE_11G; + } + } + } else { + // No need to perform a next attempt. + WiFi_AP_Candidates.markAttempt(); + } + + if (WiFi.getPhyMode() == phyMode) { + return; + } + #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = concat(F("WIFI : Set to 802.11"), (WIFI_PHY_MODE_11G == phyMode) ? 'g' : 'n'); + if (forcedByAPmode) { + log += (F(" (AP+STA mode)")); + } + if (Settings.ForceWiFi_bg_mode()) { + log += F(" Force B/G mode"); + } + addLogMove(LOG_LEVEL_INFO, log); + } + #endif + WiFi.setPhyMode(phyMode); +} + +void setWiFiNoneSleep() +{ + WiFi.setSleepMode(WIFI_NONE_SLEEP); +} + +void setWiFiEcoPowerMode() +{ + // Allow light sleep during idle times + WiFi.setSleepMode(WIFI_LIGHT_SLEEP); +} + +void setWiFiDefaultPowerMode() +{ + WiFi.setSleepMode(WIFI_MODEM_SLEEP); +} + + + + + + +} // namespace ESPEasy_WiFi_abstraction + + +#endif // ifdef ESP8266 diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstrated.h b/src/src/ESPEasyCore/ESPEasyWifi_abstrated.h new file mode 100644 index 000000000..da803cea5 --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstrated.h @@ -0,0 +1,48 @@ +#ifndef ESPEASYCORE_ESPEASYWIFI_ABSTRACTED_H +#define ESPEASYCORE_ESPEASYWIFI_ABSTRACTED_H + +#include "../../ESPEasy_common.h" + + +#include "../DataTypes/WiFiConnectionProtocol.h" + + +#if defined(ESP8266) +#include "../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h" +# include +#endif // if defined(ESP8266) +#if defined(ESP32) +#include "../ESPEasyCore/ESPEasyWiFiEvent_ESP32.h" +# include +#endif // if defined(ESP32) + +namespace ESPEasy_WiFi_abstraction { +bool WiFiConnected(); + +void WiFiDisconnect(); + +bool WifiIsAP(WiFiMode_t wifimode); +bool WifiIsSTA(WiFiMode_t wifimode); + + +void removeWiFiEventHandler(); +void registerWiFiEventHandler(); + + +WiFiConnectionProtocol getConnectionProtocol(); +float GetRSSIthreshold(float& maxTXpwr); +#if FEATURE_SET_WIFI_TX_PWR +void SetWiFiTXpower(float& dBm); +#endif // if FEATURE_SET_WIFI_TX_PWR + +void setConnectionSpeed(bool ForceWiFi_bg_mode); + +void setWiFiNoneSleep(); +void setWiFiEcoPowerMode(); +void setWiFiDefaultPowerMode(); + + +} + + +#endif // ifndef ESPEASYCORE_ESPEASYWIFI_ABSTRACTED_H From 44f4bb271359cb2e646026982ec7e0c72b919ec6 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 26 Oct 2024 18:31:07 +0200 Subject: [PATCH 002/564] [Cleanup] Get rid of ESP32-IDF code for IDF3.x or older --- src/src/CustomBuild/ESPEasyLimits.h | 4 - src/src/DataTypes/EthernetParameters.cpp | 6 - src/src/DataTypes/EthernetParameters.h | 3 - src/src/ESPEasyCore/ESPEasyEth.cpp | 10 +- src/src/ESPEasyCore/ESPEasyEthEvent.cpp | 8 - src/src/ESPEasyCore/ESPEasyEthEvent.h | 2 - .../ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp | 190 ------------------ src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h | 10 +- src/src/Helpers/ESPEasy_checks.cpp | 4 +- src/src/Helpers/StringGenerator_System.cpp | 6 +- src/src/WebServer/HardwarePage.cpp | 4 - 11 files changed, 8 insertions(+), 239 deletions(-) diff --git a/src/src/CustomBuild/ESPEasyLimits.h b/src/src/CustomBuild/ESPEasyLimits.h index 73b5ecdeb..5b98587ea 100644 --- a/src/src/CustomBuild/ESPEasyLimits.h +++ b/src/src/CustomBuild/ESPEasyLimits.h @@ -34,12 +34,8 @@ #endif #ifndef MAX_GPIO - #if ESP_IDF_VERSION_MAJOR > 3 // IDF 4+ #include #define MAX_GPIO (GPIO_NUM_MAX - 1) - #else // ESP32 Before IDF 4.0 - #define MAX_GPIO 39 - #endif #endif #endif diff --git a/src/src/DataTypes/EthernetParameters.cpp b/src/src/DataTypes/EthernetParameters.cpp index ceab27833..f6aa07a83 100644 --- a/src/src/DataTypes/EthernetParameters.cpp +++ b/src/src/DataTypes/EthernetParameters.cpp @@ -40,7 +40,6 @@ bool isValid(EthPhyType_t phyType) { #if CONFIG_ETH_USE_ESP32_EMAC case EthPhyType_t::LAN8720: case EthPhyType_t::TLK110: -# if ESP_IDF_VERSION_MAJOR > 3 case EthPhyType_t::RTL8201: #if ETH_TYPE_JL1101_SUPPORTED case EthPhyType_t::JL1101: @@ -48,7 +47,6 @@ bool isValid(EthPhyType_t phyType) { case EthPhyType_t::DP83848: case EthPhyType_t::KSZ8041: case EthPhyType_t::KSZ8081: -# endif // if ESP_IDF_VERSION_MAJOR > 3 return true; #endif // if CONFIG_ETH_USE_ESP32_EMAC @@ -94,7 +92,6 @@ eth_phy_type_t to_ESP_phy_type(EthPhyType_t phyType) # if CONFIG_ETH_USE_ESP32_EMAC case EthPhyType_t::LAN8720: return ETH_PHY_LAN8720; case EthPhyType_t::TLK110: return ETH_PHY_TLK110; -# if ESP_IDF_VERSION_MAJOR > 3 case EthPhyType_t::RTL8201: return ETH_PHY_RTL8201; # if ETH_TYPE_JL1101_SUPPORTED case EthPhyType_t::JL1101: return ETH_PHY_JL1101; @@ -102,7 +99,6 @@ eth_phy_type_t to_ESP_phy_type(EthPhyType_t phyType) case EthPhyType_t::DP83848: return ETH_PHY_DP83848; case EthPhyType_t::KSZ8041: return ETH_PHY_KSZ8041; case EthPhyType_t::KSZ8081: return ETH_PHY_KSZ8081; -# endif // if ESP_IDF_VERSION_MAJOR > 3 # endif // if CONFIG_ETH_USE_ESP32_EMAC # if ESP_IDF_VERSION_MAJOR >= 5 @@ -130,7 +126,6 @@ const __FlashStringHelper* toString(EthPhyType_t phyType) { #if CONFIG_ETH_USE_ESP32_EMAC case EthPhyType_t::LAN8720: return F("LAN8710/LAN8720"); case EthPhyType_t::TLK110: return F("TLK110"); -# if ESP_IDF_VERSION_MAJOR > 3 case EthPhyType_t::RTL8201: return F("RTL8201"); #if ETH_TYPE_JL1101_SUPPORTED case EthPhyType_t::JL1101: return F("JL1101"); @@ -138,7 +133,6 @@ const __FlashStringHelper* toString(EthPhyType_t phyType) { case EthPhyType_t::DP83848: return F("DP83848"); case EthPhyType_t::KSZ8041: return F("KSZ8041"); case EthPhyType_t::KSZ8081: return F("KSZ8081"); -# endif // if ESP_IDF_VERSION_MAJOR > 3 #endif // if CONFIG_ETH_USE_ESP32_EMAC #if ESP_IDF_VERSION_MAJOR >= 5 diff --git a/src/src/DataTypes/EthernetParameters.h b/src/src/DataTypes/EthernetParameters.h index a017e6c62..3991e692f 100644 --- a/src/src/DataTypes/EthernetParameters.h +++ b/src/src/DataTypes/EthernetParameters.h @@ -24,8 +24,6 @@ enum class EthPhyType_t : uint8_t { #if CONFIG_ETH_USE_ESP32_EMAC LAN8720 = 0, TLK110 = 1, -#if ESP_IDF_VERSION_MAJOR > 3 - RTL8201 = 2, #if ETH_TYPE_JL1101_SUPPORTED JL1101 = 3, @@ -34,7 +32,6 @@ enum class EthPhyType_t : uint8_t { KSZ8041 = 5, KSZ8081 = 6, #endif -#endif #if ESP_IDF_VERSION_MAJOR >= 5 #if CONFIG_ETH_SPI_ETHERNET_DM9051 DM9051 = 10, diff --git a/src/src/ESPEasyCore/ESPEasyEth.cpp b/src/src/ESPEasyCore/ESPEasyEth.cpp index c0b8a8ac9..36cae36e8 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth.cpp @@ -17,11 +17,7 @@ #include #include -#if ESP_IDF_VERSION_MAJOR > 3 - #include -#else - #include -#endif +#include #include @@ -114,11 +110,7 @@ MAC_address ETHMacAddress() { if(!EthEventData.ethInitSuccess) { addLog(LOG_LEVEL_ERROR, F("Call NetworkMacAddress() only on connected Ethernet!")); } else { - #if ESP_IDF_VERSION_MAJOR > 3 ETH.macAddress(mac.mac); - #else - esp_eth_get_mac(mac.mac); - #endif } return mac; } diff --git a/src/src/ESPEasyCore/ESPEasyEthEvent.cpp b/src/src/ESPEasyCore/ESPEasyEthEvent.cpp index 8f69a1417..6d6ba4e16 100644 --- a/src/src/ESPEasyCore/ESPEasyEthEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyEthEvent.cpp @@ -15,8 +15,6 @@ # include - -# if ESP_IDF_VERSION_MAJOR > 3 void EthEvent(WiFiEvent_t event, arduino_event_info_t info) { switch (event) { case ARDUINO_EVENT_ETH_START: @@ -42,11 +40,7 @@ void EthEvent(WiFiEvent_t event, arduino_event_info_t info) { case ARDUINO_EVENT_ETH_STOP: // addLog(LOG_LEVEL_INFO, F("ETH event: Stopped")); break; - # if ESP_IDF_VERSION_MAJOR > 3 case ARDUINO_EVENT_ETH_GOT_IP6: - # else // if ESP_IDF_VERSION_MAJOR > 3 - case ARDUINO_EVENT_GOT_IP6: - # endif // if ESP_IDF_VERSION_MAJOR > 3 #if FEATURE_USE_IPV6 { ip_event_got_ip6_t * event = static_cast(&info.got_ip6); @@ -65,8 +59,6 @@ void EthEvent(WiFiEvent_t event, arduino_event_info_t info) { } } -# endif // if ESP_IDF_VERSION_MAJOR > 3 - # endif // if FEATURE_ETHERNET #endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyEthEvent.h b/src/src/ESPEasyCore/ESPEasyEthEvent.h index 620f672b1..6130eddfa 100644 --- a/src/src/ESPEasyCore/ESPEasyEthEvent.h +++ b/src/src/ESPEasyCore/ESPEasyEthEvent.h @@ -10,13 +10,11 @@ // ******************************************************************************** #ifdef ESP32 #if FEATURE_ETHERNET -#if ESP_IDF_VERSION_MAJOR > 3 #include #include void EthEvent(WiFiEvent_t event, arduino_event_info_t info); #endif #endif -#endif #endif // ESPEASY_ETH_EVENT_H \ No newline at end of file diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp index 9d414fa6d..edc9dc376 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp @@ -39,7 +39,6 @@ void setUseStaticIP(bool enabled) { static bool ignoreDisconnectEvent = false; -# if ESP_IDF_VERSION_MAJOR > 3 void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { switch (event) { case ARDUINO_EVENT_WIFI_READY: @@ -104,55 +103,31 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { break; case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: - # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.setAuthMode(info.wifi_sta_authmode_change.new_mode); - # else // if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.setAuthMode(info.auth_change.new_mode); - # endif // if ESP_IDF_VERSION_MAJOR > 3 break; case ARDUINO_EVENT_WIFI_STA_CONNECTED: { char ssid_copy[33]; // Ensure space for maximum len SSID (32) plus trailing 0 - # if ESP_IDF_VERSION_MAJOR > 3 memcpy(ssid_copy, info.wifi_sta_connected.ssid, info.wifi_sta_connected.ssid_len); ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier WiFiEventData.markConnected((const char *)ssid_copy, info.wifi_sta_connected.bssid, info.wifi_sta_connected.channel); WiFiEventData.setAuthMode(info.wifi_sta_connected.authmode); // addLog(LOG_LEVEL_INFO, F("WiFi : Event WIFI_STA_CONNECTED")); - # else // if ESP_IDF_VERSION_MAJOR > 3 - memcpy(ssid_copy, info.connected.ssid, info.connected.ssid_len); - ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier - WiFiEventData.markConnected((const char *)ssid_copy, info.connected.bssid, info.connected.channel); - # endif // if ESP_IDF_VERSION_MAJOR > 3 break; } case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: if (!ignoreDisconnectEvent) { ignoreDisconnectEvent = true; - # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnect(static_cast(info.wifi_sta_disconnected.reason)); if (info.wifi_sta_disconnected.reason == WIFI_REASON_AUTH_EXPIRE) { // See: https://github.com/espressif/arduino-esp32/issues/8877#issuecomment-1807677897 - # if ESP_IDF_VERSION_MAJOR >= 5 - // FIXME TD-er: Should no longer be needed. WiFi.STA._setStatus(WL_CONNECTION_LOST); - # else // if ESP_IDF_VERSION_MAJOR >= 5 - WiFiSTAClass::_setStatus(WL_CONNECTION_LOST); - # endif // if ESP_IDF_VERSION_MAJOR >= 5 } - # else // if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.markDisconnect(static_cast(info.disconnected.reason)); - - if (info.disconnected.reason == WIFI_REASON_AUTH_EXPIRE) { - // See: https://github.com/espressif/arduino-esp32/issues/8877#issuecomment-1807677897 - WiFiSTAClass::_setStatus(WL_CONNECTION_LOST); - } - # endif // if ESP_IDF_VERSION_MAJOR > 3 WiFi.persistent(false); WiFi.disconnect(true); } @@ -174,18 +149,10 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { break; # endif // if FEATURE_USE_IPV6 case ARDUINO_EVENT_WIFI_AP_STACONNECTED: - # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markConnectedAPmode(info.wifi_ap_staconnected.mac); - # else // if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.markConnectedAPmode(info.sta_connected.mac); - # endif // if ESP_IDF_VERSION_MAJOR > 3 break; case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: - # if ESP_IDF_VERSION_MAJOR > 3 WiFiEventData.markDisconnectedAPmode(info.wifi_ap_stadisconnected.mac); - # else // if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.markDisconnectedAPmode(info.sta_disconnected.mac); - # endif // if ESP_IDF_VERSION_MAJOR > 3 break; case ARDUINO_EVENT_WIFI_SCAN_DONE: WiFiEventData.processedScanDone = false; @@ -196,11 +163,7 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { case ARDUINO_EVENT_ETH_GOT_IP: case ARDUINO_EVENT_ETH_DISCONNECTED: case ARDUINO_EVENT_ETH_STOP: - # if ESP_IDF_VERSION_MAJOR > 3 case ARDUINO_EVENT_ETH_GOT_IP6: - # else // if ESP_IDF_VERSION_MAJOR > 3 - case ARDUINO_EVENT_GOT_IP6: - # endif // if ESP_IDF_VERSION_MAJOR > 3 // Handled in EthEvent break; @@ -213,157 +176,4 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { } } -# else // if ESP_IDF_VERSION_MAJOR > 3 -void WiFiEvent(system_event_id_t event, system_event_info_t info) { - switch (event) { - case SYSTEM_EVENT_WIFI_READY: - // ESP32 WiFi ready - break; - case SYSTEM_EVENT_STA_START: - # ifndef BUILD_NO_DEBUG - - // addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); - # endif // ifndef BUILD_NO_DEBUG - break; - case SYSTEM_EVENT_STA_STOP: - # ifndef BUILD_NO_DEBUG - - // addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); - # endif // ifndef BUILD_NO_DEBUG - break; - case SYSTEM_EVENT_AP_START: - # ifndef BUILD_NO_DEBUG - - // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); - # endif // ifndef BUILD_NO_DEBUG - break; - case SYSTEM_EVENT_AP_STOP: - # ifndef BUILD_NO_DEBUG - - // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); - # endif // ifndef BUILD_NO_DEBUG - break; - case SYSTEM_EVENT_STA_LOST_IP: - // ESP32 station lost IP and the IP is reset to 0 - # if FEATURE_ETHERNET - - if (active_network_medium == NetworkMedium_t::Ethernet) { - EthEventData.markLostIP(); - } - else - # endif // if FEATURE_ETHERNET - WiFiEventData.markLostIP(); - # ifndef BUILD_NO_DEBUG - - /* - addLog(LOG_LEVEL_INFO, - active_network_medium == NetworkMedium_t::Ethernet ? - F("ETH : Event Lost IP") : F("WiFi : Event Lost IP")); - */ - # endif // ifndef BUILD_NO_DEBUG - break; - - case SYSTEM_EVENT_AP_PROBEREQRECVED: - // Receive probe request packet in soft-AP interface - // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 - # ifndef BUILD_NO_DEBUG - - // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); - # endif // ifndef BUILD_NO_DEBUG - break; - - case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: - # if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.setAuthMode(info.wifi_sta_authmode_change.new_mode); - # else // if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.setAuthMode(info.auth_change.new_mode); - # endif // if ESP_IDF_VERSION_MAJOR > 3 - break; - - case SYSTEM_EVENT_STA_CONNECTED: - { - char ssid_copy[33] = { 0 }; // Ensure space for maximum len SSID (32) plus trailing 0 - # if ESP_IDF_VERSION_MAJOR > 3 - memcpy(ssid_copy, info.wifi_sta_connected.ssid, info.wifi_sta_connected.ssid_len); - ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier - WiFiEventData.markConnected((const char *)ssid_copy, info.wifi_sta_connected.bssid, info.wifi_sta_connected.channel); - # else // if ESP_IDF_VERSION_MAJOR > 3 - memcpy(ssid_copy, info.connected.ssid, info.connected.ssid_len); - ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier - WiFiEventData.markConnected((const char *)ssid_copy, info.connected.bssid, info.connected.channel); - # endif // if ESP_IDF_VERSION_MAJOR > 3 - break; - } - case SYSTEM_EVENT_STA_DISCONNECTED: - - if (!ignoreDisconnectEvent) { - ignoreDisconnectEvent = true; - # if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.markDisconnect(static_cast(info.wifi_sta_disconnected.reason)); - # else // if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.markDisconnect(static_cast(info.disconnected.reason)); - # endif // if ESP_IDF_VERSION_MAJOR > 3 - WiFi.persistent(false); - WiFi.disconnect(true); - } - break; - case SYSTEM_EVENT_STA_GOT_IP: - ignoreDisconnectEvent = false; - WiFiEventData.markGotIP(); - break; - case SYSTEM_EVENT_AP_STACONNECTED: - # if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.markConnectedAPmode(info.wifi_ap_staconnected.mac); - # else // if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.markConnectedAPmode(info.sta_connected.mac); - # endif // if ESP_IDF_VERSION_MAJOR > 3 - break; - case SYSTEM_EVENT_AP_STADISCONNECTED: - # if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.markDisconnectedAPmode(info.wifi_ap_stadisconnected.mac); - # else // if ESP_IDF_VERSION_MAJOR > 3 - WiFiEventData.markDisconnectedAPmode(info.sta_disconnected.mac); - # endif // if ESP_IDF_VERSION_MAJOR > 3 - break; - case SYSTEM_EVENT_SCAN_DONE: - WiFiEventData.processedScanDone = false; - break; -# if FEATURE_ETHERNET - case SYSTEM_EVENT_ETH_START: - - if (ethPrepare()) { - // addLog(LOG_LEVEL_INFO, F("ETH event: Started")); - } else { - // addLog(LOG_LEVEL_ERROR, F("ETH event: Could not prepare ETH!")); - } - break; - case SYSTEM_EVENT_ETH_CONNECTED: - // addLog(LOG_LEVEL_INFO, F("ETH event: Connected")); - EthEventData.markConnected(); - break; - case SYSTEM_EVENT_ETH_GOT_IP: - EthEventData.markGotIP(); - - // addLog(LOG_LEVEL_INFO, F("ETH event: Got IP")); - break; - case SYSTEM_EVENT_ETH_DISCONNECTED: - // addLog(LOG_LEVEL_ERROR, F("ETH event: Disconnected")); - EthEventData.markDisconnect(); - break; - case SYSTEM_EVENT_ETH_STOP: - // addLog(LOG_LEVEL_INFO, F("ETH event: Stopped")); - break; - case SYSTEM_EVENT_GOT_IP6: - // addLog(LOG_LEVEL_INFO, F("ETH event: Got IP6")); - break; -# endif // FEATURE_ETHERNET - default: - { - // addLogMove(LOG_LEVEL_ERROR, concat(F("UNKNOWN WIFI/ETH EVENT: "), event)); - break; - } - } -} - -# endif // if ESP_IDF_VERSION_MAJOR > 3 #endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h index 9f7d6b904..90b15c39f 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h @@ -15,6 +15,9 @@ #include #include #include +#include + + class WiFi_Access_Static_IP : public WiFiSTAClass { public: @@ -28,12 +31,7 @@ void setUseStaticIP(bool enabled); // Functions called on events. // Make sure not to call anything in these functions that result in delay() or yield() // ******************************************************************************** - #if ESP_IDF_VERSION_MAJOR > 3 - #include - void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info); - #else - void WiFiEvent(system_event_id_t event, system_event_info_t info); - #endif +void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info); #endif diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 81340c09e..8a86e2544 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -91,7 +91,7 @@ void run_compiletime_checks() { check_size(); #endif // if FEATURE_NOTIFIER check_size(); - #if ESP_IDF_VERSION_MAJOR > 3 + #ifdef ESP32 // ESP_IDF_VERSION_MAJOR > 3 // String class has increased with 4 bytes check_size(); // Is not stored #else @@ -101,7 +101,7 @@ void run_compiletime_checks() { // LogStruct is mainly dependent on the number of lines. // Has to be round up to multiple of 4. - #if ESP_IDF_VERSION_MAJOR > 3 + #ifdef ESP32 // ESP_IDF_VERSION_MAJOR > 3 // String class has increased with 4 bytes const unsigned int LogStructSize = ((13u + 24 * LOG_STRUCT_MESSAGE_LINES) + 3) & ~3; #else diff --git a/src/src/Helpers/StringGenerator_System.cpp b/src/src/Helpers/StringGenerator_System.cpp index df5d9a368..ff7ffd40c 100644 --- a/src/src/Helpers/StringGenerator_System.cpp +++ b/src/src/Helpers/StringGenerator_System.cpp @@ -22,11 +22,7 @@ #elif defined(ESP32C6) #include # elif defined(ESP32_CLASSIC) - #if ESP_IDF_VERSION_MAJOR > 3 - #include - #else - #include - #endif + #include # else static_assert(false, "Implement processor architecture"); diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 7542abce7..f79ea8f4c 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -251,7 +251,6 @@ void handle_hardware() { # if CONFIG_ETH_USE_ESP32_EMAC toString(EthPhyType_t::LAN8720), toString(EthPhyType_t::TLK110), -#if ESP_IDF_VERSION_MAJOR > 3 toString(EthPhyType_t::RTL8201), #if ETH_TYPE_JL1101_SUPPORTED toString(EthPhyType_t::JL1101), @@ -259,7 +258,6 @@ void handle_hardware() { toString(EthPhyType_t::DP83848), toString(EthPhyType_t::KSZ8041), toString(EthPhyType_t::KSZ8081), -#endif # endif // if CONFIG_ETH_USE_ESP32_EMAC #if ESP_IDF_VERSION_MAJOR >= 5 @@ -280,7 +278,6 @@ void handle_hardware() { # if CONFIG_ETH_USE_ESP32_EMAC static_cast(EthPhyType_t::LAN8720), static_cast(EthPhyType_t::TLK110), -#if ESP_IDF_VERSION_MAJOR > 3 static_cast(EthPhyType_t::RTL8201), #if ETH_TYPE_JL1101_SUPPORTED static_cast(EthPhyType_t::JL1101), @@ -288,7 +285,6 @@ void handle_hardware() { static_cast(EthPhyType_t::DP83848), static_cast(EthPhyType_t::KSZ8041), static_cast(EthPhyType_t::KSZ8081), -#endif # endif // if CONFIG_ETH_USE_ESP32_EMAC #if ESP_IDF_VERSION_MAJOR >= 5 From 07a6c55354fccacd0eab8b51da64dd42d75d7b04 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 26 Oct 2024 21:08:46 +0200 Subject: [PATCH 003/564] [Cleanup] Fix spelling error in filename --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 +- .../{ESPEasyWifi_abstrated.h => ESPEasyWifi_abstracted.h} | 0 src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp | 2 +- src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/src/ESPEasyCore/{ESPEasyWifi_abstrated.h => ESPEasyWifi_abstracted.h} (100%) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 2245649dd..9410b0d28 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -25,7 +25,7 @@ -#include "../ESPEasyCore/ESPEasyWifi_abstrated.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstrated.h b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h similarity index 100% rename from src/src/ESPEasyCore/ESPEasyWifi_abstrated.h rename to src/src/ESPEasyCore/ESPEasyWifi_abstracted.h diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index a7d463427..01137da4c 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -1,4 +1,4 @@ -#include "../ESPEasyCore/ESPEasyWifi_abstrated.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp index 26b19eebd..f09f4216e 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp @@ -1,4 +1,4 @@ -#include "../ESPEasyCore/ESPEasyWifi_abstrated.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #ifdef ESP8266 From e5100b180d2c8ce511b2e78e7646ebfbe6eaa296 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 2 Nov 2024 13:59:21 +0100 Subject: [PATCH 004/564] [WiFi] First part of moving code around to restructure WiFi code --- src/src/Commands/InternalCommands.cpp | 10 +- src/src/Commands/InternalCommands_decoder.cpp | 18 + src/src/Commands/InternalCommands_decoder.h | 7 +- src/src/Commands/WiFi.cpp | 17 +- src/src/Commands/WiFi.h | 4 + src/src/CustomBuild/define_plugin_sets.h | 10 + src/src/DataStructs/WiFiEventData.h | 39 +- src/src/DataTypes/WiFiConnectionProtocol.h | 34 +- src/src/DataTypes/WiFi_STA_connected_state.h | 26 ++ src/src/DataTypes/WiFi_State.h | 92 +++++ src/src/ESPEasyCore/ESPEasyNetwork.cpp | 3 +- .../ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp | 43 +-- src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h | 22 +- .../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp | 103 +++-- .../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h | 26 +- .../ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 288 ++++++++++++++ .../ESPEasyCore/ESPEasyWiFi_state_machine.h | 128 +++++++ .../ESPEasyWiFi_state_machine_ESP32.cpp | 61 +++ .../ESPEasyWiFi_state_machine_ESP8266.cpp | 42 ++ src/src/ESPEasyCore/ESPEasyWifi.cpp | 362 ++---------------- src/src/ESPEasyCore/ESPEasyWifi.h | 170 +++----- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 188 +++++---- .../ESPEasyCore/ESPEasyWifi_abstracted.cpp | 151 ++++++++ src/src/ESPEasyCore/ESPEasyWifi_abstracted.h | 87 ++++- .../ESPEasyWifi_abstracted_ESP32.cpp | 289 +++++++++++--- .../ESPEasyWifi_abstracted_ESP8266.cpp | 290 +++++++++++--- src/src/ESPEasyCore/ESPEasy_setup.cpp | 7 +- src/src/Helpers/Network.cpp | 3 +- src/src/Helpers/PeriodicalActions.cpp | 3 +- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 5 +- src/src/WebServer/AccessControl.cpp | 5 +- src/src/WebServer/ESPEasy_WebServer.cpp | 3 +- src/src/WebServer/SetupPage.cpp | 3 +- src/src/WebServer/WiFiScanner.cpp | 5 +- uncrustify.cfg | 56 +-- 35 files changed, 1777 insertions(+), 823 deletions(-) create mode 100644 src/src/DataTypes/WiFi_STA_connected_state.h create mode 100644 src/src/DataTypes/WiFi_State.h create mode 100644 src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp create mode 100644 src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h create mode 100644 src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp create mode 100644 src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp create mode 100644 src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index a1ae0fa89..737b5e179 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -43,7 +43,9 @@ #include "../Commands/Timer.h" #include "../Commands/UPD.h" #include "../Commands/wd.h" +#if FEATURE_WIFI #include "../Commands/WiFi.h" +#endif #include "../DataStructs/TimingStats.h" @@ -302,14 +304,18 @@ bool InternalCommands::executeInternalCommand() case ESPEasy_cmd_e::ethdisconnect: COMMAND_CASE_A(Command_ETH_Disconnect, 0); // Network Command case ESPEasy_cmd_e::ethwifimode: COMMAND_CASE_R(Command_ETH_Wifi_Mode, 1); // Network Command #endif // FEATURE_ETHERNET +#if FEATURE_WIFI case ESPEasy_cmd_e::erasesdkwifi: COMMAND_CASE_R(Command_WiFi_Erase, 0); // WiFi.h +#endif case ESPEasy_cmd_e::event: COMMAND_CASE_A(Command_Rules_Events, -1); // Rule.h case ESPEasy_cmd_e::executerules: COMMAND_CASE_A(Command_Rules_Execute, -1); // Rule.h case ESPEasy_cmd_e::factoryreset: COMMAND_CASE_R(Command_Settings_FactoryReset, 0); // Settings.h case ESPEasy_cmd_e::gateway: COMMAND_CASE_R(Command_Gateway, 1); // Network Command case ESPEasy_cmd_e::gpio: COMMAND_CASE_A(Command_GPIO, 2); // Gpio.h case ESPEasy_cmd_e::gpiotoggle: COMMAND_CASE_A(Command_GPIO_Toggle, 1); // Gpio.h +#if FEATURE_WIFI case ESPEasy_cmd_e::hiddenssid: COMMAND_CASE_R(Command_Wifi_HiddenSSID, 1); // wifi.h +#endif case ESPEasy_cmd_e::i2cscanner: COMMAND_CASE_R(Command_i2c_Scanner, -1); // i2c.h case ESPEasy_cmd_e::inc: COMMAND_CASE_A(Command_Rules_Inc, -1); // Rules.h case ESPEasy_cmd_e::ip: COMMAND_CASE_R(Command_IP, 1); // Network Command @@ -461,7 +467,7 @@ bool InternalCommands::executeInternalCommand() case ESPEasy_cmd_e::wdconfig: COMMAND_CASE_R(Command_WD_Config, 3); // WD.h case ESPEasy_cmd_e::wdread: COMMAND_CASE_R(Command_WD_Read, 2); // WD.h #endif // ifndef LIMIT_BUILD_SIZE - +#if FEATURE_WIFI case ESPEasy_cmd_e::wifiallowap: COMMAND_CASE_R(Command_Wifi_AllowAP, 0); // WiFi.h case ESPEasy_cmd_e::wifiapmode: COMMAND_CASE_R(Command_Wifi_APMode, 0); // WiFi.h case ESPEasy_cmd_e::wificonnect: COMMAND_CASE_A(Command_Wifi_Connect, 0); // WiFi.h @@ -473,7 +479,7 @@ bool InternalCommands::executeInternalCommand() case ESPEasy_cmd_e::wifissid: COMMAND_CASE_R(Command_Wifi_SSID, 1); // WiFi.h case ESPEasy_cmd_e::wifissid2: COMMAND_CASE_R(Command_Wifi_SSID2, 1); // WiFi.h case ESPEasy_cmd_e::wifistamode: COMMAND_CASE_R(Command_Wifi_STAMode, 0); // WiFi.h - +#endif case ESPEasy_cmd_e::NotMatched: return false; diff --git a/src/src/Commands/InternalCommands_decoder.cpp b/src/src/Commands/InternalCommands_decoder.cpp index 5bbb37c0e..3d95147a7 100644 --- a/src/src/Commands/InternalCommands_decoder.cpp +++ b/src/src/Commands/InternalCommands_decoder.cpp @@ -57,9 +57,15 @@ const char Internal_commands_d[] PROGMEM = "dst|" ; +#if FEATURE_WIFI #define Int_cmd_e_offset ESPEasy_cmd_e::erasesdkwifi +#else +#define Int_cmd_e_offset ESPEasy_cmd_e::event +#endif const char Internal_commands_e[] PROGMEM = +#if FEATURE_WIFI "erasesdkwifi|" +#endif "event|" "executerules|" #if FEATURE_ETHERNET @@ -84,7 +90,9 @@ const char Internal_commands_fghij[] PROGMEM = "gateway|" "gpio|" "gpiotoggle|" +#if FEATURE_WIFI "hiddenssid|" +#endif "i2cscanner|" "inc|" "ip|" @@ -259,8 +267,14 @@ const char Internal_commands_u[] PROGMEM = "usentp|" ; +#if FEATURE_WIFI || !defined(LIMIT_BUILD_SIZE) +#if FEATURE_WIFI #define Int_cmd_w_offset ESPEasy_cmd_e::wifiallowap +#else +#define Int_cmd_w_offset ESPEasy_cmd_e::wdconfig +#endif const char Internal_commands_w[] PROGMEM = +#if FEATURE_WIFI "wifiallowap|" "wifiapmode|" "wificonnect|" @@ -272,11 +286,13 @@ const char Internal_commands_w[] PROGMEM = "wifissid|" "wifissid2|" "wifistamode|" +#endif #ifndef LIMIT_BUILD_SIZE "wdconfig|" "wdread|" #endif // ifndef LIMIT_BUILD_SIZE ; +#endif const char* getInternalCommand_Haystack_Offset(const char firstLetter, int& offset) { @@ -345,10 +361,12 @@ const char* getInternalCommand_Haystack_Offset(const char firstLetter, int& offs offset = static_cast(Int_cmd_u_offset); haystack = Internal_commands_u; break; +#if FEATURE_WIFI || !defined(LIMIT_BUILD_SIZE) case 'w': offset = static_cast(Int_cmd_w_offset); haystack = Internal_commands_w; break; +#endif default: return nullptr; diff --git a/src/src/Commands/InternalCommands_decoder.h b/src/src/Commands/InternalCommands_decoder.h index 1887cc01e..6fa6bf4cf 100644 --- a/src/src/Commands/InternalCommands_decoder.h +++ b/src/src/Commands/InternalCommands_decoder.h @@ -40,8 +40,9 @@ enum class ESPEasy_cmd_e : uint8_t { #endif // #if FEATURE_PLUGIN_PRIORITY dns, dst, - +#if FEATURE_WIFI erasesdkwifi, +#endif event, executerules, #if FEATURE_ETHERNET @@ -64,7 +65,9 @@ enum class ESPEasy_cmd_e : uint8_t { gateway, gpio, gpiotoggle, +#if FEATURE_WIFI hiddenssid, +#endif i2cscanner, inc, @@ -216,6 +219,7 @@ enum class ESPEasy_cmd_e : uint8_t { unmonitorrange, usentp, +#if FEATURE_WIFI wifiallowap, wifiapmode, wificonnect, @@ -227,6 +231,7 @@ enum class ESPEasy_cmd_e : uint8_t { wifissid, wifissid2, wifistamode, +#endif #ifndef LIMIT_BUILD_SIZE wdconfig, wdread, diff --git a/src/src/Commands/WiFi.cpp b/src/src/Commands/WiFi.cpp index 6f355ac15..2c702854d 100644 --- a/src/src/Commands/WiFi.cpp +++ b/src/src/Commands/WiFi.cpp @@ -2,11 +2,14 @@ #include "../../ESPEasy_common.h" +#if FEATURE_WIFI + #include "../Commands/Common.h" #include "../DataStructs/ESPEasy_EventStruct.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../ESPEasyCore/Serial.h" #include "../Globals/ESPEasyWiFiEvent.h" @@ -96,13 +99,13 @@ const __FlashStringHelper* Command_Wifi_Disconnect(struct EventStruct *event, co const __FlashStringHelper* Command_Wifi_APMode(struct EventStruct *event, const char *Line) { - setAP(true); + ESPEasy::net::wifi::setAP(true); return return_command_success_flashstr(); } const __FlashStringHelper* Command_Wifi_STAMode(struct EventStruct *event, const char *Line) { - setSTA(true); + ESPEasy::net::wifi::setSTA(true); return return_command_success_flashstr(); } @@ -125,12 +128,12 @@ String Command_Wifi_Mode(struct EventStruct *event, const char *Line) } if ((mode >= WIFI_OFF) && (mode < WIFI_MODE_MAX)) { - setWifiMode(mode); + ESPEasy::net::wifi::setWifiMode(mode); } else { return return_result(event, F("Wifi Mode: invalid arguments")); } } else { - return return_result(event, concat(F("WiFi Mode:"), getWifiModeString(WiFi.getMode()))); + return return_result(event, concat(F("WiFi Mode:"), ESPEasy::net::wifi::getWifiModeString(WiFi.getMode()))); } return return_command_success(); } @@ -147,7 +150,7 @@ const __FlashStringHelper* Command_WiFi_Erase(struct EventStruct *event, const c { #ifdef ESP8266 WifiDisconnect(); - setWifiMode(WIFI_OFF); + ESPEasy::net::wifi::setWifiMode(WIFI_OFF); if (!ESP.eraseConfig()) return return_command_failed_flashstr(); addLog(LOG_LEVEL_INFO, F("WiFi : Erased WiFi calibration data")); @@ -155,7 +158,7 @@ const __FlashStringHelper* Command_WiFi_Erase(struct EventStruct *event, const c #ifdef ESP32 WifiDisconnect(); - setWifiMode(WIFI_OFF); + ESPEasy::net::wifi::setWifiMode(WIFI_OFF); delay(100); esp_phy_erase_cal_data_in_nvs(); addLog(LOG_LEVEL_INFO, F("WiFi : Erased WiFi calibration data")); @@ -166,3 +169,5 @@ const __FlashStringHelper* Command_WiFi_Erase(struct EventStruct *event, const c #endif return return_command_success_flashstr(); } + +#endif \ No newline at end of file diff --git a/src/src/Commands/WiFi.h b/src/src/Commands/WiFi.h index ba81aff0e..e1b0ebc4c 100644 --- a/src/src/Commands/WiFi.h +++ b/src/src/Commands/WiFi.h @@ -1,6 +1,9 @@ #ifndef COMMAND_WIFI_H #define COMMAND_WIFI_H +#include "../../ESPEasy_common.h" + +#if FEATURE_WIFI #include String Command_Wifi_SSID(struct EventStruct *event, @@ -33,4 +36,5 @@ const __FlashStringHelper* Command_Wifi_AllowAP(struct EventStruct *event, const __FlashStringHelper* Command_WiFi_Erase(struct EventStruct *event, const char *Line); +#endif #endif // COMMAND_WIFI_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index bda798b33..bfda3f398 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -3121,6 +3121,16 @@ To create/register a plugin, you have to : #define FEATURE_ETHERNET 0 #endif +#ifndef FEATURE_WIFI +#ifdef ESP8266 +#define FEATURE_WIFI 1 +#elif SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED +#define FEATURE_WIFI 1 +#else +#define FEATURE_WIFI 0 +#endif +#endif + #ifndef FEATURE_EXT_RTC #define FEATURE_EXT_RTC 0 #endif diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index 1dbd20fdb..76a3e5ff6 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -59,27 +59,25 @@ struct WiFiEventData_t { return bitRead(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); } - void setWiFiDisconnected(); - void setWiFiGotIP(); - void setWiFiConnected(); - void setWiFiServicesInitialized(); + void setWiFiDisconnected(); + void setWiFiGotIP(); + void setWiFiConnected(); + void setWiFiServicesInitialized(); - void markGotIP(); + void markGotIP(); #if FEATURE_USE_IPV6 - void markGotIPv6(const IPAddress& ip6); + void markGotIPv6(const IPAddress& ip6); #endif - void markLostIP(); - void markDisconnect(WiFiDisconnectReason reason); - void markConnected(const String& ssid, - const uint8_t bssid[6], - uint8_t channel); - void markConnectedAPmode(const uint8_t mac[6]); - void markDisconnectedAPmode(const uint8_t mac[6]); + void markLostIP(); + void markDisconnect(WiFiDisconnectReason reason); + void markConnected(const String& ssid, + const uint8_t bssid[6], + uint8_t channel); + void markConnectedAPmode(const uint8_t mac[6]); + void markDisconnectedAPmode(const uint8_t mac[6]); - void setAuthMode(uint8_t newMode) { - auth_mode = newMode; - } + void setAuthMode(uint8_t newMode) { auth_mode = newMode; } String ESPeasyWifiStatusToString() const; @@ -135,11 +133,11 @@ struct WiFiEventData_t { // Semaphore like bools for processing data gathered from WiFi events. - bool processedConnect = true; - bool processedDisconnect = true; - bool processedGotIP = true; + bool processedConnect = true; + bool processedDisconnect = true; + bool processedGotIP = true; #if FEATURE_USE_IPV6 - bool processedGotIP6 = true; + bool processedGotIP6 = true; #endif bool processedDHCPTimeout = true; bool processedConnectAPmode = true; @@ -158,6 +156,7 @@ struct WiFiEventData_t { #ifdef ESP32 WiFiEventId_t wm_event_id = 0; #endif // ifdef ESP32 + }; #endif // ifndef DATASTRUCTS_WIFIEVENTDATA_H diff --git a/src/src/DataTypes/WiFiConnectionProtocol.h b/src/src/DataTypes/WiFiConnectionProtocol.h index a605bf3ec..54f55bf70 100644 --- a/src/src/DataTypes/WiFiConnectionProtocol.h +++ b/src/src/DataTypes/WiFiConnectionProtocol.h @@ -4,26 +4,28 @@ #include "../../ESPEasy_common.h" enum class WiFiConnectionProtocol { - Unknown, - WiFi_Protocol_11b, - WiFi_Protocol_11g, + Unknown, + WiFi_Protocol_11b, + WiFi_Protocol_11g, #ifdef ESP8266 - WiFi_Protocol_11n + WiFi_Protocol_11n #endif #ifdef ESP32 - WiFi_Protocol_HT20, - WiFi_Protocol_HT40, - WiFi_Protocol_HE20, // WiFi 6 -#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) - WiFi_Protocol_11a, // traditional (old) 5 GHz - WiFi_Protocol_VHT20, // 5 GHz WiFi 5, 802.11ac -#endif - WiFi_Protocol_LR -#endif + WiFi_Protocol_HT20, + WiFi_Protocol_HT40, + WiFi_Protocol_HE20, // WiFi 6 +# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, \ + 2, \ + 0) + WiFi_Protocol_11a, // traditional (old) 5 GHz + WiFi_Protocol_VHT20, // 5 GHz WiFi 5, 802.11ac +# endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) + WiFi_Protocol_LR +#endif // ifdef ESP32 + }; -const __FlashStringHelper * toString(WiFiConnectionProtocol proto); +const __FlashStringHelper* toString(WiFiConnectionProtocol proto); - -#endif \ No newline at end of file +#endif // ifndef DATATYPES_WIFICONNECTIONPROTOCOL_H diff --git a/src/src/DataTypes/WiFi_STA_connected_state.h b/src/src/DataTypes/WiFi_STA_connected_state.h new file mode 100644 index 000000000..5f41e6648 --- /dev/null +++ b/src/src/DataTypes/WiFi_STA_connected_state.h @@ -0,0 +1,26 @@ +#pragma once + +#include "../../ESPEasy_common.h" + +#if FEATURE_WIFI + +namespace ESPEasy { +namespace net { +namespace wifi { + + +enum class STA_connected_state { + Idle, + Connecting, + Connected, + Error_Not_Found, + Error_Connect_Failed + +}; + + +} // namespace wifi +} // namespace net +} // namespace ESPEasy + +#endif // if FEATURE_WIFI diff --git a/src/src/DataTypes/WiFi_State.h b/src/src/DataTypes/WiFi_State.h new file mode 100644 index 000000000..62d5ff9cf --- /dev/null +++ b/src/src/DataTypes/WiFi_State.h @@ -0,0 +1,92 @@ +#pragma once + +#include "../../ESPEasy_common.h" + +#if FEATURE_WIFI + + +namespace ESPEasy { +namespace net { +namespace wifi { + + +/* + + State machine: + + Start at boot: Disabled + + Disabled: + When AP or STA is needed -> OFF + + + OFF: + When STA is needed -> IdleWaiting + + + IdleWaiting: + After waiting period: + If candidate present -> start STA_Connecting + Else if AP enabled (and client connected to AP) -> Start STA_AP_Scanning + Else -> start STA_Scanning + + STA_Scanning: + When finished: + If known candidate present -> IdleWaiting + else if no known candidate present -> start AP_only -> IdleWaiting + + STA_Connecting: + When failed -> STA_Reconnecting + Else -> STA_Connected + + STA_Reconnecting: + When failed -> IdleWaiting + Else -> STA_Connected + + + STA_Connected: + If disconnected -> OFF + If connected for X minutes -> mark as stable + + + */ + + +enum class WiFiState_e +{ + // WiFi radio is off and no new attempt should be made (e.g. low power mode or Ethernet active) + Disabled, + + // WiFi radio off, to continue, everything needs to be (re)initialized + OFF, + + // Only running in AP mode + AP_only, + + // WiFi was in some kind of error state or needs waiting period + IdleWaiting, + + // STA mode + scanning + STA_Scanning, + + // STA+AP mode + scanning, + // needs some careful handling to prevent disconnecting the connected stations + STA_AP_Scanning, + + // Connecting to an AP + STA_Connecting, + + // Reconnecting to an AP + // May need to handle some specific disconnect reasons differently from connecting for the first time. + STA_Reconnecting, + + // Connected to an AP + STA_Connected + +}; + + +} // namespace wifi +} // namespace net +} // namespace ESPEasy +#endif // if FEATURE_WIFI diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 548c21280..a5bad8336 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -3,6 +3,7 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyEth.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../Globals/ESPEasy_time.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/NetworkState.h" @@ -175,7 +176,7 @@ esp_netif_t * getActiveNetworkMediumInterface() { } else #endif { - if (WifiIsSTA(WiFi.getMode())) { + if ( ESPEasy::net::wifi::WifiIsSTA(WiFi.getMode())) { iface = ESP_IF_WIFI_STA; } } diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp index edc9dc376..06d70ae52 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp @@ -27,9 +27,7 @@ # include "../Globals/ESPEasyEthEvent.h" # endif // if FEATURE_ETHERNET - -void setUseStaticIP(bool enabled) { -} +void setUseStaticIP(bool enabled) {} // ******************************************************************************** // Functions called on events. @@ -40,37 +38,38 @@ void setUseStaticIP(bool enabled) { static bool ignoreDisconnectEvent = false; void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { - switch (event) { + switch (event) + { case ARDUINO_EVENT_WIFI_READY: // ESP32 WiFi ready break; case ARDUINO_EVENT_WIFI_STA_START: - # ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG // addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); - # endif // ifndef BUILD_NO_DEBUG + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_STA_STOP: - # ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG // addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); - # endif // ifndef BUILD_NO_DEBUG + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_AP_START: - # ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); - # endif // ifndef BUILD_NO_DEBUG + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_AP_STOP: - # ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); - # endif // ifndef BUILD_NO_DEBUG + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0 - # if FEATURE_ETHERNET + # if FEATURE_ETHERNET if (active_network_medium == NetworkMedium_t::Ethernet) { // DNS records are shared among WiFi and Ethernet (very bad design!) @@ -78,9 +77,9 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { // As soon as WiFi is turned off, the DNS entry for Ethernet is cleared. EthEventData.markLostIP(); } - # endif // if FEATURE_ETHERNET + # endif // if FEATURE_ETHERNET WiFiEventData.markLostIP(); - # ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG // addLog(LOG_LEVEL_INFO, @@ -90,16 +89,16 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { */ // F("WiFi : Event Lost IP")); - # endif // ifndef BUILD_NO_DEBUG + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: // Receive probe request packet in soft-AP interface // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 - # ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG // addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); - # endif // ifndef BUILD_NO_DEBUG + # endif // ifndef BUILD_NO_DEBUG break; case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: @@ -136,7 +135,7 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { ignoreDisconnectEvent = false; WiFiEventData.markGotIP(); break; - # if FEATURE_USE_IPV6 + # if FEATURE_USE_IPV6 case ARDUINO_EVENT_WIFI_STA_GOT_IP6: { ip_event_got_ip6_t *event = static_cast(&info.got_ip6); @@ -147,7 +146,7 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { case ARDUINO_EVENT_WIFI_AP_GOT_IP6: addLog(LOG_LEVEL_INFO, F("WIFI : AP got IP6")); break; - # endif // if FEATURE_USE_IPV6 + # endif // if FEATURE_USE_IPV6 case ARDUINO_EVENT_WIFI_AP_STACONNECTED: WiFiEventData.markConnectedAPmode(info.wifi_ap_staconnected.mac); break; @@ -157,7 +156,7 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { case ARDUINO_EVENT_WIFI_SCAN_DONE: WiFiEventData.processedScanDone = false; break; -# if FEATURE_ETHERNET +# if FEATURE_ETHERNET case ARDUINO_EVENT_ETH_START: case ARDUINO_EVENT_ETH_CONNECTED: case ARDUINO_EVENT_ETH_GOT_IP: @@ -167,7 +166,7 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { // Handled in EthEvent break; -# endif // FEATURE_ETHERNET +# endif // FEATURE_ETHERNET default: { // addLogMove(LOG_LEVEL_ERROR, concat(F("UNKNOWN WIFI/ETH EVENT: "), event)); diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h index 90b15c39f..6f7e8df81 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.h @@ -3,22 +3,23 @@ #ifdef ESP32 -#include "../../ESPEasy_common.h" +# include "../../ESPEasy_common.h" -#include +# include // ******************************************************************************** // Work-around for setting _useStaticIP // See reported issue: https://github.com/esp8266/Arduino/issues/4114 // ******************************************************************************** -#include -#include -#include -#include +# include +# include +# include +# include -class WiFi_Access_Static_IP : public WiFiSTAClass { +class WiFi_Access_Static_IP : public WiFiSTAClass +{ public: void set_use_static_ip(bool enabled); @@ -31,8 +32,9 @@ void setUseStaticIP(bool enabled); // Functions called on events. // Make sure not to call anything in these functions that result in delay() or yield() // ******************************************************************************** -void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info); +void WiFiEvent(WiFiEvent_t event, + arduino_event_info_t info); -#endif +#endif // ifdef ESP32 -#endif \ No newline at end of file +#endif // ifndef ESPEASY_WIFI_EVENT_ESP32_H diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp index b96282116..b127bc194 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp @@ -1,48 +1,42 @@ #include "../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h" -#ifdef ESP8266 +#if FEATURE_WIFI +# ifdef ESP8266 -#include "../DataStructs/RTCStruct.h" +# include "../DataStructs/RTCStruct.h" -#include "../DataTypes/ESPEasyTimeSource.h" +# include "../DataTypes/ESPEasyTimeSource.h" -#include "../ESPEasyCore/ESPEasyEth.h" -#include "../ESPEasyCore/ESPEasy_Log.h" -#include "../ESPEasyCore/ESPEasyNetwork.h" -#include "../ESPEasyCore/ESPEasyWifi.h" -#include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" +# include "../ESPEasyCore/ESPEasyEth.h" +# include "../ESPEasyCore/ESPEasy_Log.h" +# include "../ESPEasyCore/ESPEasyNetwork.h" +# include "../ESPEasyCore/ESPEasyWifi.h" +# include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" -#include "../Globals/ESPEasyWiFiEvent.h" -#include "../Globals/NetworkState.h" -#include "../Globals/RTC.h" -#include "../Globals/WiFi_AP_Candidates.h" +# include "../Globals/ESPEasyWiFiEvent.h" +# include "../Globals/NetworkState.h" +# include "../Globals/RTC.h" +# include "../Globals/WiFi_AP_Candidates.h" -#include "../Helpers/ESPEasy_time_calc.h" +# include "../Helpers/ESPEasy_time_calc.h" +void WiFi_Access_Static_IP::set_use_static_ip(bool enabled) { _useStaticIp = enabled; } -void WiFi_Access_Static_IP::set_use_static_ip(bool enabled) { - _useStaticIp = enabled; -} void setUseStaticIP(bool enabled) { WiFi_Access_Static_IP tmp_wifi; tmp_wifi.set_use_static_ip(enabled); } - - - - // ******************************************************************************** // Functions called on events. // Make sure not to call anything in these functions that result in delay() or yield() // ******************************************************************************** -void onConnected(const WiFiEventStationModeConnected& event) { - WiFiEventData.markConnected(event.ssid, event.bssid, event.channel); -} +void onConnected(const WiFiEventStationModeConnected& event) { WiFiEventData.markConnected(event.ssid, event.bssid, event.channel); } void onDisconnect(const WiFiEventStationModeDisconnected& event) { WiFiEventData.markDisconnect(event.reason); + if (WiFi.status() == WL_CONNECTED) { // See https://github.com/esp8266/Arduino/issues/5912 WiFi.persistent(false); @@ -51,65 +45,62 @@ void onDisconnect(const WiFiEventStationModeDisconnected& event) { } } -void onGotIP(const WiFiEventStationModeGotIP& event) { - WiFiEventData.markGotIP(); -} +void onGotIP(const WiFiEventStationModeGotIP& event) { WiFiEventData.markGotIP(); } -void onDHCPTimeout() { - WiFiEventData.processedDHCPTimeout = false; -} +void onDHCPTimeout() { WiFiEventData.processedDHCPTimeout = false; } -void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) { - WiFiEventData.markConnectedAPmode(event.mac); -} +void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) { WiFiEventData.markConnectedAPmode(event.mac); } -void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { - WiFiEventData.markDisconnectedAPmode(event.mac); -} +void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { WiFiEventData.markDisconnectedAPmode(event.mac); } -void onStationModeAuthModeChanged(const WiFiEventStationModeAuthModeChanged& event) { - WiFiEventData.setAuthMode(event.newMode); -} +void onStationModeAuthModeChanged(const WiFiEventStationModeAuthModeChanged& event) { WiFiEventData.setAuthMode(event.newMode); } + +# if FEATURE_ESP8266_DIRECT_WIFI_SCAN -#if FEATURE_ESP8266_DIRECT_WIFI_SCAN void onWiFiScanDone(void *arg, STATUS status) { if (status == OK) { - auto *head = reinterpret_cast(arg); - int scanCount = 0; + auto *head = reinterpret_cast(arg); + int scanCount = 0; + for (bss_info *it = head; it != nullptr; it = STAILQ_NEXT(it, next)) { WiFi_AP_Candidates.process_WiFiscan(*it); ++scanCount; } WiFi_AP_Candidates.after_process_WiFiscan(); WiFiEventData.lastGetScanMoment.setNow(); -// WiFiEventData.processedScanDone = true; -# ifndef BUILD_NO_DEBUG -/* - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, concat(F("WiFi : Scan finished (ESP8266), found: "), scanCount)); - } -*/ -#endif + + // WiFiEventData.processedScanDone = true; +# ifndef BUILD_NO_DEBUG + + /* + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("WiFi : Scan finished (ESP8266), found: "), scanCount)); + } + */ +# endif // ifndef BUILD_NO_DEBUG WiFi_AP_Candidates.load_knownCredentials(); + if (WiFi_AP_Candidates.addedKnownCandidate() || !NetworkConnected()) { WiFiEventData.wifiConnectAttemptNeeded = true; - # ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG + if (WiFi_AP_Candidates.addedKnownCandidate()) { - //addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); + // addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); } - #endif + # endif // ifndef BUILD_NO_DEBUG NetworkConnectRelaxed(); } } WiFiMode_t mode = WiFi.getMode(); - setWifiMode(WIFI_OFF); + ESPEasy::net::wifi::setWifiMode(WIFI_OFF); delay(1); - setWifiMode(mode); + ESPEasy::net::wifi::setWifiMode(mode); delay(1); } -#endif +# endif // if FEATURE_ESP8266_DIRECT_WIFI_SCAN -#endif +# endif // ifdef ESP8266 +#endif // if FEATURE_WIFI diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h index aed20ebb8..d0ff23a37 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h @@ -4,9 +4,11 @@ #ifdef ESP8266 -#include "../../ESPEasy_common.h" +# include "../../ESPEasy_common.h" -#include +# if FEATURE_WIFI + +# include // ******************************************************************************** @@ -14,9 +16,11 @@ // See reported issue: https://github.com/esp8266/Arduino/issues/4114 // ******************************************************************************** -#include -#include -class WiFi_Access_Static_IP : public ESP8266WiFiSTAClass { +# include +# include + +class WiFi_Access_Static_IP : public ESP8266WiFiSTAClass +{ public: void set_use_static_ip(bool enabled); @@ -43,10 +47,12 @@ void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event); void onStationModeAuthModeChanged(const WiFiEventStationModeAuthModeChanged& event); -#if FEATURE_ESP8266_DIRECT_WIFI_SCAN -void onWiFiScanDone(void *arg, STATUS status); -#endif +# if FEATURE_ESP8266_DIRECT_WIFI_SCAN +void onWiFiScanDone(void *arg, + STATUS status); +# endif // if FEATURE_ESP8266_DIRECT_WIFI_SCAN -#endif +# endif // if FEATURE_WIFI -#endif \ No newline at end of file +#endif // ifdef ESP8266 +#endif // ifndef ESPEASY_WIFI_EVENT_ESP8266_H diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp new file mode 100644 index 000000000..5cec46c7b --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -0,0 +1,288 @@ +#include "../ESPEasyCore/ESPEasyWiFi_state_machine.h" + +#if FEATURE_WIFI + +# include "../ESPEasyCore/ESPEasyWifi.h" +# include "../ESPEasyCore/ESPEasyWifi_abstracted.h" + + +#include "../ESPEasyCore/ESPEasyNetwork.h" // for setNetworkMedium, however this should not be part of the WiFi code + + +# include "../Globals/ESPEasyWiFiEvent.h" +# include "../Globals/RTC.h" +# include "../Globals/Settings.h" +# include "../Globals/WiFi_AP_Candidates.h" + +# include "../Helpers/StringConverter.h" + +namespace ESPEasy { +namespace net { +namespace wifi { + + # define WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT 20000 + # define WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT 20000 + # define WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT 10000 + +void ESPEasyWiFi_t::setup() { + // TODO TD-er: Must maybe also call 'disable()' first? + + // TODO TD-er: Load settings + + // TODO TD-er: Check if settings have changed. + + if (_disabledAtBoot) { + disable(); + return; + } + + WiFi_pre_setup(); + begin(); +} + +void ESPEasyWiFi_t::enable() {} + +void ESPEasyWiFi_t::disable() {} + +void ESPEasyWiFi_t::begin() {} + +void ESPEasyWiFi_t::loop() +{ + if (_state != WiFiState_e::IdleWaiting) { + if (_callbackError || (_state_timeout.isSet() && _state_timeout.timeReached())) + { + // TODO TD-er: Must check what error was given??? + _callbackError = false; + setState(WiFiState_e::OFF); + } + } + + switch (_state) + { + case WiFiState_e::Disabled: + // Do nothing here, as the device is disabled. + break; + case WiFiState_e::OFF: + begin(); + setState(WiFiState_e::IdleWaiting, 100); + break; + case WiFiState_e::AP_only: + break; + case WiFiState_e::IdleWaiting: + + // Wait for timeout to expire + if (_state_timeout.timeReached()) { + // Do we have candidate to connect to ? + if (WiFi_AP_Candidates.hasCandidates()) { + setState(WiFiState_e::STA_Connecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); + } else if (WifiIsAP(WiFi.getMode())) { + // TODO TD-er: Must check if any client is connected. + // If not, then we can disable AP mode and switch to WiFiState_e::STA_Scanning + setState(WiFiState_e::STA_AP_Scanning, WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT); + } else { + setState(WiFiState_e::STA_Scanning, WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT); + } + } + break; + case WiFiState_e::STA_Scanning: + case WiFiState_e::STA_AP_Scanning: + // Check if scanning is finished + // When scanning per channel, call for scanning next channel + break; + case WiFiState_e::STA_Connecting: + case WiFiState_e::STA_Reconnecting: + + // Check if (re)connecting has finished + if (getSTA_connected_state() != STA_connected_state::Connecting) { + if (getSTA_connected_state() == STA_connected_state::Connected) { + setState(WiFiState_e::STA_Connected); + } else { + if (_state == WiFiState_e::STA_Connecting) { + setState(WiFiState_e::STA_Reconnecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); + } else { + setState(WiFiState_e::OFF); + } + } + } + break; + case WiFiState_e::STA_Connected: + + // Check if still connected + if (getSTA_connected_state() != STA_connected_state::Connected) { + setState(WiFiState_e::OFF); + } else { + // Else mark last timestamp seen as connected + _last_seen_connected.setNow(); + } + break; + } + + + { + // Check if we need to start AP + // Flag captive portal in webserver and/or whether we might be in setup mode + } + +# ifdef USE_IMPROV + { + // Check for Improv mode. + } +# endif // ifdef USE_IMPROV +} + +IPAddress ESPEasyWiFi_t::getIP() const +{ + IPAddress res; + + return res; +} + +void ESPEasyWiFi_t::disconnect() {} + +void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { + switch (newState) + { + case WiFiState_e::Disabled: + // Do nothing here, as the device is disabled. + break; + case WiFiState_e::OFF: + // TODO TD-er: Must cancel all and turn off WiFi. + break; + case WiFiState_e::AP_only: + break; + case WiFiState_e::IdleWaiting: + // Do nothing here as we're waiting till the timeout is over + break; + case WiFiState_e::STA_Scanning: + // Start scanning + break; + case WiFiState_e::STA_AP_Scanning: + // Start scanning per channel + break; + case WiFiState_e::STA_Connecting: + case WiFiState_e::STA_Reconnecting: + // Start connecting + connectSTA(); + break; + case WiFiState_e::STA_Connected: + _last_seen_connected.setNow(); + break; + } + + if (timeout == 0) + { + _state_timeout.clear(); + + } else { + _state_timeout.setMillisFromNow(timeout); + } + _last_state_change.setNow(); + _state = newState; +} + +void ESPEasyWiFi_t::checkConnectProgress() {} + +void ESPEasyWiFi_t::startScanning() +{ + _state = WiFiState_e::STA_Scanning; + WifiScan(true); + _last_state_change.setNow(); +} + +bool ESPEasyWiFi_t::connectSTA() +{ + if (!WiFi_AP_Candidates.hasCandidateCredentials()) + { + if (!WiFiEventData.warnedNoValidWiFiSettings) + { + addLog(LOG_LEVEL_ERROR, F("WIFI : No valid wifi settings")); + WiFiEventData.warnedNoValidWiFiSettings = true; + } + WiFiEventData.last_wifi_connect_attempt_moment.clear(); + WiFiEventData.wifi_connect_attempt = 1; + WiFiEventData.wifiConnectAttemptNeeded = false; + + // No need to wait longer to start AP mode. + if (!Settings.DoNotStartAP()) + { + setAP(true); + } + return false; + } + WiFiEventData.warnedNoValidWiFiSettings = false; + setSTA(true); +# if defined(ESP8266) + wifi_station_set_hostname(NetworkCreateRFCCompliantHostname().c_str()); + +# endif // if defined(ESP8266) +# if defined(ESP32) + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); +# endif // if defined(ESP32) + setConnectionSpeed(); + setupStaticIPconfig(); + + // Start the process of connecting or starting AP + if (!WiFi_AP_Candidates.getNext(true)) + { + return false; + } + + const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, strformat( + F("WIFI : Connecting %s attempt #%u"), + candidate.toString().c_str(), + _connect_attempt)); + } + WiFiEventData.markWiFiBegin(); + if (prepareWiFi()) { + setNetworkMedium(NetworkMedium_t::WIFI); + RTC.clearLastWiFi(); + RTC.lastWiFiSettingsIndex = candidate.index; + + float tx_pwr = 0; // Will be set higher based on RSSI when needed. + // FIXME TD-er: Must check WiFiEventData.wifi_connect_attempt to increase TX power +#if FEATURE_SET_WIFI_TX_PWR + if (Settings.UseMaxTXpowerForSending()) { + tx_pwr = Settings.getWiFi_TX_power(); + } + SetWiFiTXpower(tx_pwr, candidate.rssi); +#endif + // Start connect attempt now, so no longer needed to attempt new connection. + WiFiEventData.wifiConnectAttemptNeeded = false; + WiFiEventData.wifiConnectInProgress = true; + const String key = WiFi_AP_CandidatesList::get_key(candidate.index); + +#if FEATURE_USE_IPV6 + if (Settings.EnableIPv6()) { + WiFi.enableIPv6(true); + } +#endif + +#ifdef ESP32 + if (Settings.IncludeHiddenSSID()) { + setWiFiCountryPolicyManual(); + } +#endif + + + if ((Settings.HiddenSSID_SlowConnectPerBSSID() || !candidate.bits.isHidden) + && candidate.allowQuickConnect()) { + WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); + } else { + WiFi.begin(candidate.ssid.c_str(), key.c_str()); + } + // Always wait for a second + WiFi.waitForConnectResult(1000); // https://github.com/arendst/Tasmota/issues/14985 + + } + + return true; +} + +} // namespace wifi +} // namespace net +} // namespace ESPEasy + +#endif // if FEATURE_WIFI diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h new file mode 100644 index 000000000..9ae2f044e --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h @@ -0,0 +1,128 @@ +#pragma once + +#include "../../ESPEasy_common.h" + +#if FEATURE_WIFI + +# include "../DataStructs/WiFi_AP_Candidate.h" +# include "../Helpers/LongTermTimer.h" + +# include "../DataTypes/WiFi_STA_connected_state.h" +# include "../DataTypes/WiFi_State.h" + + +# include + + +namespace ESPEasy { +namespace net { +namespace wifi { + +class ESPEasyWiFi_t +{ +public: + + // Called after settings have changed or at boot + void setup(); + + // Start the process of connecting or start AP, depending on the existing configuration. + void enable(); + + // Terminate WiFi activity + void disable(); + +private: + void begin(); + +public: + + // Process the state machine for managing WiFi connection + void loop(); + + WiFiState_e getState() const + { + return _state; + } + + // Get the IP-address in this order: + // - STA interface if connected, + // - AP interface if active + // - 0.0.0.0 if neither connected nor active. + IPAddress getIP() const; + + void disconnect(); + +private: + + void setState(WiFiState_e newState, uint32_t timeout = 0); + + // Handle timeouts + start of AP mode + void checkConnectProgress(); + + // Check to see if we already have some AP to connect to. + void checkScanningProgress(); + + void startScanning(); + + bool connectSTA(); + + + STA_connected_state getSTA_connected_state(); + + WiFi_AP_Candidate _active_sta; + WiFi_AP_Candidate _AP_conf; + + String _last_ssid; + MAC_address _last_bssid; + uint8_t _last_channel = 0; + WiFiState_e _state = WiFiState_e::Disabled; + + LongTermTimer _last_state_change; + LongTermTimer _state_timeout; + LongTermTimer _last_seen_connected; + LongTermTimer _AP_start_timestamp; + + uint32_t _connect_attempt = 0; + + + uint32_t _nrReconnects = 0; + + bool _callbackError = false; + + // Special modes for initial setup or re-configuration of a node via serial port/IMPROV + bool _improvActive = false; + bool _setupActive = false; + + +// WiFi settings => Move to separate class/struct +bool _disabledAtBoot = false; +bool _passiveScan = false; +bool _includeHiddenSSID = false; +float _TX_power = -1; + +// Manual IP settings +// IP +// Gateway +// Subnet +// DNS + + + +// soft AP configuration => TODO TD-er: Implement +// bool _must_Start_AP; // "Do Not Start AP" +// bool _has_ap{false}; // Maybe just check for active mode? +// WiFiAP _ap_config; +// WPA AP mode key +// Don't force /setup in AP-Mode + + + + + + +}; // class ESPEasyWiFi_t + +} // namespace wifi +} // namespace net +} // namespace ESPEasy +#endif // if FEATURE_WIFI diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp new file mode 100644 index 000000000..96c546ef0 --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp @@ -0,0 +1,61 @@ +#include "../ESPEasyCore/ESPEasyWiFi_state_machine.h" + +#ifdef ESP32 +# if FEATURE_WIFI + +# include +# include // Needed to call ESP-IDF functions like esp_wifi_.... + +# include + +# include +# include + +# include "../ESPEasyCore/ESPEasyWifi_abstracted.h" + + +namespace ESPEasy { +namespace net { +namespace wifi { + +STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() +{ + switch (WiFi.status()) + { + case WL_CONNECTED: + return STA_connected_state::Connected; + + case WL_NO_SSID_AVAIL: + return STA_connected_state::Error_Not_Found; + + case WL_CONNECT_FAILED: + case WL_CONNECTION_LOST: + return STA_connected_state::Error_Connect_Failed; + + case WL_IDLE_STATUS: + return STA_connected_state::Idle; + + + case WL_NO_SHIELD: + case WL_STOPPED: + case WL_SCAN_COMPLETED: + case WL_DISCONNECTED: + // TODO: what to do here? Do we need an extra connected state? + break; + } + + // TODO: Keep track of whether connection is in progress + // The status() function does not return a reply stating "connecting" + + /* if (_sta_connecting) { + return STA_connected_state::Connecting; + } + */ + return STA_connected_state::Idle; +} + +} // namespace wifi +} // namespace net +} // namespace ESPEasy +# endif // if FEATURE_WIFI +#endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp new file mode 100644 index 000000000..0cc60ec33 --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp @@ -0,0 +1,42 @@ +#include "../ESPEasyCore/ESPEasyWiFi_state_machine.h" + +#ifdef ESP8266 +# if FEATURE_WIFI + +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" + +namespace ESPEasy { +namespace net { +namespace wifi { + + +STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() +{ + // Perform check on SDK function, see: https://github.com/esp8266/Arduino/issues/7432 + station_status_t status = wifi_station_get_connect_status(); + + switch (status) + { + case STATION_GOT_IP: + return STA_connected_state::Connected; + case STATION_NO_AP_FOUND: + return STA_connected_state::Error_Not_Found; + case STATION_CONNECT_FAIL: + case STATION_WRONG_PASSWORD: + return STA_connected_state::Error_Connect_Failed; + case STATION_CONNECTING: + return STA_connected_state::Connecting; + case STATION_IDLE: + break; + + default: + break; + } + return STA_connected_state::Idle; +} + +} // namespace wifi +} // namespace net +} // namespace ESPEasy +# endif // if FEATURE_WIFI +#endif // ifdef ESP8266 diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 9410b0d28..72f38eab2 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1,5 +1,7 @@ #include "../ESPEasyCore/ESPEasyWifi.h" +#if FEATURE_WIFI + #include "../../ESPEasy-Globals.h" #include "../DataStructs/TimingStats.h" #include "../ESPEasyCore/ESPEasyNetwork.h" @@ -35,129 +37,6 @@ #include #endif -// FIXME TD-er: Cleanup of WiFi code -#ifdef ESPEASY_WIFI_CLEANUP_WORK_IN_PROGRESS -bool ESPEasyWiFi_t::begin() { - return true; -} - -void ESPEasyWiFi_t::end() { - - -} - - -void ESPEasyWiFi_t::loop() { - switch (_state) { - case WiFiState_e::OFF: - break; - case WiFiState_e::AP_only: - break; - case WiFiState_e::ErrorRecovery: - // Wait for timeout to expire - // Start again from scratch - break; - case WiFiState_e::STA_Scanning: - case WiFiState_e::STA_AP_Scanning: - // Check if scanning is finished - // When scanning per channel, call for scanning next channel - break; - case WiFiState_e::STA_Connecting: - case WiFiState_e::STA_Reconnecting: - // Check if (re)connecting has finished - break; - case WiFiState_e::STA_Connected: - // Check if still connected - // Reconnect if not. - // Else mark last timestamp seen as connected - break; - } - - - { - // Check if we need to start AP - // Flag captive portal in webserver and/or whether we might be in setup mode - } - -#ifdef USE_IMPROV - { - // Check for Improv mode. - } -#endif - - -} - - -IPAddress ESPEasyWiFi_t::getIP() const { - - IPAddress res; - - - return res; -} - -void ESPEasyWiFi_t::disconnect() { - -} - - -void ESPEasyWiFi_t::checkConnectProgress() { - -} - -void ESPEasyWiFi_t::startScanning() { - _state = WiFiState_e::STA_Scanning; - WifiScan(true); - _last_state_change.setNow(); -} - - -bool ESPEasyWiFi_t::connectSTA() { - if (!WiFi_AP_Candidates.hasCandidateCredentials()) { - if (!WiFiEventData.warnedNoValidWiFiSettings) { - addLog(LOG_LEVEL_ERROR, F("WIFI : No valid wifi settings")); - WiFiEventData.warnedNoValidWiFiSettings = true; - } - WiFiEventData.last_wifi_connect_attempt_moment.clear(); - WiFiEventData.wifi_connect_attempt = 1; - WiFiEventData.wifiConnectAttemptNeeded = false; - - // No need to wait longer to start AP mode. - if (!Settings.DoNotStartAP()) { - setAP(true); - } - return false; - } - WiFiEventData.warnedNoValidWiFiSettings = false; - setSTA(true); - #if defined(ESP8266) - wifi_station_set_hostname(NetworkCreateRFCCompliantHostname().c_str()); - - #endif // if defined(ESP8266) - #if defined(ESP32) - WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); - #endif // if defined(ESP32) - setConnectionSpeed(); - setupStaticIPconfig(); - - - - // Start the process of connecting or starting AP - if (WiFi_AP_Candidates.getNext(true)) { - // Try to connect to AP - - } else { - // No (known) AP, start scanning - startScanning(); - } - - - return true; -} - -#endif // ESPEASY_WIFI_CLEANUP_WORK_IN_PROGRESS - // ******************************************************************************** // WiFi state @@ -239,7 +118,7 @@ bool WiFiConnected() { } #endif - if (!WifiIsSTA(WiFi.getMode())) { + if (! ESPEasy::net::wifi::WifiIsSTA(WiFi.getMode())) { lastState = false; return lastState; } @@ -265,7 +144,7 @@ bool WiFiConnected() { if (WiFiEventData.unprocessedWifiEvents()) { return false; } - bool wifi_isconnected = ESPEasy_WiFi_abstraction::WiFiConnected(); + bool wifi_isconnected = ESPEasy::net::wifi::WiFiConnected(); if (recursiveCall) return wifi_isconnected; recursiveCall = true; @@ -307,12 +186,12 @@ bool WiFiConnected() { if (WiFiEventData.timerAPoff.isSet() && !WiFiEventData.timerAPoff.timeReached()) { if (!Settings.DoNotStartAP()) { // Timer reached, so enable AP mode. - if (!WifiIsAP(WiFi.getMode())) { + if (! ESPEasy::net::wifi::WifiIsAP(WiFi.getMode())) { if (!WiFiEventData.wifiConnectAttemptNeeded) { addLog(LOG_LEVEL_INFO, F("WiFi : WiFiConnected(), start AP")); WifiScan(false); - setSTA(false); // Force reset WiFi + reduce power consumption - setAP(true); + ESPEasy::net::wifi::setSTA(false); // Force reset WiFi + reduce power consumption + ESPEasy::net::wifi::setAP(true); } } } @@ -324,7 +203,7 @@ bool WiFiConnected() { // When made this far in the code, we apparently do not have valid WiFi connection. - if (!WiFiEventData.timerAPstart.isSet() && !WifiIsAP(WiFi.getMode())) { + if (!WiFiEventData.timerAPstart.isSet() && ! ESPEasy::net::wifi::WifiIsAP(WiFi.getMode())) { // First run we do not have WiFi connection any more, set timer to start AP mode // Only allow the automatic AP mode in the first N minutes after boot. if (getUptimeMinutes() < WIFI_ALLOW_AP_AFTERBOOT_PERIOD) { @@ -455,9 +334,9 @@ void AttemptWiFiConnect() { if (WiFiEventData.unprocessedWifiEvents()) { return; } - setSTA(false); + ESPEasy::net::wifi::setSTA(false); - setSTA(true); + ESPEasy::net::wifi::setSTA(true); if (WiFi_AP_Candidates.getNext(WiFiScanAllowed())) { const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); @@ -549,7 +428,7 @@ void AttemptWiFiConnect() { // Set Wifi config // ******************************************************************************** bool prepareWiFi() { - ESPEasy_WiFi_abstraction::registerWiFiEventHandler(); + ESPEasy::net::wifi::registerWiFiEventHandler(); if (!WiFi_AP_Candidates.hasCandidateCredentials()) { if (!WiFiEventData.warnedNoValidWiFiSettings) { @@ -563,12 +442,12 @@ bool prepareWiFi() { // No need to wait longer to start AP mode. if (!Settings.DoNotStartAP()) { WifiScan(false); -// setAP(true); +// ESPEasy::net::wifi::setAP(true); } return false; } WiFiEventData.warnedNoValidWiFiSettings = false; - setSTA(true); + ESPEasy::net::wifi::setSTA(true); #if defined(ESP8266) wifi_station_set_hostname(NetworkCreateRFCCompliantHostname().c_str()); @@ -577,7 +456,7 @@ bool prepareWiFi() { #if defined(ESP32) WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); #endif // if defined(ESP32) - setConnectionSpeed(); + ESPEasy::net::wifi::setConnectionSpeed(); setupStaticIPconfig(); WiFiEventData.wifiConnectAttemptNeeded = true; @@ -653,7 +532,7 @@ void resetWiFi() { // Send this log only after WifiDisconnect() or else sending to syslog may cause issues addLog(LOG_LEVEL_INFO, F("Reset WiFi.")); - // setWifiMode(WIFI_OFF); + // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); initWiFi(); } @@ -670,7 +549,7 @@ void initWiFi() // WiFi = ESP8266WiFiClass(); #endif // ifdef ESP8266 #ifdef ESP32 - ESPEasy_WiFi_abstraction::removeWiFiEventHandler(); + ESPEasy::net::wifi::removeWiFiEventHandler(); #endif @@ -680,12 +559,12 @@ void initWiFi() WiFi.disconnect(false); delay(1); if (active_network_medium != NetworkMedium_t::NotSet) { - setSTA(true); + ESPEasy::net::wifi::setSTA(true); WifiScan(false); } - setWifiMode(WIFI_OFF); + ESPEasy::net::wifi::setWifiMode(WIFI_OFF); - ESPEasy_WiFi_abstraction::registerWiFiEventHandler(); + ESPEasy::net::wifi::registerWiFiEventHandler(); delay(100); } @@ -741,7 +620,7 @@ void SetWiFiTXpower(float dBm, float rssi) { dBm = minTXpwr; } -ESPEasy_WiFi_abstraction::SetWiFiTXpower(dBm); +ESPEasy::net::wifi::SetWiFiTXpower(dBm); if (WiFiEventData.wifi_TX_pwr < dBm) { // Will increase the TX power, give power supply of the unit some rest @@ -779,7 +658,7 @@ ESPEasy_WiFi_abstraction::SetWiFiTXpower(dBm); float GetRSSIthreshold(float& maxTXpwr) { maxTXpwr = Settings.getWiFi_TX_power(); - return ESPEasy_WiFi_abstraction::GetRSSIthreshold(maxTXpwr); + return ESPEasy::net::wifi::GetRSSIthreshold(maxTXpwr); } int GetRSSI_quality() { @@ -793,7 +672,7 @@ int GetRSSI_quality() { } WiFiConnectionProtocol getConnectionProtocol() { - return ESPEasy_WiFi_abstraction::getConnectionProtocol(); + return ESPEasy::net::wifi::getConnectionProtocol(); } #ifdef ESP32 @@ -824,7 +703,7 @@ void WifiDisconnect() # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : WifiDisconnect()")); #endif - ESPEasy_WiFi_abstraction::WiFiDisconnect(); + ESPEasy::net::wifi::WiFiDisconnect(); WiFiEventData.setWiFiDisconnected(); WiFiEventData.markDisconnect(WIFI_DISCONNECT_REASON_UNSPECIFIED); /* @@ -918,7 +797,7 @@ bool WiFiScanAllowed() { void WifiScan(bool async, uint8_t channel) { - setSTA(true); + ESPEasy::net::wifi::setSTA(true); if (!WiFiScanAllowed()) { return; } @@ -1043,7 +922,7 @@ void WiFiScan_log_to_serial() if (WiFi_AP_Candidates.scanComplete() <= 0) { WiFiMode_t cur_wifimode = WiFi.getMode(); WifiScan(false); - setWifiMode(cur_wifimode); + ESPEasy::net::wifi::setWifiMode(cur_wifimode); } const int8_t scanCompleteStatus = WiFi_AP_Candidates.scanComplete(); @@ -1072,61 +951,10 @@ void WiFiScan_log_to_serial() serialPrintln(""); } -// ******************************************************************************** -// Manage Wifi Modes -// ******************************************************************************** -void setSTA(bool enable) { - switch (WiFi.getMode()) { - case WIFI_OFF: - if (enable) { setWifiMode(WIFI_STA); } - break; - case WIFI_STA: - - if (!enable) { setWifiMode(WIFI_OFF); } - break; - case WIFI_AP: - - if (enable) { setWifiMode(WIFI_AP_STA); } - break; - case WIFI_AP_STA: - - if (!enable) { setWifiMode(WIFI_AP); } - break; - default: - break; - } -} - -void setAP(bool enable) { - WiFiMode_t wifimode = WiFi.getMode(); - - switch (wifimode) { - case WIFI_OFF: - - if (enable) { - setWifiMode(WIFI_AP); - } - break; - case WIFI_STA: - - if (enable) { setWifiMode(WIFI_AP_STA); } - break; - case WIFI_AP: - - if (!enable) { setWifiMode(WIFI_OFF); } - break; - case WIFI_AP_STA: - - if (!enable) { setWifiMode(WIFI_STA); } - break; - default: - break; - } -} // Only internal scope -void setAPinternal(bool enable) +void setAPinternal(bool enable) { if (enable) { // create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password! @@ -1146,7 +974,7 @@ void setAPinternal(bool enable) } int channel = 1; - if (WifiIsSTA(WiFi.getMode()) && WiFiConnected()) { + if ( ESPEasy::net::wifi::WifiIsSTA(WiFi.getMode()) && WiFiConnected()) { channel = WiFi.channel(); } @@ -1188,136 +1016,8 @@ void setAPinternal(bool enable) } } -const __FlashStringHelper * getWifiModeString(WiFiMode_t wifimode) -{ - switch (wifimode) { - case WIFI_OFF: return F("OFF"); - case WIFI_STA: return F("STA"); - case WIFI_AP: return F("AP"); - case WIFI_AP_STA: return F("AP+STA"); - default: - break; - } - return F("Unknown"); -} - -void setWifiMode(WiFiMode_t new_mode) { - const WiFiMode_t cur_mode = WiFi.getMode(); - static WiFiMode_t processing_wifi_mode = cur_mode; - if (cur_mode == new_mode) { - return; - } - if (processing_wifi_mode == new_mode) { - // Prevent loops - return; - } - processing_wifi_mode = new_mode; - - if (cur_mode == WIFI_OFF) { - #if defined(ESP32) - // Needs to be set while WiFi is off - WiFi.hostname(NetworkCreateRFCCompliantHostname()); - #endif - WiFiEventData.markWiFiTurnOn(); - } - if (new_mode != WIFI_OFF) { - #ifdef ESP8266 - // See: https://github.com/esp8266/Arduino/issues/6172#issuecomment-500457407 - WiFi.forceSleepWake(); // Make sure WiFi is really active. - #endif - delay(100); - } else { - WifiDisconnect(); -// delay(100); - processDisconnect(); - WiFiEventData.clear_processed_flags(); - } - - addLog(LOG_LEVEL_INFO, concat(F("WIFI : Set WiFi to "), getWifiModeString(new_mode))); - - int retry = 2; - while (!WiFi.mode(new_mode) && retry > 0) { - addLog(LOG_LEVEL_INFO, F("WIFI : Cannot set mode!!!!!")); - delay(100); - --retry; - } - retry = 2; - while (WiFi.getMode() != new_mode && retry > 0) { - addLog(LOG_LEVEL_INFO, F("WIFI : mode not yet set")); - delay(100); - --retry; - } - if (new_mode == WIFI_OFF) { - - // FIXME TD-er: Is this correct to mark Turn ON ???? - WiFiEventData.markWiFiTurnOn(); - #if defined(ESP32) - // Needs to be set while WiFi is off - WiFi.hostname(NetworkCreateRFCCompliantHostname()); - #endif - delay(100); - #if defined(ESP32) - esp_wifi_set_ps(WIFI_PS_NONE); -// esp_wifi_set_ps(WIFI_PS_MAX_MODEM); - #endif - #ifdef ESP8266 - WiFi.forceSleepBegin(); - #endif // ifdef ESP8266 - delay(1); - } else { - if (cur_mode == WIFI_OFF) { - ESPEasy_WiFi_abstraction::registerWiFiEventHandler(); - } - // Only set power mode when AP is not enabled - // When AP is enabled, the sleep mode is already set to WIFI_NONE_SLEEP - if (!WifiIsAP(new_mode)) { - if (Settings.WifiNoneSleep()) { - ESPEasy_WiFi_abstraction::setWiFiNoneSleep(); - } else if (Settings.EcoPowerMode()) { - ESPEasy_WiFi_abstraction::setWiFiEcoPowerMode(); - } else { - // Default - ESPEasy_WiFi_abstraction::setWiFiDefaultPowerMode(); - } - } -#if FEATURE_SET_WIFI_TX_PWR - SetWiFiTXpower(); -#endif - if (WifiIsSTA(new_mode)) { -// WiFi.setAutoConnect(Settings.SDK_WiFi_autoreconnect()); - WiFi.setAutoReconnect(Settings.SDK_WiFi_autoreconnect()); - } - delay(100); // Must allow for some time to init. - } - const bool new_mode_AP_enabled = WifiIsAP(new_mode); - - if (WifiIsAP(cur_mode) && !new_mode_AP_enabled) { - eventQueue.add(F("WiFi#APmodeDisabled")); - } - - if (WifiIsAP(cur_mode) != new_mode_AP_enabled) { - // Mode has changed - setAPinternal(new_mode_AP_enabled); - } - #if FEATURE_MDNS - #ifdef ESP8266 - // notifyAPChange() is not present in the ESP32 MDNSResponder - MDNS.notifyAPChange(); - #endif - #endif -} - -bool WifiIsAP(WiFiMode_t wifimode) -{ - return ESPEasy_WiFi_abstraction::WifiIsAP(wifimode); -} - -bool WifiIsSTA(WiFiMode_t wifimode) -{ - return ESPEasy_WiFi_abstraction::WifiIsSTA(wifimode); -} bool WiFiUseStaticIP() { return Settings.IP[0] != 0 && Settings.IP[0] != 255; @@ -1325,7 +1025,7 @@ bool WiFiUseStaticIP() { bool wifiAPmodeActivelyUsed() { - if (!WifiIsAP(WiFi.getMode()) || (!WiFiEventData.timerAPoff.isSet())) { + if (! ESPEasy::net::wifi::WifiIsAP(WiFi.getMode()) || (!WiFiEventData.timerAPoff.isSet())) { // AP not active or soon to be disabled in processDisableAPmode() return false; } @@ -1335,10 +1035,6 @@ bool wifiAPmodeActivelyUsed() // reconnect? } -void setConnectionSpeed() { - ESPEasy_WiFi_abstraction::setConnectionSpeed(Settings.ForceWiFi_bg_mode()); -} - void setupStaticIPconfig() { setUseStaticIP(WiFiUseStaticIP()); @@ -1443,3 +1139,5 @@ void logConnectionStatus() { */ #endif // ifndef BUILD_NO_DEBUG } + +#endif \ No newline at end of file diff --git a/src/src/ESPEasyCore/ESPEasyWifi.h b/src/src/ESPEasyCore/ESPEasyWifi.h index 393c335d1..d30d9c4e5 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.h +++ b/src/src/ESPEasyCore/ESPEasyWifi.h @@ -3,106 +3,36 @@ #include "../../ESPEasy_common.h" -#if defined(ESP8266) - # include -#endif // if defined(ESP8266) -#if defined(ESP32) - # include -#endif // if defined(ESP32) +#if FEATURE_WIFI -#include "../DataTypes/WiFiConnectionProtocol.h" -#include "../DataStructs/WiFi_AP_Candidate.h" +# if defined(ESP8266) + # include +# endif // if defined(ESP8266) +# if defined(ESP32) + # include +# endif // if defined(ESP32) -#include "../Helpers/LongTermTimer.h" +# include "../DataTypes/WiFiConnectionProtocol.h" +# include "../DataStructs/WiFi_AP_Candidate.h" -#define WIFI_RECONNECT_WAIT 30000 // in milliSeconds -#define WIFI_AP_OFF_TIMER_DURATION 300000 // in milliSeconds -#if FEATURE_CUSTOM_PROVISIONING -#define WIFI_CONNECTION_CONSIDERED_STABLE 60000 // in milliSeconds -#else -#define WIFI_CONNECTION_CONSIDERED_STABLE 60000 // in milliSeconds -#endif -#define WIFI_ALLOW_AP_AFTERBOOT_PERIOD 5 // in minutes -#define WIFI_SCAN_INTERVAL_AP_USED 125000 // in milliSeconds -#define WIFI_SCAN_INTERVAL_MINIMAL 60000 // in milliSeconds +# include "../Helpers/LongTermTimer.h" + +# define WIFI_RECONNECT_WAIT 30000 // in milliSeconds +# define WIFI_AP_OFF_TIMER_DURATION 300000 // in milliSeconds +# if FEATURE_CUSTOM_PROVISIONING +# define WIFI_CONNECTION_CONSIDERED_STABLE 60000 // in milliSeconds +# else +# define WIFI_CONNECTION_CONSIDERED_STABLE 60000 // in milliSeconds +# endif // if FEATURE_CUSTOM_PROVISIONING +# define WIFI_ALLOW_AP_AFTERBOOT_PERIOD 5 // in minutes +# define WIFI_SCAN_INTERVAL_AP_USED 125000 // in milliSeconds +# define WIFI_SCAN_INTERVAL_MINIMAL 60000 // in milliSeconds -#ifdef ESPEASY_WIFI_CLEANUP_WORK_IN_PROGRESS - -enum class WiFiState_e { - // WiFi radio off - OFF, - // Only running in AP mode - AP_only, - // WiFi was in some kind of error state, waiting period - ErrorRecovery, - // STA mode + scanning - STA_Scanning, - // STA+AP mode + scanning, - // needs some careful handling to prevent disconnecting the connected stations - STA_AP_Scanning, - // Connecting to an AP - STA_Connecting, - // Reconnecting to an AP - // May need to handle some specific disconnect reasons differently from connecting for the first time. - STA_Reconnecting, - // Connected to an AP - STA_Connected -}; +# ifdef ESPEASY_WIFI_CLEANUP_WORK_IN_PROGRESS -class ESPEasyWiFi_t { -public: - - // Start the process of connecting or start AP, depending on the existing configuration. - bool begin(); - - // Terminate WiFi activity - void end(); - - // Process the state machine for managing WiFi connection - void loop(); - - WiFiState_e getState() const { return _state; } - - // Get the IP-address in this order: - // - STA interface if connected, - // - AP interface if active - // - 0.0.0.0 if neither connected nor active. - IPAddress getIP() const; - - void disconnect(); - - - - -private: - - // Handle timeouts + start of AP mode - void checkConnectProgress(); - - // Check to see if we already have some AP to connect to. - void checkScanningProgress(); - - void startScanning(); - - bool connectSTA(); - - - WiFi_AP_Candidate _active_sta; - WiFi_AP_Candidate _AP_conf; - - String _last_ssid; - MAC_address _last_bssid; - uint8_t _last_channel = 0; - WiFiState_e _state = WiFiState_e::OFF; - - LongTermTimer _last_state_change; - LongTermTimer _last_seen_connected; -}; - - -#endif // ESPEASY_WIFI_CLEANUP_WORK_IN_PROGRESS +# endif // ESPEASY_WIFI_CLEANUP_WORK_IN_PROGRESS bool WiFiConnected(); void WiFiConnectRelaxed(); @@ -113,41 +43,45 @@ void resetWiFi(); void initWiFi(); -#if FEATURE_SET_WIFI_TX_PWR -void SetWiFiTXpower(); -void SetWiFiTXpower(float dBm); // 0-20.5 -void SetWiFiTXpower(float dBm, float rssi); -#endif +# if FEATURE_SET_WIFI_TX_PWR +void SetWiFiTXpower(); +void SetWiFiTXpower(float dBm); // 0-20.5 +void SetWiFiTXpower(float dBm, + float rssi); +# endif // if FEATURE_SET_WIFI_TX_PWR float GetRSSIthreshold(float& maxTXpwr); + // Return some quality based on RSSI. // <-97 => 0 , >-50 => 10 // -97 ... -50 => 1 ... 9 -int GetRSSI_quality(); +int GetRSSI_quality(); WiFiConnectionProtocol getConnectionProtocol(); -#ifdef ESP32 +# ifdef ESP32 + // TSF time is 64-bit timer in usec, sent by the AP along with other packets. // On tested access points, this seems to be the uptime in usec. // Could be used among nodes connected to the same AP to increase time sync accuracy. int64_t WiFi_get_TSF_time(); -#endif -void WifiDisconnect(); -bool WiFiScanAllowed(); -void WifiScan(bool async, uint8_t channel = 0); -void WiFiScan_log_to_serial(); -void setSTA(bool enable); -void setAP(bool enable); -const __FlashStringHelper * getWifiModeString(WiFiMode_t wifimode); -void setWifiMode(WiFiMode_t wifimode); -bool WifiIsAP(WiFiMode_t wifimode); -bool WifiIsSTA(WiFiMode_t wifimode); -bool WiFiUseStaticIP(); -bool wifiAPmodeActivelyUsed(); -void setConnectionSpeed(); -void setupStaticIPconfig(); -String formatScanResult(int i, const String& separator); -String formatScanResult(int i, const String& separator, int32_t& rssi); +# endif // ifdef ESP32 +void WifiDisconnect(); +bool WiFiScanAllowed(); +void WifiScan(bool async, + uint8_t channel = 0); +void WiFiScan_log_to_serial(); + +void setAPinternal(bool enable); // FIXME TD-er: Move to ESPEasyWifi_abstracted... + +bool WiFiUseStaticIP(); +bool wifiAPmodeActivelyUsed(); +void setupStaticIPconfig(); +String formatScanResult(int i, + const String& separator); +String formatScanResult(int i, + const String& separator, + int32_t & rssi); void logConnectionStatus(); +#endif // if FEATURE_WIFI -#endif // ESPEASY_WIFI_H \ No newline at end of file +#endif // ESPEASY_WIFI_H diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index ba4761597..739440fad 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -3,10 +3,11 @@ #include "../../ESPEasy-Globals.h" #if FEATURE_ETHERNET -#include "../ESPEasyCore/ESPEasyEth_ProcessEvent.h" +# include "../ESPEasyCore/ESPEasyEth_ProcessEvent.h" #endif #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" @@ -39,7 +40,6 @@ #include "../WebServer/ESPEasy_WebServer.h" - // ******************************************************************************** // Called from the loop() to make sure events are processed as soon as possible. // These functions are called from Setup() or Loop() and thus may call delay() or yield() @@ -52,39 +52,45 @@ void handle_unprocessedNetworkEvents() if (active_network_medium == NetworkMedium_t::WIFI) { const bool should_be_initialized = (WiFiEventData.WiFiGotIP() && WiFiEventData.WiFiConnected()) || NetworkConnected(); + if (WiFiEventData.WiFiServicesInitialized() != should_be_initialized) { if (!WiFiEventData.WiFiServicesInitialized()) { - WiFiEventData.processedDHCPTimeout = true; // FIXME TD-er: Find out when this happens (happens on ESP32 sometimes) + WiFiEventData.processedDHCPTimeout = true; // FIXME TD-er: Find out when this happens (happens on ESP32 sometimes) + if (WiFiConnected()) { if (!WiFiEventData.WiFiGotIP()) { - # ifndef BUILD_NO_DEBUG + #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WiFi : Missed gotIP event")); #endif WiFiEventData.processedGotIP = false; processGotIP(); } + if (!WiFiEventData.WiFiConnected()) { - # ifndef BUILD_NO_DEBUG + #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WiFi : Missed connected event")); #endif WiFiEventData.processedConnect = false; processConnect(); } + // Apparently we are connected, so no need to process any late disconnect event WiFiEventData.processedDisconnect = true; - } + } WiFiEventData.setWiFiServicesInitialized(); -//#ifdef ESP32 + + // #ifdef ESP32 setWebserverRunning(false); delay(1); setWebserverRunning(true); delay(1); -/* -#else - CheckRunningServices(); -#endif -*/ + + /* + #else + CheckRunningServices(); + #endif + */ } } } @@ -104,7 +110,7 @@ void handle_unprocessedNetworkEvents() // WiFi connection is not yet available, so introduce some extra delays to // help the background tasks managing wifi connections delay(0); - + if (!WiFiEventData.processedConnect) { #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); @@ -127,12 +133,13 @@ void handle_unprocessedNetworkEvents() WifiDisconnect(); } - if (WiFi.status() == WL_DISCONNECTED && WiFiEventData.wifiConnectInProgress) { - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && + if ((WiFi.status() == WL_DISCONNECTED) && WiFiEventData.wifiConnectInProgress) { + if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { logConnectionStatus(); resetWiFi(); } + if (!WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { WiFiEventData.wifiConnectInProgress = false; } @@ -152,9 +159,10 @@ void handle_unprocessedNetworkEvents() if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { static LongTermTimer lastDisconnectMoment_log; static uint8_t lastWiFiStatus_log = 0; - uint8_t cur_wifi_status = WiFi.status(); - if (WiFiEventData.lastDisconnectMoment.get() != lastDisconnectMoment_log.get() || - lastWiFiStatus_log != cur_wifi_status) { + uint8_t cur_wifi_status = WiFi.status(); + + if ((WiFiEventData.lastDisconnectMoment.get() != lastDisconnectMoment_log.get()) || + (lastWiFiStatus_log != cur_wifi_status)) { lastDisconnectMoment_log.set(WiFiEventData.lastDisconnectMoment.get()); lastWiFiStatus_log = cur_wifi_status; String wifilog = F("WIFI : Disconnected: WiFi.status() = "); @@ -162,13 +170,13 @@ void handle_unprocessedNetworkEvents() wifilog += F(" RSSI: "); wifilog += String(WiFi.RSSI()); wifilog += F(" status: "); - #ifdef ESP8266 + # ifdef ESP8266 station_status_t status = wifi_station_get_connect_status(); wifilog += SDKwifiStatusToString(status); - #endif - #ifdef ESP32 + # endif // ifdef ESP8266 + # ifdef ESP32 wifilog += ArduinoWifiStatusToString(WiFi.status()); - #endif + # endif addLogMove(LOG_LEVEL_DEBUG, wifilog); } } @@ -191,7 +199,7 @@ void handle_unprocessedNetworkEvents() if (WiFiEventData.WiFiServicesInitialized()) { if (WiFiEventData.lastConnectMoment.isSet() && WiFiEventData.lastConnectMoment.timeoutReached(WIFI_CONNECTION_CONSIDERED_STABLE)) { // Connection considered stable - WiFiEventData.wifi_connect_attempt = 0; + WiFiEventData.wifi_connect_attempt = 0; WiFiEventData.wifi_considered_stable = true; WiFi_AP_Candidates.markCurrentConnectionStable(); @@ -226,12 +234,12 @@ void processDisconnect() { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = strformat( - F("WIFI : Disconnected! Reason: '%s'"), + F("WIFI : Disconnected! Reason: '%s'"), getLastDisconnectReason().c_str()); if (WiFiEventData.lastConnectedDuration_us > 0) { log += concat( - F(" Connected for "), + F(" Connected for "), format_msec_duration(WiFiEventData.lastConnectedDuration_us / 1000ll)); } addLogMove(LOG_LEVEL_INFO, log); @@ -239,14 +247,14 @@ void processDisconnect() { logConnectionStatus(); if (WiFiEventData.processingDisconnect.isSet()) { - if (WiFiEventData.processingDisconnect.millisPassedSince() > 5000 || WiFiEventData.processedDisconnect) { + if ((WiFiEventData.processingDisconnect.millisPassedSince() > 5000) || WiFiEventData.processedDisconnect) { WiFiEventData.processedDisconnect = true; WiFiEventData.processingDisconnect.clear(); } } - if (WiFiEventData.processedDisconnect || + if (WiFiEventData.processedDisconnect || WiFiEventData.processingDisconnect.isSet()) { return; } WiFiEventData.processingDisconnect.setNow(); WiFiEventData.setWiFiDisconnected(); @@ -260,36 +268,42 @@ void processDisconnect() { // FIXME TD-er: With AutoReconnect enabled, WiFi must be reset or else we completely loose track of the actual WiFi state bool mustRestartWiFi = Settings.WiFiRestart_connection_lost() || WiFi.getAutoReconnect(); - if (WiFiEventData.lastConnectedDuration_us > 0 && (WiFiEventData.lastConnectedDuration_us / 1000) < 5000) { - if (!WiFi_AP_Candidates.getBestCandidate().usable()) -// addLog(LOG_LEVEL_INFO, F("WIFI : !getBestCandidate().usable() => mustRestartWiFi = true")); + + if ((WiFiEventData.lastConnectedDuration_us > 0) && ((WiFiEventData.lastConnectedDuration_us / 1000) < 5000)) { + if (!WiFi_AP_Candidates.getBestCandidate().usable()) { + // addLog(LOG_LEVEL_INFO, F("WIFI : !getBestCandidate().usable() => mustRestartWiFi = true")); mustRestartWiFi = true; + } } - + if (WiFi.status() == WL_IDLE_STATUS) { -// addLog(LOG_LEVEL_INFO, F("WIFI : WiFi.status() == WL_IDLE_STATUS => mustRestartWiFi = true")); + // addLog(LOG_LEVEL_INFO, F("WIFI : WiFi.status() == WL_IDLE_STATUS => mustRestartWiFi = true")); mustRestartWiFi = true; } #ifdef USES_ESPEASY_NOW + if (use_EspEasy_now) { -// mustRestartWiFi = true; + // mustRestartWiFi = true; } - #endif - //WifiDisconnect(); // Needed or else node may not reconnect reliably. + #endif // ifdef USES_ESPEASY_NOW + + // WifiDisconnect(); // Needed or else node may not reconnect reliably. if (mustRestartWiFi) { WiFiEventData.processedDisconnect = true; resetWiFi(); -// WifiScan(false); -// delay(100); -// setWifiMode(WIFI_OFF); -// initWiFi(); -// delay(100); + + // WifiScan(false); + // delay(100); + // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); + // initWiFi(); + // delay(100); } -// delay(500); + + // delay(500); logConnectionStatus(); WiFiEventData.processedDisconnect = true; WiFiEventData.processingDisconnect.clear(); @@ -297,11 +311,13 @@ void processDisconnect() { void processConnect() { if (WiFiEventData.processedConnect) { return; } - //delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 + + // delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 if (checkAndResetWiFi()) { return; } WiFiEventData.processedConnect = true; + if (WiFi.status() == WL_DISCONNECTED) { // Apparently not really connected return; @@ -315,21 +331,24 @@ void processConnect() { const bool mustResetCredentials = CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS; #else const bool mustResetCredentials = false; - #endif + #endif // ifdef CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS #ifdef CUSTOM_EMERGENCY_FALLBACK_START_AP const bool mustStartAP = CUSTOM_EMERGENCY_FALLBACK_START_AP; #else const bool mustStartAP = false; - #endif + #endif // ifdef CUSTOM_EMERGENCY_FALLBACK_START_AP + if (mustStartAP) { int allowedUptimeMinutes = 10; #ifdef CUSTOM_EMERGENCY_FALLBACK_ALLOW_MINUTES_UPTIME allowedUptimeMinutes = CUSTOM_EMERGENCY_FALLBACK_ALLOW_MINUTES_UPTIME; #endif + if (getUptimeMinutes() < allowedUptimeMinutes) { WiFiEventData.timerAPstart.setNow(); } } + if (mustResetCredentials && !WiFiEventData.performedClearWiFiCredentials) { WiFiEventData.performedClearWiFiCredentials = true; SecuritySettings.clearWiFiCredentials(); @@ -341,7 +360,7 @@ void processConnect() { if (loglevelActiveFor(LOG_LEVEL_INFO)) { const LongTermTimer::Duration connect_duration = WiFiEventData.last_wifi_connect_attempt_moment.timeDiff(WiFiEventData.lastConnectMoment); - String log = strformat( + String log = strformat( F("WIFI : Connected! AP: %s (%s) Ch: %d"), WiFi.SSID().c_str(), WiFi.BSSIDstr().c_str(), @@ -356,7 +375,7 @@ void processConnect() { addLogMove(LOG_LEVEL_INFO, log); } -// WiFiEventData.last_wifi_connect_attempt_moment.clear(); + // WiFiEventData.last_wifi_connect_attempt_moment.clear(); if (Settings.UseRules) { if (WiFiEventData.bssid_changed) { @@ -366,7 +385,7 @@ void processConnect() { if (WiFiEventData.channel_changed) { eventQueue.add(F("WiFi#ChangedWiFichannel")); } - } + } if (useStaticIP()) { WiFiEventData.markGotIP(); // in static IP config the got IP event is never fired. @@ -380,6 +399,7 @@ void processGotIP() { if (WiFiEventData.processedGotIP) { return; } + if (checkAndResetWiFi()) { return; } @@ -388,15 +408,17 @@ void processGotIP() { if (!useStaticIP()) { #ifdef ESP8266 + if (!ip.isSet()) { - #else - if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0) { - #endif + #else // ifdef ESP8266 + + if ((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0)) { + #endif // ifdef ESP8266 return; } } - const IPAddress gw = WiFi.gatewayIP(); - const IPAddress subnet = WiFi.subnetMask(); + const IPAddress gw = WiFi.gatewayIP(); + const IPAddress subnet = WiFi.subnetMask(); const LongTermTimer::Duration dhcp_duration = WiFiEventData.lastConnectMoment.timeDiff(WiFiEventData.lastGetIPmoment); WiFiEventData.dns0_cache = WiFi.dnsIP(0); WiFiEventData.dns1_cache = WiFi.dnsIP(1); @@ -462,17 +484,22 @@ void processGotIP() { } #if FEATURE_USE_IPV6 + void processGotIPv6() { if (!WiFiEventData.processedGotIP6) { WiFiEventData.processedGotIP6 = true; - if (loglevelActiveFor(LOG_LEVEL_INFO)) + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, String(F("WIFI : STA got IP6 ")) + WiFiEventData.unprocessed_IP6.toString(true)); -#if FEATURE_ESPEASY_P2P -// updateUDPport(true); -#endif + } +# if FEATURE_ESPEASY_P2P + + // updateUDPport(true); +# endif // if FEATURE_ESPEASY_P2P } } -#endif + +#endif // if FEATURE_USE_IPV6 // A client disconnected from the AP on this node. void processDisconnectAPmode() { @@ -480,6 +507,7 @@ void processDisconnectAPmode() { WiFiEventData.processedDisconnectAPmode = true; #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { const int nrStationsConnected = WiFi.softAPgetStationNum(); String log = F("AP Mode: Client disconnected: "); @@ -488,16 +516,18 @@ void processDisconnectAPmode() { log += nrStationsConnected; addLogMove(LOG_LEVEL_INFO, log); } -#endif +#endif // ifndef BUILD_NO_DEBUG } // Client connects to AP on this node void processConnectAPmode() { if (WiFiEventData.processedConnectAPmode) { return; } WiFiEventData.processedConnectAPmode = true; + // Extend timer to switch off AP. WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_DURATION); #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("AP Mode: Client connected: "); log += WiFiEventData.lastMacConnectedAPmode.toString(); @@ -505,9 +535,10 @@ void processConnectAPmode() { log += WiFi.softAPgetStationNum(); addLogMove(LOG_LEVEL_INFO, log); } -#endif +#endif // ifndef BUILD_NO_DEBUG #if FEATURE_DNS_SERVER + // Start DNS, only used if the ESP has no valid WiFi config // It will reply with it's own address on all DNS requests // (captive portal concept) @@ -522,16 +553,18 @@ void processConnectAPmode() { void processDisableAPmode() { if (!WiFiEventData.timerAPoff.isSet()) { return; } - if (!WifiIsAP(WiFi.getMode())) { + if (!ESPEasy::net::wifi::WifiIsAP(WiFi.getMode())) { return; } + // disable AP after timeout and no clients connected. if (WiFiEventData.timerAPoff.timeReached() && (WiFi.softAPgetStationNum() == 0)) { - setAP(false); + ESPEasy::net::wifi::setAP(false); } - if (!WifiIsAP(WiFi.getMode())) { + if (!ESPEasy::net::wifi::WifiIsAP(WiFi.getMode())) { WiFiEventData.timerAPoff.clear(); + if (WiFiEventData.wifiConnectAttemptNeeded) { // Force a reconnect cycle WifiDisconnect(); @@ -541,24 +574,28 @@ void processDisableAPmode() { void processScanDone() { WiFi_AP_Candidates.load_knownCredentials(); - if (WiFiEventData.processedScanDone) { return; } + if (WiFiEventData.processedScanDone) { return; } // Better act on the scan done event, as it may get triggered for normal wifi begin calls. int8_t scanCompleteStatus = WiFi.scanComplete(); - switch (scanCompleteStatus) { + + switch (scanCompleteStatus) + { case 0: // Nothing (yet) found + if (WiFiEventData.lastGetScanMoment.timeoutReached(5000)) { WiFi.scanDelete(); WiFiEventData.processedScanDone = true; } return; case -1: // WIFI_SCAN_RUNNING + // FIXME TD-er: Set timeout... if (WiFiEventData.lastGetScanMoment.timeoutReached(5000)) { - # ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_ERROR, F("WiFi : Scan Running Timeout")); + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_ERROR, F("WiFi : Scan Running Timeout")); #endif WiFi.scanDelete(); WiFiEventData.processedScanDone = true; @@ -573,11 +610,12 @@ void processScanDone() { WiFiEventData.lastGetScanMoment.setNow(); WiFiEventData.processedScanDone = true; -# ifndef BUILD_NO_DEBUG +#ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, concat(F("WiFi : Scan finished, found: "), scanCompleteStatus)); } -#endif +#endif // ifndef BUILD_NO_DEBUG #if !FEATURE_ESP8266_DIRECT_WIFI_SCAN WiFi_AP_Candidates.process_WiFiscan(scanCompleteStatus); @@ -587,14 +625,16 @@ void processScanDone() { if (WiFi_AP_Candidates.addedKnownCandidate() && !NetworkConnected()) { if (!WiFiEventData.wifiConnectInProgress) { WiFiEventData.wifiConnectAttemptNeeded = true; - # ifndef BUILD_NO_DEBUG + #ifndef BUILD_NO_DEBUG + if (WiFi_AP_Candidates.addedKnownCandidate()) { addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); } - #endif + #endif // ifndef BUILD_NO_DEBUG #ifdef ESP32 -// setSTA(false); -#endif + + // ESPEasy::net::wifi::setSTA(false); +#endif // ifdef ESP32 NetworkConnectRelaxed(); #ifdef USES_ESPEASY_NOW temp_disable_EspEasy_now_timer = millis() + 20000; @@ -605,7 +645,3 @@ void processScanDone() { } } - - - - diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp new file mode 100644 index 000000000..2cd0fe1f2 --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp @@ -0,0 +1,151 @@ +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" + +#if FEATURE_WIFI + +# include "../Globals/EventQueue.h" +# include "../Globals/Settings.h" +# include "../Globals/ESPEasyWiFiEvent.h" + +# include "../Helpers/StringConverter.h" + +namespace ESPEasy { +namespace net { +namespace wifi { + +const __FlashStringHelper* getWifiModeString(WiFiMode_t wifimode) +{ + switch (wifimode) + { + case WIFI_OFF: return F("OFF"); + case WIFI_STA: return F("STA"); + case WIFI_AP: return F("AP"); + case WIFI_AP_STA: return F("AP+STA"); + default: + break; + } + return F("Unknown"); +} + +bool setSTA(bool enable) { return setSTA_AP(enable, WifiIsAP(WiFi.getMode())); } + +bool setAP(bool enable) { return setSTA_AP(WifiIsSTA(WiFi.getMode()), enable); } + +bool setSTA_AP(bool sta_enable, bool ap_enable) +{ + if (ap_enable) { + return setWifiMode(sta_enable ? WIFI_AP_STA : WIFI_AP); + } + return setWifiMode(sta_enable ? WIFI_STA : WIFI_OFF); +} + +// ******************************************************************************** +// Configure WiFi TX power +// ******************************************************************************** +# if FEATURE_SET_WIFI_TX_PWR + +void SetWiFiTXpower() { + SetWiFiTXpower(0); // Just some minimal value, will be adjusted in SetWiFiTXpower +} + +void SetWiFiTXpower(float dBm) { SetWiFiTXpower(dBm, WiFi.RSSI()); } + +void SetWiFiTXpower(float dBm, float rssi) { + const WiFiMode_t cur_mode = WiFi.getMode(); + + if (cur_mode == WIFI_OFF) { + return; + } + + if (Settings.UseMaxTXpowerForSending()) { + dBm = 30; // Just some max, will be limited later + } + + // Range ESP32 : -1dBm - 20dBm + // Range ESP8266: 0dBm - 20.5dBm + float maxTXpwr; + float threshold = GetRSSIthreshold(maxTXpwr); + # ifdef ESP8266 + float minTXpwr{}; + # endif + # ifdef ESP32 + float minTXpwr = -1.0f; + # endif + + threshold += Settings.WiFi_sensitivity_margin; // Margin in dBm on top of threshold + + // Assume AP sends with max set by ETSI standard. + // 2.4 GHz: 100 mWatt (20 dBm) + // US and some other countries allow 1000 mW (30 dBm) + // We cannot send with over 20 dBm, thus it makes no sense to force higher TX power all the time. + const float newrssi = rssi - 20; + + if (newrssi < threshold) { + minTXpwr = threshold - newrssi; + } + + if (minTXpwr > maxTXpwr) { + minTXpwr = maxTXpwr; + } + + if (dBm > maxTXpwr) { + dBm = maxTXpwr; + } else if (dBm < minTXpwr) { + dBm = minTXpwr; + } + + doSetWiFiTXpower(dBm); + + if (WiFiEventData.wifi_TX_pwr < dBm) { + // Will increase the TX power, give power supply of the unit some rest + delay(1); + } + + WiFiEventData.wifi_TX_pwr = dBm; + + delay(0); + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + const int TX_pwr_int = WiFiEventData.wifi_TX_pwr * 4; + const int maxTXpwr_int = maxTXpwr * 4; + + if (TX_pwr_int != maxTXpwr_int) { + static int last_log = -1; + + if (TX_pwr_int != last_log) { + last_log = TX_pwr_int; + String log = strformat( + F("WiFi : Set TX power to %ddBm sensitivity: %ddBm"), + static_cast(dBm), + static_cast(threshold)); + + if (rssi < 0) { + log += strformat(F(" RSSI: %ddBm"), static_cast(rssi)); + } + addLogMove(LOG_LEVEL_DEBUG, log); + } + } + } + # endif // ifndef BUILD_NO_DEBUG +} + +# endif // if FEATURE_SET_WIFI_TX_PWR + +int GetRSSI_quality() { + long rssi = WiFi.RSSI(); + + if (-50 < rssi) { return 10; } + + if (rssi <= -98) { return 0; } + rssi = rssi + 97; // Range 0..47 => 1..9 + return (rssi / 5) + 1; +} + +void setConnectionSpeed() { setConnectionSpeed(Settings.ForceWiFi_bg_mode()); } + +} // namespace wifi +} // namespace net +} // namespace ESPEasy + + +#endif // if FEATURE_WIFI diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h index da803cea5..4eab7584a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h @@ -3,27 +3,60 @@ #include "../../ESPEasy_common.h" +#if FEATURE_WIFI -#include "../DataTypes/WiFiConnectionProtocol.h" +# include "../DataTypes/WiFiConnectionProtocol.h" +# include "../DataTypes/WiFi_STA_connected_state.h" +# include "../DataTypes/WiFi_State.h" -#if defined(ESP8266) -#include "../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h" -# include -#endif // if defined(ESP8266) -#if defined(ESP32) -#include "../ESPEasyCore/ESPEasyWiFiEvent_ESP32.h" -# include -#endif // if defined(ESP32) +# if defined(ESP8266) +# include "../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h" +# include +# endif // if defined(ESP8266) +# if defined(ESP32) +# include "../ESPEasyCore/ESPEasyWiFiEvent_ESP32.h" +# include +# include +# endif // if defined(ESP32) -namespace ESPEasy_WiFi_abstraction { -bool WiFiConnected(); +namespace ESPEasy { +namespace net { +namespace wifi { -void WiFiDisconnect(); -bool WifiIsAP(WiFiMode_t wifimode); -bool WifiIsSTA(WiFiMode_t wifimode); +// Call before starting WiFi +bool WiFi_pre_setup(); +// Call before setting WiFi into STA mode +bool WiFi_pre_STA_setup(); + +STA_connected_state getSTA_connected_state(); + + +bool WiFiConnected(); + +void WiFiDisconnect(); + +// ******************************************************************************** +// Manage Wifi Modes +// ******************************************************************************** +bool WifiIsAP(WiFiMode_t wifimode); +bool WifiIsSTA(WiFiMode_t wifimode); + +const __FlashStringHelper* getWifiModeString(WiFiMode_t wifimode); + +bool setSTA(bool enable); +bool setAP(bool enable); +bool setSTA_AP(bool sta_enable, + bool ap_enable); + +bool setWifiMode(WiFiMode_t new_mode); + + +// ******************************************************************************** +// Event handlers +// ******************************************************************************** void removeWiFiEventHandler(); void registerWiFiEventHandler(); @@ -31,18 +64,36 @@ void registerWiFiEventHandler(); WiFiConnectionProtocol getConnectionProtocol(); float GetRSSIthreshold(float& maxTXpwr); -#if FEATURE_SET_WIFI_TX_PWR -void SetWiFiTXpower(float& dBm); -#endif // if FEATURE_SET_WIFI_TX_PWR +// ******************************************************************************** +// Configure WiFi TX power +// ******************************************************************************** + +# if FEATURE_SET_WIFI_TX_PWR +void SetWiFiTXpower(); +void SetWiFiTXpower(float dBm); +void SetWiFiTXpower(float dBm, + float rssi); + +// Actually set the TX power using platform specific calls. +void doSetWiFiTXpower(float& dBm); +# endif // if FEATURE_SET_WIFI_TX_PWR + +int GetRSSI_quality(); + +void setConnectionSpeed(); void setConnectionSpeed(bool ForceWiFi_bg_mode); void setWiFiNoneSleep(); void setWiFiEcoPowerMode(); void setWiFiDefaultPowerMode(); +void setWiFiCountryPolicyManual(); -} +} // namespace wifi +} // namespace net +} // namespace ESPEasy +#endif // if FEATURE_WIFI #endif // ifndef ESPEASYCORE_ESPEASYWIFI_ABSTRACTED_H diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index 01137da4c..4f7a25cee 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -1,23 +1,86 @@ #include "../ESPEasyCore/ESPEasyWifi_abstracted.h" -#ifdef ESP32 +#if FEATURE_WIFI +# ifdef ESP32 -# include "../Globals/ESPEasyWiFiEvent.h" -# include "../Globals/WiFi_AP_Candidates.h" -# include "../ESPEasyCore/ESPEasyWiFiEvent_ESP32.h" +# include "../Globals/ESPEasyWiFiEvent.h" +# include "../Globals/EventQueue.h" +# include "../Globals/Settings.h" +# include "../Globals/WiFi_AP_Candidates.h" +# include "../ESPEasyCore/ESPEasyWiFiEvent_ESP32.h" + +# include "../Helpers/StringConverter.h" -# include -# include // Needed to call ESP-IDF functions like esp_wifi_.... +# include "../ESPEasyCore/ESPEasyNetwork.h" // Needed for NetworkCreateRFCCompliantHostname, WiFi code should not include network code +# include "../ESPEasyCore/ESPEasyWifi.h" // Needed for WifiDisconnect. Maybe this should be moved to these 'abstract' files? -# include +# include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" -namespace ESPEasy_WiFi_abstraction { -bool WiFiConnected() { - return WiFi.isConnected(); +# include +# include // Needed to call ESP-IDF functions like esp_wifi_.... + +# include + + +namespace ESPEasy { +namespace net { +namespace wifi { + +bool WiFi_pre_setup() { + + registerWiFiEventHandler(); + WiFi.persistent(false); + + return setSTA_AP(false, false); } +bool WiFi_pre_STA_setup() +{ + if (!setSTA(true)) { return false; } + + WiFi.setAutoReconnect(false); + delay(10); + return true; +} + +STA_connected_state getSTA_connected_state() +{ + switch (WiFi.status()) + { + case WL_CONNECTED: + return STA_connected_state::Connected; + + case WL_NO_SSID_AVAIL: + return STA_connected_state::Error_Not_Found; + + case WL_CONNECT_FAILED: + case WL_CONNECTION_LOST: + return STA_connected_state::Error_Connect_Failed; + + case WL_NO_SHIELD: + case WL_STOPPED: + case WL_IDLE_STATUS: + case WL_SCAN_COMPLETED: + case WL_DISCONNECTED: + // ToDo TD-er: What to do here? Should we add some disconnected state? + break; + + } + + // TODO: Keep track of whether connection is in progress + // The status() function does not return a reply stating "connecting" + + /* if (_sta_connecting) { + return STA_connected_state::Connecting; + } + */ + return STA_connected_state::Idle; +} + +bool WiFiConnected() { return WiFi.isConnected(); } + void WiFiDisconnect() { removeWiFiEventHandler(); WiFi.disconnect(); @@ -31,14 +94,138 @@ void WiFiDisconnect() { } } -bool WifiIsAP(WiFiMode_t wifimode) -{ - return (wifimode == WIFI_MODE_AP) || (wifimode == WIFI_MODE_APSTA); -} +bool WifiIsAP(WiFiMode_t wifimode) { return (wifimode == WIFI_MODE_AP) || (wifimode == WIFI_MODE_APSTA); } -bool WifiIsSTA(WiFiMode_t wifimode) +bool WifiIsSTA(WiFiMode_t wifimode) { return (wifimode & WIFI_MODE_STA) != 0; } + +bool setWifiMode(WiFiMode_t new_mode) { - return (wifimode & WIFI_MODE_STA) != 0; + const WiFiMode_t cur_mode = WiFi.getMode(); + + // Made this static flag an int as ESP8266 and ESP32 differ in the "not set" values + static int8_t processing_wifi_mode = -1; + + if (cur_mode == new_mode) { + return true; + } + + if (processing_wifi_mode == static_cast(new_mode)) { + // Prevent loops + return true; + } + processing_wifi_mode = static_cast(new_mode); + + + if (cur_mode == WIFI_OFF) { + # if defined(ESP32) + + // Needs to be set while WiFi is off + WiFi.hostname(NetworkCreateRFCCompliantHostname()); + # endif // if defined(ESP32) + WiFiEventData.markWiFiTurnOn(); + } + + if (new_mode != WIFI_OFF) { + # ifdef ESP8266 + + // See: https://github.com/esp8266/Arduino/issues/6172#issuecomment-500457407 + WiFi.forceSleepWake(); // Make sure WiFi is really active. + # endif // ifdef ESP8266 + delay(100); + } else { + WifiDisconnect(); + + // delay(100); + processDisconnect(); + WiFiEventData.clear_processed_flags(); + } + + addLog(LOG_LEVEL_INFO, concat(F("WIFI : Set WiFi to "), getWifiModeString(new_mode))); + + int retry = 2; + + while (!WiFi.mode(new_mode) && retry > 0) { + delay(100); + --retry; + } + retry = 2; + + while (WiFi.getMode() != new_mode && retry > 0) { + addLog(LOG_LEVEL_INFO, F("WIFI : mode not yet set")); + delay(100); + --retry; + } + + if (WiFi.getMode() != new_mode) { + addLog(LOG_LEVEL_ERROR, F("WIFI : Cannot set mode!!!!!")); + return false; + } + + + if (new_mode == WIFI_OFF) { + + // FIXME TD-er: Is this correct to mark Turn ON ???? + WiFiEventData.markWiFiTurnOn(); + # if defined(ESP32) + + // Needs to be set while WiFi is off + WiFi.hostname(NetworkCreateRFCCompliantHostname()); + # endif // if defined(ESP32) + delay(100); + # if defined(ESP32) + esp_wifi_set_ps(WIFI_PS_NONE); + + // esp_wifi_set_ps(WIFI_PS_MAX_MODEM); + # endif // if defined(ESP32) + # ifdef ESP8266 + WiFi.forceSleepBegin(); + # endif // ifdef ESP8266 + delay(1); + } else { + if (cur_mode == WIFI_OFF) { + registerWiFiEventHandler(); + } + + // Only set power mode when AP is not enabled + // When AP is enabled, the sleep mode is already set to WIFI_NONE_SLEEP + if (!WifiIsAP(new_mode)) { + if (Settings.WifiNoneSleep()) { + setWiFiNoneSleep(); + } else if (Settings.EcoPowerMode()) { + setWiFiEcoPowerMode(); + } else { + // Default + setWiFiDefaultPowerMode(); + } + } +# if FEATURE_SET_WIFI_TX_PWR + SetWiFiTXpower(); +# endif + + if (WifiIsSTA(new_mode)) { + // WiFi.setAutoConnect(Settings.SDK_WiFi_autoreconnect()); + WiFi.setAutoReconnect(Settings.SDK_WiFi_autoreconnect()); + } + delay(100); // Must allow for some time to init. + } + const bool new_mode_AP_enabled = WifiIsAP(new_mode); + + if (WifiIsAP(cur_mode) && !new_mode_AP_enabled) { + eventQueue.add(F("WiFi#APmodeDisabled")); + } + + if (WifiIsAP(cur_mode) != new_mode_AP_enabled) { + // Mode has changed + setAPinternal(new_mode_AP_enabled); + } + # if FEATURE_MDNS + # ifdef ESP8266 + + // notifyAPChange() is not present in the ESP32 MDNSResponder + MDNS.notifyAPChange(); + # endif // ifdef ESP8266 + # endif // if FEATURE_MDNS + return true; } void removeWiFiEventHandler() @@ -56,9 +243,12 @@ void registerWiFiEventHandler() } float GetRSSIthreshold(float& maxTXpwr) { + maxTXpwr = Settings.getWiFi_TX_power(); + float threshold = WIFI_SENSITIVITY_n; - switch (getConnectionProtocol()) { + switch (getConnectionProtocol()) + { case WiFiConnectionProtocol::WiFi_Protocol_11b: threshold = WIFI_SENSITIVITY_11b; @@ -77,11 +267,11 @@ float GetRSSIthreshold(float& maxTXpwr) { if (maxTXpwr > MAX_TX_PWR_DBM_n) { maxTXpwr = MAX_TX_PWR_DBM_n; } break; -# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) +# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) case WiFiConnectionProtocol::WiFi_Protocol_11a: case WiFiConnectionProtocol::WiFi_Protocol_VHT20: // FIXME TD-er: Must determine max. TX power for these 5 GHz modi -# endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) +# endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) case WiFiConnectionProtocol::WiFi_Protocol_LR: case WiFiConnectionProtocol::Unknown: break; @@ -95,26 +285,28 @@ WiFiConnectionProtocol getConnectionProtocol() wifi_phy_mode_t phymode; esp_wifi_sta_get_negotiated_phymode(&phymode); - switch (phymode) { + switch (phymode) + { case WIFI_PHY_MODE_11B: return WiFiConnectionProtocol::WiFi_Protocol_11b; case WIFI_PHY_MODE_11G: return WiFiConnectionProtocol::WiFi_Protocol_11g; case WIFI_PHY_MODE_HT20: return WiFiConnectionProtocol::WiFi_Protocol_HT20; case WIFI_PHY_MODE_HT40: return WiFiConnectionProtocol::WiFi_Protocol_HT40; case WIFI_PHY_MODE_HE20: return WiFiConnectionProtocol::WiFi_Protocol_HE20; case WIFI_PHY_MODE_LR: return WiFiConnectionProtocol::WiFi_Protocol_LR; -# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) +# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) // 5 GHz case WIFI_PHY_MODE_11A: return WiFiConnectionProtocol::WiFi_Protocol_11a; case WIFI_PHY_MODE_VHT20: return WiFiConnectionProtocol::WiFi_Protocol_VHT20; -# endif // if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) +# endif // if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) } } return WiFiConnectionProtocol::Unknown; } -# if FEATURE_SET_WIFI_TX_PWR -void SetWiFiTXpower(float& dBm) +# if FEATURE_SET_WIFI_TX_PWR + +void doSetWiFiTXpower(float& dBm) { int8_t power = dBm * 4; @@ -125,7 +317,7 @@ void SetWiFiTXpower(float& dBm) } } -# endif // if FEATURE_SET_WIFI_TX_PWR +# endif // if FEATURE_SET_WIFI_TX_PWR void setConnectionSpeed(bool ForceWiFi_bg_mode) { // Does not (yet) work, so commented out. @@ -143,12 +335,13 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { if (!ForceWiFi_bg_mode || (WiFiEventData.connectionFailures > 10)) { // Set to use BGN protocol |= WIFI_PROTOCOL_11N; - #ifdef ESP32C6 + # ifdef ESP32C6 protocol |= WIFI_PROTOCOL_11AX; - #endif + # endif } const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); + if (candidate.phy_known()) { // Check to see if the access point is set to "N-only" if ((protocol & WIFI_PROTOCOL_11N) == 0) { @@ -158,48 +351,46 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { protocol |= WIFI_PROTOCOL_11N; addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11n only")); } -#ifdef ESP32C6 +# ifdef ESP32C6 + if (candidate.bits.phy_11ax) { // Set to use WiFi6 protocol |= WIFI_PROTOCOL_11AX; addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11ax")); } -#endif +# endif // ifdef ESP32C6 } } } - if (ESPEasy_WiFi_abstraction::WifiIsSTA(WiFi.getMode())) { + if (WifiIsSTA(WiFi.getMode())) { // Set to use "Long GI" making it more resilliant to reflections // See: https://www.tp-link.com/us/configuration-guides/q_a_basic_wireless_concepts/?configurationId=2958#_idTextAnchor038 esp_wifi_config_80211_tx_rate(WIFI_IF_STA, WIFI_PHY_RATE_MCS3_LGI); esp_wifi_set_protocol(WIFI_IF_STA, protocol); } - if (ESPEasy_WiFi_abstraction::WifiIsAP(WiFi.getMode())) { + if (WifiIsAP(WiFi.getMode())) { esp_wifi_set_protocol(WIFI_IF_AP, protocol); } } -void setWiFiNoneSleep() -{ - WiFi.setSleep(WIFI_PS_NONE); -} +void setWiFiNoneSleep() { WiFi.setSleep(WIFI_PS_NONE); } void setWiFiEcoPowerMode() { // Allow light sleep during idle times -# ifdef ESP8266 +# ifdef ESP8266 WiFi.setSleepMode(WIFI_LIGHT_SLEEP); -# endif // ifdef ESP8266 -# ifdef ESP32 +# endif // ifdef ESP8266 +# ifdef ESP32 // Maximum modem power saving. // In this mode, interval to receive beacons is determined by the listen_interval parameter in wifi_sta_config_t // FIXME TD-er: Must test if this is desired behavior in ESP32. WiFi.setSleep(WIFI_PS_MAX_MODEM); -# endif // ifdef ESP32 +# endif // ifdef ESP32 } void setWiFiDefaultPowerMode() @@ -209,11 +400,21 @@ void setWiFiDefaultPowerMode() WiFi.setSleep(WIFI_PS_MIN_MODEM); } +void setWiFiCountryPolicyManual() +{ + wifi_country_t config = { + .cc = "01", + .schan = 1, + .nchan = 14, + .policy = WIFI_COUNTRY_POLICY_MANUAL, + }; + esp_wifi_set_country(&config); +} +} // namespace wifi +} // namespace net +} // namespace ESPEasy - -} // namespace ESPEasy_WiFi_abstraction - - -#endif // ifdef ESP32 +# endif // ifdef ESP32 +#endif // if FEATURE_WIFI diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp index f09f4216e..a4891c5b9 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp @@ -1,43 +1,72 @@ #include "../ESPEasyCore/ESPEasyWifi_abstracted.h" -#ifdef ESP8266 +#if FEATURE_WIFI +# ifdef ESP8266 -# include "../Globals/ESPEasyWiFiEvent.h" -# include "../Globals/WiFi_AP_Candidates.h" +# include "../Helpers/StringConverter.h" -# include "../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h" +# include "../Globals/ESPEasyWiFiEvent.h" +# include "../Globals/Settings.h" +# include "../Globals/WiFi_AP_Candidates.h" -namespace ESPEasy_WiFi_abstraction { -bool WiFiConnected() +# include "../ESPEasyCore/ESPEasyWiFiEvent_ESP8266.h" + +namespace ESPEasy { +namespace net { +namespace wifi { + +bool WiFi_pre_setup() { + registerWiFiEventHandler(); + + setSTA_AP(false, false); + delay(100); + return true; +} + +bool WiFi_pre_STA_setup() { + if (! setSTA(true)) { return false; } + + // Assign to 2 separate bools to make sure both are executed. + const bool autoConnect = WiFi.setAutoConnect(false); + const bool autoReconnect = WiFi.setAutoReconnect(false); + + if (!autoConnect || !autoReconnect) { + addLog(LOG_LEVEL_ERROR, F("WiFi : Disabling auto (re)connect failed")); + } + delay(100); + return true; +} + +STA_connected_state getSTA_connected_state() { - bool wifi_isconnected = WiFi.isConnected(); - // Perform check on SDK function, see: https://github.com/esp8266/Arduino/issues/7432 station_status_t status = wifi_station_get_connect_status(); - switch (status) { + switch (status) + { case STATION_GOT_IP: - wifi_isconnected = true; - break; + return STA_connected_state::Connected; case STATION_NO_AP_FOUND: + return STA_connected_state::Error_Not_Found; case STATION_CONNECT_FAIL: case STATION_WRONG_PASSWORD: - wifi_isconnected = false; - break; - case STATION_IDLE: + return STA_connected_state::Error_Connect_Failed; case STATION_CONNECTING: + return STA_connected_state::Connecting; + case STATION_IDLE: break; default: - wifi_isconnected = false; break; } - return wifi_isconnected; + return STA_connected_state::Idle; } +bool WiFiConnected() { return getSTA_connected_state() == STA_connected_state::Connected; } + void WiFiDisconnect() { // Only call disconnect when STA is active - if (ESPEasy_WiFi_abstraction::WifiIsSTA(WiFi.getMode())) { + if ( WifiIsSTA(WiFi.getMode())) { wifi_station_disconnect(); } station_config conf{}; @@ -47,14 +76,170 @@ void WiFiDisconnect() { ETS_UART_INTR_ENABLE(); } -bool WifiIsAP(WiFiMode_t wifimode) -{ - return (wifimode == WIFI_AP) || (wifimode == WIFI_AP_STA); -} +bool WifiIsAP(WiFiMode_t wifimode) { return (wifimode == WIFI_AP) || (wifimode == WIFI_AP_STA); } -bool WifiIsSTA(WiFiMode_t wifimode) +bool WifiIsSTA(WiFiMode_t wifimode) { return (wifimode & WIFI_STA) != 0; } + +bool setWifiMode(WiFiMode_t new_mode) { - return (wifimode & WIFI_STA) != 0; + const WiFiMode_t cur_mode = WiFi.getMode(); + + // Made this static flag an int as ESP8266 and ESP32 differ in the "not set" values + static int8_t processing_wifi_mode = -1; + + if (cur_mode == new_mode) { + return true; + } + + if (processing_wifi_mode == static_cast(new_mode)) { + // Prevent loops + return true; + } + processing_wifi_mode = static_cast(new_mode); + + + if (! WifiIsSTA(new_mode)) { + // calls lwIP's dhcp_stop(), + // safe to call even if not started + // See: https://github.com/esp8266/Arduino/pull/5703/files + wifi_station_dhcpc_stop(); + } + + if (new_mode != WIFI_OFF) { + // See: https://github.com/esp8266/Arduino/issues/6172#issuecomment-500457407 + WiFi.forceSleepWake(); // Make sure WiFi is really active. + delay(100); + } + + addLog(LOG_LEVEL_INFO, concat(F("WIFI : Set WiFi to "), getWifiModeString(new_mode))); + + int retry = 2; + + while (!WiFi.mode(new_mode) && retry > 0) { + delay(100); + --retry; + } + retry = 2; + + while (WiFi.getMode() != new_mode && retry > 0) { + addLog(LOG_LEVEL_INFO, F("WIFI : mode not yet set")); + delay(100); + --retry; + } + + if (WiFi.getMode() != new_mode) { + addLog(LOG_LEVEL_ERROR, F("WIFI : Cannot set mode!!!!!")); + return false; + } + + + if (new_mode == WIFI_OFF) { + WiFi.forceSleepBegin(); + delay(1); + } + + + /* + if (cur_mode == WIFI_OFF) { + #if defined(ESP32) + // Needs to be set while WiFi is off + WiFi.hostname(NetworkCreateRFCCompliantHostname()); + #endif + WiFiEventData.markWiFiTurnOn(); + } + if (new_mode != WIFI_OFF) { + #ifdef ESP8266 + // See: https://github.com/esp8266/Arduino/issues/6172#issuecomment-500457407 + WiFi.forceSleepWake(); // Make sure WiFi is really active. + #endif + delay(100); + } else { + WifiDisconnect(); + // delay(100); + processDisconnect(); + WiFiEventData.clear_processed_flags(); + } + + addLog(LOG_LEVEL_INFO, concat(F("WIFI : Set WiFi to "), getWifiModeString(new_mode))); + + int retry = 2; + while (!WiFi.mode(new_mode) && retry > 0) { + delay(100); + --retry; + } + retry = 2; + while (WiFi.getMode() != new_mode && retry > 0) { + addLog(LOG_LEVEL_INFO, F("WIFI : mode not yet set")); + delay(100); + --retry; + } + if (WiFi.getMode() != new_mode) { + addLog(LOG_LEVEL_ERROR, F("WIFI : Cannot set mode!!!!!")); + return false; + } + + + if (new_mode == WIFI_OFF) { + + // FIXME TD-er: Is this correct to mark Turn ON ???? + WiFiEventData.markWiFiTurnOn(); + #if defined(ESP32) + // Needs to be set while WiFi is off + WiFi.hostname(NetworkCreateRFCCompliantHostname()); + #endif + delay(100); + #if defined(ESP32) + esp_wifi_set_ps(WIFI_PS_NONE); + // esp_wifi_set_ps(WIFI_PS_MAX_MODEM); + #endif + #ifdef ESP8266 + WiFi.forceSleepBegin(); + #endif // ifdef ESP8266 + delay(1); + } else { + if (cur_mode == WIFI_OFF) { + registerWiFiEventHandler(); + } + // Only set power mode when AP is not enabled + // When AP is enabled, the sleep mode is already set to WIFI_NONE_SLEEP + if (! WifiIsAP(new_mode)) { + if (Settings.WifiNoneSleep()) { + setWiFiNoneSleep(); + } else if (Settings.EcoPowerMode()) { + setWiFiEcoPowerMode(); + } else { + // Default + setWiFiDefaultPowerMode(); + } + } + #if FEATURE_SET_WIFI_TX_PWR + SetWiFiTXpower(); + #endif + if ( WifiIsSTA(new_mode)) { + // WiFi.setAutoConnect(Settings.SDK_WiFi_autoreconnect()); + WiFi.setAutoReconnect(Settings.SDK_WiFi_autoreconnect()); + } + delay(100); // Must allow for some time to init. + } + const bool new_mode_AP_enabled = WifiIsAP(new_mode); + + if ( WifiIsAP(cur_mode) && !new_mode_AP_enabled) { + eventQueue.add(F("WiFi#APmodeDisabled")); + } + + if ( WifiIsAP(cur_mode) != new_mode_AP_enabled) { + // Mode has changed + setAPinternal(new_mode_AP_enabled); + } + */ +# if FEATURE_MDNS + # ifdef ESP8266 + + // notifyAPChange() is not present in the ESP32 MDNSResponder + MDNS.notifyAPChange(); + # endif // ifdef ESP8266 + # endif // if FEATURE_MDNS + return true; } void removeWiFiEventHandler() { @@ -79,9 +264,12 @@ void registerWiFiEventHandler() } float GetRSSIthreshold(float& maxTXpwr) { + maxTXpwr = Settings.getWiFi_TX_power(); + float threshold = WIFI_SENSITIVITY_n; - switch (getConnectionProtocol()) { + switch (getConnectionProtocol()) + { case WiFiConnectionProtocol::WiFi_Protocol_11b: threshold = WIFI_SENSITIVITY_11b; @@ -106,7 +294,8 @@ float GetRSSIthreshold(float& maxTXpwr) { WiFiConnectionProtocol getConnectionProtocol() { if (WiFi.RSSI() < 0) { - switch (wifi_get_phy_mode()) { + switch (wifi_get_phy_mode()) + { case PHY_MODE_11B: return WiFiConnectionProtocol::WiFi_Protocol_11b; case PHY_MODE_11G: @@ -118,20 +307,20 @@ WiFiConnectionProtocol getConnectionProtocol() return WiFiConnectionProtocol::Unknown; } -# if FEATURE_SET_WIFI_TX_PWR -void SetWiFiTXpower(float& dBm) -{ - WiFi.setOutputPower(dBm); -} +# if FEATURE_SET_WIFI_TX_PWR -# endif // if FEATURE_SET_WIFI_TX_PWR +void doSetWiFiTXpower(float& dBm) { WiFi.setOutputPower(dBm); } + +# endif // if FEATURE_SET_WIFI_TX_PWR void setConnectionSpeed(bool ForceWiFi_bg_mode) { // ESP8266 only supports 802.11g mode when running in STA+AP - const bool forcedByAPmode = ESPEasy_WiFi_abstraction::WifiIsAP(WiFi.getMode()); - WiFiPhyMode_t phyMode = (ForceWiFi_bg_mode || forcedByAPmode) ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N; + const bool forcedByAPmode = WifiIsAP(WiFi.getMode()); + WiFiPhyMode_t phyMode = (ForceWiFi_bg_mode || forcedByAPmode) ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N; + if (!forcedByAPmode) { const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); + if (candidate.phy_known() && (candidate.bits.phy_11g != candidate.bits.phy_11n)) { if ((WIFI_PHY_MODE_11G == phyMode) && !candidate.bits.phy_11g) { phyMode = WIFI_PHY_MODE_11N; @@ -139,9 +328,10 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { } else if ((WIFI_PHY_MODE_11N == phyMode) && !candidate.bits.phy_11n) { phyMode = WIFI_PHY_MODE_11G; addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11g only")); - } + } } else { bool useAlternate = WiFiEventData.connectionFailures > 10; + if (useAlternate) { phyMode = (WIFI_PHY_MODE_11G == phyMode) ? WIFI_PHY_MODE_11N : WIFI_PHY_MODE_11G; } @@ -154,25 +344,25 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { if (WiFi.getPhyMode() == phyMode) { return; } - #ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = concat(F("WIFI : Set to 802.11"), (WIFI_PHY_MODE_11G == phyMode) ? 'g' : 'n'); + if (forcedByAPmode) { log += (F(" (AP+STA mode)")); } + if (Settings.ForceWiFi_bg_mode()) { log += F(" Force B/G mode"); } addLogMove(LOG_LEVEL_INFO, log); } - #endif + # endif // ifndef BUILD_NO_DEBUG WiFi.setPhyMode(phyMode); } -void setWiFiNoneSleep() -{ - WiFi.setSleepMode(WIFI_NONE_SLEEP); -} +void setWiFiNoneSleep() { WiFi.setSleepMode(WIFI_NONE_SLEEP); } void setWiFiEcoPowerMode() { @@ -180,17 +370,15 @@ void setWiFiEcoPowerMode() WiFi.setSleepMode(WIFI_LIGHT_SLEEP); } -void setWiFiDefaultPowerMode() -{ - WiFi.setSleepMode(WIFI_MODEM_SLEEP); +void setWiFiDefaultPowerMode() { WiFi.setSleepMode(WIFI_MODEM_SLEEP); } + +void setWiFiCountryPolicyManual() { + // Not yet implemented/required for ESP8266 } +} // namespace wifi +} // namespace net +} // namespace ESPEasy - - - - -} // namespace ESPEasy_WiFi_abstraction - - -#endif // ifdef ESP8266 +# endif // ifdef ESP8266 +#endif // if FEATURE_WIFI diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 84a6384a3..cf3cca101 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -10,6 +10,7 @@ #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyRules.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" #include "../ESPEasyCore/Serial.h" #include "../Globals/Cache.h" @@ -393,7 +394,7 @@ void ESPEasy_setup() if (initWiFi) { WiFi_AP_Candidates.clearCache(); WiFi_AP_Candidates.load_knownCredentials(); - setSTA(true); + ESPEasy::net::wifi::setSTA(true); if (!WiFi_AP_Candidates.hasCandidates()) { WiFiEventData.wifiSetup = true; RTC.clearLastWiFi(); // Must scan all channels @@ -416,14 +417,14 @@ void ESPEasy_setup() addLog(LOG_LEVEL_INFO, F("Setup: Scan all channels")); WifiScan(false); } -// setWifiMode(WIFI_OFF); +// ESPEasy::net::wifi::setWifiMode(WIFI_OFF); } #ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("WifiScan()")); #endif - // setWifiMode(WIFI_STA); + // ESPEasy::net::wifi::setWifiMode(WIFI_STA); checkRuleSets(); #ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("checkRuleSets()")); diff --git a/src/src/Helpers/Network.cpp b/src/src/Helpers/Network.cpp index 4d4d8cab8..0afe0376b 100644 --- a/src/src/Helpers/Network.cpp +++ b/src/src/Helpers/Network.cpp @@ -3,6 +3,7 @@ #include "../../ESPEasy_common.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../Globals/Settings.h" @@ -52,7 +53,7 @@ void statusLED(bool traffic) } // AP mode is active - else if (WifiIsAP(WiFi.getMode())) + else if ( ESPEasy::net::wifi::WifiIsAP(WiFi.getMode())) { nStatusValue = ((millis() >> 1) & PWMRANGE_FULL) - (PWMRANGE_FULL >> 2); // ramp up for 2 sec, 3/4 luminosity } diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 4d444567d..d34444883 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -12,6 +12,7 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../ESPEasyCore/ESPEasyRules.h" #include "../ESPEasyCore/Serial.h" #include "../Globals/ESPEasyWiFiEvent.h" @@ -490,7 +491,7 @@ void prepareShutdown(IntendedRebootReason_e reason) process_serialWriteBuffer(); flushAndDisconnectAllClients(); saveUserVarToRTC(); - setWifiMode(WIFI_OFF); + ESPEasy::net::wifi::setWifiMode(WIFI_OFF); ESPEASY_FS.end(); process_serialWriteBuffer(); delay(100); // give the node time to flush all before reboot or sleep diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 21b047aa4..7a4430166 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -144,12 +144,15 @@ bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { load_knownCredentials(); if (candidates.empty()) { - if (scanAllowed) { + return false; + +/* if (scanAllowed) { return false; } loadCandidatesFromScanned(); attemptsLeft = 1; if (candidates.empty()) { return false; } + */ } currentCandidate = candidates.front(); diff --git a/src/src/WebServer/AccessControl.cpp b/src/src/WebServer/AccessControl.cpp index 2723391ad..b463b3613 100644 --- a/src/src/WebServer/AccessControl.cpp +++ b/src/src/WebServer/AccessControl.cpp @@ -3,6 +3,7 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../Globals/SecuritySettings.h" #include "../Globals/Services.h" @@ -57,7 +58,7 @@ bool getIPallowedRange(IPAddress& low, IPAddress& high) switch (SecuritySettings.IPblockLevel) { case LOCAL_SUBNET_ALLOWED: - if (WifiIsAP(WiFi.getMode())) { + if ( ESPEasy::net::wifi::WifiIsAP(WiFi.getMode())) { // WiFi is active as accesspoint, do not check. return false; } @@ -114,7 +115,7 @@ boolean clientIPallowed() return true; } - if (WifiIsAP(WiFi.getMode())) { + if ( ESPEasy::net::wifi::WifiIsAP(WiFi.getMode())) { // @TD-er Fixme: Should match subnet of SoftAP. return true; } diff --git a/src/src/WebServer/ESPEasy_WebServer.cpp b/src/src/WebServer/ESPEasy_WebServer.cpp index 467efb1b1..b5311c349 100644 --- a/src/src/WebServer/ESPEasy_WebServer.cpp +++ b/src/src/WebServer/ESPEasy_WebServer.cpp @@ -53,6 +53,7 @@ #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyRules.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../Globals/CPlugins.h" #include "../Globals/Device.h" @@ -127,7 +128,7 @@ void sendHeadandTail_stdtemplate(bool Tail, bool rebooting) { sendHeadandTail(F("TmplStd"), Tail, rebooting); if (!Tail) { - if (!clientIPinSubnet() && WifiIsAP(WiFi.getMode()) && (WiFi.softAPgetStationNum() > 0)) { + if (!clientIPinSubnet() && ESPEasy::net::wifi::WifiIsAP(WiFi.getMode()) && (WiFi.softAPgetStationNum() > 0)) { addHtmlError(F("Warning: Connected via AP")); } diff --git a/src/src/WebServer/SetupPage.cpp b/src/src/WebServer/SetupPage.cpp index 373f98634..51ea58abb 100644 --- a/src/src/WebServer/SetupPage.cpp +++ b/src/src/WebServer/SetupPage.cpp @@ -13,6 +13,7 @@ # include "../ESPEasyCore/ESPEasyNetwork.h" # include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" # include "../Globals/ESPEasyWiFiEvent.h" # include "../Globals/NetworkState.h" @@ -250,7 +251,7 @@ void handle_setup_scan_and_show(const String& ssid, const String& other, const S WiFiMode_t cur_wifimode = WiFi.getMode(); WifiScan(false); scanCompleteStatus = WiFi_AP_Candidates.scanComplete(); - setWifiMode(cur_wifimode); + ESPEasy::net::wifi::setWifiMode(cur_wifimode); } diff --git a/src/src/WebServer/WiFiScanner.cpp b/src/src/WebServer/WiFiScanner.cpp index 88a530219..207e23413 100644 --- a/src/src/WebServer/WiFiScanner.cpp +++ b/src/src/WebServer/WiFiScanner.cpp @@ -5,6 +5,7 @@ #include "../WebServer/HTML_wrappers.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../Globals/WiFi_AP_Candidates.h" #include "../Helpers/StringGenerator_WiFi.h" @@ -31,7 +32,7 @@ void handle_wifiscanner_json() { if (WiFi_AP_Candidates.scanComplete() <= 0) { WiFiMode_t cur_wifimode = WiFi.getMode(); WifiScan(false); - setWifiMode(cur_wifimode); + ESPEasy::net::wifi::setWifiMode(cur_wifimode); } for (auto it = WiFi_AP_Candidates.scanned_begin(); it != WiFi_AP_Candidates.scanned_end(); ++it) @@ -68,7 +69,7 @@ void handle_wifiscanner() { WiFiMode_t cur_wifimode = WiFi.getMode(); WifiScan(false); int8_t scanCompleteStatus = WiFi_AP_Candidates.scanComplete(); - setWifiMode(cur_wifimode); + ESPEasy::net::wifi::setWifiMode(cur_wifimode); navMenuIndex = MENU_INDEX_TOOLS; TXBuffer.startStream(); diff --git a/uncrustify.cfg b/uncrustify.cfg index 72537534e..2ece31b8d 100644 --- a/uncrustify.cfg +++ b/uncrustify.cfg @@ -950,7 +950,7 @@ indent_namespace = false # true/false # Whether to indent only the first namespace, and not any nested namespaces. # Requires indent_namespace=true. -indent_namespace_single_indent = false # true/false +indent_namespace_single_indent = true # true/false # The number of spaces to indent a namespace block. # If set to zero, use the value indent_columns @@ -1242,7 +1242,7 @@ indent_ignore_asm_block = false # true/false nl_collapse_empty_body = true # true/false # Don't split one-line braced assignments, as in 'foo_t f = { 1, 2 };'. -nl_assign_leave_one_liners = false # true/false +nl_assign_leave_one_liners = true # true/false # Don't split one-line braced statements inside a 'class xx { }' body. nl_class_leave_one_liners = false # true/false @@ -1251,19 +1251,19 @@ nl_class_leave_one_liners = false # true/false nl_enum_leave_one_liners = false # true/false # Don't split one-line get or set functions. -nl_getset_leave_one_liners = false # true/false +nl_getset_leave_one_liners = true # true/false # (C#) Don't split one-line property get or set functions. nl_cs_property_leave_one_liners = false # true/false # Don't split one-line function definitions, as in 'int foo() { return 0; }'. -nl_func_leave_one_liners = false # true/false +nl_func_leave_one_liners = true # true/false # Don't split one-line C++11 lambdas, as in '[]() { return 0; }'. nl_cpp_lambda_leave_one_liners = false # true/false # Don't split one-line if/else statements, as in 'if(...) b++;'. -nl_if_leave_one_liners = false # true/false +nl_if_leave_one_liners = true # true/false # Don't split one-line while statements, as in 'while(...) b++;'. nl_while_leave_one_liners = false # true/false @@ -1410,16 +1410,16 @@ nl_using_brace = ignore # ignore/add/remove/force # Add or remove newline between two open or close braces. Due to general # newline/brace handling, REMOVE may not work. -nl_brace_brace = ignore # ignore/add/remove/force +nl_brace_brace = add # ignore/add/remove/force # Add or remove newline between 'do' and '{'. -nl_do_brace = ignore # ignore/add/remove/force +nl_do_brace = add # ignore/add/remove/force # Add or remove newline between '}' and 'while' of 'do' statement. nl_brace_while = ignore # ignore/add/remove/force # Add or remove newline between 'switch' and '{'. -nl_switch_brace = ignore # ignore/add/remove/force +nl_switch_brace = add # ignore/add/remove/force # Add or remove newline between 'synchronized' and '{'. nl_synchronized_brace = ignore # ignore/add/remove/force @@ -1429,7 +1429,7 @@ nl_synchronized_brace = ignore # ignore/add/remove/force # # Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch and # nl_catch_brace. -nl_multi_line_cond = false # true/false +nl_multi_line_cond = true # true/false # Force a newline in a define after the macro name for multi-line defines. nl_multi_line_define = false # true/false @@ -1444,7 +1444,7 @@ nl_after_case = false # true/false # Add or remove newline between a case ':' and '{'. # # Overrides nl_after_case. -nl_case_colon_brace = ignore # ignore/add/remove/force +nl_case_colon_brace = add # ignore/add/remove/force # Add or remove newline between ')' and 'throw'. nl_before_throw = ignore # ignore/add/remove/force @@ -1456,7 +1456,7 @@ nl_namespace_brace = remove # ignore/add/remove/force nl_template_class = ignore # ignore/add/remove/force # Add or remove newline between 'class' and '{'. -nl_class_brace = remove # ignore/add/remove/force +nl_class_brace = add # ignore/add/remove/force # Add or remove newline before or after (depending on pos_class_comma, # may not be IGNORE) each',' in the base class list. @@ -1465,11 +1465,11 @@ nl_class_init_args = add # ignore/add/remove/force # Add or remove newline after each ',' in the constructor member # initialization. Related to nl_constr_colon, pos_constr_colon and # pos_constr_comma. -nl_constr_init_args = ignore # ignore/add/remove/force +nl_constr_init_args = add # ignore/add/remove/force # Add or remove newline before first element, after comma, and after last # element, in 'enum'. -nl_enum_own_lines = ignore # ignore/add/remove/force +nl_enum_own_lines = add # ignore/add/remove/force # Add or remove newline between return type and function name in a function # definition. @@ -1610,7 +1610,7 @@ nl_cpp_ldef_brace = ignore # ignore/add/remove/force nl_return_expr = ignore # ignore/add/remove/force # Whether to add a newline after semicolons, except in 'for' statements. -nl_after_semicolon = false # true/false +nl_after_semicolon = true # true/false # (Java) Add or remove newline between the ')' and '{{' of the double brace # initializer. @@ -1752,7 +1752,7 @@ nl_create_while_one_liner = true # true/false # Whether to collapse a function definition whose body (not counting braces) # is only one line so that the entire definition (prototype, braces, body) is # a single line. -nl_create_func_def_one_liner = false # true/false +nl_create_func_def_one_liner = true # true/false # Whether to split one-line simple unbraced if statements into two lines by # adding a newline, as in 'if(b) i++;'. @@ -1780,7 +1780,7 @@ nl_max_blank_in_func = 0 # unsigned number nl_before_func_body_proto = 0 # unsigned number # The number of newlines before a multi-line function definition. -nl_before_func_body_def = 0 # unsigned number +nl_before_func_body_def = 2 # unsigned number # The number of newlines before a class constructor/destructor prototype. nl_before_func_class_proto = 0 # unsigned number @@ -1789,7 +1789,7 @@ nl_before_func_class_proto = 0 # unsigned number nl_before_func_class_def = 0 # unsigned number # The number of newlines after a function prototype. -nl_after_func_proto = 0 # unsigned number +nl_after_func_proto = 1 # unsigned number # The number of newlines after a function prototype, if not followed by # another function prototype. @@ -1816,7 +1816,7 @@ nl_after_func_body = 2 # unsigned number # declaration. Also affects class constructors/destructors. # # Overrides nl_after_func_body. -nl_after_func_body_class = 0 # unsigned number +nl_after_func_body_class = 2 # unsigned number # The number of newlines after '}' of a single line function body. Also # affects class constructors/destructors. @@ -1884,13 +1884,13 @@ nl_after_multiline_comment = true # true/false nl_after_label_colon = false # true/false # The number of newlines after '}' or ';' of a struct/enum/union definition. -nl_after_struct = 0 # unsigned number +nl_after_struct = 2 # unsigned number # The number of newlines before a class definition. -nl_before_class = 0 # unsigned number +nl_before_class = 2 # unsigned number # The number of newlines after '}' or ';' of a class definition. -nl_after_class = 0 # unsigned number +nl_after_class = 2 # unsigned number # The number of newlines before an access specifier label. This also includes # the Qt-specific 'signals:' and 'slots:'. Will not change the newline count @@ -1944,10 +1944,10 @@ nl_property_brace = ignore # ignore/add/remove/force nl_inside_namespace = 0 # unsigned number # Whether to remove blank lines after '{'. -eat_blanks_after_open_brace = true # true/false +eat_blanks_after_open_brace = false # true/false # Whether to remove blank lines before '}'. -eat_blanks_before_close_brace = true # true/false +eat_blanks_before_close_brace = false # true/false # How aggressively to remove extra newlines not in preprocessor. # @@ -2531,11 +2531,11 @@ mod_add_long_function_closebrace_comment = 0 # unsigned number # If a namespace body exceeds the specified number of newlines and doesn't # have a comment after the close brace, a comment will be added. -mod_add_long_namespace_closebrace_comment = 0 # unsigned number +mod_add_long_namespace_closebrace_comment = 10 # unsigned number # If a class body exceeds the specified number of newlines and doesn't have a # comment after the close brace, a comment will be added. -mod_add_long_class_closebrace_comment = 0 # unsigned number +mod_add_long_class_closebrace_comment = 10 # unsigned number # If a switch body exceeds the specified number of newlines and doesn't have a # comment after the close brace, a comment will be added. @@ -2543,14 +2543,14 @@ mod_add_long_switch_closebrace_comment = 0 # unsigned number # If an #ifdef body exceeds the specified number of newlines and doesn't have # a comment after the #endif, a comment will be added. -mod_add_long_ifdef_endif_comment = 1 # unsigned number +mod_add_long_ifdef_endif_comment = 2 # unsigned number # If an #ifdef or #else body exceeds the specified number of newlines and # doesn't have a comment after the #else, a comment will be added. -mod_add_long_ifdef_else_comment = 1 # unsigned number +mod_add_long_ifdef_else_comment = 2 # unsigned number # Whether to sort consecutive single-line 'import' statements. -mod_sort_import = false # true/false +mod_sort_import = true # true/false # (C#) Whether to sort consecutive single-line 'using' statements. mod_sort_using = false # true/false From b5f360de1d21be90b987076bdbc06926d00b9a5f Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 3 Nov 2024 00:47:56 +0100 Subject: [PATCH 005/564] [WiFi] Start using simplified state machine for WiFi --- src/src/DataStructs/WiFiEventData.cpp | 2 +- src/src/DataTypes/WiFi_State.cpp | 31 + src/src/DataTypes/WiFi_State.h | 2 + .../ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 183 ++-- .../ESPEasyCore/ESPEasyWiFi_state_machine.h | 4 +- .../ESPEasyWiFi_state_machine_ESP32.cpp | 4 +- .../ESPEasyWiFi_state_machine_ESP8266.cpp | 2 +- src/src/ESPEasyCore/ESPEasyWifi.cpp | 896 ++++-------------- src/src/ESPEasyCore/ESPEasyWifi.h | 2 +- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 411 ++++---- .../ESPEasyWifi_abstracted_ESP32.cpp | 2 +- .../ESPEasyWifi_abstracted_ESP8266.cpp | 2 +- src/src/ESPEasyCore/ESPEasy_loop.cpp | 3 + src/src/Globals/ESPEasyWiFiEvent.cpp | 1 + src/src/Globals/ESPEasyWiFiEvent.h | 3 + src/src/Helpers/WiFi_AP_CandidatesList.cpp | 10 +- src/src/Helpers/WiFi_AP_CandidatesList.h | 4 +- 17 files changed, 580 insertions(+), 982 deletions(-) create mode 100644 src/src/DataTypes/WiFi_State.cpp diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index f34da0d7e..0996d94c4 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -160,7 +160,7 @@ void WiFiEventData_t::setWiFiConnected() { } void WiFiEventData_t::setWiFiServicesInitialized() { - if (!unprocessedWifiEvents() && WiFiConnected() && WiFiGotIP()) { + if (/*!unprocessedWifiEvents() && */ WiFiConnected() && WiFiGotIP()) { # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WiFi : WiFi services initialized")); #endif diff --git a/src/src/DataTypes/WiFi_State.cpp b/src/src/DataTypes/WiFi_State.cpp new file mode 100644 index 000000000..5aa6382d5 --- /dev/null +++ b/src/src/DataTypes/WiFi_State.cpp @@ -0,0 +1,31 @@ +#include "../DataTypes/WiFi_State.h" + +#if FEATURE_WIFI + + +namespace ESPEasy { +namespace net { +namespace wifi { + +const __FlashStringHelper* toString(WiFiState_e state) +{ + switch (state) + { + case ESPEasy::net::wifi::WiFiState_e::Disabled: return F("Disabled"); + case ESPEasy::net::wifi::WiFiState_e::OFF: return F("OFF"); + case ESPEasy::net::wifi::WiFiState_e::AP_only: return F("AP_only"); + case ESPEasy::net::wifi::WiFiState_e::IdleWaiting: return F("IdleWaiting"); + case ESPEasy::net::wifi::WiFiState_e::STA_Scanning: return F("STA_Scanning"); + case ESPEasy::net::wifi::WiFiState_e::STA_AP_Scanning: return F("STA_AP_Scanning"); + case ESPEasy::net::wifi::WiFiState_e::STA_Connecting: return F("STA_Connecting"); + case ESPEasy::net::wifi::WiFiState_e::STA_Reconnecting: return F("STA_Reconnecting"); + case ESPEasy::net::wifi::WiFiState_e::STA_Connected: return F("STA_Connected"); + } + return F(""); +} + +} // namespace wifi +} // namespace net +} // namespace ESPEasy + +#endif // if FEATURE_WIFI diff --git a/src/src/DataTypes/WiFi_State.h b/src/src/DataTypes/WiFi_State.h index 62d5ff9cf..f20ce86e3 100644 --- a/src/src/DataTypes/WiFi_State.h +++ b/src/src/DataTypes/WiFi_State.h @@ -85,6 +85,8 @@ enum class WiFiState_e }; +const __FlashStringHelper * toString(WiFiState_e state); + } // namespace wifi } // namespace net diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index 5cec46c7b..923a009ba 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -6,8 +6,9 @@ # include "../ESPEasyCore/ESPEasyWifi_abstracted.h" -#include "../ESPEasyCore/ESPEasyNetwork.h" // for setNetworkMedium, however this should not be part of the WiFi code +# include "../ESPEasyCore/ESPEasyNetwork.h" // for setNetworkMedium, however this should not be part of the WiFi code +# include "../ESPEasyCore/ESPEasy_Log.h" # include "../Globals/ESPEasyWiFiEvent.h" # include "../Globals/RTC.h" @@ -20,8 +21,8 @@ namespace ESPEasy { namespace net { namespace wifi { - # define WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT 20000 - # define WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT 20000 + # define WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT 2000 + # define WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT 10000 # define WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT 10000 void ESPEasyWiFi_t::setup() { @@ -44,12 +45,16 @@ void ESPEasyWiFi_t::enable() {} void ESPEasyWiFi_t::disable() {} -void ESPEasyWiFi_t::begin() {} +void ESPEasyWiFi_t::begin() { setState(WiFiState_e::IdleWaiting, 100); } void ESPEasyWiFi_t::loop() { + // TODO TD-er: Must inspect WiFiEventData to see if we need to update some state here. + + if (_state != WiFiState_e::IdleWaiting) { - if (_callbackError || (_state_timeout.isSet() && _state_timeout.timeReached())) + if (_callbackError || + (_state_timeout.isSet() && _state_timeout.timeReached())) { // TODO TD-er: Must check what error was given??? _callbackError = false; @@ -64,20 +69,20 @@ void ESPEasyWiFi_t::loop() break; case WiFiState_e::OFF: begin(); - setState(WiFiState_e::IdleWaiting, 100); + + // setState(WiFiState_e::IdleWaiting, 100); break; case WiFiState_e::AP_only: break; case WiFiState_e::IdleWaiting: - // Wait for timeout to expire if (_state_timeout.timeReached()) { // Do we have candidate to connect to ? if (WiFi_AP_Candidates.hasCandidates()) { setState(WiFiState_e::STA_Connecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); } else if (WifiIsAP(WiFi.getMode())) { - // TODO TD-er: Must check if any client is connected. - // If not, then we can disable AP mode and switch to WiFiState_e::STA_Scanning + // TODO TD-er: Must check if any client is connected. + // If not, then we can disable AP mode and switch to WiFiState_e::STA_Scanning setState(WiFiState_e::STA_AP_Scanning, WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT); } else { setState(WiFiState_e::STA_Scanning, WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT); @@ -86,6 +91,11 @@ void ESPEasyWiFi_t::loop() break; case WiFiState_e::STA_Scanning: case WiFiState_e::STA_AP_Scanning: + + if (_state_timeout.timeReached() || (WiFi.scanComplete() >= 0)) { + setState(WiFiState_e::OFF, 100); + } + // Check if scanning is finished // When scanning per channel, call for scanning next channel break; @@ -93,18 +103,21 @@ void ESPEasyWiFi_t::loop() case WiFiState_e::STA_Reconnecting: // Check if (re)connecting has finished - if (getSTA_connected_state() != STA_connected_state::Connecting) { - if (getSTA_connected_state() == STA_connected_state::Connected) { - setState(WiFiState_e::STA_Connected); + { + const STA_connected_state sta_connected_state = getSTA_connected_state(); + + if (sta_connected_state == STA_connected_state::Connected) { + setState(WiFiState_e::STA_Connected); + } else if (_state_timeout.timeReached()) { + if (_state == WiFiState_e::STA_Connecting) { + setState(WiFiState_e::STA_Reconnecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); } else { - if (_state == WiFiState_e::STA_Connecting) { - setState(WiFiState_e::STA_Reconnecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); - } else { - setState(WiFiState_e::OFF); - } + setState(WiFiState_e::OFF); } } + break; + } case WiFiState_e::STA_Connected: // Check if still connected @@ -130,6 +143,11 @@ void ESPEasyWiFi_t::loop() # endif // ifdef USE_IMPROV } +bool ESPEasyWiFi_t::connected() const +{ + return getSTA_connected_state() == STA_connected_state::Connected; +} + IPAddress ESPEasyWiFi_t::getIP() const { IPAddress res; @@ -140,6 +158,26 @@ IPAddress ESPEasyWiFi_t::getIP() const void ESPEasyWiFi_t::disconnect() {} void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog( + LOG_LEVEL_INFO, + concat(F("WiFi : Set state from: "), toString(_state)) + + concat(F(" to: "), toString(newState)) + + concat(F(" timeout: "), timeout)); + } + + if (timeout == 0) + { + _state_timeout.clear(); + + } else { + _state_timeout.setMillisFromNow(timeout); + } + + _last_state_change.setNow(); + _state = newState; + + switch (newState) { case WiFiState_e::Disabled: @@ -155,6 +193,7 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { break; case WiFiState_e::STA_Scanning: // Start scanning + startScanning(); break; case WiFiState_e::STA_AP_Scanning: // Start scanning per channel @@ -166,18 +205,9 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { break; case WiFiState_e::STA_Connected: _last_seen_connected.setNow(); + _state_timeout.clear(); break; } - - if (timeout == 0) - { - _state_timeout.clear(); - - } else { - _state_timeout.setMillisFromNow(timeout); - } - _last_state_change.setNow(); - _state = newState; } void ESPEasyWiFi_t::checkConnectProgress() {} @@ -216,7 +246,8 @@ bool ESPEasyWiFi_t::connectSTA() # endif // if defined(ESP8266) # if defined(ESP32) - WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + + // WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); # endif // if defined(ESP32) setConnectionSpeed(); setupStaticIPconfig(); @@ -224,59 +255,67 @@ bool ESPEasyWiFi_t::connectSTA() // Start the process of connecting or starting AP if (!WiFi_AP_Candidates.getNext(true)) { + startScanning(); return false; } - const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); + const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, strformat( - F("WIFI : Connecting %s attempt #%u"), - candidate.toString().c_str(), - _connect_attempt)); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, strformat( + F("WIFI : Connecting %s attempt #%u"), + candidate.toString().c_str(), + _connect_attempt)); + } + WiFiEventData.markWiFiBegin(); + + if (prepareWiFi()) { + setNetworkMedium(NetworkMedium_t::WIFI); + RTC.clearLastWiFi(); + RTC.lastWiFiSettingsIndex = candidate.index; + + float tx_pwr = 0; // Will be set higher based on RSSI when needed. + // FIXME TD-er: Must check WiFiEventData.wifi_connect_attempt to increase TX power +# if FEATURE_SET_WIFI_TX_PWR + + if (Settings.UseMaxTXpowerForSending()) { + tx_pwr = Settings.getWiFi_TX_power(); } - WiFiEventData.markWiFiBegin(); - if (prepareWiFi()) { - setNetworkMedium(NetworkMedium_t::WIFI); - RTC.clearLastWiFi(); - RTC.lastWiFiSettingsIndex = candidate.index; - - float tx_pwr = 0; // Will be set higher based on RSSI when needed. - // FIXME TD-er: Must check WiFiEventData.wifi_connect_attempt to increase TX power -#if FEATURE_SET_WIFI_TX_PWR - if (Settings.UseMaxTXpowerForSending()) { - tx_pwr = Settings.getWiFi_TX_power(); - } - SetWiFiTXpower(tx_pwr, candidate.rssi); -#endif - // Start connect attempt now, so no longer needed to attempt new connection. - WiFiEventData.wifiConnectAttemptNeeded = false; - WiFiEventData.wifiConnectInProgress = true; - const String key = WiFi_AP_CandidatesList::get_key(candidate.index); + SetWiFiTXpower(tx_pwr, candidate.rssi); +# endif // if FEATURE_SET_WIFI_TX_PWR -#if FEATURE_USE_IPV6 - if (Settings.EnableIPv6()) { - WiFi.enableIPv6(true); - } -#endif + // Start connect attempt now, so no longer needed to attempt new connection. + WiFiEventData.wifiConnectAttemptNeeded = false; + WiFiEventData.wifiConnectInProgress = true; + const String key = WiFi_AP_CandidatesList::get_key(candidate.index); -#ifdef ESP32 - if (Settings.IncludeHiddenSSID()) { - setWiFiCountryPolicyManual(); - } -#endif - - - if ((Settings.HiddenSSID_SlowConnectPerBSSID() || !candidate.bits.isHidden) - && candidate.allowQuickConnect()) { - WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); - } else { - WiFi.begin(candidate.ssid.c_str(), key.c_str()); - } - // Always wait for a second - WiFi.waitForConnectResult(1000); // https://github.com/arendst/Tasmota/issues/14985 +# if FEATURE_USE_IPV6 + if (Settings.EnableIPv6()) { + WiFi.enableIPv6(true); } +# endif // if FEATURE_USE_IPV6 + +# ifdef ESP32 + + if (Settings.IncludeHiddenSSID()) { + setWiFiCountryPolicyManual(); + } +# endif // ifdef ESP32 + + + if ((Settings.HiddenSSID_SlowConnectPerBSSID() || !candidate.bits.isHidden) + && candidate.allowQuickConnect() + && (_state == WiFiState_e::STA_Reconnecting)) { + WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); + } else { + WiFi.begin(candidate.ssid.c_str(), key.c_str()); + } + + // Always wait for a second + WiFi.waitForConnectResult(1000); // https://github.com/arendst/Tasmota/issues/14985 + + } return true; } diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h index 9ae2f044e..a5ec96ad0 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h @@ -44,6 +44,8 @@ public: return _state; } + bool connected() const; + // Get the IP-address in this order: // - STA interface if connected, // - AP interface if active @@ -67,7 +69,7 @@ private: bool connectSTA(); - STA_connected_state getSTA_connected_state(); + STA_connected_state getSTA_connected_state() const; WiFi_AP_Candidate _active_sta; WiFi_AP_Candidate _AP_conf; diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp index 96c546ef0..bdeeb3ea7 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp @@ -18,7 +18,7 @@ namespace ESPEasy { namespace net { namespace wifi { -STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() +STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() const { switch (WiFi.status()) { @@ -33,7 +33,7 @@ STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() return STA_connected_state::Error_Connect_Failed; case WL_IDLE_STATUS: - return STA_connected_state::Idle; + return STA_connected_state::Connecting; case WL_NO_SHIELD: diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp index 0cc60ec33..aad6d5367 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp @@ -10,7 +10,7 @@ namespace net { namespace wifi { -STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() +STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() const { // Perform check on SDK function, see: https://github.com/esp8266/Arduino/issues/7432 station_status_t status = wifi_station_get_connect_status(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 72f38eab2..994720c03 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -2,40 +2,39 @@ #if FEATURE_WIFI -#include "../../ESPEasy-Globals.h" -#include "../DataStructs/TimingStats.h" -#include "../ESPEasyCore/ESPEasyNetwork.h" -#include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" -#include "../ESPEasyCore/ESPEasy_Log.h" -#include "../ESPEasyCore/Serial.h" -#include "../Globals/ESPEasyWiFiEvent.h" -#include "../Globals/EventQueue.h" -#include "../Globals/NetworkState.h" -#include "../Globals/Nodes.h" -#include "../Globals/RTC.h" -#include "../Globals/SecuritySettings.h" -#include "../Globals/Services.h" -#include "../Globals/Settings.h" -#include "../Globals/WiFi_AP_Candidates.h" -#include "../Helpers/ESPEasy_time_calc.h" -#include "../Helpers/Hardware_defines.h" -#include "../Helpers/Misc.h" -#include "../Helpers/Networking.h" -#include "../Helpers/StringConverter.h" -#include "../Helpers/StringGenerator_WiFi.h" -#include "../Helpers/StringProvider.h" +# include "../../ESPEasy-Globals.h" +# include "../DataStructs/TimingStats.h" +# include "../ESPEasyCore/ESPEasyNetwork.h" +# include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" +# include "../ESPEasyCore/ESPEasy_Log.h" +# include "../ESPEasyCore/Serial.h" +# include "../Globals/ESPEasyWiFiEvent.h" +# include "../Globals/EventQueue.h" +# include "../Globals/NetworkState.h" +# include "../Globals/Nodes.h" +# include "../Globals/RTC.h" +# include "../Globals/SecuritySettings.h" +# include "../Globals/Services.h" +# include "../Globals/Settings.h" +# include "../Globals/WiFi_AP_Candidates.h" +# include "../Helpers/ESPEasy_time_calc.h" +# include "../Helpers/Hardware_defines.h" +# include "../Helpers/Misc.h" +# include "../Helpers/Networking.h" +# include "../Helpers/StringConverter.h" +# include "../Helpers/StringGenerator_WiFi.h" +# include "../Helpers/StringProvider.h" - -#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" +# include "../ESPEasyCore/ESPEasyWifi_abstracted.h" -#ifdef ESP32 -#include -#include // Needed to call ESP-IDF functions like esp_wifi_.... +# ifdef ESP32 +# include +# include // Needed to call ESP-IDF functions like esp_wifi_.... -#include -#endif +# include +# endif // ifdef ESP32 // ******************************************************************************** @@ -78,10 +77,10 @@ - Set timerAPstart when "valid WiFi connection" state is observed. - Disable timerAPstart when ESPEASY_WIFI_SERVICES_INITIALIZED wifi state is reached. - For the first attempt to connect after a cold boot (RTC values are 0), a WiFi scan will be + For the first attempt to connect after a cold boot (RTC values are 0), a WiFi scan will be performed to find the strongest known SSID. This will set RTC.lastBSSID and RTC.lastWiFiChannel - + Quick reconnect (using BSSID/channel of last connection) when both apply: - If wifi_connect_attempt < 3 - RTC.lastBSSID is known @@ -106,321 +105,28 @@ // ******************************************************************************** bool WiFiConnected() { START_TIMER; - - static bool recursiveCall = false; - static uint32_t lastCheckedTime = 0; - static bool lastState = false; - -#if FEATURE_USE_IPV6 - if (!WiFiEventData.processedGotIP6) { - processGotIPv6(); - } -#endif - - if (! ESPEasy::net::wifi::WifiIsSTA(WiFi.getMode())) { - lastState = false; - return lastState; - } - const int32_t timePassed = timePassedSince(lastCheckedTime); + if (lastCheckedTime != 0) { - if (timePassed < 100) { - if (WiFiEventData.lastDisconnectMoment.isSet() && - WiFiEventData.lastDisconnectMoment.millisPassedSince() > timePassed) - { - // Try to rate-limit the nr of calls to this function or else it will be called 1000's of times a second. - return lastState; - } - } if (timePassed < 10) { // Rate limit time spent in WiFiConnected() to max. 100x per sec to process the rest of this function - return lastState; + return ESPEasyWiFi.connected(); } - } - - - - if (WiFiEventData.unprocessedWifiEvents()) { return false; } - - bool wifi_isconnected = ESPEasy::net::wifi::WiFiConnected(); - - if (recursiveCall) return wifi_isconnected; - recursiveCall = true; - - - // For ESP82xx, do not rely on WiFi.status() with event based wifi. - const int32_t wifi_rssi = WiFi.RSSI(); - bool validWiFi = (wifi_rssi < 0) && wifi_isconnected && hasIPaddr(); - /* - if (validWiFi && WiFi.channel() != WiFiEventData.usedChannel) { - validWiFi = false; - } - */ - if (validWiFi != WiFiEventData.WiFiServicesInitialized()) { - // else wifiStatus is no longer in sync. - if (checkAndResetWiFi()) { - // Wifi has been reset, so no longer valid WiFi - validWiFi = false; - } - } - - if (validWiFi) { - // Connected, thus disable any timer to start AP mode. (except when in WiFi setup mode) - if (!WiFiEventData.wifiSetupConnect) { - WiFiEventData.timerAPstart.clear(); - } - STOP_TIMER(WIFI_ISCONNECTED_STATS); - recursiveCall = false; - // Only return true after some time since it got connected. -#if FEATURE_SET_WIFI_TX_PWR - SetWiFiTXpower(); -#endif - lastState = WiFiEventData.wifi_considered_stable || WiFiEventData.lastConnectMoment.timeoutReached(100); lastCheckedTime = millis(); - return lastState; } - if ((WiFiEventData.timerAPstart.isSet()) && WiFiEventData.timerAPstart.timeReached()) { - if (WiFiEventData.timerAPoff.isSet() && !WiFiEventData.timerAPoff.timeReached()) { - if (!Settings.DoNotStartAP()) { - // Timer reached, so enable AP mode. - if (! ESPEasy::net::wifi::WifiIsAP(WiFi.getMode())) { - if (!WiFiEventData.wifiConnectAttemptNeeded) { - addLog(LOG_LEVEL_INFO, F("WiFi : WiFiConnected(), start AP")); - WifiScan(false); - ESPEasy::net::wifi::setSTA(false); // Force reset WiFi + reduce power consumption - ESPEasy::net::wifi::setAP(true); - } - } - } - } else { - WiFiEventData.timerAPstart.clear(); - WiFiEventData.timerAPoff.clear(); - } - } - - - // When made this far in the code, we apparently do not have valid WiFi connection. - if (!WiFiEventData.timerAPstart.isSet() && ! ESPEasy::net::wifi::WifiIsAP(WiFi.getMode())) { - // First run we do not have WiFi connection any more, set timer to start AP mode - // Only allow the automatic AP mode in the first N minutes after boot. - if (getUptimeMinutes() < WIFI_ALLOW_AP_AFTERBOOT_PERIOD) { - WiFiEventData.timerAPstart.setMillisFromNow(WIFI_RECONNECT_WAIT); - // Fixme TD-er: Make this more elegant as it now needs to know about the extra time needed for the AP start timer. - WiFiEventData.timerAPoff.setMillisFromNow(WIFI_RECONNECT_WAIT + WIFI_AP_OFF_TIMER_DURATION); - } - } - - const bool timeoutReached = WiFiEventData.last_wifi_connect_attempt_moment.isSet() && - WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(2 * DEFAULT_WIFI_CONNECTION_TIMEOUT); - - if (timeoutReached && !WiFiEventData.wifiSetup) { - // It took too long to make a connection, set flag we need to try again - //if (!wifiAPmodeActivelyUsed()) { - WiFiEventData.wifiConnectAttemptNeeded = true; - //} - WiFiEventData.wifiConnectInProgress = false; - if (!WiFiEventData.WiFiDisconnected()) { - # ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, F("WiFi : wifiConnectTimeoutReached")); - #endif - WifiDisconnect(); - } - } - delay(0); - STOP_TIMER(WIFI_NOTCONNECTED_STATS); - recursiveCall = false; - return false; + ESPEasyWiFi.loop(); + return ESPEasyWiFi.connected(); } -void WiFiConnectRelaxed() { - if (!WiFiEventData.processedDisconnect) { - processDisconnect(); - } - if (!WiFiEventData.WiFiConnectAllowed() || WiFiEventData.wifiConnectInProgress) { - if (WiFiEventData.wifiConnectInProgress) { - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { - if (WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { - WiFiEventData.wifiConnectInProgress = false; - } - } - } - - if (WiFiEventData.wifiConnectInProgress) { - return; // already connected or connect attempt in progress need to disconnect first - } - } - if (!WiFiEventData.processedScanDone) { - // Scan is still active, so do not yet connect. - return; - } - - if (WiFiEventData.unprocessedWifiEvents()) { - # ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - String log = F("WiFi : Connecting not possible, unprocessed WiFi events: "); - if (!WiFiEventData.processedConnect) { - log += F(" conn"); - } - if (!WiFiEventData.processedDisconnect) { - log += F(" disconn"); - } - if (!WiFiEventData.processedGotIP) { - log += F(" gotIP"); - } -#if FEATURE_USE_IPV6 - if (!WiFiEventData.processedGotIP6) { - log += F(" gotIP6"); - } -#endif - - if (!WiFiEventData.processedDHCPTimeout) { - log += F(" DHCP_t/o"); - } - - addLogMove(LOG_LEVEL_ERROR, log); - logConnectionStatus(); - } - #endif - return; - } - - if (!WiFiEventData.wifiSetupConnect && wifiAPmodeActivelyUsed()) { - return; - } - - - // FIXME TD-er: Should not try to prepare when a scan is still busy. - // This is a logic error which may lead to strange issues if some kind of timeout happens and/or RF calibration was not OK. - // Split this function into separate parts, with the last part being the actual connect attempt either after a scan is complete or quick connect is possible. - - AttemptWiFiConnect(); -} +void WiFiConnectRelaxed() { AttemptWiFiConnect(); } void AttemptWiFiConnect() { - if (!WiFiEventData.wifiConnectAttemptNeeded) { - return; + if (!WiFiConnected()) { + ESPEasyWiFi.setup(); } - - if (WiFiEventData.wifiConnectInProgress) { - return; - } - - setNetworkMedium(NetworkMedium_t::WIFI); - if (active_network_medium != NetworkMedium_t::WIFI) - { - return; - } - - - if (WiFiEventData.wifiSetupConnect) { - // wifiSetupConnect is when run from the setup page. - RTC.clearLastWiFi(); // Force slow connect - WiFiEventData.wifi_connect_attempt = 0; - WiFiEventData.wifiSetupConnect = false; - if (WiFiEventData.timerAPoff.isSet()) { - WiFiEventData.timerAPoff.setMillisFromNow(WIFI_RECONNECT_WAIT + WIFI_AP_OFF_TIMER_DURATION); - } - } - - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { - if (!WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { - return; - } - } - - if (WiFiEventData.unprocessedWifiEvents()) { - return; - } - ESPEasy::net::wifi::setSTA(false); - - ESPEasy::net::wifi::setSTA(true); - - if (WiFi_AP_Candidates.getNext(WiFiScanAllowed())) { - const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, strformat( - F("WIFI : Connecting %s attempt #%u"), - candidate.toString().c_str(), - WiFiEventData.wifi_connect_attempt)); - } - WiFiEventData.markWiFiBegin(); - if (prepareWiFi()) { - setNetworkMedium(NetworkMedium_t::WIFI); - RTC.clearLastWiFi(); - RTC.lastWiFiSettingsIndex = candidate.index; - - float tx_pwr = 0; // Will be set higher based on RSSI when needed. - // FIXME TD-er: Must check WiFiEventData.wifi_connect_attempt to increase TX power -#if FEATURE_SET_WIFI_TX_PWR - if (Settings.UseMaxTXpowerForSending()) { - tx_pwr = Settings.getWiFi_TX_power(); - } - SetWiFiTXpower(tx_pwr, candidate.rssi); -#endif - // Start connect attempt now, so no longer needed to attempt new connection. - WiFiEventData.wifiConnectAttemptNeeded = false; - WiFiEventData.wifiConnectInProgress = true; - const String key = WiFi_AP_CandidatesList::get_key(candidate.index); - -#if FEATURE_USE_IPV6 - if (Settings.EnableIPv6()) { - WiFi.enableIPv6(true); - } -#endif - -#ifdef ESP32 - if (Settings.IncludeHiddenSSID()) { - wifi_country_t config = { - .cc = "01", - .schan = 1, - .nchan = 14, - .policy = WIFI_COUNTRY_POLICY_MANUAL, - }; - esp_wifi_set_country(&config); - } -#endif - - - if ((Settings.HiddenSSID_SlowConnectPerBSSID() || !candidate.bits.isHidden) - && candidate.allowQuickConnect()) { - WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); - } else { - WiFi.begin(candidate.ssid.c_str(), key.c_str()); - } -#ifdef ESP32 - // Always wait for a second on ESP32 - WiFi.waitForConnectResult(1000); // https://github.com/arendst/Tasmota/issues/14985 -#else - if (Settings.WaitWiFiConnect() || candidate.bits.isHidden) { -// WiFi.waitForConnectResult(candidate.isHidden ? 3000 : 1000); // https://github.com/arendst/Tasmota/issues/14985 - WiFi.waitForConnectResult(1000); // https://github.com/arendst/Tasmota/issues/14985 - } -#endif - delay(1); - } else { - WiFiEventData.wifiConnectInProgress = false; - } - } else { - if (!wifiAPmodeActivelyUsed() || WiFiEventData.wifiSetupConnect) { - if (!prepareWiFi()) { - //return; - } - - if (WiFiScanAllowed()) { - // Maybe not scan async to give the ESP some slack in power consumption? - const bool async = false; - WifiScan(async); - } - // Limit nr of attempts as we don't have any AP candidates. - WiFiEventData.last_wifi_connect_attempt_moment.setMillisFromNow(60000); - WiFiEventData.timerAPstart.setNow(); - } - } - logConnectionStatus(); } @@ -428,160 +134,50 @@ void AttemptWiFiConnect() { // Set Wifi config // ******************************************************************************** bool prepareWiFi() { - ESPEasy::net::wifi::registerWiFiEventHandler(); - - if (!WiFi_AP_Candidates.hasCandidateCredentials()) { - if (!WiFiEventData.warnedNoValidWiFiSettings) { - addLog(LOG_LEVEL_ERROR, F("WIFI : No valid wifi settings")); - WiFiEventData.warnedNoValidWiFiSettings = true; - } -// WiFiEventData.last_wifi_connect_attempt_moment.clear(); - WiFiEventData.wifi_connect_attempt = 1; - WiFiEventData.wifiConnectAttemptNeeded = false; - - // No need to wait longer to start AP mode. - if (!Settings.DoNotStartAP()) { - WifiScan(false); -// ESPEasy::net::wifi::setAP(true); - } - return false; - } - WiFiEventData.warnedNoValidWiFiSettings = false; - ESPEasy::net::wifi::setSTA(true); - - #if defined(ESP8266) - wifi_station_set_hostname(NetworkCreateRFCCompliantHostname().c_str()); - - #endif // if defined(ESP8266) - #if defined(ESP32) - WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); - #endif // if defined(ESP32) - ESPEasy::net::wifi::setConnectionSpeed(); - setupStaticIPconfig(); - WiFiEventData.wifiConnectAttemptNeeded = true; +// ESPEasyWiFi.setup(); return true; } -bool checkAndResetWiFi() { - #ifdef ESP8266 - station_status_t status = wifi_station_get_connect_status(); - - switch(status) { - case STATION_GOT_IP: - if (WiFi.RSSI() < 0 && WiFi.localIP().isSet()) { - //if (WiFi.channel() == WiFiEventData.usedChannel || WiFiEventData.usedChannel == 0) { - // This is a valid status, no need to reset - return false; - //} - } - break; - case STATION_NO_AP_FOUND: - case STATION_CONNECT_FAIL: - case STATION_WRONG_PASSWORD: - // Reason to reset WiFi - break; - case STATION_IDLE: - case STATION_CONNECTING: - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && !WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { - return false; - } - break; - } - #endif - #ifdef ESP32 - if (WiFi.isConnected()) { - //if (WiFi.channel() == WiFiEventData.usedChannel || WiFiEventData.usedChannel == 0) { - return false; - //} - } - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && !WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { - return false; - } - #endif - # ifndef BUILD_NO_DEBUG - String log = F("WiFi : WiFiConnected() out of sync: "); - log += WiFiEventData.ESPeasyWifiStatusToString(); - log += F(" RSSI: "); - log += String(WiFi.RSSI()); - #ifdef ESP8266 - log += F(" status: "); - log += SDKwifiStatusToString(status); - #endif - #endif - - // Call for reset first, to make sure a syslog call will not try to send. - resetWiFi(); - # ifndef BUILD_NO_DEBUG - addLogMove(LOG_LEVEL_INFO, log); - #endif - return true; -} - +bool checkAndResetWiFi() { return true; } void resetWiFi() { - //if (wifiAPmodeActivelyUsed()) return; - if (WiFiEventData.lastWiFiResetMoment.isSet() && !WiFiEventData.lastWiFiResetMoment.timeoutReached(1000)) { - // Don't reset WiFi too often - return; - } - FeedSW_watchdog(); - WiFiEventData.clearAll(); - WifiDisconnect(); + /* //if (wifiAPmodeActivelyUsed()) return; + if (WiFiEventData.lastWiFiResetMoment.isSet() && !WiFiEventData.lastWiFiResetMoment.timeoutReached(1000)) { + // Don't reset WiFi too often + return; + } + FeedSW_watchdog(); + WiFiEventData.clearAll(); + WifiDisconnect(); - // Send this log only after WifiDisconnect() or else sending to syslog may cause issues - addLog(LOG_LEVEL_INFO, F("Reset WiFi.")); + // Send this log only after WifiDisconnect() or else sending to syslog may cause issues + addLog(LOG_LEVEL_INFO, F("Reset WiFi.")); - // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); + // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); - initWiFi(); + initWiFi(); + */ } +void initWiFi() { ESPEasyWiFi.setup(); } - -void initWiFi() -{ -#ifdef ESP8266 - - // See https://github.com/esp8266/Arduino/issues/5527#issuecomment-460537616 - // FIXME TD-er: Do not destruct WiFi object, it may cause crashes with queued UDP traffic. -// WiFi.~ESP8266WiFiClass(); -// WiFi = ESP8266WiFiClass(); -#endif // ifdef ESP8266 -#ifdef ESP32 - ESPEasy::net::wifi::removeWiFiEventHandler(); -#endif - - - WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters - // The WiFi.disconnect() ensures that the WiFi is working correctly. If this is not done before receiving WiFi connections, - // those WiFi connections will take a long time to make or sometimes will not work at all. - WiFi.disconnect(false); - delay(1); - if (active_network_medium != NetworkMedium_t::NotSet) { - ESPEasy::net::wifi::setSTA(true); - WifiScan(false); - } - ESPEasy::net::wifi::setWifiMode(WIFI_OFF); - - ESPEasy::net::wifi::registerWiFiEventHandler(); - delay(100); -} +void loopWiFi() { ESPEasyWiFi.loop(); } // ******************************************************************************** // Configure WiFi TX power // ******************************************************************************** -#if FEATURE_SET_WIFI_TX_PWR +# if FEATURE_SET_WIFI_TX_PWR + void SetWiFiTXpower() { SetWiFiTXpower(0); // Just some minimal value, will be adjusted in SetWiFiTXpower } -void SetWiFiTXpower(float dBm) { - SetWiFiTXpower(dBm, WiFi.RSSI()); -} +void SetWiFiTXpower(float dBm) { SetWiFiTXpower(dBm, WiFi.RSSI()); } void SetWiFiTXpower(float dBm, float rssi) { const WiFiMode_t cur_mode = WiFi.getMode(); + if (cur_mode == WIFI_OFF) { return; } @@ -594,12 +190,12 @@ void SetWiFiTXpower(float dBm, float rssi) { // Range ESP8266: 0dBm - 20.5dBm float maxTXpwr; float threshold = GetRSSIthreshold(maxTXpwr); - #ifdef ESP8266 + # ifdef ESP8266 float minTXpwr{}; - #endif - #ifdef ESP32 + # endif + # ifdef ESP32 float minTXpwr = -1.0f; - #endif + # endif threshold += Settings.WiFi_sensitivity_margin; // Margin in dBm on top of threshold @@ -608,19 +204,22 @@ void SetWiFiTXpower(float dBm, float rssi) { // US and some other countries allow 1000 mW (30 dBm) // We cannot send with over 20 dBm, thus it makes no sense to force higher TX power all the time. const float newrssi = rssi - 20; + if (newrssi < threshold) { minTXpwr = threshold - newrssi; } + if (minTXpwr > maxTXpwr) { minTXpwr = maxTXpwr; } + if (dBm > maxTXpwr) { dBm = maxTXpwr; } else if (dBm < minTXpwr) { dBm = minTXpwr; } -ESPEasy::net::wifi::SetWiFiTXpower(dBm); + ESPEasy::net::wifi::SetWiFiTXpower(dBm); if (WiFiEventData.wifi_TX_pwr < dBm) { // Will increase the TX power, give power supply of the unit some rest @@ -630,18 +229,22 @@ ESPEasy::net::wifi::SetWiFiTXpower(dBm); WiFiEventData.wifi_TX_pwr = dBm; delay(0); - #ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - const int TX_pwr_int = WiFiEventData.wifi_TX_pwr * 4; + const int TX_pwr_int = WiFiEventData.wifi_TX_pwr * 4; const int maxTXpwr_int = maxTXpwr * 4; + if (TX_pwr_int != maxTXpwr_int) { static int last_log = -1; + if (TX_pwr_int != last_log) { last_log = TX_pwr_int; String log = strformat( F("WiFi : Set TX power to %ddBm sensitivity: %ddBm"), static_cast(dBm), static_cast(threshold)); + if (rssi < 0) { log += strformat(F(" RSSI: %ddBm"), static_cast(rssi)); } @@ -649,12 +252,10 @@ ESPEasy::net::wifi::SetWiFiTXpower(dBm); } } } - #endif + # endif // ifndef BUILD_NO_DEBUG } -#endif - - +# endif // if FEATURE_SET_WIFI_TX_PWR float GetRSSIthreshold(float& maxTXpwr) { maxTXpwr = Settings.getWiFi_TX_power(); @@ -671,52 +272,18 @@ int GetRSSI_quality() { return (rssi / 5) + 1; } -WiFiConnectionProtocol getConnectionProtocol() { - return ESPEasy::net::wifi::getConnectionProtocol(); -} +WiFiConnectionProtocol getConnectionProtocol() { return ESPEasy::net::wifi::getConnectionProtocol(); } -#ifdef ESP32 -int64_t WiFi_get_TSF_time() -{ - return esp_wifi_get_tsf_time(WIFI_IF_STA); -} -#endif +# ifdef ESP32 +int64_t WiFi_get_TSF_time() { return esp_wifi_get_tsf_time(WIFI_IF_STA); } + +# endif // ifdef ESP32 // ******************************************************************************** // Disconnect from Wifi AP // ******************************************************************************** -void WifiDisconnect() -{ - if (!WiFiEventData.processedDisconnect || - WiFiEventData.processingDisconnect.isSet()) { - return; - } - if (WiFi.status() == WL_DISCONNECTED) { - return; - } - // Prevent recursion - static LongTermTimer processingDisconnectTimer; - if (processingDisconnectTimer.isSet() && - !processingDisconnectTimer.timeoutReached(200)) return; - processingDisconnectTimer.setNow(); - # ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, F("WiFi : WifiDisconnect()")); - #endif - ESPEasy::net::wifi::WiFiDisconnect(); - WiFiEventData.setWiFiDisconnected(); - WiFiEventData.markDisconnect(WIFI_DISCONNECT_REASON_UNSPECIFIED); - /* - if (!Settings.UseLastWiFiFromRTC()) { - RTC.clearLastWiFi(); - } - */ - delay(100); - WiFiEventData.processingDisconnect.clear(); - WiFiEventData.processedDisconnect = false; - processDisconnect(); - processingDisconnectTimer.clear(); -} +void WifiDisconnect() { ESPEasyWiFi.disconnect(); } // ******************************************************************************** // Scan WiFi network @@ -725,83 +292,17 @@ bool WiFiScanAllowed() { if (WiFi_AP_Candidates.scanComplete() == WIFI_SCAN_RUNNING) { return false; } - if (!WiFiEventData.processedScanDone) { - processScanDone(); - } - if (!WiFiEventData.processedDisconnect) { - processDisconnect(); - } - - if (WiFiEventData.wifiConnectInProgress) { - return false; - } - - if (WiFiEventData.intent_to_reboot) { - return false; - } - - if (WiFiEventData.unprocessedWifiEvents()) { - # ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - String log = F("WiFi : Scan not allowed, unprocessed WiFi events: "); - if (!WiFiEventData.processedConnect) { - log += F(" conn"); - } - if (!WiFiEventData.processedDisconnect) { - log += F(" disconn"); - } - if (!WiFiEventData.processedGotIP) { - log += F(" gotIP"); - } - if (!WiFiEventData.processedDHCPTimeout) { - log += F(" DHCP_t/o"); - } - - addLogMove(LOG_LEVEL_ERROR, log); - logConnectionStatus(); - } - #endif - return false; - } - /* - if (!wifiAPmodeActivelyUsed() && !NetworkConnected()) { - return true; - } - */ - WiFi_AP_Candidates.purge_expired(); - if (WiFiEventData.wifiConnectInProgress) { - return false; - } - if (WiFiEventData.lastScanMoment.isSet()) { - if (NetworkConnected() && WiFi_AP_Candidates.getBestCandidate().usable()) { - # ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_ERROR, F("WiFi : Scan not needed, good candidate present")); - #endif - return false; - } - } - - if (WiFiEventData.lastDisconnectMoment.isSet() && WiFiEventData.lastDisconnectMoment.millisPassedSince() < WIFI_RECONNECT_WAIT) { - if (!NetworkConnected()) { - return WiFiEventData.processedConnect; - } - } - if (WiFiEventData.lastScanMoment.isSet()) { - const LongTermTimer::Duration scanInterval = wifiAPmodeActivelyUsed() ? WIFI_SCAN_INTERVAL_AP_USED : WIFI_SCAN_INTERVAL_MINIMAL; - if (WiFiEventData.lastScanMoment.millisPassedSince() < scanInterval) { - return false; - } - } return WiFiEventData.processedConnect; } - void WifiScan(bool async, uint8_t channel) { - ESPEasy::net::wifi::setSTA(true); + ESPEasy::net::wifi::setSTA(true); + if (!WiFiScanAllowed()) { return; } -#ifdef ESP32 +# ifdef ESP32 + // TD-er: Don't run async scan on ESP32. // Since IDF 4.4 it seems like the active channel may be messed up when running async scan // Perform a disconnect after scanning. @@ -810,20 +311,21 @@ void WifiScan(bool async, uint8_t channel) { if (Settings.IncludeHiddenSSID()) { wifi_country_t config = { - .cc = "01", - .schan = 1, - .nchan = 14, + .cc = "01", + .schan = 1, + .nchan = 14, .policy = WIFI_COUNTRY_POLICY_MANUAL, }; esp_wifi_set_country(&config); } -#endif +# endif // ifdef ESP32 START_TIMER; WiFiEventData.lastScanMoment.setNow(); # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { if (channel == 0) { addLog(LOG_LEVEL_INFO, F("WiFi : Start network scan all channels")); @@ -831,31 +333,33 @@ void WifiScan(bool async, uint8_t channel) { addLogMove(LOG_LEVEL_INFO, strformat(F("WiFi : Start network scan ch: %d "), channel)); } } - #endif - bool show_hidden = true; + # endif // ifndef BUILD_NO_DEBUG + bool show_hidden = true; WiFiEventData.processedScanDone = false; WiFiEventData.lastGetScanMoment.setNow(); WiFiEventData.lastScanChannel = channel; unsigned int nrScans = 1 + (async ? 0 : Settings.NumberExtraWiFiScans); + while (nrScans > 0) { if (!async) { WiFi_AP_Candidates.begin_sync_scan(); FeedSW_watchdog(); } --nrScans; -#ifdef ESP8266 -#if FEATURE_ESP8266_DIRECT_WIFI_SCAN +# ifdef ESP8266 +# if FEATURE_ESP8266_DIRECT_WIFI_SCAN { static bool FIRST_SCAN = true; struct scan_config config; memset(&config, 0, sizeof(config)); - config.ssid = nullptr; - config.bssid = nullptr; - config.channel = channel; - config.show_hidden = show_hidden ? 1 : 0;; - config.scan_type = WIFI_SCAN_TYPE_ACTIVE; + config.ssid = nullptr; + config.bssid = nullptr; + config.channel = channel; + config.show_hidden = show_hidden ? 1 : 0; + config.scan_type = WIFI_SCAN_TYPE_ACTIVE; + if (FIRST_SCAN) { config.scan_time.active.min = 100; config.scan_time.active.max = 200; @@ -865,50 +369,55 @@ void WifiScan(bool async, uint8_t channel) { } FIRST_SCAN = false; wifi_station_scan(&config, &onWiFiScanDone); + if (!async) { // will resume when SYSTEM_EVENT_SCAN_DONE event is fired - do { + do + { delay(0); } while (!WiFiEventData.processedScanDone); } - + } -#else +# else // if FEATURE_ESP8266_DIRECT_WIFI_SCAN WiFi.scanNetworks(async, show_hidden, channel); -#endif -#endif -#ifdef ESP32 - const bool passive = Settings.PassiveWiFiScan(); +# endif // if FEATURE_ESP8266_DIRECT_WIFI_SCAN +# endif // ifdef ESP8266 +# ifdef ESP32 + const bool passive = Settings.PassiveWiFiScan(); const uint32_t max_ms_per_chan = 120; WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan /*, channel */); -#endif +# endif // ifdef ESP32 + if (!async) { FeedSW_watchdog(); processScanDone(); } } -#if FEATURE_TIMING_STATS +# if FEATURE_TIMING_STATS + if (async) { STOP_TIMER(WIFI_SCAN_ASYNC); } else { STOP_TIMER(WIFI_SCAN_SYNC); } -#endif +# endif // if FEATURE_TIMING_STATS -#ifdef ESP32 -#if ESP_IDF_VERSION_MAJOR<5 +# ifdef ESP32 +# if ESP_IDF_VERSION_MAJOR < 5 RTC.clearLastWiFi(); + if (WiFiConnected()) { - # ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Disconnect after scan")); - #endif + # endif const bool needReconnect = WiFiEventData.wifiConnectAttemptNeeded; WifiDisconnect(); WiFiEventData.wifiConnectAttemptNeeded = needReconnect; } -#endif -#endif +# endif // if ESP_IDF_VERSION_MAJOR < 5 +# endif // ifdef ESP32 } @@ -919,6 +428,7 @@ void WiFiScan_log_to_serial() { // Direct Serial is allowed here, since this function will only be called from serial input. serialPrintln(F("WIFI : SSID Scan start")); + if (WiFi_AP_Candidates.scanComplete() <= 0) { WiFiMode_t cur_wifimode = WiFi.getMode(); WifiScan(false); @@ -926,6 +436,7 @@ void WiFiScan_log_to_serial() } const int8_t scanCompleteStatus = WiFi_AP_Candidates.scanComplete(); + if (scanCompleteStatus <= 0) { serialPrintln(F("WIFI : No networks found")); } @@ -940,6 +451,7 @@ void WiFiScan_log_to_serial() for (auto it = WiFi_AP_Candidates.scanned_begin(); it != WiFi_AP_Candidates.scanned_end(); ++it) { ++i; + // Print SSID and RSSI for each network found serialPrint(F("WIFI : ")); serialPrint(String(i)); @@ -951,10 +463,8 @@ void WiFiScan_log_to_serial() serialPrintln(""); } - - // Only internal scope -void setAPinternal(bool enable) +void setAPinternal(bool enable) { if (enable) { // create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password! @@ -965,67 +475,65 @@ void setAPinternal(bool enable) if (!WiFi.softAPConfig(apIP, apIP, subnet)) { addLog(LOG_LEVEL_ERROR, strformat( - ("WIFI : [AP] softAPConfig failed! IP: %s, GW: %s, SN: %s"), - apIP.toString().c_str(), - apIP.toString().c_str(), - subnet.toString().c_str() - ) - ); + ("WIFI : [AP] softAPConfig failed! IP: %s, GW: %s, SN: %s"), + apIP.toString().c_str(), + apIP.toString().c_str(), + subnet.toString().c_str() + ) + ); } int channel = 1; - if ( ESPEasy::net::wifi::WifiIsSTA(WiFi.getMode()) && WiFiConnected()) { + + if (ESPEasy::net::wifi::WifiIsSTA(WiFi.getMode()) && WiFiConnected()) { channel = WiFi.channel(); } if (WiFi.softAP(softAPSSID.c_str(), pwd.c_str(), channel)) { eventQueue.add(F("WiFi#APmodeEnabled")); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, strformat( - F("WIFI : AP Mode enabled. SSID: %s IP: %s ch: %d"), - softAPSSID.c_str(), - formatIP(WiFi.softAPIP()).c_str(), - channel)); + F("WIFI : AP Mode enabled. SSID: %s IP: %s ch: %d"), + softAPSSID.c_str(), + formatIP(WiFi.softAPIP()).c_str(), + channel)); } } else { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { addLogMove(LOG_LEVEL_ERROR, strformat( - F("WIFI : Error while starting AP Mode with SSID: %s IP: %s"), - softAPSSID.c_str(), - formatIP(apIP).c_str())); + F("WIFI : Error while starting AP Mode with SSID: %s IP: %s"), + softAPSSID.c_str(), + formatIP(apIP).c_str())); } } - #ifdef ESP32 + # ifdef ESP32 - #else // ifdef ESP32 + # else // ifdef ESP32 if (wifi_softap_dhcps_status() != DHCP_STARTED) { if (!wifi_softap_dhcps_start()) { addLog(LOG_LEVEL_ERROR, F("WIFI : [AP] wifi_softap_dhcps_start failed!")); } } - #endif // ifdef ESP32 + # endif // ifdef ESP32 WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_DURATION); } else { - #if FEATURE_DNS_SERVER + # if FEATURE_DNS_SERVER + if (dnsServerActive) { dnsServerActive = false; dnsServer.stop(); } - #endif // if FEATURE_DNS_SERVER + # endif // if FEATURE_DNS_SERVER } } - - - -bool WiFiUseStaticIP() { - return Settings.IP[0] != 0 && Settings.IP[0] != 255; -} +bool WiFiUseStaticIP() { return Settings.IP[0] != 0 && Settings.IP[0] != 255; } bool wifiAPmodeActivelyUsed() { - if (! ESPEasy::net::wifi::WifiIsAP(WiFi.getMode()) || (!WiFiEventData.timerAPoff.isSet())) { + if (!ESPEasy::net::wifi::WifiIsAP(WiFi.getMode()) || (!WiFiEventData.timerAPoff.isSet())) { // AP not active or soon to be disabled in processDisableAPmode() return false; } @@ -1039,10 +547,10 @@ void setupStaticIPconfig() { setUseStaticIP(WiFiUseStaticIP()); if (!WiFiUseStaticIP()) { return; } - const IPAddress ip (Settings.IP); - const IPAddress gw (Settings.Gateway); - const IPAddress subnet (Settings.Subnet); - const IPAddress dns (Settings.DNS); + const IPAddress ip(Settings.IP); + const IPAddress gw(Settings.Gateway); + const IPAddress subnet(Settings.Subnet); + const IPAddress dns(Settings.DNS); WiFiEventData.dns0_cache = dns; @@ -1050,11 +558,11 @@ void setupStaticIPconfig() { if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, strformat( - F("IP : Static IP : %s GW: %s SN: %s DNS: %s"), - formatIP(ip).c_str(), - formatIP(gw).c_str(), - formatIP(subnet).c_str(), - getValue(LabelType::DNS).c_str())); + F("IP : Static IP : %s GW: %s SN: %s DNS: %s"), + formatIP(ip).c_str(), + formatIP(gw).c_str(), + formatIP(subnet).c_str(), + getValue(LabelType::DNS).c_str())); } } @@ -1069,19 +577,20 @@ String formatScanResult(int i, const String& separator) { String formatScanResult(int i, const String& separator, int32_t& rssi) { WiFi_AP_Candidate tmp(i); + rssi = tmp.rssi; return tmp.toString(separator); } - void logConnectionStatus() { static unsigned long lastLog = 0; - if (lastLog != 0 && timePassedSince(lastLog) < 1000) { + + if ((lastLog != 0) && (timePassedSince(lastLog) < 1000)) { return; } lastLog = millis(); -#ifndef BUILD_NO_DEBUG - #ifdef ESP8266 +# ifndef BUILD_NO_DEBUG + # ifdef ESP8266 const uint8_t arduino_corelib_wifistatus = WiFi.status(); const uint8_t sdk_wifistatus = wifi_station_get_connect_status(); @@ -1094,50 +603,51 @@ void logConnectionStatus() { addLogMove(LOG_LEVEL_ERROR, log); } } - #endif + # endif // ifdef ESP8266 if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, strformat( - F("WIFI : Arduino wifi status: %s ESPeasy internal wifi status: %s"), - ArduinoWifiStatusToString(WiFi.status()).c_str(), - WiFiEventData.ESPeasyWifiStatusToString().c_str())); + F("WIFI : Arduino wifi status: %s ESPeasy internal wifi status: %s"), + ArduinoWifiStatusToString(WiFi.status()).c_str(), + WiFiEventData.ESPeasyWifiStatusToString().c_str())); } -/* - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - switch (WiFi.status()) { - case WL_NO_SSID_AVAIL: { - log = F("WIFI : No SSID found matching: "); - break; - } - case WL_CONNECT_FAILED: { - log = F("WIFI : Connection failed to: "); - break; - } - case WL_DISCONNECTED: { - log = F("WIFI : WiFi.status() = WL_DISCONNECTED SSID: "); - break; - } - case WL_IDLE_STATUS: { - log = F("WIFI : Connection in IDLE state: "); - break; - } - case WL_CONNECTED: { - break; - } - default: - break; - } + /* + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; - if (log.length() > 0) { - const char *ssid = getLastWiFiSettingsSSID(); - log += ssid; - addLog(LOG_LEVEL_INFO, log); - } - } - */ -#endif // ifndef BUILD_NO_DEBUG + switch (WiFi.status()) { + case WL_NO_SSID_AVAIL: { + log = F("WIFI : No SSID found matching: "); + break; + } + case WL_CONNECT_FAILED: { + log = F("WIFI : Connection failed to: "); + break; + } + case WL_DISCONNECTED: { + log = F("WIFI : WiFi.status() = WL_DISCONNECTED SSID: "); + break; + } + case WL_IDLE_STATUS: { + log = F("WIFI : Connection in IDLE state: "); + break; + } + case WL_CONNECTED: { + break; + } + default: + break; + } + + if (log.length() > 0) { + const char *ssid = getLastWiFiSettingsSSID(); + log += ssid; + addLog(LOG_LEVEL_INFO, log); + } + } + */ +# endif // ifndef BUILD_NO_DEBUG } -#endif \ No newline at end of file +#endif // if FEATURE_WIFI diff --git a/src/src/ESPEasyCore/ESPEasyWifi.h b/src/src/ESPEasyCore/ESPEasyWifi.h index d30d9c4e5..c1d421389 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.h +++ b/src/src/ESPEasyCore/ESPEasyWifi.h @@ -41,7 +41,7 @@ bool prepareWiFi(); bool checkAndResetWiFi(); void resetWiFi(); void initWiFi(); - +void loopWiFi(); # if FEATURE_SET_WIFI_TX_PWR void SetWiFiTXpower(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 739440fad..f1aa0b284 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -51,34 +51,31 @@ void handle_unprocessedNetworkEvents() #endif if (active_network_medium == NetworkMedium_t::WIFI) { - const bool should_be_initialized = (WiFiEventData.WiFiGotIP() && WiFiEventData.WiFiConnected()) || NetworkConnected(); + if (WiFiConnected() && !WiFiEventData.WiFiServicesInitialized()) { + WiFiEventData.processedConnect = false; + WiFiEventData.processedGotIP = false; + if (!WiFiEventData.processedConnect) { + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); + #endif // ifndef BUILD_NO_DEBUG + processConnect(); - if (WiFiEventData.WiFiServicesInitialized() != should_be_initialized) - { - if (!WiFiEventData.WiFiServicesInitialized()) { - WiFiEventData.processedDHCPTimeout = true; // FIXME TD-er: Find out when this happens (happens on ESP32 sometimes) +// FIXME TD-er: Forcefully set the connected flag for now + WiFiEventData.setWiFiConnected(); + } - if (WiFiConnected()) { - if (!WiFiEventData.WiFiGotIP()) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WiFi : Missed gotIP event")); - #endif - WiFiEventData.processedGotIP = false; - processGotIP(); - } + if (!WiFiEventData.processedGotIP) { + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processGotIP()")); + #endif // ifndef BUILD_NO_DEBUG + processGotIP(); - if (!WiFiEventData.WiFiConnected()) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WiFi : Missed connected event")); - #endif - WiFiEventData.processedConnect = false; - processConnect(); - } + // FIXME TD-er: Forcefully set the GotIP flag for now + WiFiEventData.setWiFiGotIP(); + } + WiFiEventData.setWiFiServicesInitialized(); - // Apparently we are connected, so no need to process any late disconnect event - WiFiEventData.processedDisconnect = true; - } - WiFiEventData.setWiFiServicesInitialized(); + if (WiFiEventData.WiFiServicesInitialized()) { // #ifdef ESP32 setWebserverRunning(false); @@ -95,127 +92,129 @@ void handle_unprocessedNetworkEvents() } } - if (WiFiEventData.unprocessedWifiEvents()) { - // Process disconnect events before connect events. - if (!WiFiEventData.processedDisconnect) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processDisconnect()")); - #endif // ifndef BUILD_NO_DEBUG - processDisconnect(); - } - } - - if (active_network_medium == NetworkMedium_t::WIFI) { - if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents() || WiFiEventData.wifiConnectAttemptNeeded) { - // WiFi connection is not yet available, so introduce some extra delays to - // help the background tasks managing wifi connections - delay(0); - - if (!WiFiEventData.processedConnect) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); - #endif // ifndef BUILD_NO_DEBUG - processConnect(); + /* if (WiFiEventData.unprocessedWifiEvents()) { + // Process disconnect events before connect events. + if (!WiFiEventData.processedDisconnect) { + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processDisconnect()")); + #endif // ifndef BUILD_NO_DEBUG + processDisconnect(); } + } - if (!WiFiEventData.processedGotIP) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processGotIP()")); - #endif // ifndef BUILD_NO_DEBUG - processGotIP(); - } + if (active_network_medium == NetworkMedium_t::WIFI) { + if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents() || WiFiEventData.wifiConnectAttemptNeeded) { + // WiFi connection is not yet available, so introduce some extra delays to + // help the background tasks managing wifi connections + delay(0); - if (!WiFiEventData.processedDHCPTimeout) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, F("WIFI : DHCP timeout, Calling disconnect()")); - #endif // ifndef BUILD_NO_DEBUG - WiFiEventData.processedDHCPTimeout = true; - WifiDisconnect(); - } - - if ((WiFi.status() == WL_DISCONNECTED) && WiFiEventData.wifiConnectInProgress) { - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && - WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { - logConnectionStatus(); - resetWiFi(); + if (!WiFiEventData.processedConnect) { + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); + #endif // ifndef BUILD_NO_DEBUG + processConnect(); } - if (!WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { - WiFiEventData.wifiConnectInProgress = false; + if (!WiFiEventData.processedGotIP) { + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processGotIP()")); + #endif // ifndef BUILD_NO_DEBUG + processGotIP(); } + + if (!WiFiEventData.processedDHCPTimeout) { + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_INFO, F("WIFI : DHCP timeout, Calling disconnect()")); + #endif // ifndef BUILD_NO_DEBUG + WiFiEventData.processedDHCPTimeout = true; + WifiDisconnect(); + } + + if ((WiFi.status() == WL_DISCONNECTED) && WiFiEventData.wifiConnectInProgress) { + if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && + WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { + logConnectionStatus(); + resetWiFi(); + } + + if (!WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { + WiFiEventData.wifiConnectInProgress = false; + } + delay(10); + } + + if (!WiFiEventData.wifiConnectInProgress) { + WiFiEventData.wifiConnectAttemptNeeded = true; + NetworkConnectRelaxed(); + } + } + + + if (WiFiEventData.WiFiDisconnected()) { + #ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + static LongTermTimer lastDisconnectMoment_log; + static uint8_t lastWiFiStatus_log = 0; + uint8_t cur_wifi_status = WiFi.status(); + + if ((WiFiEventData.lastDisconnectMoment.get() != lastDisconnectMoment_log.get()) || + (lastWiFiStatus_log != cur_wifi_status)) { + lastDisconnectMoment_log.set(WiFiEventData.lastDisconnectMoment.get()); + lastWiFiStatus_log = cur_wifi_status; + String wifilog = F("WIFI : Disconnected: WiFi.status() = "); + wifilog += WiFiEventData.ESPeasyWifiStatusToString(); + wifilog += F(" RSSI: "); + wifilog += String(WiFi.RSSI()); + wifilog += F(" status: "); + # ifdef ESP8266 + station_status_t status = wifi_station_get_connect_status(); + wifilog += SDKwifiStatusToString(status); + # endif // ifdef ESP8266 + # ifdef ESP32 + wifilog += ArduinoWifiStatusToString(WiFi.status()); + # endif + addLogMove(LOG_LEVEL_DEBUG, wifilog); + } + } + #endif // ifndef BUILD_NO_DEBUG + + // While connecting to WiFi make sure the device has ample time to do so delay(10); } - if (!WiFiEventData.wifiConnectInProgress) { - WiFiEventData.wifiConnectAttemptNeeded = true; - NetworkConnectRelaxed(); - } - } + if (!WiFiEventData.processedDisconnectAPmode) { processDisconnectAPmode(); } + if (!WiFiEventData.processedConnectAPmode) { processConnectAPmode(); } - if (WiFiEventData.WiFiDisconnected()) { - #ifndef BUILD_NO_DEBUG + if (WiFiEventData.timerAPoff.isSet()) { processDisableAPmode(); } - if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - static LongTermTimer lastDisconnectMoment_log; - static uint8_t lastWiFiStatus_log = 0; - uint8_t cur_wifi_status = WiFi.status(); + if (!WiFiEventData.processedScanDone) { processScanDone(); } - if ((WiFiEventData.lastDisconnectMoment.get() != lastDisconnectMoment_log.get()) || - (lastWiFiStatus_log != cur_wifi_status)) { - lastDisconnectMoment_log.set(WiFiEventData.lastDisconnectMoment.get()); - lastWiFiStatus_log = cur_wifi_status; - String wifilog = F("WIFI : Disconnected: WiFi.status() = "); - wifilog += WiFiEventData.ESPeasyWifiStatusToString(); - wifilog += F(" RSSI: "); - wifilog += String(WiFi.RSSI()); - wifilog += F(" status: "); - # ifdef ESP8266 - station_status_t status = wifi_station_get_connect_status(); - wifilog += SDKwifiStatusToString(status); - # endif // ifdef ESP8266 - # ifdef ESP32 - wifilog += ArduinoWifiStatusToString(WiFi.status()); - # endif - addLogMove(LOG_LEVEL_DEBUG, wifilog); - } - } - #endif // ifndef BUILD_NO_DEBUG + if (WiFiEventData.wifi_connect_attempt > 0) { + // We only want to clear this counter if the connection is currently stable. + if (WiFiEventData.WiFiServicesInitialized()) { + if (WiFiEventData.lastConnectMoment.isSet() && WiFiEventData.lastConnectMoment.timeoutReached(WIFI_CONNECTION_CONSIDERED_STABLE)) + #{ + // Connection considered stable + WiFiEventData.wifi_connect_attempt = 0; + WiFiEventData.wifi_considered_stable = true; + WiFi_AP_Candidates.markCurrentConnectionStable(); - // While connecting to WiFi make sure the device has ample time to do so - delay(10); - } - - if (!WiFiEventData.processedDisconnectAPmode) { processDisconnectAPmode(); } - - if (!WiFiEventData.processedConnectAPmode) { processConnectAPmode(); } - - if (WiFiEventData.timerAPoff.isSet()) { processDisableAPmode(); } - - if (!WiFiEventData.processedScanDone) { processScanDone(); } - - if (WiFiEventData.wifi_connect_attempt > 0) { - // We only want to clear this counter if the connection is currently stable. - if (WiFiEventData.WiFiServicesInitialized()) { - if (WiFiEventData.lastConnectMoment.isSet() && WiFiEventData.lastConnectMoment.timeoutReached(WIFI_CONNECTION_CONSIDERED_STABLE)) { - // Connection considered stable - WiFiEventData.wifi_connect_attempt = 0; - WiFiEventData.wifi_considered_stable = true; - WiFi_AP_Candidates.markCurrentConnectionStable(); - - if (WiFi.getAutoReconnect() != Settings.SDK_WiFi_autoreconnect()) { - WiFi.setAutoReconnect(Settings.SDK_WiFi_autoreconnect()); - delay(1); - } - } else { - if (WiFi.getAutoReconnect()) { - WiFi.setAutoReconnect(false); - delay(1); + if (WiFi.getAutoReconnect() != Settings.SDK_WiFi_autoreconnect()) { + WiFi.setAutoReconnect(Settings.SDK_WiFi_autoreconnect()); + delay(1); + } + } else { + if (WiFi.getAutoReconnect()) { + WiFi.setAutoReconnect(false); + delay(1); + } } } } - } - } + } + */ #if FEATURE_ETHERNET check_Eth_DNS_valid(); #endif // if FEATURE_ETHERNET @@ -230,119 +229,124 @@ void handle_unprocessedNetworkEvents() // These functions are called from Setup() or Loop() and thus may call delay() or yield() // ******************************************************************************** void processDisconnect() { - if (WiFiEventData.processedDisconnect) { return; } + /* + if (WiFiEventData.processedDisconnect) { return; } - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = strformat( + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = strformat( F("WIFI : Disconnected! Reason: '%s'"), getLastDisconnectReason().c_str()); - if (WiFiEventData.lastConnectedDuration_us > 0) { + if (WiFiEventData.lastConnectedDuration_us > 0) { log += concat( F(" Connected for "), format_msec_duration(WiFiEventData.lastConnectedDuration_us / 1000ll)); - } - addLogMove(LOG_LEVEL_INFO, log); - } - logConnectionStatus(); + } + addLogMove(LOG_LEVEL_INFO, log); + } + logConnectionStatus(); - if (WiFiEventData.processingDisconnect.isSet()) { - if ((WiFiEventData.processingDisconnect.millisPassedSince() > 5000) || WiFiEventData.processedDisconnect) { + if (WiFiEventData.processingDisconnect.isSet()) { + if ((WiFiEventData.processingDisconnect.millisPassedSince() > 5000) || WiFiEventData.processedDisconnect) { WiFiEventData.processedDisconnect = true; WiFiEventData.processingDisconnect.clear(); - } - } + } + } - if (WiFiEventData.processedDisconnect || + if (WiFiEventData.processedDisconnect || WiFiEventData.processingDisconnect.isSet()) { return; } - WiFiEventData.processingDisconnect.setNow(); - WiFiEventData.setWiFiDisconnected(); - WiFiEventData.wifiConnectAttemptNeeded = true; - delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 + WiFiEventData.processingDisconnect.setNow(); + WiFiEventData.setWiFiDisconnected(); + WiFiEventData.wifiConnectAttemptNeeded = true; + delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 - if (Settings.UseRules) { - eventQueue.add(F("WiFi#Disconnected")); - } + if (Settings.UseRules) { + eventQueue.add(F("WiFi#Disconnected")); + } - // FIXME TD-er: With AutoReconnect enabled, WiFi must be reset or else we completely loose track of the actual WiFi state - bool mustRestartWiFi = Settings.WiFiRestart_connection_lost() || WiFi.getAutoReconnect(); + // FIXME TD-er: With AutoReconnect enabled, WiFi must be reset or else we completely loose track of the actual WiFi state + bool mustRestartWiFi = Settings.WiFiRestart_connection_lost() || WiFi.getAutoReconnect(); - if ((WiFiEventData.lastConnectedDuration_us > 0) && ((WiFiEventData.lastConnectedDuration_us / 1000) < 5000)) { - if (!WiFi_AP_Candidates.getBestCandidate().usable()) { + if ((WiFiEventData.lastConnectedDuration_us > 0) && ((WiFiEventData.lastConnectedDuration_us / 1000) < 5000)) { + if (!WiFi_AP_Candidates.getBestCandidate().usable()) { // addLog(LOG_LEVEL_INFO, F("WIFI : !getBestCandidate().usable() => mustRestartWiFi = true")); mustRestartWiFi = true; - } - } + } + } - if (WiFi.status() == WL_IDLE_STATUS) { - // addLog(LOG_LEVEL_INFO, F("WIFI : WiFi.status() == WL_IDLE_STATUS => mustRestartWiFi = true")); - mustRestartWiFi = true; - } + if (WiFi.status() == WL_IDLE_STATUS) { + // addLog(LOG_LEVEL_INFO, F("WIFI : WiFi.status() == WL_IDLE_STATUS => mustRestartWiFi = true")); + mustRestartWiFi = true; + } - #ifdef USES_ESPEASY_NOW + #ifdef USES_ESPEASY_NOW - if (use_EspEasy_now) { - // mustRestartWiFi = true; - } - #endif // ifdef USES_ESPEASY_NOW + if (use_EspEasy_now) { + // mustRestartWiFi = true; + } + #endif // ifdef USES_ESPEASY_NOW - // WifiDisconnect(); // Needed or else node may not reconnect reliably. + // WifiDisconnect(); // Needed or else node may not reconnect reliably. - if (mustRestartWiFi) { - WiFiEventData.processedDisconnect = true; - resetWiFi(); + if (mustRestartWiFi) { + WiFiEventData.processedDisconnect = true; + resetWiFi(); - // WifiScan(false); - // delay(100); - // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); - // initWiFi(); - // delay(100); - } + // WifiScan(false); + // delay(100); + // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); + // initWiFi(); + // delay(100); + } - // delay(500); - logConnectionStatus(); - WiFiEventData.processedDisconnect = true; - WiFiEventData.processingDisconnect.clear(); + // delay(500); + logConnectionStatus(); + WiFiEventData.processedDisconnect = true; + WiFiEventData.processingDisconnect.clear(); + */ } void processConnect() { if (WiFiEventData.processedConnect) { return; } - // delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 - if (checkAndResetWiFi()) { - return; - } + /* + // delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 + if (checkAndResetWiFi()) { + return; + } + */ WiFiEventData.processedConnect = true; - if (WiFi.status() == WL_DISCONNECTED) { - // Apparently not really connected - return; - } - + /* + if (WiFi.status() == WL_DISCONNECTED) { + // Apparently not really connected + return; + } + */ WiFiEventData.setWiFiConnected(); ++WiFiEventData.wifi_reconnects; if (WiFi_AP_Candidates.getCurrent().bits.isEmergencyFallback) { - #ifdef CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS + #ifdef CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS const bool mustResetCredentials = CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS; - #else + #else const bool mustResetCredentials = false; - #endif // ifdef CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS - #ifdef CUSTOM_EMERGENCY_FALLBACK_START_AP + #endif // ifdef CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS + #ifdef CUSTOM_EMERGENCY_FALLBACK_START_AP const bool mustStartAP = CUSTOM_EMERGENCY_FALLBACK_START_AP; - #else + #else const bool mustStartAP = false; - #endif // ifdef CUSTOM_EMERGENCY_FALLBACK_START_AP + #endif // ifdef CUSTOM_EMERGENCY_FALLBACK_START_AP if (mustStartAP) { int allowedUptimeMinutes = 10; - #ifdef CUSTOM_EMERGENCY_FALLBACK_ALLOW_MINUTES_UPTIME + #ifdef CUSTOM_EMERGENCY_FALLBACK_ALLOW_MINUTES_UPTIME allowedUptimeMinutes = CUSTOM_EMERGENCY_FALLBACK_ALLOW_MINUTES_UPTIME; - #endif + #endif if (getUptimeMinutes() < allowedUptimeMinutes) { WiFiEventData.timerAPstart.setNow(); @@ -359,8 +363,9 @@ void processConnect() { } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - const LongTermTimer::Duration connect_duration = WiFiEventData.last_wifi_connect_attempt_moment.timeDiff(WiFiEventData.lastConnectMoment); - String log = strformat( + const LongTermTimer::Duration connect_duration = + WiFiEventData.last_wifi_connect_attempt_moment.timeDiff(WiFiEventData.lastConnectMoment); + String log = strformat( F("WIFI : Connected! AP: %s (%s) Ch: %d"), WiFi.SSID().c_str(), WiFi.BSSIDstr().c_str(), @@ -407,13 +412,13 @@ void processGotIP() { IPAddress ip = NetworkLocalIP(); if (!useStaticIP()) { - #ifdef ESP8266 + #ifdef ESP8266 if (!ip.isSet()) { - #else // ifdef ESP8266 + #else // ifdef ESP8266 if ((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0)) { - #endif // ifdef ESP8266 + #endif // ifdef ESP8266 return; } } @@ -451,13 +456,13 @@ void processGotIP() { WiFi.config(ip, gw, subnet, WiFiEventData.dns0_cache, WiFiEventData.dns1_cache); } -#if FEATURE_MQTT + #if FEATURE_MQTT mqtt_reconnect_count = 0; MQTTclient_should_reconnect = true; timermqtt_interval = 100; Scheduler.setIntervalTimer(SchedulerIntervalTimer_e::TIMER_MQTT); scheduleNextMQTTdelayQueue(); -#endif // if FEATURE_MQTT + #endif // if FEATURE_MQTT Scheduler.sendGratuitousARP_now(); if (Settings.UseRules) @@ -477,9 +482,9 @@ void processGotIP() { if ((WiFiEventData.WiFiConnected() || WiFi.isConnected()) && hasIPaddr()) { WiFiEventData.setWiFiGotIP(); } - #if FEATURE_ESPEASY_P2P + #if FEATURE_ESPEASY_P2P refreshNodeList(); - #endif + #endif logConnectionStatus(); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index 4f7a25cee..c3d91e9c9 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -45,7 +45,7 @@ bool WiFi_pre_STA_setup() return true; } -STA_connected_state getSTA_connected_state() +STA_connected_state getSTA_connected_state() { switch (WiFi.status()) { diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp index a4891c5b9..7388948fd 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp @@ -37,7 +37,7 @@ bool WiFi_pre_STA_setup() { return true; } -STA_connected_state getSTA_connected_state() +STA_connected_state getSTA_connected_state() { // Perform check on SDK function, see: https://github.com/esp8266/Arduino/issues/7432 station_status_t status = wifi_station_get_connect_status(); diff --git a/src/src/ESPEasyCore/ESPEasy_loop.cpp b/src/src/ESPEasyCore/ESPEasy_loop.cpp index b18aedb86..d157addb6 100644 --- a/src/src/ESPEasyCore/ESPEasy_loop.cpp +++ b/src/src/ESPEasyCore/ESPEasy_loop.cpp @@ -5,6 +5,7 @@ #include "../Commands/ExecuteCommand.h" #include "../DataStructs/TimingStats.h" #include "../ESPEasyCore/ESPEasyNetwork.h" +#include "../ESPEasyCore/ESPEasyWifi.h" #include "../ESPEasyCore/ESPEasyWifi_ProcessEvent.h" #include "../ESPEasyCore/ESPEasy_backgroundtasks.h" #include "../ESPEasyCore/ESPEasy_Log.h" @@ -72,6 +73,8 @@ void ESPEasy_loop() updateLoopStats(); + loopWiFi(); + handle_unprocessedNetworkEvents(); bool firstLoopConnectionsEstablished = NetworkConnected() && firstLoop; diff --git a/src/src/Globals/ESPEasyWiFiEvent.cpp b/src/src/Globals/ESPEasyWiFiEvent.cpp index 9ec0c0a46..3428e2d35 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.cpp +++ b/src/src/Globals/ESPEasyWiFiEvent.cpp @@ -14,5 +14,6 @@ WiFiEventHandler APModeStationDisconnectedHandler; #endif // ifdef ESP8266 WiFiEventData_t WiFiEventData; +ESPEasy::net::wifi::ESPEasyWiFi_t ESPEasyWiFi; diff --git a/src/src/Globals/ESPEasyWiFiEvent.h b/src/src/Globals/ESPEasyWiFiEvent.h index 068e3f773..d01d3e49a 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.h +++ b/src/src/Globals/ESPEasyWiFiEvent.h @@ -4,6 +4,8 @@ #include "../../ESPEasy_common.h" +#include "../ESPEasyCore/ESPEasyWiFi_state_machine.h" + #include "../DataStructs/WiFiEventData.h" @@ -34,6 +36,7 @@ extern WiFiEventHandler APModeStationDisconnectedHandler; extern WiFiEventData_t WiFiEventData; +extern ESPEasy::net::wifi::ESPEasyWiFi_t ESPEasyWiFi; #endif // GLOBALS_ESPEASYWIFIEVENT_H diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 7a4430166..15681f954 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -41,7 +41,7 @@ void WiFi_AP_CandidatesList::load_knownCredentials() { _mustLoadCredentials = false; known.clear(); candidates.clear(); -// attemptsLeft = 1; +// attemptsLeft = WiFi_CONNECT_ATTEMPTS; _addedKnownCandidate = false; // addFromRTC(); @@ -137,7 +137,7 @@ void WiFi_AP_CandidatesList::after_process_WiFiscan() { scanned_new.unique(); _mustLoadCredentials = true; WiFi.scanDelete(); - attemptsLeft = 1; + attemptsLeft = WiFi_CONNECT_ATTEMPTS; } bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { @@ -150,7 +150,7 @@ bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { return false; } loadCandidatesFromScanned(); - attemptsLeft = 1; + attemptsLeft = WiFi_CONNECT_ATTEMPTS; if (candidates.empty()) { return false; } */ } @@ -174,7 +174,7 @@ bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { if (mustPop) { if (attemptsLeft == 0) { - if (currentCandidate.bits.isHidden) { + if (currentCandidate.bits.isHidden && !Settings.HiddenSSID_SlowConnectPerBSSID()) { // We tried to connect to hidden SSIDs in 1 run, so pop all hidden candidates. for (auto cand_it = candidates.begin(); cand_it != candidates.end() && cand_it->bits.isHidden; ) { cand_it = candidates.erase(cand_it); @@ -186,7 +186,7 @@ bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { } known_it = known.begin(); - attemptsLeft = 1; + attemptsLeft = WiFi_CONNECT_ATTEMPTS; } else { markAttempt(); } diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index 2c76e04e4..0ad3ba906 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -7,6 +7,8 @@ #include +#define WiFi_CONNECT_ATTEMPTS 2 + typedef std::list::const_iterator WiFi_AP_Candidate_const_iterator; struct WiFi_AP_CandidatesList { @@ -110,7 +112,7 @@ private: bool _mustLoadCredentials = true; bool _addedKnownCandidate = false; public: - int attemptsLeft = 1; + int attemptsLeft = WiFi_CONNECT_ATTEMPTS; }; #endif // ifndef HELPERS_WIFI_AP_CANDIDATESLIST_H From ae7d49e5bb2000073482dcf98c6a2b7d30a707a1 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 5 Nov 2024 00:44:01 +0100 Subject: [PATCH 006/564] [WiFi] Restructure ESP32/ESP8266 code --- src/src/CustomBuild/define_plugin_sets.h | 9 +- src/src/DataStructs/NodeStruct.cpp | 4 +- src/src/DataStructs/WiFiEventData.cpp | 183 ++++++--- src/src/DataStructs/WiFiEventData.h | 22 +- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 380 ++---------------- src/src/ESPEasyCore/ESPEasyNetwork.h | 2 + src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp | 297 ++++++++++++++ .../ESPEasyCore/ESPEasyNetwork_ESP8266.cpp | 87 ++++ .../ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 50 ++- .../ESPEasyWifi_abstracted_ESP32.cpp | 19 +- src/src/Helpers/StringProvider.cpp | 2 + 11 files changed, 580 insertions(+), 475 deletions(-) create mode 100644 src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp create mode 100644 src/src/ESPEasyCore/ESPEasyNetwork_ESP8266.cpp diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index bfda3f398..f2d2506c7 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1104,9 +1104,6 @@ To create/register a plugin, you have to : #define PLUGIN_SET_MAX #define CONTROLLER_SET_ALL #define NOTIFIER_SET_ALL - #ifndef TESTING_FEATURE_USE_IPV6 - #define TESTING_FEATURE_USE_IPV6 - #endif #ifndef PLUGIN_ENERGY_COLLECTION #define PLUGIN_ENERGY_COLLECTION #endif @@ -3511,11 +3508,7 @@ To create/register a plugin, you have to : #ifndef FEATURE_USE_IPV6 # if ESP_IDF_VERSION_MAJOR>=5 && defined(LWIP_IPV6) -# ifdef TESTING_FEATURE_USE_IPV6 -# define FEATURE_USE_IPV6 1 -# else -# define FEATURE_USE_IPV6 0 -# endif +# define FEATURE_USE_IPV6 1 # else # define FEATURE_USE_IPV6 0 # endif diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 70256c2fe..99a8ac800 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -313,8 +313,10 @@ bool NodeStruct::match(const MAC_address& mac) const bool NodeStruct::isThisNode() const { // Check to see if we process a node we've sent ourselves. + #if FEATURE_WIFI if (WifiSoftAPmacAddress() == ap_mac) return true; - if (WifiSTAmacAddress() == sta_mac) return true; + #endif + if (NetworkMacAddress() == sta_mac) return true; return false; } diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 0996d94c4..9adb2c62b 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -10,41 +10,44 @@ #include "../Helpers/Networking.h" -#define WIFI_RECONNECT_WAIT 30000 // in milliSeconds +#define WIFI_RECONNECT_WAIT 30000 // in milliSeconds -#define CONNECT_TIMEOUT_MAX 4000 // in milliSeconds +#define CONNECT_TIMEOUT_MAX 4000 // in milliSeconds #if FEATURE_USE_IPV6 -#include +# include // ----------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------- Private functions ------------------------------------------------ // ----------------------------------------------------------------------------------------------------------------------- esp_netif_t* get_esp_interface_netif(esp_interface_t interface); -#endif +#endif // if FEATURE_USE_IPV6 - - -bool WiFiEventData_t::WiFiConnectAllowed() const { +bool WiFiEventData_t::WiFiConnectAllowed() const { if (WiFi.status() == WL_IDLE_STATUS) { // FIXME TD-er: What to do now? Set a timer? - //return false; - if (last_wifi_connect_attempt_moment.isSet() && - !last_wifi_connect_attempt_moment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { + // return false; + if (last_wifi_connect_attempt_moment.isSet() && + !last_wifi_connect_attempt_moment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { return false; } } - if (!wifiConnectAttemptNeeded) return false; - if (intent_to_reboot) return false; - if (wifiSetupConnect) return true; + + if (!wifiConnectAttemptNeeded) { return false; } + + if (intent_to_reboot) { return false; } + + if (wifiSetupConnect) { return true; } + if (wifiConnectInProgress) { - if (last_wifi_connect_attempt_moment.isSet() && - !last_wifi_connect_attempt_moment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { + if (last_wifi_connect_attempt_moment.isSet() && + !last_wifi_connect_attempt_moment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { return false; } - } + } + if (lastDisconnectMoment.isSet()) { // TODO TD-er: Make this time more dynamic. if (!lastDisconnectMoment.timeoutReached(1000)) { @@ -59,25 +62,29 @@ bool WiFiEventData_t::unprocessedWifiEvents() const { #if FEATURE_USE_IPV6 && processedGotIP6 #endif - ) + ) { return false; } + if (!processedConnect) { if (lastConnectMoment.isSet() && lastConnectMoment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { return false; } } + if (!processedGotIP) { if (lastGetIPmoment.isSet() && lastGetIPmoment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { return false; } } + if (!processedDisconnect) { if (lastDisconnectMoment.isSet() && lastDisconnectMoment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { return false; } } + if (!processedDHCPTimeout) { return false; } @@ -97,22 +104,23 @@ void WiFiEventData_t::clearAll() { void WiFiEventData_t::markWiFiTurnOn() { setWiFiDisconnected(); -// lastDisconnectMoment.clear(); + + // lastDisconnectMoment.clear(); lastConnectMoment.clear(); lastGetIPmoment.clear(); - wifi_considered_stable = false; - + wifi_considered_stable = false; + clear_processed_flags(); } void WiFiEventData_t::clear_processed_flags() { // Mark all flags to default to prevent handling old events. WiFi.scanDelete(); - processedConnect = true; - processedDisconnect = true; - processedGotIP = true; + processedConnect = true; + processedDisconnect = true; + processedGotIP = true; #if FEATURE_USE_IPV6 - processedGotIP6 = true; + processedGotIP6 = true; #endif processedDHCPTimeout = true; processedConnectAPmode = true; @@ -128,17 +136,17 @@ void WiFiEventData_t::clear_processed_flags() { void WiFiEventData_t::markWiFiBegin() { markWiFiTurnOn(); last_wifi_connect_attempt_moment.setNow(); - wifiConnectInProgress = true; - usedChannel = 0; + wifiConnectInProgress = true; + usedChannel = 0; ++wifi_connect_attempt; + if (!timerAPstart.isSet()) { timerAPstart.setMillisFromNow(3 * WIFI_RECONNECT_WAIT); } } - void WiFiEventData_t::setWiFiDisconnected() { - wifiStatus = ESPEASY_WIFI_DISCONNECTED; + wifiStatus = ESPEASY_WIFI_DISCONNECTED; last_wifi_connect_attempt_moment.clear(); wifiConnectInProgress = false; } @@ -146,9 +154,11 @@ void WiFiEventData_t::setWiFiDisconnected() { void WiFiEventData_t::setWiFiGotIP() { bitSet(wifiStatus, ESPEASY_WIFI_GOT_IP); processedGotIP = true; + if (valid_DNS_address(WiFi.dnsIP(0))) { dns0_cache = WiFi.dnsIP(0); } + if (valid_DNS_address(WiFi.dnsIP(1))) { dns1_cache = WiFi.dnsIP(1); } @@ -161,14 +171,14 @@ void WiFiEventData_t::setWiFiConnected() { void WiFiEventData_t::setWiFiServicesInitialized() { if (/*!unprocessedWifiEvents() && */ WiFiConnected() && WiFiGotIP()) { - # ifndef BUILD_NO_DEBUG + #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WiFi : WiFi services initialized")); #endif bitSet(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); - wifiConnectInProgress = false; + wifiConnectInProgress = false; wifiConnectAttemptNeeded = false; - dns0_cache = WiFi.dnsIP(0); - dns1_cache = WiFi.dnsIP(1); + dns0_cache = WiFi.dnsIP(0); + dns1_cache = WiFi.dnsIP(1); } } @@ -183,12 +193,13 @@ void WiFiEventData_t::markGotIP() { } #if FEATURE_USE_IPV6 - void WiFiEventData_t::markGotIPv6(const IPAddress& ip6) { - processedGotIP6 = false; - unprocessed_IP6 = ip6; - } -#endif +void WiFiEventData_t::markGotIPv6(const IPAddress& ip6) { + processedGotIP6 = false; + unprocessed_IP6 = ip6; +} + +#endif // if FEATURE_USE_IPV6 void WiFiEventData_t::markLostIP() { bitClear(wifiStatus, ESPEASY_WIFI_GOT_IP); @@ -196,13 +207,13 @@ void WiFiEventData_t::markLostIP() { } void WiFiEventData_t::markDisconnect(WiFiDisconnectReason reason) { -/* - #if defined(ESP32) - if ((WiFi.getMode() & WIFI_MODE_STA) == 0) return; - #else // if defined(ESP32) - if ((WiFi.getMode() & WIFI_STA) == 0) return; - #endif // if defined(ESP32) -*/ + /* + #if defined(ESP32) + if ((WiFi.getMode() & WIFI_MODE_STA) == 0) return; + #else // if defined(ESP32) + if ((WiFi.getMode() & WIFI_STA) == 0) return; + #endif // if defined(ESP32) + */ lastDisconnectMoment.setNow(); usedChannel = 0; @@ -210,26 +221,29 @@ void WiFiEventData_t::markDisconnect(WiFiDisconnectReason reason) { // There was an unsuccessful connection attempt lastConnectedDuration_us = last_wifi_connect_attempt_moment.timeDiff(lastDisconnectMoment); } else { - if (last_wifi_connect_attempt_moment.isSet()) + if (last_wifi_connect_attempt_moment.isSet()) { lastConnectedDuration_us = lastConnectMoment.timeDiff(lastDisconnectMoment); - else + } + else { lastConnectedDuration_us = 0; + } } - lastDisconnectReason = reason; - processedDisconnect = false; + lastDisconnectReason = reason; + processedDisconnect = false; wifiConnectInProgress = false; } void WiFiEventData_t::markConnected(const String& ssid, const uint8_t bssid[6], uint8_t channel) { usedChannel = channel; lastConnectMoment.setNow(); - processedConnect = false; - channel_changed = RTC.lastWiFiChannel != channel; - last_ssid = ssid; - bssid_changed = false; - auth_mode = WiFi_AP_Candidates.getCurrent().enc_type; + processedConnect = false; + channel_changed = RTC.lastWiFiChannel != channel; + last_ssid = ssid; + bssid_changed = false; + auth_mode = WiFi_AP_Candidates.getCurrent().enc_type; RTC.lastWiFiChannel = channel; + for (uint8_t i = 0; i < 6; ++i) { if (RTC.lastBSSID[i] != bssid[i]) { bssid_changed = true; @@ -237,10 +251,11 @@ void WiFiEventData_t::markConnected(const String& ssid, const uint8_t bssid[6], } } #if FEATURE_USE_IPV6 + if (Settings.EnableIPv6()) { WiFi.enableIPv6(true); } -#endif +#endif // if FEATURE_USE_IPV6 } void WiFiEventData_t::markConnectedAPmode(const uint8_t mac[6]) { @@ -253,19 +268,20 @@ void WiFiEventData_t::markDisconnectedAPmode(const uint8_t mac[6]) { processedDisconnectAPmode = false; } - - String WiFiEventData_t::ESPeasyWifiStatusToString() const { String log; + if (WiFiDisconnected()) { log = F("DISCONNECTED"); } else { if (WiFiConnected()) { log += F("Conn. "); } + if (WiFiGotIP()) { log += F("IP "); } + if (WiFiServicesInitialized()) { log += F("Init"); } @@ -273,12 +289,63 @@ String WiFiEventData_t::ESPeasyWifiStatusToString() const { return log; } - uint32_t WiFiEventData_t::getSuggestedTimeout(int index, uint32_t minimum_timeout) const { auto it = connectDurations.find(index); + if (it == connectDurations.end()) { return 3 * minimum_timeout; } const uint32_t res = 3 * it->second; return constrain(res, minimum_timeout, CONNECT_TIMEOUT_MAX); -} \ No newline at end of file +} + + +#ifdef ESP8266 + bool WiFiEventData_t::WiFiDisconnected() const { + return wifiStatus == ESPEASY_WIFI_DISCONNECTED; + } + + bool WiFiEventData_t::WiFiGotIP() const { + return bitRead(wifiStatus, ESPEASY_WIFI_GOT_IP); + } + + bool WiFiEventData_t::WiFiConnected() const { + return bitRead(wifiStatus, ESPEASY_WIFI_CONNECTED); + } + + bool WiFiEventData_t::WiFiServicesInitialized() const { + return bitRead(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); + } + +#endif + +#ifdef ESP32 + bool WiFiEventData_t::WiFiDisconnected() const { + return !WiFi.STA.connected(); + } + + bool WiFiEventData_t::WiFiGotIP() const { + return WiFi.STA.hasIP(); + } + +#if FEATURE_USE_IPV6 + bool WiFiEventData_t::WiFiGotIPv6() const { + return WiFi.STA.hasGlobalIPv6(); + } +#endif + + bool WiFiEventData_t::WiFiConnected() const { + return WiFi.STA.connected(); + } + + bool WiFiEventData_t::WiFiServicesInitialized() const { + return WiFiConnected() && +#if FEATURE_USE_IPV6 +(WiFiGotIP() || WiFi.STA.hasGlobalIPv6() || WiFi.STA.hasLinkLocalIPv6()); +#else + WiFiGotIP(); +#endif + } + + #endif + diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index 76a3e5ff6..27e8db8c5 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -43,21 +43,13 @@ struct WiFiEventData_t { void clear_processed_flags(); void markWiFiBegin(); - bool WiFiDisconnected() const { - return wifiStatus == ESPEASY_WIFI_DISCONNECTED; - } - - bool WiFiGotIP() const { - return bitRead(wifiStatus, ESPEASY_WIFI_GOT_IP); - } - - bool WiFiConnected() const { - return bitRead(wifiStatus, ESPEASY_WIFI_CONNECTED); - } - - bool WiFiServicesInitialized() const { - return bitRead(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); - } + bool WiFiDisconnected() const; + bool WiFiGotIP() const; +#if FEATURE_USE_IPV6 + bool WiFiGotIPv6() const; +#endif + bool WiFiConnected() const; + bool WiFiServicesInitialized() const; void setWiFiDisconnected(); void setWiFiGotIP(); diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index a5bad8336..b2c697b0c 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -1,331 +1,28 @@ #include "../ESPEasyCore/ESPEasyNetwork.h" -#include "../ESPEasyCore/ESPEasy_Log.h" -#include "../ESPEasyCore/ESPEasyEth.h" -#include "../ESPEasyCore/ESPEasyWifi.h" + #include "../ESPEasyCore/ESPEasyWifi_abstracted.h" -#include "../Globals/ESPEasy_time.h" -#include "../Globals/ESPEasyWiFiEvent.h" + #include "../Globals/NetworkState.h" #include "../Globals/Settings.h" -#include "../Helpers/Network.h" -#include "../Helpers/Networking.h" +#include "../Globals/ESPEasy_time.h" + #include "../Helpers/StringConverter.h" #include "../Helpers/MDNS_Helper.h" -#if FEATURE_ETHERNET -#include "../Globals/ESPEasyEthEvent.h" -#include -#endif - - -#if FEATURE_USE_IPV6 -#include - -// ----------------------------------------------------------------------------------------------------------------------- -// ---------------------------------------------------- Private functions ------------------------------------------------ -// ----------------------------------------------------------------------------------------------------------------------- - -esp_netif_t* get_esp_interface_netif(esp_interface_t interface); -#endif - - -void setNetworkMedium(NetworkMedium_t new_medium) { -#if !(FEATURE_ETHERNET) - if (new_medium == NetworkMedium_t::Ethernet) { - new_medium = NetworkMedium_t::WIFI; - } -#endif - if (active_network_medium == new_medium) { - return; - } - switch (active_network_medium) { - case NetworkMedium_t::Ethernet: - #if FEATURE_ETHERNET - // FIXME TD-er: How to 'end' ETH? -// ETH.end(); - if (new_medium == NetworkMedium_t::WIFI) { - WiFiEventData.clearAll(); -#if ESP_IDF_VERSION_MAJOR >= 5 - WiFi.STA.setDefault(); -#endif - } - #endif - break; - case NetworkMedium_t::WIFI: - WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_DURATION); - WiFiEventData.timerAPstart.clear(); - if (new_medium == NetworkMedium_t::Ethernet) { -#if ESP_IDF_VERSION_MAJOR >= 5 -#if FEATURE_ETHERNET - ETH.setDefault(); -#endif -#endif - WifiDisconnect(); - } - break; - case NetworkMedium_t::NotSet: - break; - } - statusLED(true); - active_network_medium = new_medium; - addLog(LOG_LEVEL_INFO, concat(F("Set Network mode: "), toString(active_network_medium))); -} - - -/*********************************************************************************************\ - Ethernet or Wifi Support for ESP32 Build flag FEATURE_ETHERNET -\*********************************************************************************************/ -void NetworkConnectRelaxed() { - if (NetworkConnected()) return; -#if FEATURE_ETHERNET - if(active_network_medium == NetworkMedium_t::Ethernet) { - if (ETHConnectRelaxed()) { - return; - } - // Failed to start the Ethernet network, probably not present of wrong parameters. - // So set the runtime active medium to WiFi to try connecting to WiFi or at least start the AP. - setNetworkMedium(NetworkMedium_t::WIFI); - } -#endif - // Failed to start the Ethernet network, probably not present of wrong parameters. - // So set the runtime active medium to WiFi to try connecting to WiFi or at least start the AP. - WiFiConnectRelaxed(); -} - -bool NetworkConnected() { - #if FEATURE_ETHERNET - if(active_network_medium == NetworkMedium_t::Ethernet) { - return ETHConnected(); - } - #endif - return WiFiConnected(); -} - -IPAddress NetworkLocalIP() { - #if FEATURE_ETHERNET - if(active_network_medium == NetworkMedium_t::Ethernet) { - if(EthEventData.ethInitSuccess) { - return ETH.localIP(); - } else { - addLog(LOG_LEVEL_ERROR, F("Call NetworkLocalIP() only on connected Ethernet!")); - return IPAddress(); - } - } - #endif - return WiFi.localIP(); -} - -IPAddress NetworkSubnetMask() { - #if FEATURE_ETHERNET - if(active_network_medium == NetworkMedium_t::Ethernet) { - if(EthEventData.ethInitSuccess) { - return ETH.subnetMask(); - } else { - addLog(LOG_LEVEL_ERROR, F("Call NetworkSubnetMask() only on connected Ethernet!")); - return IPAddress(); - } - } - #endif - return WiFi.subnetMask(); -} - -IPAddress NetworkGatewayIP() { - #if FEATURE_ETHERNET - if(active_network_medium == NetworkMedium_t::Ethernet) { - if(EthEventData.ethInitSuccess) { - return ETH.gatewayIP(); - } else { - addLog(LOG_LEVEL_ERROR, F("Call NetworkGatewayIP() only on connected Ethernet!")); - return IPAddress(); - } - } - #endif - return WiFi.gatewayIP(); -} - -IPAddress NetworkDnsIP(uint8_t dns_no) { - scrubDNS(); - #if FEATURE_ETHERNET - if(active_network_medium == NetworkMedium_t::Ethernet) { - if(EthEventData.ethInitSuccess) { - return ETH.dnsIP(dns_no); - } else { - addLog(LOG_LEVEL_ERROR, F("Call NetworkDnsIP(uint8_t dns_no) only on connected Ethernet!")); - return IPAddress(); - } - } - #endif - return WiFi.dnsIP(dns_no); -} - -#if FEATURE_USE_IPV6 -esp_netif_t * getActiveNetworkMediumInterface() { - esp_interface_t iface = ESP_IF_MAX; - #if FEATURE_ETHERNET - if(active_network_medium == NetworkMedium_t::Ethernet) { - if(EthEventData.ethInitSuccess) { - esp_netif_t *res = ETH.netif(); - if (res == nullptr) { - res = get_esp_interface_netif(ESP_IF_ETH); - } - if (res != nullptr) - return res; - } - } else - #endif - { - if ( ESPEasy::net::wifi::WifiIsSTA(WiFi.getMode())) { - iface = ESP_IF_WIFI_STA; - } - } - if (ESP_IF_MAX == iface) - return nullptr; - return get_esp_interface_netif(iface); -} - -IPAddress NetworkLocalIP6() { - esp_netif_t * iface = getActiveNetworkMediumInterface(); - esp_ip6_addr_t addr; - if (nullptr == iface || - esp_netif_get_ip6_linklocal(iface, &addr)) - { - return IN6ADDR_ANY; - } - - IPAddress res(IPv6, (const uint8_t*)addr.addr, addr.zone); - return res; -} - -IPAddress NetworkGlobalIP6() { - esp_netif_t * iface = getActiveNetworkMediumInterface(); - esp_ip6_addr_t addr; - if (nullptr == iface || - esp_netif_get_ip6_global(iface, &addr)) - { - return IN6ADDR_ANY; - } - - IPAddress res(IPv6, (const uint8_t*)addr.addr, addr.zone); - return res; -} - -IP6Addresses_t NetworkAllIPv6() { - IP6Addresses_t addresses; - esp_netif_t * iface = getActiveNetworkMediumInterface(); - if (nullptr != iface) { - esp_ip6_addr_t esp_ip6_addr[LWIP_IPV6_NUM_ADDRESSES]{}; - - int count = esp_netif_get_all_ip6(iface, esp_ip6_addr); - for (int i = 0; i < count; ++i) { - addresses.emplace_back(IPv6, (const uint8_t*)esp_ip6_addr[i].addr, esp_ip6_addr[i].zone); - } - } - - return addresses; -} - -bool IPv6_from_MAC(const MAC_address& mac, IPAddress& ipv6) -{ - if (ipv6 == IN6ADDR_ANY) { return false; } - int index_offset = 8; - - for (int i = 0; i < 6; ++i, ++index_offset) { - ipv6[index_offset] = mac.mac[i]; - - if (i == 0) { - // invert bit 2 - bitToggle(ipv6[index_offset], 1); - } - - if (i == 2) { - ipv6[++index_offset] = 0xFF; - ipv6[++index_offset] = 0xFE; - } - } -/* - addLog(LOG_LEVEL_INFO, strformat( - F("IPv6_from_MAC: Mac %s IP %s"), - mac.toString().c_str(), - ipv6.toString(true).c_str() - )); -*/ - return true; -} - -bool is_IPv6_based_on_MAC(const MAC_address& mac, const IPAddress& ipv6) -{ - IPAddress tmp = ipv6; - - if (IPv6_from_MAC(mac, tmp)) { - return ipv6 == tmp; - } - return false; -} - -bool IPv6_link_local_from_MAC(const MAC_address& mac, IPAddress& ipv6) -{ - ipv6 = NetworkLocalIP6(); - return IPv6_from_MAC(mac, ipv6); -} - -bool is_IPv6_link_local_from_MAC(const MAC_address& mac) -{ - return is_IPv6_based_on_MAC(mac, NetworkLocalIP6()); -} - -// Assume we're in the same subnet, thus use our own IPv6 global address -bool IPv6_global_from_MAC(const MAC_address& mac, IPAddress& ipv6) -{ - ipv6 = NetworkGlobalIP6(); - return IPv6_from_MAC(mac, ipv6); -} - -bool is_IPv6_global_from_MAC(const MAC_address& mac) -{ - return is_IPv6_based_on_MAC(mac, NetworkGlobalIP6()); -} - -#endif // if FEATURE_USE_IPV6 - - - -MAC_address NetworkMacAddress() { - #if FEATURE_ETHERNET - if(active_network_medium == NetworkMedium_t::Ethernet) { - return ETHMacAddress(); - } - #endif - MAC_address mac; - WiFi.macAddress(mac.mac); - return mac; -} - -String NetworkGetHostname() { - #ifdef ESP32 - #if FEATURE_ETHERNET - if(Settings.NetworkMedium == NetworkMedium_t::Ethernet && EthEventData.ethInitSuccess) { - return String(ETH.getHostname()); - } - #endif - return String(WiFi.getHostname()); - #else - return String(WiFi.hostname()); - #endif -} - // ******************************************************************************** // Determine Wifi AP name to set. (also used for mDNS) // ******************************************************************************** String NetworkGetHostNameFromSettings(bool force_add_unitnr) { - if (force_add_unitnr) return Settings.getHostname(true); + if (force_add_unitnr) { return Settings.getHostname(true); } return Settings.getHostname(); } String NetworkCreateRFCCompliantHostname(bool force_add_unitnr) { String hostname(NetworkGetHostNameFromSettings(force_add_unitnr)); + // Create hostname with - instead of spaces // See RFC952. @@ -334,8 +31,10 @@ String NetworkCreateRFCCompliantHostname(bool force_add_unitnr) { // * numerals (0-9) // * Hyphen (-) replaceUnicodeByChar(hostname, '-'); + for (size_t i = 0; i < hostname.length(); ++i) { const char c = hostname[i]; + if (!isAlphaNumeric(c)) { hostname[i] = '-'; } @@ -343,21 +42,26 @@ String NetworkCreateRFCCompliantHostname(bool force_add_unitnr) { // May not start or end with a hyphen const String dash('-'); + while (hostname.startsWith(dash)) { hostname = hostname.substring(1); } + while (hostname.endsWith(dash)) { hostname = hostname.substring(0, hostname.length() - 1); } // May not contain only numerals bool onlyNumerals = true; + for (size_t i = 0; onlyNumerals && i < hostname.length(); ++i) { const char c = hostname[i]; + if (!isdigit(c)) { onlyNumerals = false; } } + if (onlyNumerals) { hostname = concat(F("ESPEasy-"), hostname); } @@ -369,59 +73,23 @@ String NetworkCreateRFCCompliantHostname(bool force_add_unitnr) { return hostname; } -MAC_address WifiSoftAPmacAddress() { - MAC_address mac; - WiFi.softAPmacAddress(mac.mac); - return mac; -} - -MAC_address WifiSTAmacAddress() { - MAC_address mac; - WiFi.macAddress(mac.mac); - return mac; -} - void CheckRunningServices() { // First try to get the time, since that may be used in logs - if (Settings.UseNTP() && node_time.getTimeSource() > timeSource_t::NTP_time_source) { + if (Settings.UseNTP() && (node_time.getTimeSource() > timeSource_t::NTP_time_source)) { node_time.lastNTPSyncTime_ms = 0; node_time.initTime(); } -#if FEATURE_SET_WIFI_TX_PWR - if (active_network_medium == NetworkMedium_t::WIFI) +#if FEATURE_WIFI +# if FEATURE_SET_WIFI_TX_PWR + + if (active_network_medium == NetworkMedium_t::WIFI) { - SetWiFiTXpower(); + ESPEasy::net::wifi::SetWiFiTXpower(); } -#endif +# endif // if FEATURE_SET_WIFI_TX_PWR +#endif // if FEATURE_WIFI + +#if FEATURE_MDNS set_mDNS(); + #endif } - -#if FEATURE_ETHERNET -bool EthFullDuplex() -{ - if (EthEventData.ethInitSuccess) - return ETH.fullDuplex(); - return false; -} - -bool EthLinkUp() -{ - if (EthEventData.ethInitSuccess) { - #if ESP_IDF_VERSION_MAJOR < 5 - // FIXME TD-er: See: https://github.com/espressif/arduino-esp32/issues/6105 - return EthEventData.EthConnected(); - #else - return ETH.linkUp(); - #endif - } - return false; -} - -uint8_t EthLinkSpeed() -{ - if (EthEventData.ethInitSuccess) { - return ETH.linkSpeed(); - } - return 0; -} -#endif diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.h b/src/src/ESPEasyCore/ESPEasyNetwork.h index c6e00d7af..436fab792 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.h +++ b/src/src/ESPEasyCore/ESPEasyNetwork.h @@ -40,8 +40,10 @@ MAC_address NetworkMacAddress(); String NetworkGetHostNameFromSettings(bool force_add_unitnr = false); String NetworkGetHostname(); String NetworkCreateRFCCompliantHostname(bool force_add_unitnr = false); +#if FEATURE_WIFI MAC_address WifiSoftAPmacAddress(); MAC_address WifiSTAmacAddress(); +#endif void CheckRunningServices(); diff --git a/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp new file mode 100644 index 000000000..becbf000c --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp @@ -0,0 +1,297 @@ +#ifdef ESP32 + +#include "../ESPEasyCore/ESPEasyNetwork.h" + +#include "../ESPEasyCore/ESPEasy_Log.h" +#include "../ESPEasyCore/ESPEasyEth.h" +#include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" +#include "../Globals/ESPEasy_time.h" +#include "../Globals/ESPEasyWiFiEvent.h" +#include "../Globals/NetworkState.h" +#include "../Globals/Settings.h" + +#include "../Globals/ESPEasyEthEvent.h" + +#include "../Helpers/Network.h" +#include "../Helpers/Networking.h" +#include "../Helpers/StringConverter.h" +#include "../Helpers/MDNS_Helper.h" + +#include + +#if FEATURE_ETHERNET +# include +#endif + +void setNetworkMedium(NetworkMedium_t new_medium) { +#if !(FEATURE_ETHERNET) + + if (new_medium == NetworkMedium_t::Ethernet) { + new_medium = NetworkMedium_t::WIFI; + } +#endif // if !(FEATURE_ETHERNET) + + if (new_medium == active_network_medium) { + return; + } + + switch (active_network_medium) + { + case NetworkMedium_t::WIFI: + WiFi.STA.end(); + break; + case NetworkMedium_t::Ethernet: +#if FEATURE_ETHERNET + ETH.end(); +#endif // if FEATURE_ETHERNET + break; + case NetworkMedium_t::NotSet: + break; + } + + switch (new_medium) + { + case NetworkMedium_t::WIFI: + WiFi.STA.setDefault(); + break; + case NetworkMedium_t::Ethernet: +#if FEATURE_ETHERNET + ETH.setDefault(); +#endif // if FEATURE_ETHERNET + break; + case NetworkMedium_t::NotSet: + break; + } + statusLED(true); + active_network_medium = new_medium; + addLog(LOG_LEVEL_INFO, concat(F("Set Network mode: "), toString(active_network_medium))); +} + +/*********************************************************************************************\ + Ethernet or Wifi Support for ESP32 Build flag FEATURE_ETHERNET +\*********************************************************************************************/ +void NetworkConnectRelaxed() { + if (NetworkConnected()) { return; } +#if FEATURE_ETHERNET + + if (active_network_medium == NetworkMedium_t::Ethernet) { + if (ETHConnectRelaxed()) { + return; + } + + // Failed to start the Ethernet network, probably not present of wrong parameters. + // So set the runtime active medium to WiFi to try connecting to WiFi or at least start the AP. + setNetworkMedium(NetworkMedium_t::WIFI); + } +#endif // if FEATURE_ETHERNET + + // Failed to start the Ethernet network, probably not present of wrong parameters. + // So set the runtime active medium to WiFi to try connecting to WiFi or at least start the AP. + WiFiConnectRelaxed(); +} + +bool NetworkConnected() { + auto network_if = Network.getDefaultInterface(); + + if (network_if == nullptr) { + return false; + } + return network_if->connected(); +} + +IPAddress NetworkLocalIP() { + auto network_if = Network.getDefaultInterface(); + + if (network_if == nullptr) { + return IPAddress(); + } + return network_if->localIP(); +} + +IPAddress NetworkSubnetMask() { + auto network_if = Network.getDefaultInterface(); + + if (network_if == nullptr) { + return IPAddress(); + } + return network_if->subnetMask(); +} + +IPAddress NetworkGatewayIP() { + auto network_if = Network.getDefaultInterface(); + + if (network_if == nullptr) { + return IPAddress(); + } + return network_if->gatewayIP(); +} + +IPAddress NetworkDnsIP(uint8_t dns_no) { + auto network_if = Network.getDefaultInterface(); + + if (network_if == nullptr) { + return IPAddress(); + } + return network_if->dnsIP(dns_no); +} + +#if FEATURE_USE_IPV6 + +IPAddress NetworkLocalIP6() { + auto network_if = Network.getDefaultInterface(); + + if (network_if == nullptr) { + return IN6ADDR_ANY; + } + return network_if->linkLocalIPv6(); +} + +IPAddress NetworkGlobalIP6() { + auto network_if = Network.getDefaultInterface(); + + if (network_if == nullptr) { + return IN6ADDR_ANY; + } + return network_if->globalIPv6(); +} + +IP6Addresses_t NetworkAllIPv6() { + IP6Addresses_t addresses; + auto network_if = Network.getDefaultInterface(); + + if (network_if != nullptr) { + esp_ip6_addr_t esp_ip6_addr[LWIP_IPV6_NUM_ADDRESSES]{}; + + int count = esp_netif_get_all_ip6(network_if->netif(), esp_ip6_addr); + + for (int i = 0; i < count; ++i) { + addresses.emplace_back(IPv6, (const uint8_t *)esp_ip6_addr[i].addr, esp_ip6_addr[i].zone); + } + } + + return addresses; +} + +bool IPv6_from_MAC(const MAC_address& mac, IPAddress& ipv6) +{ + if (ipv6 == IN6ADDR_ANY) { return false; } + int index_offset = 8; + + for (int i = 0; i < 6; ++i, ++index_offset) { + ipv6[index_offset] = mac.mac[i]; + + if (i == 0) { + // invert bit 2 + bitToggle(ipv6[index_offset], 1); + } + + if (i == 2) { + ipv6[++index_offset] = 0xFF; + ipv6[++index_offset] = 0xFE; + } + } + + /* + addLog(LOG_LEVEL_INFO, strformat( + F("IPv6_from_MAC: Mac %s IP %s"), + mac.toString().c_str(), + ipv6.toString(true).c_str() + )); + */ + return true; +} + +bool is_IPv6_based_on_MAC(const MAC_address& mac, const IPAddress& ipv6) +{ + IPAddress tmp = ipv6; + + if (IPv6_from_MAC(mac, tmp)) { + return ipv6 == tmp; + } + return false; +} + +bool IPv6_link_local_from_MAC(const MAC_address& mac, IPAddress& ipv6) +{ + ipv6 = NetworkLocalIP6(); + return IPv6_from_MAC(mac, ipv6); +} + +bool is_IPv6_link_local_from_MAC(const MAC_address& mac) { return is_IPv6_based_on_MAC(mac, NetworkLocalIP6()); } + +// Assume we're in the same subnet, thus use our own IPv6 global address +bool IPv6_global_from_MAC(const MAC_address& mac, IPAddress& ipv6) +{ + ipv6 = NetworkGlobalIP6(); + return IPv6_from_MAC(mac, ipv6); +} + +bool is_IPv6_global_from_MAC(const MAC_address& mac) { return is_IPv6_based_on_MAC(mac, NetworkGlobalIP6()); } + +#endif // if FEATURE_USE_IPV6 + +MAC_address NetworkMacAddress() { + MAC_address res; + auto network_if = Network.getDefaultInterface(); + + if (network_if != nullptr) { + network_if->macAddress(res.mac); + } + return res; +} + +String NetworkGetHostname() { + auto network_if = Network.getDefaultInterface(); + + if (network_if != nullptr) { + return network_if->getHostname(); + } + return EMPTY_STRING; +} + +#if FEATURE_WIFI +MAC_address WifiSoftAPmacAddress() { + MAC_address mac; + + WiFi.AP.macAddress(mac.mac); + return mac; +} + +MAC_address WifiSTAmacAddress() { + MAC_address mac; + + WiFi.macAddress(mac.mac); + return mac; +} +#endif + +#if FEATURE_ETHERNET + +bool EthFullDuplex() +{ + if (EthEventData.ethInitSuccess) { + return ETH.fullDuplex(); + } + return false; +} + +bool EthLinkUp() +{ + if (EthEventData.ethInitSuccess) { + return ETH.linkUp(); + } + return false; +} + +uint8_t EthLinkSpeed() +{ + if (EthEventData.ethInitSuccess) { + return ETH.linkSpeed(); + } + return 0; +} + +#endif // if FEATURE_ETHERNET + +#endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyNetwork_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyNetwork_ESP8266.cpp new file mode 100644 index 000000000..f31ea0c89 --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasyNetwork_ESP8266.cpp @@ -0,0 +1,87 @@ +#ifdef ESP8266 + +#include "../ESPEasyCore/ESPEasyNetwork.h" + +#include "../ESPEasyCore/ESPEasy_Log.h" +#include "../ESPEasyCore/ESPEasyEth.h" +#include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" +#include "../Globals/ESPEasy_time.h" +#include "../Globals/ESPEasyWiFiEvent.h" +#include "../Globals/NetworkState.h" +#include "../Globals/Settings.h" + +#include "../Helpers/Network.h" +#include "../Helpers/Networking.h" +#include "../Helpers/StringConverter.h" +#include "../Helpers/MDNS_Helper.h" + +void setNetworkMedium(NetworkMedium_t new_medium) { + if (new_medium == NetworkMedium_t::Ethernet) { + new_medium = NetworkMedium_t::WIFI; + } + + if (new_medium == active_network_medium) { + return; + } + + switch (active_network_medium) + { + case NetworkMedium_t::Ethernet: + break; + case NetworkMedium_t::WIFI: + WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_DURATION); + WiFiEventData.timerAPstart.clear(); + break; + case NetworkMedium_t::NotSet: + break; + } + statusLED(true); + active_network_medium = new_medium; + addLog(LOG_LEVEL_INFO, concat(F("Set Network mode: "), toString(active_network_medium))); +} + +/*********************************************************************************************\ + Ethernet or Wifi Support for ESP32 Build flag FEATURE_ETHERNET +\*********************************************************************************************/ +void NetworkConnectRelaxed() { + if (NetworkConnected()) { return; } + WiFiConnectRelaxed(); +} + +bool NetworkConnected() { return WiFiConnected(); } + +IPAddress NetworkLocalIP() { return WiFi.localIP(); } + +IPAddress NetworkSubnetMask() { return WiFi.subnetMask(); } + +IPAddress NetworkGatewayIP() { return WiFi.gatewayIP(); } + +IPAddress NetworkDnsIP(uint8_t dns_no) { return WiFi.dnsIP(dns_no); } + +MAC_address NetworkMacAddress() { + MAC_address mac; + + WiFi.macAddress(mac.mac); + return mac; +} + +String NetworkGetHostname() { return String(WiFi.hostname()); } + +#if FEATURE_WIFI +MAC_address WifiSoftAPmacAddress() { + MAC_address mac; + + WiFi.softAPmacAddress(mac.mac); + return mac; +} + +MAC_address WifiSTAmacAddress() { + MAC_address mac; + + WiFi.macAddress(mac.mac); + return mac; +} +#endif + +#endif // ifdef ESP8266 diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index 923a009ba..225c6f687 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -21,7 +21,7 @@ namespace ESPEasy { namespace net { namespace wifi { - # define WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT 2000 + # define WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT 6000 # define WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT 10000 # define WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT 10000 @@ -53,7 +53,7 @@ void ESPEasyWiFi_t::loop() if (_state != WiFiState_e::IdleWaiting) { - if (_callbackError || + if (_callbackError || (_state_timeout.isSet() && _state_timeout.timeReached())) { // TODO TD-er: Must check what error was given??? @@ -135,12 +135,6 @@ void ESPEasyWiFi_t::loop() // Check if we need to start AP // Flag captive portal in webserver and/or whether we might be in setup mode } - -# ifdef USE_IMPROV - { - // Check for Improv mode. - } -# endif // ifdef USE_IMPROV } bool ESPEasyWiFi_t::connected() const @@ -150,12 +144,17 @@ bool ESPEasyWiFi_t::connected() const IPAddress ESPEasyWiFi_t::getIP() const { - IPAddress res; + if (WiFi.STA.hasIP()) { + return WiFi.STA.localIP(); + } - return res; + if (WiFi.AP.hasIP()) { + return WiFi.AP.localIP(); + } + return IPAddress(); } -void ESPEasyWiFi_t::disconnect() {} +void ESPEasyWiFi_t::disconnect() { WiFi.disconnect(Settings.WiFiRestart_connection_lost()); } void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -200,8 +199,13 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { break; case WiFiState_e::STA_Connecting: case WiFiState_e::STA_Reconnecting: + // Start connecting - connectSTA(); + if (!connectSTA()) { + // TODO TD-er: Must keep track of failed attempts and start AP when either no credentials present or nr. of attempts failed > some + // threshold. + setState(WiFiState_e::IdleWaiting, 100); + } break; case WiFiState_e::STA_Connected: _last_seen_connected.setNow(); @@ -255,7 +259,6 @@ bool ESPEasyWiFi_t::connectSTA() // Start the process of connecting or starting AP if (!WiFi_AP_Candidates.getNext(true)) { - startScanning(); return false; } @@ -303,13 +306,22 @@ bool ESPEasyWiFi_t::connectSTA() } # endif // ifdef ESP32 - - if ((Settings.HiddenSSID_SlowConnectPerBSSID() || !candidate.bits.isHidden) - && candidate.allowQuickConnect() - && (_state == WiFiState_e::STA_Reconnecting)) { - WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); + if (candidate.bits.isHidden /*&& Settings.HiddenSSID_SlowConnectPerBSSID()*/) { + WiFi.disconnect(); + delay(100); + WiFi.begin("" /*candidate.ssid.c_str()*/, key.c_str(), candidate.channel, candidate.bssid.mac); + // If the ssid returned from the scan is empty, it is a hidden SSID + // it appears that the WiFi.begin() function is asynchronous and takes + // additional time to connect to a hidden SSID. Therefore a delay of 1000ms + // is added for hidden SSIDs before calling WiFi.status() + delay(1000); +// WiFi.waitForConnectResult(6000); } else { - WiFi.begin(candidate.ssid.c_str(), key.c_str()); + if (candidate.allowQuickConnect()) { + WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); + } else { + WiFi.begin(candidate.ssid.c_str(), key.c_str()); + } } // Always wait for a second diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index c3d91e9c9..a7cb9bda5 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -45,7 +45,7 @@ bool WiFi_pre_STA_setup() return true; } -STA_connected_state getSTA_connected_state() +STA_connected_state getSTA_connected_state() { switch (WiFi.status()) { @@ -117,11 +117,8 @@ bool setWifiMode(WiFiMode_t new_mode) if (cur_mode == WIFI_OFF) { - # if defined(ESP32) - // Needs to be set while WiFi is off WiFi.hostname(NetworkCreateRFCCompliantHostname()); - # endif // if defined(ESP32) WiFiEventData.markWiFiTurnOn(); } @@ -166,20 +163,13 @@ bool setWifiMode(WiFiMode_t new_mode) // FIXME TD-er: Is this correct to mark Turn ON ???? WiFiEventData.markWiFiTurnOn(); - # if defined(ESP32) // Needs to be set while WiFi is off WiFi.hostname(NetworkCreateRFCCompliantHostname()); - # endif // if defined(ESP32) delay(100); - # if defined(ESP32) esp_wifi_set_ps(WIFI_PS_NONE); // esp_wifi_set_ps(WIFI_PS_MAX_MODEM); - # endif // if defined(ESP32) - # ifdef ESP8266 - WiFi.forceSleepBegin(); - # endif // ifdef ESP8266 delay(1); } else { if (cur_mode == WIFI_OFF) { @@ -380,17 +370,10 @@ void setWiFiNoneSleep() { WiFi.setSleep(WIFI_PS_NONE); } void setWiFiEcoPowerMode() { - // Allow light sleep during idle times -# ifdef ESP8266 - WiFi.setSleepMode(WIFI_LIGHT_SLEEP); -# endif // ifdef ESP8266 -# ifdef ESP32 - // Maximum modem power saving. // In this mode, interval to receive beacons is determined by the listen_interval parameter in wifi_sta_config_t // FIXME TD-er: Must test if this is desired behavior in ESP32. WiFi.setSleep(WIFI_PS_MAX_MODEM); -# endif // ifdef ESP32 } void setWiFiDefaultPowerMode() diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index ec1ad917a..9da859818 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -488,6 +488,7 @@ String getValue(LabelType::Enum label) { case LabelType::DNS_1: return formatIP(NetworkDnsIP(0)); case LabelType::DNS_2: return formatIP(NetworkDnsIP(1)); case LabelType::ALLOWED_IP_RANGE: return describeAllowedIPrange(); +#if FEATURE_WIFI case LabelType::STA_MAC: return WifiSTAmacAddress().toString(); case LabelType::AP_MAC: return WifiSoftAPmacAddress().toString(); case LabelType::SSID: return WiFi.SSID(); @@ -495,6 +496,7 @@ String getValue(LabelType::Enum label) { case LabelType::CHANNEL: retval = WiFi.channel(); break; case LabelType::ENCRYPTION_TYPE_STA: return // WiFi_AP_Candidates.getCurrent().encryption_type(); WiFi_encryptionType(WiFiEventData.auth_mode); +#endif case LabelType::CONNECTED: #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { From 7fed5ff3627228c444fffc215bd6d66ef43112d0 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 9 Nov 2024 16:34:49 +0100 Subject: [PATCH 007/564] [WiFi] Allow connecting to hidden SSID network --- .../ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp | 14 +------ .../ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 34 +++++++++------- .../ESPEasyWiFi_state_machine_ESP32.cpp | 22 ++++++++++ .../ESPEasyWiFi_state_machine_ESP8266.cpp | 14 +++++++ src/src/ESPEasyCore/ESPEasyWifi.cpp | 8 +--- .../ESPEasyCore/ESPEasyWifi_abstracted.cpp | 2 + src/src/ESPEasyCore/ESPEasyWifi_abstracted.h | 3 -- .../ESPEasyWifi_abstracted_ESP32.cpp | 40 +------------------ .../ESPEasyWifi_abstracted_ESP8266.cpp | 27 ------------- src/src/Helpers/WiFi_AP_CandidatesList.h | 2 +- 10 files changed, 63 insertions(+), 103 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp index 06d70ae52..d1156a195 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp @@ -117,19 +117,7 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { break; } case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: - - if (!ignoreDisconnectEvent) { - ignoreDisconnectEvent = true; - WiFiEventData.markDisconnect(static_cast(info.wifi_sta_disconnected.reason)); - - if (info.wifi_sta_disconnected.reason == WIFI_REASON_AUTH_EXPIRE) { - // See: https://github.com/espressif/arduino-esp32/issues/8877#issuecomment-1807677897 - // FIXME TD-er: Should no longer be needed. - WiFi.STA._setStatus(WL_CONNECTION_LOST); - } - WiFi.persistent(false); - WiFi.disconnect(true); - } + WiFiEventData.markDisconnect(static_cast(info.wifi_sta_disconnected.reason)); break; case ARDUINO_EVENT_WIFI_STA_GOT_IP: ignoreDisconnectEvent = false; diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index 225c6f687..8060c61ea 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -16,12 +16,13 @@ # include "../Globals/WiFi_AP_Candidates.h" # include "../Helpers/StringConverter.h" +#include "../Helpers/StringGenerator_WiFi.h" namespace ESPEasy { namespace net { namespace wifi { - # define WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT 6000 + # define WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT 10000 # define WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT 10000 # define WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT 10000 @@ -142,17 +143,6 @@ bool ESPEasyWiFi_t::connected() const return getSTA_connected_state() == STA_connected_state::Connected; } -IPAddress ESPEasyWiFi_t::getIP() const -{ - if (WiFi.STA.hasIP()) { - return WiFi.STA.localIP(); - } - - if (WiFi.AP.hasIP()) { - return WiFi.AP.localIP(); - } - return IPAddress(); -} void ESPEasyWiFi_t::disconnect() { WiFi.disconnect(Settings.WiFiRestart_connection_lost()); } @@ -243,6 +233,13 @@ bool ESPEasyWiFi_t::connectSTA() } return false; } + if (WiFiEventData.lastDisconnectReason != WIFI_DISCONNECT_REASON_UNSPECIFIED) { + addLog(LOG_LEVEL_INFO, concat( + F("WiFi : Disconnect reason: "), + getLastDisconnectReason())); + WiFiEventData.processedDisconnect = true; + } + WiFiEventData.warnedNoValidWiFiSettings = false; setSTA(true); # if defined(ESP8266) @@ -307,9 +304,12 @@ bool ESPEasyWiFi_t::connectSTA() # endif // ifdef ESP32 if (candidate.bits.isHidden /*&& Settings.HiddenSSID_SlowConnectPerBSSID()*/) { - WiFi.disconnect(); +// WiFi.disconnect(false, true); +# ifdef ESP32 + WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); +#endif delay(100); - WiFi.begin("" /*candidate.ssid.c_str()*/, key.c_str(), candidate.channel, candidate.bssid.mac); + WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); // If the ssid returned from the scan is empty, it is a hidden SSID // it appears that the WiFi.begin() function is asynchronous and takes // additional time to connect to a hidden SSID. Therefore a delay of 1000ms @@ -318,8 +318,14 @@ bool ESPEasyWiFi_t::connectSTA() // WiFi.waitForConnectResult(6000); } else { if (candidate.allowQuickConnect()) { +# ifdef ESP32 + WiFi.setScanMethod(WIFI_FAST_SCAN); +#endif WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); } else { +# ifdef ESP32 + WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); +#endif WiFi.begin(candidate.ssid.c_str(), key.c_str()); } } diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp index bdeeb3ea7..1e2066d3a 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp @@ -9,6 +9,7 @@ # include # include +# include # include # include "../ESPEasyCore/ESPEasyWifi_abstracted.h" @@ -18,8 +19,29 @@ namespace ESPEasy { namespace net { namespace wifi { + +IPAddress ESPEasyWiFi_t::getIP() const +{ + if (WiFi.STA.hasIP()) { + return WiFi.STA.localIP(); + } + + if (WiFi.AP.hasIP()) { + return WiFi.AP.localIP(); + } + return IPAddress(); +} + STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() const { + if (WiFi.STA.connected()) { + if (WiFi.STA.hasIP()) { + return STA_connected_state::Connected; + } + return STA_connected_state::Connecting; + } + + switch (WiFi.status()) { case WL_CONNECTED: diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp index aad6d5367..ff8de9bb8 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp @@ -10,6 +10,20 @@ namespace net { namespace wifi { +IPAddress ESPEasyWiFi_t::getIP() const +{ + IPAddress ip = WiFi.localIP(); + if (ip.isSet()) { + return ip; + } + ip = WiFi.softAPIP(); + if (ip.isSet()) { + return ip; + } + return IPAddress(); +} + + STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() const { // Perform check on SDK function, see: https://github.com/esp8266/Arduino/issues/7432 diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 994720c03..19feae0f7 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -310,13 +310,7 @@ void WifiScan(bool async, uint8_t channel) { async = false; if (Settings.IncludeHiddenSSID()) { - wifi_country_t config = { - .cc = "01", - .schan = 1, - .nchan = 14, - .policy = WIFI_COUNTRY_POLICY_MANUAL, - }; - esp_wifi_set_country(&config); + ESPEasy::net::wifi::setWiFiCountryPolicyManual(); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp index 2cd0fe1f2..155e4f63e 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp @@ -26,6 +26,8 @@ const __FlashStringHelper* getWifiModeString(WiFiMode_t wifimode) return F("Unknown"); } +bool WiFiConnected() { return ESPEasyWiFi.connected(); } + bool setSTA(bool enable) { return setSTA_AP(enable, WifiIsAP(WiFi.getMode())); } bool setAP(bool enable) { return setSTA_AP(WifiIsSTA(WiFi.getMode()), enable); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h index 4eab7584a..3fd86c22b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h @@ -31,9 +31,6 @@ bool WiFi_pre_setup(); // Call before setting WiFi into STA mode bool WiFi_pre_STA_setup(); -STA_connected_state getSTA_connected_state(); - - bool WiFiConnected(); void WiFiDisconnect(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index a7cb9bda5..2f5f28a23 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -45,42 +45,6 @@ bool WiFi_pre_STA_setup() return true; } -STA_connected_state getSTA_connected_state() -{ - switch (WiFi.status()) - { - case WL_CONNECTED: - return STA_connected_state::Connected; - - case WL_NO_SSID_AVAIL: - return STA_connected_state::Error_Not_Found; - - case WL_CONNECT_FAILED: - case WL_CONNECTION_LOST: - return STA_connected_state::Error_Connect_Failed; - - case WL_NO_SHIELD: - case WL_STOPPED: - case WL_IDLE_STATUS: - case WL_SCAN_COMPLETED: - case WL_DISCONNECTED: - // ToDo TD-er: What to do here? Should we add some disconnected state? - break; - - } - - // TODO: Keep track of whether connection is in progress - // The status() function does not return a reply stating "connecting" - - /* if (_sta_connecting) { - return STA_connected_state::Connecting; - } - */ - return STA_connected_state::Idle; -} - -bool WiFiConnected() { return WiFi.isConnected(); } - void WiFiDisconnect() { removeWiFiEventHandler(); WiFi.disconnect(); @@ -385,7 +349,7 @@ void setWiFiDefaultPowerMode() void setWiFiCountryPolicyManual() { - wifi_country_t config = { +/* wifi_country_t config = { .cc = "01", .schan = 1, .nchan = 14, @@ -393,7 +357,7 @@ void setWiFiCountryPolicyManual() }; esp_wifi_set_country(&config); -} + */} } // namespace wifi } // namespace net diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp index 7388948fd..ceb659e7b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp @@ -37,33 +37,6 @@ bool WiFi_pre_STA_setup() { return true; } -STA_connected_state getSTA_connected_state() -{ - // Perform check on SDK function, see: https://github.com/esp8266/Arduino/issues/7432 - station_status_t status = wifi_station_get_connect_status(); - - switch (status) - { - case STATION_GOT_IP: - return STA_connected_state::Connected; - case STATION_NO_AP_FOUND: - return STA_connected_state::Error_Not_Found; - case STATION_CONNECT_FAIL: - case STATION_WRONG_PASSWORD: - return STA_connected_state::Error_Connect_Failed; - case STATION_CONNECTING: - return STA_connected_state::Connecting; - case STATION_IDLE: - break; - - default: - break; - } - return STA_connected_state::Idle; -} - -bool WiFiConnected() { return getSTA_connected_state() == STA_connected_state::Connected; } - void WiFiDisconnect() { // Only call disconnect when STA is active if ( WifiIsSTA(WiFi.getMode())) { diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index 0ad3ba906..9e6f29f1c 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -7,7 +7,7 @@ #include -#define WiFi_CONNECT_ATTEMPTS 2 +#define WiFi_CONNECT_ATTEMPTS 1 typedef std::list::const_iterator WiFi_AP_Candidate_const_iterator; From 2e6fa428c706b3d77644f473eae46118bb5bffe8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 9 Nov 2024 16:58:23 +0100 Subject: [PATCH 008/564] [WiFi] Fix build issue due to enum naming conflict --- src/src/DataTypes/WiFi_State.cpp | 2 +- src/src/DataTypes/WiFi_State.h | 2 +- src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/src/DataTypes/WiFi_State.cpp b/src/src/DataTypes/WiFi_State.cpp index 5aa6382d5..b583582ec 100644 --- a/src/src/DataTypes/WiFi_State.cpp +++ b/src/src/DataTypes/WiFi_State.cpp @@ -12,7 +12,7 @@ const __FlashStringHelper* toString(WiFiState_e state) switch (state) { case ESPEasy::net::wifi::WiFiState_e::Disabled: return F("Disabled"); - case ESPEasy::net::wifi::WiFiState_e::OFF: return F("OFF"); + case ESPEasy::net::wifi::WiFiState_e::WiFiOFF: return F("OFF"); case ESPEasy::net::wifi::WiFiState_e::AP_only: return F("AP_only"); case ESPEasy::net::wifi::WiFiState_e::IdleWaiting: return F("IdleWaiting"); case ESPEasy::net::wifi::WiFiState_e::STA_Scanning: return F("STA_Scanning"); diff --git a/src/src/DataTypes/WiFi_State.h b/src/src/DataTypes/WiFi_State.h index f20ce86e3..794ecdc17 100644 --- a/src/src/DataTypes/WiFi_State.h +++ b/src/src/DataTypes/WiFi_State.h @@ -58,7 +58,7 @@ enum class WiFiState_e Disabled, // WiFi radio off, to continue, everything needs to be (re)initialized - OFF, + WiFiOFF, // Only running in AP mode AP_only, diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index 8060c61ea..d3e9e97a3 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -59,7 +59,7 @@ void ESPEasyWiFi_t::loop() { // TODO TD-er: Must check what error was given??? _callbackError = false; - setState(WiFiState_e::OFF); + setState(WiFiState_e::WiFiOFF); } } @@ -68,7 +68,7 @@ void ESPEasyWiFi_t::loop() case WiFiState_e::Disabled: // Do nothing here, as the device is disabled. break; - case WiFiState_e::OFF: + case WiFiState_e::WiFiOFF: begin(); // setState(WiFiState_e::IdleWaiting, 100); @@ -94,7 +94,7 @@ void ESPEasyWiFi_t::loop() case WiFiState_e::STA_AP_Scanning: if (_state_timeout.timeReached() || (WiFi.scanComplete() >= 0)) { - setState(WiFiState_e::OFF, 100); + setState(WiFiState_e::WiFiOFF, 100); } // Check if scanning is finished @@ -113,7 +113,7 @@ void ESPEasyWiFi_t::loop() if (_state == WiFiState_e::STA_Connecting) { setState(WiFiState_e::STA_Reconnecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); } else { - setState(WiFiState_e::OFF); + setState(WiFiState_e::WiFiOFF); } } @@ -123,7 +123,7 @@ void ESPEasyWiFi_t::loop() // Check if still connected if (getSTA_connected_state() != STA_connected_state::Connected) { - setState(WiFiState_e::OFF); + setState(WiFiState_e::WiFiOFF); } else { // Else mark last timestamp seen as connected _last_seen_connected.setNow(); @@ -172,7 +172,7 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { case WiFiState_e::Disabled: // Do nothing here, as the device is disabled. break; - case WiFiState_e::OFF: + case WiFiState_e::WiFiOFF: // TODO TD-er: Must cancel all and turn off WiFi. break; case WiFiState_e::AP_only: From 0eacd3d63e7aaf76f27a5cbf93544dd7de5535dc Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 9 Nov 2024 22:14:57 +0100 Subject: [PATCH 009/564] [IPv6] Disable IPv6 for ESP32-C2 --- src/src/CustomBuild/define_plugin_sets.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index f2d2506c7..f762035ea 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -3507,7 +3507,7 @@ To create/register a plugin, you have to : #endif #ifndef FEATURE_USE_IPV6 -# if ESP_IDF_VERSION_MAJOR>=5 && defined(LWIP_IPV6) +# if ESP_IDF_VERSION_MAJOR>=5 && defined(LWIP_IPV6) && !defined(ESP32C2) # define FEATURE_USE_IPV6 1 # else # define FEATURE_USE_IPV6 0 From 40df9b2b3a34323b874a20b13857ecd6e3019744 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 10 Nov 2024 14:42:00 +0100 Subject: [PATCH 010/564] [PSRAM] Free GPIO-16 and -17 on ESP32-classic when no PSRAM present --- src/src/ESPEasyCore/ESPEasy_setup.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index cf3cca101..6f705edfe 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -64,6 +64,8 @@ # include "hal/efuse_hal.h" #else #include +// IDF5.3 fix esp_gpio_reserve used in init PSRAM. +#include "esp_private/esp_gpio_reserve.h" #endif #endif @@ -151,6 +153,10 @@ void ESPEasy_setup() #endif uint32_t pkg_version = chip_ver & 0x7; if (pkg_version <= 3) { // D0WD, S0WD, D2WD + #if ESP_IDF_VERSION_MAJOR >= 5 + // Thanks Theo Arends from Tasmota + esp_gpio_revoke(BIT64(GPIO_NUM_16 | GPIO_NUM_17)); + #endif gpio_reset_pin(GPIO_NUM_16); gpio_reset_pin(GPIO_NUM_17); } From a1fa226502bc6a777e9b48bbb7886248fc0dd7c6 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 10 Nov 2024 15:35:59 +0100 Subject: [PATCH 011/564] [PSRAM] Fix build on ESP-IDF 5.1 + add special case of ESP32-picoD4 --- src/src/ESPEasyCore/ESPEasy_setup.cpp | 43 +++++++++++++++++++----- src/src/Helpers/Hardware_device_info.cpp | 3 +- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 6f705edfe..1eeb9c137 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -63,9 +63,13 @@ # include "hal/efuse_ll.h" # include "hal/efuse_hal.h" #else -#include +# include +# include + +# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) // IDF5.3 fix esp_gpio_reserve used in init PSRAM. -#include "esp_private/esp_gpio_reserve.h" +# include "esp_private/esp_gpio_reserve.h" +# endif #endif #endif @@ -148,17 +152,38 @@ void ESPEasy_setup() // test if the CPU is not pico #if ESP_IDF_VERSION_MAJOR < 5 uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); + uint32_t pkg_version = chip_ver & 0x7; #else + uint32_t pkg_version = bootloader_common_get_chip_ver_pkg(); uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_PACKAGE); #endif - uint32_t pkg_version = chip_ver & 0x7; - if (pkg_version <= 3) { // D0WD, S0WD, D2WD - #if ESP_IDF_VERSION_MAJOR >= 5 + if (pkg_version <= 7) { // D0WD, S0WD, D2WD + gpio_num_t PSRAM_CLK = GPIO_NUM_17; + gpio_num_t PSRAM_CS = GPIO_NUM_16; + switch (pkg_version) { + case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5: + PSRAM_CLK = static_cast(CONFIG_D2WD_PSRAM_CLK_IO); + PSRAM_CS = static_cast(CONFIG_D2WD_PSRAM_CS_IO); + break; + case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4: + case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302: + PSRAM_CLK = static_cast(GPIO_NUM_NC); + PSRAM_CS = static_cast(CONFIG_PICO_PSRAM_CS_IO); + break; + } + +#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) // Thanks Theo Arends from Tasmota - esp_gpio_revoke(BIT64(GPIO_NUM_16 | GPIO_NUM_17)); - #endif - gpio_reset_pin(GPIO_NUM_16); - gpio_reset_pin(GPIO_NUM_17); + if (PSRAM_CLK != GPIO_NUM_NC) { + esp_gpio_revoke(BIT64(PSRAM_CLK) | BIT64(PSRAM_CS)); + } else { + esp_gpio_revoke(BIT64(PSRAM_CS)); + } +#endif + if (PSRAM_CLK != GPIO_NUM_NC) { + gpio_reset_pin(PSRAM_CLK); + } + gpio_reset_pin(PSRAM_CS); } } #endif // if CONFIG_IDF_TARGET_ESP32 diff --git a/src/src/Helpers/Hardware_device_info.cpp b/src/src/Helpers/Hardware_device_info.cpp index 2c21db896..4de0c6b14 100644 --- a/src/src/Helpers/Hardware_device_info.cpp +++ b/src/src/Helpers/Hardware_device_info.cpp @@ -503,10 +503,11 @@ const __FlashStringHelper* getChipModel() { */ # if ESP_IDF_VERSION_MAJOR < 5 uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); + pkg_version = chip_ver & 0x7; # else // if ESP_IDF_VERSION_MAJOR < 5 uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_PACKAGE); # endif // if ESP_IDF_VERSION_MAJOR < 5 - pkg_version = chip_ver & 0x7; + // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HDW: ESP32 Model %d, Revision %d, Core %d, Package %d"), chip_info.model, chip_revision, // chip_info.cores, chip_ver); From aaa6be7dbd72b095abecfb27acd20139831f2917 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 10 Nov 2024 15:45:04 +0100 Subject: [PATCH 012/564] [PSRAM] Cleanup code --- src/src/ESPEasyCore/ESPEasy_setup.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 1eeb9c137..bc6264d52 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -158,19 +158,19 @@ void ESPEasy_setup() uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_PACKAGE); #endif if (pkg_version <= 7) { // D0WD, S0WD, D2WD - gpio_num_t PSRAM_CLK = GPIO_NUM_17; - gpio_num_t PSRAM_CS = GPIO_NUM_16; - switch (pkg_version) { - case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5: - PSRAM_CLK = static_cast(CONFIG_D2WD_PSRAM_CLK_IO); - PSRAM_CS = static_cast(CONFIG_D2WD_PSRAM_CS_IO); - break; - case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4: - case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302: - PSRAM_CLK = static_cast(GPIO_NUM_NC); - PSRAM_CS = static_cast(CONFIG_PICO_PSRAM_CS_IO); - break; - } + gpio_num_t PSRAM_CLK = static_cast(CONFIG_D0WD_PSRAM_CLK_IO); + gpio_num_t PSRAM_CS = static_cast(CONFIG_D0WD_PSRAM_CS_IO); + switch (pkg_version) { + case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5: + PSRAM_CLK = static_cast(CONFIG_D2WD_PSRAM_CLK_IO); + PSRAM_CS = static_cast(CONFIG_D2WD_PSRAM_CS_IO); + break; + case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4: + case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302: + PSRAM_CLK = static_cast(GPIO_NUM_NC); + PSRAM_CS = static_cast(CONFIG_PICO_PSRAM_CS_IO); + break; + } #if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) // Thanks Theo Arends from Tasmota From c78edee911e2e2416f134e752a8daf3cbc3d673f Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 10 Nov 2024 20:13:19 +0100 Subject: [PATCH 013/564] [PSRAM] Fix solo1 builds --- src/src/ESPEasyCore/ESPEasy_setup.cpp | 215 +++++++++++++++----------- 1 file changed, 121 insertions(+), 94 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index bc6264d52..2d4293e6d 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -47,44 +47,46 @@ #ifdef ESP32 -#if ESP_IDF_VERSION_MAJOR < 5 -#include -#include -#include -#include -#else -#include -#include -#include -#endif +# if ESP_IDF_VERSION_MAJOR < 5 +# include +# include +# include +# include +# else // if ESP_IDF_VERSION_MAJOR < 5 +# include +# include +# include +# endif // if ESP_IDF_VERSION_MAJOR < 5 -#if CONFIG_IDF_TARGET_ESP32 -#if ESP_IDF_VERSION_MAJOR < 5 -# include "hal/efuse_ll.h" -# include "hal/efuse_hal.h" -#else -# include -# include +# if CONFIG_IDF_TARGET_ESP32 +# if ESP_IDF_VERSION_MAJOR < 5 +# include "hal/efuse_ll.h" +# include "hal/efuse_hal.h" +# else // if ESP_IDF_VERSION_MAJOR < 5 +# include +# include + +# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) -# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) // IDF5.3 fix esp_gpio_reserve used in init PSRAM. -# include "esp_private/esp_gpio_reserve.h" -# endif -#endif -#endif +# include "esp_private/esp_gpio_reserve.h" +# endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) +# endif // if ESP_IDF_VERSION_MAJOR < 5 +# endif // if CONFIG_IDF_TARGET_ESP32 -#endif +#endif // ifdef ESP32 #ifdef USE_RTOS_MULTITASKING + void RTOS_TaskServers(void *parameter) { while (true) { delay(100); web_server.handleClient(); - #if FEATURE_ESPEASY_P2P + # if FEATURE_ESPEASY_P2P checkUDP(); - #endif + # endif } } @@ -113,7 +115,6 @@ void RTOS_HandleSchedule(void *parameter) #endif // ifdef USE_RTOS_MULTITASKING - /*********************************************************************************************\ * ISR call back function for handling the watchdog. \*********************************************************************************************/ @@ -129,8 +130,9 @@ void sw_watchdog_callback(void *arg) void ESPEasy_setup() { #if defined(ESP8266_DISABLE_EXTRA4K) || defined(USE_SECOND_HEAP) -// disable_extra4k_at_link_time(); -#endif + + // disable_extra4k_at_link_time(); +#endif // if defined(ESP8266_DISABLE_EXTRA4K) || defined(USE_SECOND_HEAP) #ifdef PHASE_LOCKED_WAVEFORM enablePhaseLockedWaveform(); #endif @@ -138,29 +140,37 @@ void ESPEasy_setup() HeapSelectDram ephemeral; #endif #ifdef ESP32 -#ifdef DISABLE_ESP32_BROWNOUT - DisableBrownout(); // Workaround possible weak LDO resulting in brownout detection during Wifi connection -#endif // DISABLE_ESP32_BROWNOUT +# ifdef DISABLE_ESP32_BROWNOUT + DisableBrownout(); // Workaround possible weak LDO resulting in brownout detection during Wifi connection +# endif // DISABLE_ESP32_BROWNOUT -#ifdef BOARD_HAS_PSRAM +# ifdef BOARD_HAS_PSRAM psramInit(); -#endif +# endif + +# if CONFIG_IDF_TARGET_ESP32 -#if CONFIG_IDF_TARGET_ESP32 // restore GPIO16/17 if no PSRAM is found if (!FoundPSRAM()) { // test if the CPU is not pico - #if ESP_IDF_VERSION_MAJOR < 5 - uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); + # if ESP_IDF_VERSION_MAJOR < 5 + uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); uint32_t pkg_version = chip_ver & 0x7; - #else + # else // if ESP_IDF_VERSION_MAJOR < 5 uint32_t pkg_version = bootloader_common_get_chip_ver_pkg(); - uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_PACKAGE); - #endif - if (pkg_version <= 7) { // D0WD, S0WD, D2WD + uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_PACKAGE); + # endif // if ESP_IDF_VERSION_MAJOR < 5 + + if (pkg_version <= 7) { // D0WD, S0WD, D2WD +#ifdef CORE32SOLO1 + gpio_num_t PSRAM_CLK = GPIO_NUM_17; + gpio_num_t PSRAM_CS = GPIO_NUM_16; +#else gpio_num_t PSRAM_CLK = static_cast(CONFIG_D0WD_PSRAM_CLK_IO); gpio_num_t PSRAM_CS = static_cast(CONFIG_D0WD_PSRAM_CS_IO); - switch (pkg_version) { + + switch (pkg_version) + { case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5: PSRAM_CLK = static_cast(CONFIG_D2WD_PSRAM_CLK_IO); PSRAM_CS = static_cast(CONFIG_D2WD_PSRAM_CS_IO); @@ -171,22 +181,24 @@ void ESPEasy_setup() PSRAM_CS = static_cast(CONFIG_PICO_PSRAM_CS_IO); break; } +#endif +# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) -#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) // Thanks Theo Arends from Tasmota if (PSRAM_CLK != GPIO_NUM_NC) { esp_gpio_revoke(BIT64(PSRAM_CLK) | BIT64(PSRAM_CS)); } else { esp_gpio_revoke(BIT64(PSRAM_CS)); } -#endif +# endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) + if (PSRAM_CLK != GPIO_NUM_NC) { gpio_reset_pin(PSRAM_CLK); } gpio_reset_pin(PSRAM_CS); } } -#endif // if CONFIG_IDF_TARGET_ESP32 +# endif // if CONFIG_IDF_TARGET_ESP32 initADC(); #endif // ESP32 #ifndef BUILD_NO_RAM_TRACKER @@ -194,21 +206,22 @@ void ESPEasy_setup() lowestRAM = FreeMem(); #endif // ifndef BUILD_NO_RAM_TRACKER -/* -#ifdef ESP32 -{ - ESPEasy_NVS_Helper preferences; - ResetFactoryDefaultPreference.init(preferences); -} -#endif -*/ + /* + #ifdef ESP32 + { + ESPEasy_NVS_Helper preferences; + ResetFactoryDefaultPreference.init(preferences); + } + #endif + */ #ifndef BUILD_NO_DEBUG -// checkAll_internalCommands(); -#endif + + // checkAll_internalCommands(); +#endif // ifndef BUILD_NO_DEBUG PluginSetup(); CPluginSetup(); - + initWiFi(); WiFiEventData.clearAll(); @@ -246,6 +259,7 @@ void ESPEasy_setup() logMemUsageAfter(F("initLog()")); #endif #ifdef BOARD_HAS_PSRAM + if (FoundPSRAM()) { if (UsePSRAM()) { addLog(LOG_LEVEL_INFO, F("Using PSRAM")); @@ -253,7 +267,7 @@ void ESPEasy_setup() addLog(LOG_LEVEL_ERROR, F("PSRAM found, unable to use")); } } - #endif + #endif // ifdef BOARD_HAS_PSRAM if (SpiffsSectors() < 32) { @@ -285,7 +299,7 @@ void ESPEasy_setup() readBootCause(); { - String log = F("INIT : "); + String log = F("INIT : "); log += getLastBootCauseString(); if (readFromRTC()) @@ -346,20 +360,21 @@ void ESPEasy_setup() #endif #ifdef ESP32 + // Configure dynamic frequency scaling: // maximum and minimum frequencies are set in sdkconfig, // automatic light sleep is enabled if tickless idle support is enabled. ESP_PM_CONFIG_T pm_config = { - .max_freq_mhz = getCPU_MaxFreqMHz(), - .min_freq_mhz = Settings.EcoPowerMode() ? getCPU_MinFreqMHz() : getCPU_MaxFreqMHz(), -#if CONFIG_FREERTOS_USE_TICKLESS_IDLE - .light_sleep_enable = Settings.EcoPowerMode() -#else - .light_sleep_enable = false -#endif + .max_freq_mhz = getCPU_MaxFreqMHz(), + .min_freq_mhz = Settings.EcoPowerMode() ? getCPU_MinFreqMHz() : getCPU_MaxFreqMHz(), +# if CONFIG_FREERTOS_USE_TICKLESS_IDLE + .light_sleep_enable = Settings.EcoPowerMode() +# else + .light_sleep_enable = false +# endif // if CONFIG_FREERTOS_USE_TICKLESS_IDLE }; esp_pm_configure(&pm_config); -#endif +#endif // ifdef ESP32 #ifndef BUILD_NO_RAM_TRACKER @@ -382,10 +397,11 @@ void ESPEasy_setup() toDisable = disableController(toDisable); } #if FEATURE_NOTIFIER + if (toDisable != 0) { toDisable = disableNotification(toDisable); } - #endif + #endif // if FEATURE_NOTIFIER if (toDisable != 0) { toDisable = disableRules(toDisable); @@ -399,10 +415,11 @@ void ESPEasy_setup() toDisable = disableAllControllers(toDisable); } #if FEATURE_NOTIFIER + if (toDisable != 0) { toDisable = disableAllNotifications(toDisable); } -#endif +#endif // if FEATURE_NOTIFIER } #if FEATURE_ETHERNET @@ -410,7 +427,8 @@ void ESPEasy_setup() // This only works after LoadSettings(); // Do not call setNetworkMedium here as that may try to clean up settings. active_network_medium = Settings.NetworkMedium; - #else + #else // if FEATURE_ETHERNET + if (Settings.NetworkMedium == NetworkMedium_t::Ethernet) { Settings.NetworkMedium = NetworkMedium_t::WIFI; } @@ -419,13 +437,15 @@ void ESPEasy_setup() setNetworkMedium(Settings.NetworkMedium); bool initWiFi = active_network_medium == NetworkMedium_t::WIFI; + // FIXME TD-er: Must add another check for 'delayed start WiFi' for poorly designed ESP8266 nodes. if (initWiFi) { WiFi_AP_Candidates.clearCache(); WiFi_AP_Candidates.load_knownCredentials(); - ESPEasy::net::wifi::setSTA(true); + ESPEasy::net::wifi::setSTA(true); + if (!WiFi_AP_Candidates.hasCandidates()) { WiFiEventData.wifiSetup = true; RTC.clearLastWiFi(); // Must scan all channels @@ -444,11 +464,13 @@ void ESPEasy_setup() WiFi_AP_Candidates.clearCache(); processScanDone(); WiFi_AP_Candidates.load_knownCredentials(); + if (!WiFi_AP_Candidates.hasCandidates()) { addLog(LOG_LEVEL_INFO, F("Setup: Scan all channels")); WifiScan(false); } -// ESPEasy::net::wifi::setWifiMode(WIFI_OFF); + + // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); } #ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("WifiScan()")); @@ -485,11 +507,12 @@ void ESPEasy_setup() addLogMove(LOG_LEVEL_INFO, concat(F("INIT : Free RAM:"), FreeMem())); } -# ifndef BUILD_NO_DEBUG +#ifndef BUILD_NO_DEBUG + if (Settings.UseSerial && (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)) { ESPEasy_Console.setDebugOutput(true); } -#endif +#endif // ifndef BUILD_NO_DEBUG timermqtt_interval = 100; // Interval for checking MQTT timerAwakeFromDeepSleep = millis(); @@ -499,18 +522,19 @@ void ESPEasy_setup() #endif #if FEATURE_NOTIFIER NPluginInit(); - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("NPluginInit()")); - #endif + # endif #endif // if FEATURE_NOTIFIER PluginInit(); initSerial(); // Plugins may have altered serial, so re-init serial - + #ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("PluginInit()")); #endif + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log.reserve(80); @@ -523,11 +547,11 @@ void ESPEasy_setup() addLogMove(LOG_LEVEL_INFO, log); } -/* - if ((getDeviceCount() + 1) >= PLUGIN_MAX) { - addLog(LOG_LEVEL_ERROR, concat(F("Programming error! - Increase PLUGIN_MAX ("), getDeviceCount()) + ')'); - } -*/ + /* + if ((getDeviceCount() + 1) >= PLUGIN_MAX) { + addLog(LOG_LEVEL_ERROR, concat(F("Programming error! - Increase PLUGIN_MAX ("), getDeviceCount()) + ')'); + } + */ clearAllCaches(); #ifndef BUILD_NO_RAM_TRACKER @@ -547,38 +571,41 @@ void ESPEasy_setup() rulesProcessing(event); // TD-er: Process events in the setup() now. } #ifdef ESP32 + if (Settings.UseRules) { const uint32_t gpio_strap = GPIO_REG_READ(GPIO_STRAP_REG); -// BOOT_MODE_GET(); - // Event values: + // BOOT_MODE_GET(); + + // Event values: // ESP32 : GPIO-5, GPIO-15, GPIO-4, GPIO-2, GPIO-0, GPIO-12 // ESP32-C3: bit 0: GPIO2, bit 2: GPIO8, bit 3: GPIO9 // ESP32-S2: Unclear what bits represent which strapping state. // ESP32-S3: bit5 ~ bit2 correspond to strapping pins GPIO3, GPIO45, GPIO0, and GPIO46 respectively. String event = F("System#BootMode="); - event += bitRead(gpio_strap, 0); + event += bitRead(gpio_strap, 0); event += ','; - event += bitRead(gpio_strap, 1); + event += bitRead(gpio_strap, 1); event += ','; - event += bitRead(gpio_strap, 2); + event += bitRead(gpio_strap, 2); event += ','; - event += bitRead(gpio_strap, 3); + event += bitRead(gpio_strap, 3); event += ','; - event += bitRead(gpio_strap, 4); + event += bitRead(gpio_strap, 4); event += ','; - event += bitRead(gpio_strap, 5); + event += bitRead(gpio_strap, 5); rulesProcessing(event); } - #endif + #endif // ifdef ESP32 #if FEATURE_ETHERNET + if (Settings.ETH_Pin_power_rst != -1) { GPIO_Write(PLUGIN_GPIO, Settings.ETH_Pin_power_rst, 1); } - #endif + #endif // if FEATURE_ETHERNET NetworkConnectRelaxed(); #ifndef BUILD_NO_RAM_TRACKER @@ -597,9 +624,9 @@ void ESPEasy_setup() #if FEATURE_ARDUINO_OTA ArduinoOTAInit(); - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("ArduinoOTAInit()")); - #endif + # endif #endif // if FEATURE_ARDUINO_OTA if (node_time.systemTimePresent()) { @@ -638,9 +665,9 @@ void ESPEasy_setup() RTOS_HandleSchedule, /* Function to implement the task */ "RTOS_HandleSchedule", /* Name of the task */ 16384, /* Stack size in words */ - nullptr, /* Task input parameter */ + nullptr, /* Task input parameter */ 1, /* Priority of the task */ - nullptr, /* Task handle. */ + nullptr, /* Task handle. */ 1); /* Core where the task should run */ } #endif // ifdef USE_RTOS_MULTITASKING From 9d9821cc631429732cece9963de435c3f2ffee01 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 6 Dec 2024 13:20:44 +0100 Subject: [PATCH 014/564] [WiFi] Add some debug log to track GotIP event --- platformio_core_defs.ini | 3 +- src/src/DataStructs/WiFiEventData.cpp | 30 +++++++++++++++++-- src/src/DataStructs/WiFiEventData.h | 2 ++ .../ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp | 8 ++++- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 1327c044d..41bce130b 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -198,7 +198,7 @@ lib_extra_dirs = ; ESP_IDF 5.3.1 [core_esp32_IDF5_3_1__3_0_5_LittleFS] platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.10.31/platform-espressif32.zip -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3112/framework-arduinoespressif32-all-release_v5.3-1c74f314.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3180/framework-arduinoespressif32-all-release_v5.3-1c74f314.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 @@ -218,6 +218,7 @@ build_flags = -DESP32_STAGE -include "ESPEasy_config.h" -include "esp32x_fixes.h" -Wnull-dereference + -DUPDATE_NOCRYPT lib_ignore = lib_extra_dirs = lib/lib_ssl diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 9adb2c62b..d0429bfcd 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -9,6 +9,8 @@ #include "../Helpers/ESPEasy_Storage.h" #include "../Helpers/Networking.h" +#include "../Helpers/StringConverter.h" + #define WIFI_RECONNECT_WAIT 30000 // in milliSeconds @@ -170,6 +172,12 @@ void WiFiEventData_t::setWiFiConnected() { } void WiFiEventData_t::setWiFiServicesInitialized() { + if (!processedConnect) { + setWiFiConnected(); + } + if (!processedGotIP) { + setWiFiGotIP(); + } if (/*!unprocessedWifiEvents() && */ WiFiConnected() && WiFiGotIP()) { #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WiFi : WiFi services initialized")); @@ -177,8 +185,13 @@ void WiFiEventData_t::setWiFiServicesInitialized() { bitSet(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); wifiConnectInProgress = false; wifiConnectAttemptNeeded = false; - dns0_cache = WiFi.dnsIP(0); - dns1_cache = WiFi.dnsIP(1); + if (valid_DNS_address(WiFi.dnsIP(0))) { + dns0_cache = WiFi.dnsIP(0); + } + + if (valid_DNS_address(WiFi.dnsIP(1))) { + dns1_cache = WiFi.dnsIP(1); + } } } @@ -192,6 +205,19 @@ void WiFiEventData_t::markGotIP() { processedGotIP = false; } +void WiFiEventData_t::markGotIP(const IPAddress& ip, const IPAddress& netmask, const IPAddress& gw) +{ + addLog( + LOG_LEVEL_INFO, + strformat( + F("WiFi : GotIP ip: %s, sn: %s, gw: %s"), + ip.toString().c_str(), + netmask.toString().c_str(), + gw.toString().c_str())); + markGotIP(); + +} + #if FEATURE_USE_IPV6 void WiFiEventData_t::markGotIPv6(const IPAddress& ip6) { diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index 27e8db8c5..d44c371fc 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -58,6 +58,8 @@ struct WiFiEventData_t { void markGotIP(); + void markGotIP(const IPAddress& ip, const IPAddress& netmask, const IPAddress& gw); + #if FEATURE_USE_IPV6 void markGotIPv6(const IPAddress& ip6); #endif diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp index d1156a195..25f89e97c 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp @@ -120,9 +120,15 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { WiFiEventData.markDisconnect(static_cast(info.wifi_sta_disconnected.reason)); break; case ARDUINO_EVENT_WIFI_STA_GOT_IP: + { ignoreDisconnectEvent = false; - WiFiEventData.markGotIP(); + ip_event_got_ip_t *event = static_cast(&info.got_ip); + const IPAddress ip(event->ip_info.ip.addr); + const IPAddress netmask(event->ip_info.ip.addr); + const IPAddress gw(event->ip_info.ip.addr); + WiFiEventData.markGotIP(ip, netmask, gw); break; + } # if FEATURE_USE_IPV6 case ARDUINO_EVENT_WIFI_STA_GOT_IP6: { From 6ab4ba66deacc2db4641e4d8c7bcd29c46fde5cf Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 6 Dec 2024 21:26:59 +0100 Subject: [PATCH 015/564] [WiFi] Fix not showing /setup page --- src/src/DataStructs/WiFiEventData.cpp | 94 ++++++++++--------- .../ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp | 19 +++- src/src/ESPEasyCore/ESPEasy_setup.cpp | 2 +- 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index d0429bfcd..b696ed0c0 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -175,9 +175,11 @@ void WiFiEventData_t::setWiFiServicesInitialized() { if (!processedConnect) { setWiFiConnected(); } + if (!processedGotIP) { setWiFiGotIP(); } + if (/*!unprocessedWifiEvents() && */ WiFiConnected() && WiFiGotIP()) { #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WiFi : WiFi services initialized")); @@ -185,6 +187,7 @@ void WiFiEventData_t::setWiFiServicesInitialized() { bitSet(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); wifiConnectInProgress = false; wifiConnectAttemptNeeded = false; + if (valid_DNS_address(WiFi.dnsIP(0))) { dns0_cache = WiFi.dnsIP(0); } @@ -208,14 +211,17 @@ void WiFiEventData_t::markGotIP() { void WiFiEventData_t::markGotIP(const IPAddress& ip, const IPAddress& netmask, const IPAddress& gw) { addLog( - LOG_LEVEL_INFO, + LOG_LEVEL_INFO, strformat( - F("WiFi : GotIP ip: %s, sn: %s, gw: %s"), - ip.toString().c_str(), - netmask.toString().c_str(), - gw.toString().c_str())); + F("WiFi : GotIP IP: %s, GW: %s, SN: %s DNS: %s / %s"), + formatIP(ip).c_str(), + formatIP(gw).c_str(), + formatIP(netmask).c_str(), + formatIP(WiFi.dnsIP(0)).c_str(), + formatIP(WiFi.dnsIP(1)).c_str() + )); markGotIP(); - + } #if FEATURE_USE_IPV6 @@ -325,53 +331,55 @@ uint32_t WiFiEventData_t::getSuggestedTimeout(int index, uint32_t minimum_timeou return constrain(res, minimum_timeout, CONNECT_TIMEOUT_MAX); } - #ifdef ESP8266 - bool WiFiEventData_t::WiFiDisconnected() const { - return wifiStatus == ESPEASY_WIFI_DISCONNECTED; - } - bool WiFiEventData_t::WiFiGotIP() const { - return bitRead(wifiStatus, ESPEASY_WIFI_GOT_IP); - } +bool WiFiEventData_t::WiFiDisconnected() const { + return wifiStatus == ESPEASY_WIFI_DISCONNECTED; +} - bool WiFiEventData_t::WiFiConnected() const { - return bitRead(wifiStatus, ESPEASY_WIFI_CONNECTED); - } +bool WiFiEventData_t::WiFiGotIP() const { + return bitRead(wifiStatus, ESPEASY_WIFI_GOT_IP); +} - bool WiFiEventData_t::WiFiServicesInitialized() const { - return bitRead(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); - } +bool WiFiEventData_t::WiFiConnected() const { + return bitRead(wifiStatus, ESPEASY_WIFI_CONNECTED); +} -#endif +bool WiFiEventData_t::WiFiServicesInitialized() const { + return bitRead(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); +} + +#endif // ifdef ESP8266 #ifdef ESP32 - bool WiFiEventData_t::WiFiDisconnected() const { - return !WiFi.STA.connected(); - } - bool WiFiEventData_t::WiFiGotIP() const { - return WiFi.STA.hasIP(); - } +bool WiFiEventData_t::WiFiDisconnected() const { + return !WiFi.STA.connected(); +} -#if FEATURE_USE_IPV6 - bool WiFiEventData_t::WiFiGotIPv6() const { - return WiFi.STA.hasGlobalIPv6(); - } -#endif +bool WiFiEventData_t::WiFiGotIP() const { + return WiFi.STA.hasIP(); +} - bool WiFiEventData_t::WiFiConnected() const { - return WiFi.STA.connected(); - } +# if FEATURE_USE_IPV6 - bool WiFiEventData_t::WiFiServicesInitialized() const { - return WiFiConnected() && -#if FEATURE_USE_IPV6 -(WiFiGotIP() || WiFi.STA.hasGlobalIPv6() || WiFi.STA.hasLinkLocalIPv6()); -#else - WiFiGotIP(); -#endif - } +bool WiFiEventData_t::WiFiGotIPv6() const { + return WiFi.STA.hasGlobalIPv6(); +} - #endif +# endif // if FEATURE_USE_IPV6 +bool WiFiEventData_t::WiFiConnected() const { + return WiFi.STA.connected(); +} + +bool WiFiEventData_t::WiFiServicesInitialized() const { + return WiFiConnected() && +# if FEATURE_USE_IPV6 + (WiFiGotIP() || WiFi.STA.hasGlobalIPv6() || WiFi.STA.hasLinkLocalIPv6()); +# else + WiFiGotIP(); +# endif // if FEATURE_USE_IPV6 +} + + #endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp index 25f89e97c..c3720b8bc 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp @@ -21,6 +21,7 @@ # include "../Globals/WiFi_AP_Candidates.h" # include "../Helpers/ESPEasy_time_calc.h" +# include "../Helpers/StringConverter.h" # if FEATURE_ETHERNET @@ -37,8 +38,8 @@ void setUseStaticIP(bool enabled) {} static bool ignoreDisconnectEvent = false; -void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { - switch (event) +void WiFiEvent(WiFiEvent_t event_id, arduino_event_info_t info) { + switch (event_id) { case ARDUINO_EVENT_WIFI_READY: // ESP32 WiFi ready @@ -55,6 +56,13 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { // addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); # endif // ifndef BUILD_NO_DEBUG break; + case ARDUINO_EVENT_WIFI_OFF: + # ifndef BUILD_NO_DEBUG + + // addLog(LOG_LEVEL_INFO, F("WiFi : Event WIFI off")); + # endif // ifndef BUILD_NO_DEBUG + break; + case ARDUINO_EVENT_WIFI_AP_START: # ifndef BUILD_NO_DEBUG @@ -121,11 +129,12 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { break; case ARDUINO_EVENT_WIFI_STA_GOT_IP: { + // FIXME TD-er: Must also check event->esp_netif to see which interface got this event. ignoreDisconnectEvent = false; ip_event_got_ip_t *event = static_cast(&info.got_ip); const IPAddress ip(event->ip_info.ip.addr); - const IPAddress netmask(event->ip_info.ip.addr); - const IPAddress gw(event->ip_info.ip.addr); + const IPAddress netmask(event->ip_info.netmask.addr); + const IPAddress gw(event->ip_info.gw.addr); WiFiEventData.markGotIP(ip, netmask, gw); break; } @@ -163,7 +172,7 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { # endif // FEATURE_ETHERNET default: { - // addLogMove(LOG_LEVEL_ERROR, concat(F("UNKNOWN WIFI/ETH EVENT: "), event)); + addLogMove(LOG_LEVEL_ERROR, concat(F("UNKNOWN WIFI/ETH EVENT: "), event_id)); break; } } diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 2d4293e6d..91e2ebc58 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -446,7 +446,7 @@ void ESPEasy_setup() WiFi_AP_Candidates.load_knownCredentials(); ESPEasy::net::wifi::setSTA(true); - if (!WiFi_AP_Candidates.hasCandidates()) { + if (!WiFi_AP_Candidates.hasCandidateCredentials()) { WiFiEventData.wifiSetup = true; RTC.clearLastWiFi(); // Must scan all channels // Wait until scan has finished to make sure as many as possible are found From 64b9f4800bbd45cfd8f7cd344566e8e9daa3569e Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 6 Dec 2024 23:27:05 +0100 Subject: [PATCH 016/564] [WiFi] Update to latest ESP-IDF SDK + handle gotIP event on ESP8266 --- platformio_core_defs.ini | 2 +- src/src/DataStructs/WiFiEventData.cpp | 1 - src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp | 8 +++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 41bce130b..1676c1134 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -198,7 +198,7 @@ lib_extra_dirs = ; ESP_IDF 5.3.1 [core_esp32_IDF5_3_1__3_0_5_LittleFS] platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.10.31/platform-espressif32.zip -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3180/framework-arduinoespressif32-all-release_v5.3-1c74f314.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3184/framework-arduinoespressif32-all-release_v5.3-35321e8b.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index b696ed0c0..2305ce5bc 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -221,7 +221,6 @@ void WiFiEventData_t::markGotIP(const IPAddress& ip, const IPAddress& netmask, c formatIP(WiFi.dnsIP(1)).c_str() )); markGotIP(); - } #if FEATURE_USE_IPV6 diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp index b127bc194..2fb82ba1d 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP8266.cpp @@ -45,7 +45,13 @@ void onDisconnect(const WiFiEventStationModeDisconnected& event) { } } -void onGotIP(const WiFiEventStationModeGotIP& event) { WiFiEventData.markGotIP(); } +void onGotIP(const WiFiEventStationModeGotIP& event) +{ + WiFiEventData.markGotIP( + event.ip, + event.mask, + event.gw); +} void onDHCPTimeout() { WiFiEventData.processedDHCPTimeout = false; } From bf3485344ee7fbdabc6684b2e5c2735b21609e1f Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 6 Jan 2025 15:12:45 +0100 Subject: [PATCH 017/564] [WiFi] Fix event handling for WiFi on ESP32 --- src/src/DataStructs/WiFiEventData.cpp | 22 +- .../ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 29 +- .../ESPEasyCore/ESPEasyWiFi_state_machine.h | 45 +- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 201 ------- .../ESPEasyWifi_abstracted_ESP32.cpp | 11 +- src/src/Helpers/Networking.cpp | 566 ++++++++++-------- 6 files changed, 377 insertions(+), 497 deletions(-) diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 2305ce5bc..e8bf8be67 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -210,16 +210,18 @@ void WiFiEventData_t::markGotIP() { void WiFiEventData_t::markGotIP(const IPAddress& ip, const IPAddress& netmask, const IPAddress& gw) { - addLog( - LOG_LEVEL_INFO, - strformat( - F("WiFi : GotIP IP: %s, GW: %s, SN: %s DNS: %s / %s"), - formatIP(ip).c_str(), - formatIP(gw).c_str(), - formatIP(netmask).c_str(), - formatIP(WiFi.dnsIP(0)).c_str(), - formatIP(WiFi.dnsIP(1)).c_str() - )); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog( + LOG_LEVEL_INFO, + strformat( + F("WiFi : GotIP IP: %s, GW: %s, SN: %s DNS: %s / %s"), + formatIP(ip).c_str(), + formatIP(gw).c_str(), + formatIP(netmask).c_str(), + formatIP(WiFi.dnsIP(0)).c_str(), + formatIP(WiFi.dnsIP(1)).c_str() + )); + } markGotIP(); } diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index d3e9e97a3..16ce48675 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -16,7 +16,7 @@ # include "../Globals/WiFi_AP_Candidates.h" # include "../Helpers/StringConverter.h" -#include "../Helpers/StringGenerator_WiFi.h" +# include "../Helpers/StringGenerator_WiFi.h" namespace ESPEasy { namespace net { @@ -143,7 +143,6 @@ bool ESPEasyWiFi_t::connected() const return getSTA_connected_state() == STA_connected_state::Connected; } - void ESPEasyWiFi_t::disconnect() { WiFi.disconnect(Settings.WiFiRestart_connection_lost()); } void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { @@ -209,6 +208,7 @@ void ESPEasyWiFi_t::checkConnectProgress() {} void ESPEasyWiFi_t::startScanning() { _state = WiFiState_e::STA_Scanning; + setSTA(true); WifiScan(true); _last_state_change.setNow(); } @@ -233,12 +233,13 @@ bool ESPEasyWiFi_t::connectSTA() } return false; } - if (WiFiEventData.lastDisconnectReason != WIFI_DISCONNECT_REASON_UNSPECIFIED) { - addLog(LOG_LEVEL_INFO, concat( - F("WiFi : Disconnect reason: "), - getLastDisconnectReason())); - WiFiEventData.processedDisconnect = true; - } + + if (WiFiEventData.lastDisconnectReason != WIFI_DISCONNECT_REASON_UNSPECIFIED) { + addLog(LOG_LEVEL_INFO, concat( + F("WiFi : Disconnect reason: "), + getLastDisconnectReason())); + WiFiEventData.processedDisconnect = true; + } WiFiEventData.warnedNoValidWiFiSettings = false; setSTA(true); @@ -304,28 +305,30 @@ bool ESPEasyWiFi_t::connectSTA() # endif // ifdef ESP32 if (candidate.bits.isHidden /*&& Settings.HiddenSSID_SlowConnectPerBSSID()*/) { -// WiFi.disconnect(false, true); + // WiFi.disconnect(false, true); # ifdef ESP32 WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); -#endif +# endif delay(100); WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); + // If the ssid returned from the scan is empty, it is a hidden SSID // it appears that the WiFi.begin() function is asynchronous and takes // additional time to connect to a hidden SSID. Therefore a delay of 1000ms // is added for hidden SSIDs before calling WiFi.status() delay(1000); -// WiFi.waitForConnectResult(6000); + + // WiFi.waitForConnectResult(6000); } else { if (candidate.allowQuickConnect()) { # ifdef ESP32 WiFi.setScanMethod(WIFI_FAST_SCAN); -#endif +# endif WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); } else { # ifdef ESP32 WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); -#endif +# endif WiFi.begin(candidate.ssid.c_str(), key.c_str()); } } diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h index a5ec96ad0..f6656cb5f 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h @@ -30,8 +30,9 @@ public: // Terminate WiFi activity void disable(); - + private: + void begin(); public: @@ -56,7 +57,8 @@ public: private: - void setState(WiFiState_e newState, uint32_t timeout = 0); + void setState(WiFiState_e newState, + uint32_t timeout = 0); // Handle timeouts + start of AP mode void checkConnectProgress(); @@ -93,33 +95,28 @@ private: // Special modes for initial setup or re-configuration of a node via serial port/IMPROV bool _improvActive = false; - bool _setupActive = false; + bool _setupActive = false; -// WiFi settings => Move to separate class/struct -bool _disabledAtBoot = false; -bool _passiveScan = false; -bool _includeHiddenSSID = false; -float _TX_power = -1; - -// Manual IP settings -// IP -// Gateway -// Subnet -// DNS - - - -// soft AP configuration => TODO TD-er: Implement -// bool _must_Start_AP; // "Do Not Start AP" -// bool _has_ap{false}; // Maybe just check for active mode? -// WiFiAP _ap_config; -// WPA AP mode key -// Don't force /setup in AP-Mode - + // WiFi settings => Move to separate class/struct + bool _disabledAtBoot = false; + bool _passiveScan = false; + bool _includeHiddenSSID = false; + float _TX_power = -1; + // Manual IP settings + // IP + // Gateway + // Subnet + // DNS + // soft AP configuration => TODO TD-er: Implement + // bool _must_Start_AP; // "Do Not Start AP" + // bool _has_ap{false}; // Maybe just check for active mode? + // WiFiAP _ap_config; + // WPA AP mode key + // Don't force /setup in AP-Mode }; // class ESPEasyWiFi_t diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index f1aa0b284..25ff3edfe 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -92,129 +92,6 @@ void handle_unprocessedNetworkEvents() } } - /* if (WiFiEventData.unprocessedWifiEvents()) { - // Process disconnect events before connect events. - if (!WiFiEventData.processedDisconnect) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processDisconnect()")); - #endif // ifndef BUILD_NO_DEBUG - processDisconnect(); - } - } - - if (active_network_medium == NetworkMedium_t::WIFI) { - if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents() || WiFiEventData.wifiConnectAttemptNeeded) { - // WiFi connection is not yet available, so introduce some extra delays to - // help the background tasks managing wifi connections - delay(0); - - if (!WiFiEventData.processedConnect) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); - #endif // ifndef BUILD_NO_DEBUG - processConnect(); - } - - if (!WiFiEventData.processedGotIP) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processGotIP()")); - #endif // ifndef BUILD_NO_DEBUG - processGotIP(); - } - - if (!WiFiEventData.processedDHCPTimeout) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, F("WIFI : DHCP timeout, Calling disconnect()")); - #endif // ifndef BUILD_NO_DEBUG - WiFiEventData.processedDHCPTimeout = true; - WifiDisconnect(); - } - - if ((WiFi.status() == WL_DISCONNECTED) && WiFiEventData.wifiConnectInProgress) { - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && - WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { - logConnectionStatus(); - resetWiFi(); - } - - if (!WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { - WiFiEventData.wifiConnectInProgress = false; - } - delay(10); - } - - if (!WiFiEventData.wifiConnectInProgress) { - WiFiEventData.wifiConnectAttemptNeeded = true; - NetworkConnectRelaxed(); - } - } - - - if (WiFiEventData.WiFiDisconnected()) { - #ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - static LongTermTimer lastDisconnectMoment_log; - static uint8_t lastWiFiStatus_log = 0; - uint8_t cur_wifi_status = WiFi.status(); - - if ((WiFiEventData.lastDisconnectMoment.get() != lastDisconnectMoment_log.get()) || - (lastWiFiStatus_log != cur_wifi_status)) { - lastDisconnectMoment_log.set(WiFiEventData.lastDisconnectMoment.get()); - lastWiFiStatus_log = cur_wifi_status; - String wifilog = F("WIFI : Disconnected: WiFi.status() = "); - wifilog += WiFiEventData.ESPeasyWifiStatusToString(); - wifilog += F(" RSSI: "); - wifilog += String(WiFi.RSSI()); - wifilog += F(" status: "); - # ifdef ESP8266 - station_status_t status = wifi_station_get_connect_status(); - wifilog += SDKwifiStatusToString(status); - # endif // ifdef ESP8266 - # ifdef ESP32 - wifilog += ArduinoWifiStatusToString(WiFi.status()); - # endif - addLogMove(LOG_LEVEL_DEBUG, wifilog); - } - } - #endif // ifndef BUILD_NO_DEBUG - - // While connecting to WiFi make sure the device has ample time to do so - delay(10); - } - - if (!WiFiEventData.processedDisconnectAPmode) { processDisconnectAPmode(); } - - if (!WiFiEventData.processedConnectAPmode) { processConnectAPmode(); } - - if (WiFiEventData.timerAPoff.isSet()) { processDisableAPmode(); } - - if (!WiFiEventData.processedScanDone) { processScanDone(); } - - if (WiFiEventData.wifi_connect_attempt > 0) { - // We only want to clear this counter if the connection is currently stable. - if (WiFiEventData.WiFiServicesInitialized()) { - if (WiFiEventData.lastConnectMoment.isSet() && WiFiEventData.lastConnectMoment.timeoutReached(WIFI_CONNECTION_CONSIDERED_STABLE)) - #{ - // Connection considered stable - WiFiEventData.wifi_connect_attempt = 0; - WiFiEventData.wifi_considered_stable = true; - WiFi_AP_Candidates.markCurrentConnectionStable(); - - if (WiFi.getAutoReconnect() != Settings.SDK_WiFi_autoreconnect()) { - WiFi.setAutoReconnect(Settings.SDK_WiFi_autoreconnect()); - delay(1); - } - } else { - if (WiFi.getAutoReconnect()) { - WiFi.setAutoReconnect(false); - delay(1); - } - } - } - } - } - */ #if FEATURE_ETHERNET check_Eth_DNS_valid(); #endif // if FEATURE_ETHERNET @@ -229,85 +106,7 @@ void handle_unprocessedNetworkEvents() // These functions are called from Setup() or Loop() and thus may call delay() or yield() // ******************************************************************************** void processDisconnect() { - /* - if (WiFiEventData.processedDisconnect) { return; } - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = strformat( - F("WIFI : Disconnected! Reason: '%s'"), - getLastDisconnectReason().c_str()); - - if (WiFiEventData.lastConnectedDuration_us > 0) { - log += concat( - F(" Connected for "), - format_msec_duration(WiFiEventData.lastConnectedDuration_us / 1000ll)); - } - addLogMove(LOG_LEVEL_INFO, log); - } - logConnectionStatus(); - - if (WiFiEventData.processingDisconnect.isSet()) { - if ((WiFiEventData.processingDisconnect.millisPassedSince() > 5000) || WiFiEventData.processedDisconnect) { - WiFiEventData.processedDisconnect = true; - WiFiEventData.processingDisconnect.clear(); - } - } - - - if (WiFiEventData.processedDisconnect || - WiFiEventData.processingDisconnect.isSet()) { return; } - WiFiEventData.processingDisconnect.setNow(); - WiFiEventData.setWiFiDisconnected(); - WiFiEventData.wifiConnectAttemptNeeded = true; - delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 - - if (Settings.UseRules) { - eventQueue.add(F("WiFi#Disconnected")); - } - - - // FIXME TD-er: With AutoReconnect enabled, WiFi must be reset or else we completely loose track of the actual WiFi state - bool mustRestartWiFi = Settings.WiFiRestart_connection_lost() || WiFi.getAutoReconnect(); - - if ((WiFiEventData.lastConnectedDuration_us > 0) && ((WiFiEventData.lastConnectedDuration_us / 1000) < 5000)) { - if (!WiFi_AP_Candidates.getBestCandidate().usable()) { - // addLog(LOG_LEVEL_INFO, F("WIFI : !getBestCandidate().usable() => mustRestartWiFi = true")); - - mustRestartWiFi = true; - } - } - - if (WiFi.status() == WL_IDLE_STATUS) { - // addLog(LOG_LEVEL_INFO, F("WIFI : WiFi.status() == WL_IDLE_STATUS => mustRestartWiFi = true")); - mustRestartWiFi = true; - } - - - #ifdef USES_ESPEASY_NOW - - if (use_EspEasy_now) { - // mustRestartWiFi = true; - } - #endif // ifdef USES_ESPEASY_NOW - - // WifiDisconnect(); // Needed or else node may not reconnect reliably. - - if (mustRestartWiFi) { - WiFiEventData.processedDisconnect = true; - resetWiFi(); - - // WifiScan(false); - // delay(100); - // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); - // initWiFi(); - // delay(100); - } - - // delay(500); - logConnectionStatus(); - WiFiEventData.processedDisconnect = true; - WiFiEventData.processingDisconnect.clear(); - */ } void processConnect() { diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index 2f5f28a23..919f57745 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -46,7 +46,7 @@ bool WiFi_pre_STA_setup() } void WiFiDisconnect() { - removeWiFiEventHandler(); +// removeWiFiEventHandler(); WiFi.disconnect(); delay(100); { @@ -70,6 +70,9 @@ bool setWifiMode(WiFiMode_t new_mode) static int8_t processing_wifi_mode = -1; if (cur_mode == new_mode) { + if (cur_mode != WIFI_OFF) { + registerWiFiEventHandler(); + } return true; } @@ -81,6 +84,8 @@ bool setWifiMode(WiFiMode_t new_mode) if (cur_mode == WIFI_OFF) { + registerWiFiEventHandler(); + // Needs to be set while WiFi is off WiFi.hostname(NetworkCreateRFCCompliantHostname()); WiFiEventData.markWiFiTurnOn(); @@ -99,6 +104,7 @@ bool setWifiMode(WiFiMode_t new_mode) // delay(100); processDisconnect(); WiFiEventData.clear_processed_flags(); + removeWiFiEventHandler(); } addLog(LOG_LEVEL_INFO, concat(F("WIFI : Set WiFi to "), getWifiModeString(new_mode))); @@ -136,10 +142,11 @@ bool setWifiMode(WiFiMode_t new_mode) // esp_wifi_set_ps(WIFI_PS_MAX_MODEM); delay(1); } else { +/* if (cur_mode == WIFI_OFF) { registerWiFiEventHandler(); } - +*/ // Only set power mode when AP is not enabled // When AP is enabled, the sleep mode is already set to WIFI_NONE_SLEEP if (!WifiIsAP(new_mode)) { diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index d18cb7c81..b7eaa510f 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -16,7 +16,7 @@ #include "../Globals/ESPEasy_Scheduler.h" #ifdef USES_ESPEASY_NOW -#include "../Globals/ESPEasy_now_handler.h" +# include "../Globals/ESPEasy_now_handler.h" #endif #include "../Globals/EventQueue.h" @@ -50,18 +50,18 @@ // SSDP // #if LWIP_VERSION_MAJOR == 2 #define IPADDR2STR(addr) (uint8_t)((uint32_t)addr & 0xFF), (uint8_t)(((uint32_t)addr >> 8) & 0xFF), \ - (uint8_t)(((uint32_t)addr >> 16) & 0xFF), (uint8_t)(((uint32_t)addr >> 24) & 0xFF) + (uint8_t)(((uint32_t)addr >> 16) & 0xFF), (uint8_t)(((uint32_t)addr >> 24) & 0xFF) // #endif #include #ifdef ESP8266 -#include -#include -#include -#include -#endif +# include +# include +# include +# include +#endif // ifdef ESP8266 #ifdef SUPPORT_ARP # include @@ -70,13 +70,9 @@ # include # include -void _etharp_gratuitous_func(struct netif *netif) { - etharp_gratuitous(netif); -} +void _etharp_gratuitous_func(struct netif *netif) { etharp_gratuitous(netif); } -void etharp_gratuitous_r(struct netif *netif) { - tcpip_callback_with_block((tcpip_callback_fn)_etharp_gratuitous_func, netif, 0); -} +void etharp_gratuitous_r(struct netif *netif) { tcpip_callback_with_block((tcpip_callback_fn)_etharp_gratuitous_func, netif, 0); } # endif // ifdef ESP32 @@ -133,7 +129,7 @@ void sendSyslog(uint8_t logLevel, const String& message) header += F(" EspEasy: "); header.trim(); header.replace(' ', '_'); - + #ifdef ESP8266 portUDP.write(header.c_str(), header.length()); #endif // ifdef ESP8266 @@ -143,7 +139,7 @@ void sendSyslog(uint8_t logLevel, const String& message) } #ifdef ESP8266 - portUDP.write(message.c_str(), message.length()); + portUDP.write(message.c_str(), message.length()); #endif // ifdef ESP8266 #ifdef ESP32 portUDP.write(reinterpret_cast(message.c_str()), message.length()); @@ -199,11 +195,11 @@ void sendUDP(uint8_t unit, const uint8_t *data, uint8_t size) # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { - addLogMove(LOG_LEVEL_DEBUG_MORE, strformat( - F("UDP : Send UDP message to %d (%s)"), - unit, - remoteNodeIP.toString().c_str() - )); + addLogMove(LOG_LEVEL_DEBUG_MORE, strformat( + F("UDP : Send UDP message to %d (%s)"), + unit, + remoteNodeIP.toString().c_str() + )); } # endif // ifndef BUILD_NO_DEBUG @@ -223,7 +219,7 @@ void updateUDPport(bool force) { static uint16_t lastUsedUDPPort = 0; - if (!force && Settings.UDPPort == lastUsedUDPPort) { + if (!force && (Settings.UDPPort == lastUsedUDPPort)) { return; } @@ -255,10 +251,13 @@ void updateUDPport(bool force) Check UDP messages (ESPEasy propiertary protocol) \*********************************************************************************************/ boolean runningUPDCheck = false; + void checkUDP() { - if (!NetworkConnected()) + if (!NetworkConnected()) { return; + } + if (Settings.UDPPort == 0) { return; } @@ -268,7 +267,7 @@ void checkUDP() } START_TIMER - runningUPDCheck = true; + runningUPDCheck = true; // UDP events int packetSize = portUDP.parsePacket(); @@ -297,7 +296,7 @@ void checkUDP() // and then crash due to memory allocation failures if ((packetSize >= 2) && (packetSize < UDP_PACKETSIZE_MAX)) { // Allocate buffer to process packet. - // Resize it to be 1 byte larger so we can 0-terminate it + // Resize it to be 1 byte larger so we can 0-terminate it // in case it is some plain text string std::vector packetBuffer; packetBuffer.resize(packetSize + 1); @@ -313,14 +312,14 @@ void checkUDP() # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - addLogMove(LOG_LEVEL_DEBUG, - strformat(F("UDP : %s Command: %s"), - formatIP(remoteIP, true).c_str(), - wrapWithQuotesIfContainsParameterSeparatorChar(String(&packetBuffer[0])).c_str() - )); + addLogMove(LOG_LEVEL_DEBUG, + strformat(F("UDP : %s Command: %s"), + formatIP(remoteIP, true).c_str(), + wrapWithQuotesIfContainsParameterSeparatorChar(String(&packetBuffer[0])).c_str() + )); } - #endif - ExecuteCommand_all({EventValueSource::Enum::VALUE_SOURCE_SYSTEM, &packetBuffer[0]}, true); + # endif // ifndef BUILD_NO_DEBUG + ExecuteCommand_all({ EventValueSource::Enum::VALUE_SOURCE_SYSTEM, &packetBuffer[0] }, true); } else { @@ -333,6 +332,7 @@ void checkUDP() break; } int copy_length = sizeof(NodeStruct); + // Older versions sent 80 bytes, regardless of the size of NodeStruct // Make sure the extra data received is ignored as it was also not initialized if (len == 80) { @@ -351,16 +351,16 @@ void checkUDP() # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { - addLogMove(LOG_LEVEL_DEBUG_MORE, - strformat(F("UDP : %s (%d) %s,%s,%d"), - formatIP(remoteIP).c_str(), - received.unit, - received.STA_MAC().toString().c_str(), - formatIP(received.IP(), true).c_str(), - received.unit)); + addLogMove(LOG_LEVEL_DEBUG_MORE, + strformat(F("UDP : %s (%d) %s,%s,%d"), + formatIP(remoteIP).c_str(), + received.unit, + received.STA_MAC().toString().c_str(), + formatIP(received.IP(), true).c_str(), + received.unit)); } -#endif // ifndef BUILD_NO_DEBUG +# endif // ifndef BUILD_NO_DEBUG } break; } @@ -372,8 +372,9 @@ void checkUDP() TempEvent.Par1 = remoteIP[3]; TempEvent.Par2 = len; String dummy; + // TD-er: Disabled the PLUGIN_UDP_IN call as we don't have any plugin using this. - //PluginCall(PLUGIN_UDP_IN, &TempEvent, dummy); + // PluginCall(PLUGIN_UDP_IN, &TempEvent, dummy); CPluginCall(CPlugin::Function::CPLUGIN_UDP_IN, &TempEvent); break; } @@ -401,7 +402,8 @@ String formatUnitToIPAddress(uint8_t unit, uint8_t formatCode) { IPAddress unitIPAddress = getIPAddressForUnit(unit); if (unitIPAddress[0] == 0) { // Invalid? - switch (formatCode) { + switch (formatCode) + { case 1: // Return empty string { return EMPTY_STRING; @@ -425,29 +427,29 @@ IPAddress getIPAddressForUnit(uint8_t unit) { } auto it = Nodes.find(unit); - if (it == Nodes.end() || it->second.ip[0] == 0) { + if ((it == Nodes.end()) || (it->second.ip[0] == 0)) { IPAddress ip; return ip; } -#if FEATURE_USE_IPV6 -/* - // FIXME TD-er: for now do not try to send to IPv6 - if (it->second.hasIPv6_mac_based_link_local) { - return it->second.IPv6_link_local(); - } - if (it->second.hasIPv6_mac_based_link_global) { - return it->second.IPv6_global(); - } -*/ -#endif +# if FEATURE_USE_IPV6 + + /* + // FIXME TD-er: for now do not try to send to IPv6 + if (it->second.hasIPv6_mac_based_link_local) { + return it->second.IPv6_link_local(); + } + if (it->second.hasIPv6_mac_based_link_global) { + return it->second.IPv6_global(); + } + */ +# endif // if FEATURE_USE_IPV6 return it->second.IP(); } - String getNameForUnit(uint8_t unit) { auto it = Nodes.find(unit); - if (it == Nodes.end() || it->second.getNodeName().isEmpty()) { + if ((it == Nodes.end()) || it->second.getNodeName().isEmpty()) { return EMPTY_STRING; } return it->second.getNodeName(); @@ -465,7 +467,7 @@ long getAgeForUnit(uint8_t unit) { uint16_t getBuildnrForUnit(uint8_t unit) { auto it = Nodes.find(unit); - if (it == Nodes.end() || it->second.build == 0) { + if ((it == Nodes.end()) || (it->second.build == 0)) { return 0; } return it->second.build; @@ -508,20 +510,22 @@ void refreshNodeList() Nodes.refreshNodeList(max_age_allowed, max_age); - #ifdef USES_ESPEASY_NOW - #ifdef ESP8266 + # ifdef USES_ESPEASY_NOW + # ifdef ESP8266 + // FIXME TD-er: Do not perform regular scans on ESP32 as long as we cannot scan per channel if (!Nodes.isEndpoint()) { WifiScan(true, Nodes.getESPEasyNOW_channel()); } - #endif - #endif + # endif // ifdef ESP8266 + # endif // ifdef USES_ESPEASY_NOW if (max_age > (0.75 * max_age_allowed)) { Scheduler.sendGratuitousARP_now(); } sendSysInfoUDP(1); - #ifdef USES_ESPEASY_NOW + # ifdef USES_ESPEASY_NOW + if (Nodes.recentlyBecameDistanceZero()) { // Send to all channels ESPEasy_now_handler.sendDiscoveryAnnounce(-1); @@ -530,7 +534,7 @@ void refreshNodeList() } ESPEasy_now_handler.sendNTPquery(); ESPEasy_now_handler.sendTraceRoute(); - #endif // ifdef USES_ESPEASY_NOW + # endif // ifdef USES_ESPEASY_NOW } /*********************************************************************************************\ @@ -560,7 +564,7 @@ void sendSysInfoUDP(uint8_t repeats) // Prepare UDP packet to send constexpr size_t data_size = sizeof(NodeStruct) + 2; - uint8_t data[data_size] = {0}; + uint8_t data[data_size] = { 0 }; data[0] = 255; data[1] = 1; memcpy(&data[2], thisNode, sizeof(NodeStruct)); @@ -606,42 +610,42 @@ void SSDP_schema() { (uint16_t)chipId & 0xff); web_server.client().print(F( - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/xml\r\n" - "Connection: close\r\n" - "Access-Control-Allow-Origin: *\r\n" - "\r\n" - "" - "" - "" - "1" - "0" - "" - "http://")); + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/xml\r\n" + "Connection: close\r\n" + "Access-Control-Allow-Origin: *\r\n" + "\r\n" + "" + "" + "" + "1" + "0" + "" + "http://")); web_server.client().print(formatIP(ip)); web_server.client().print(F(":80/" - "" - "urn:schemas-upnp-org:device:BinaryLight:1" - "")); + "" + "urn:schemas-upnp-org:device:BinaryLight:1" + "")); web_server.client().print(Settings.getName()); web_server.client().print(F("" - "/" - "")); + "/" + "")); web_server.client().print(String(ESP.getChipId())); web_server.client().print(F("" - "ESP Easy" - "")); + "ESP Easy" + "")); web_server.client().print(getValue(LabelType::GIT_BUILD)); web_server.client().print(F("" - "http://www.letscontrolit.com" - "http://www.letscontrolit.com" - "http://www.letscontrolit.com" - "uuid:")); + "http://www.letscontrolit.com" + "http://www.letscontrolit.com" + "http://www.letscontrolit.com" + "uuid:")); web_server.client().print(String(uuid)); web_server.client().print(F("" - "\r\n" - "\r\n")); + "\r\n" + "\r\n")); } /********************************************************************************************\ @@ -667,7 +671,6 @@ unsigned long _notify_time; static const IPAddress SSDP_MULTICAST_ADDR(239, 255, 255, 250); - /********************************************************************************************\ Launch SSDP listener and send initial notify \*********************************************************************************************/ @@ -807,10 +810,24 @@ void SSDP_update() { _respondToAddr = _server->getRemoteAddress(); _respondToPort = _server->getRemotePort(); - typedef enum { METHOD, URI, PROTO, KEY, VALUE, ABORT } states; + typedef enum { + METHOD, + URI, + PROTO, + KEY, + VALUE, + ABORT + + } states; states state = METHOD; - typedef enum { START, MAN, ST, MX } headers; + typedef enum { + START, + MAN, + ST, + MX + + } headers; headers header = START; uint8_t cursor = 0; @@ -823,7 +840,8 @@ void SSDP_update() { (c == '\r' || c == '\n') ? cr++ : cr = 0; - switch (state) { + switch (state) + { case METHOD: if (c == ' ') { @@ -874,7 +892,8 @@ void SSDP_update() { case VALUE: if (cr == 2) { - switch (header) { + switch (header) + { case START: break; case MAN: @@ -916,14 +935,16 @@ void SSDP_update() { } break; case ABORT: - _pending = false; _delay = 0; + _pending = false; + _delay = 0; break; } } } if (_pending && timeOutReached(_process_time + _delay)) { - _pending = false; _delay = 0; + _pending = false; + _delay = 0; SSDP_send(NONE); } else if ((_notify_time == 0) || timeOutReached(_notify_time + (SSDP_INTERVAL * 1000L))) { _notify_time = millis(); @@ -940,7 +961,6 @@ void SSDP_update() { # endif // if FEATURE_SSDP #endif // if defined(ESP8266) - // ******************************************************************************** // Return subnet range of WiFi. // ******************************************************************************** @@ -974,7 +994,6 @@ bool getSubnetRange(IPAddress& low, IPAddress& high) # include #endif // ifdef CORE_POST_2_5_0 - bool hasIPaddr() { if (useStaticIP()) { return true; } @@ -1000,10 +1019,11 @@ bool hasIPaddr() { bool useStaticIP() { #if FEATURE_ETHERNET + if (active_network_medium == NetworkMedium_t::Ethernet) { return ethUseStaticIP(); } - #endif + #endif // if FEATURE_ETHERNET return WiFiUseStaticIP(); } @@ -1011,10 +1031,11 @@ bool useStaticIP() { bool NetworkConnected(uint32_t timeout_ms) { #ifdef USES_ESPEASY_NOW + if (isESPEasy_now_only()) { return false; } -#endif +#endif // ifdef USES_ESPEASY_NOW if (timeout_ms > 500) { timeout_ms = 500; @@ -1073,6 +1094,7 @@ bool hostReachable(const IPAddress& ip) { } #if FEATURE_HTTP_CLIENT + bool connectClient(WiFiClient& client, const char *hostname, uint16_t port, uint32_t timeout_ms) { IPAddress ip; @@ -1090,14 +1112,15 @@ bool connectClient(WiFiClient& client, IPAddress ip, uint16_t port, uint32_t tim client.stop(); return false; } -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { addLog(LOG_LEVEL_DEBUG, strformat( - F("connectClient: '%s' port: %u"), - ip.toString().c_str(), - port)); + F("connectClient: '%s' port: %u"), + ip.toString().c_str(), + port)); } -#endif +# endif // ifndef BUILD_NO_DEBUG // In case of domain name resolution error result can be negative. // https://github.com/esp8266/Arduino/blob/18f643c7e2d6a0da9d26ff2b14c94e6536ab78c1/libraries/Ethernet/src/Dns.cpp#L44 @@ -1107,32 +1130,35 @@ bool connectClient(WiFiClient& client, IPAddress ip, uint16_t port, uint32_t tim delay(0); if (!connected) { -#ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - addLog(LOG_LEVEL_ERROR, strformat( - F("connectClient: connect failed to '%s' port: %u"), - ip.toString().c_str(), - port)); - } -#endif +# ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + addLog(LOG_LEVEL_ERROR, strformat( + F("connectClient: connect failed to '%s' port: %u"), + ip.toString().c_str(), + port)); + } +# endif // ifndef BUILD_NO_DEBUG Scheduler.sendGratuitousARP_now(); client.stop(); // Make sure to start over without some stale connection } STOP_TIMER(CONNECT_CLIENT_STATS); -#if defined(ESP32) || defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) -#else +# if defined(ESP32) || defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) +# else if (connected) { client.keepAlive(); // Use default keep alive values } -#endif // if defined(ESP32) || defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) +# endif // if defined(ESP32) || defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) return connected; } + #endif // FEATURE_HTTP_CLIENT void scrubDNS() { #if FEATURE_ETHERNET + if (active_network_medium == NetworkMedium_t::Ethernet) { if (EthEventData.EthServicesInitialized()) { setDNS(0, EthEventData.dns0_cache); @@ -1140,7 +1166,8 @@ void scrubDNS() { } return; } - #endif + #endif // if FEATURE_ETHERNET + if (WiFiEventData.WiFiServicesInitialized()) { setDNS(0, WiFiEventData.dns0_cache); setDNS(1, WiFiEventData.dns1_cache); @@ -1148,48 +1175,57 @@ void scrubDNS() { } bool valid_DNS_address(const IPAddress& dns) { - return (/*dns.v4() != (uint32_t)0x00000000 && */ - dns != IPAddress((uint32_t)0xFD000000) && + return /*dns.v4() != (uint32_t)0x00000000 && */ + dns != IPAddress((uint32_t)0xFD000000) && #ifdef ESP32 - // Bug where IPv6 global prefix is set as DNS - // Global IPv6 prefixes currently start with 2xxx:: - (dns[0] & 0xF0) != 0x20 && -#endif - dns != INADDR_NONE); + + // Bug where IPv6 global prefix is set as DNS + // Global IPv6 prefixes currently start with 2xxx:: + (dns[0] & 0xF0) != 0x20 && +#endif // ifdef ESP32 + dns != INADDR_NONE; } bool setDNS(int index, const IPAddress& dns) { - if (index >= 2) return false; + if (index >= 2) { return false; } #ifdef ESP8266 - if(dns.isSet() && dns != WiFi.dnsIP(index)) { - dns_setserver(index, dns); - #ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, concat(F("IP : Set DNS: "), formatIP(dns))); - } - #endif - return true; - } - #endif - #ifdef ESP32 - ip_addr_t d; - d.type = IPADDR_TYPE_V4; - if (valid_DNS_address(dns) || dns == INADDR_NONE) { - // Set DNS0-Server - d.u_addr.ip4.addr = static_cast(dns); - const ip_addr_t* cur_dns = dns_getserver(index); - if (cur_dns != nullptr && cur_dns->u_addr.ip4.addr == d.u_addr.ip4.addr) { - // Still the same as before - return false; - } - dns_setserver(index, &d); + if (dns.isSet() && (dns != WiFi.dnsIP(index))) { + dns_setserver(index, dns); + # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, concat(F("IP : Set DNS: "), formatIP(dns))); + addLogMove(LOG_LEVEL_INFO, strformat(F("IP : Set DNS(%d): %s"), index, formatIP(dns).c_str())); + } + # endif // ifndef BUILD_NO_DEBUG + return true; + } + #endif // ifdef ESP8266 + #ifdef ESP32 + + if (valid_DNS_address(dns)) { + const ip_addr_t*cur_dns = dns_getserver(index); + + if (cur_dns != nullptr) { + const IPAddress cur_dns_IP(cur_dns); + + if (valid_DNS_address(cur_dns_IP) && (cur_dns_IP == dns)) { + // Still the same as before + return false; + } + } + + // Set DNS-Server + ip_addr_t d; + dns.to_ip_addr_t(&d); + dns_setserver(index, &d); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, strformat(F("IP : Set DNS(%d): %s"), index, formatIP(dns).c_str())); } return true; } - #endif + #endif // ifdef ESP32 return false; } @@ -1228,7 +1264,7 @@ bool hostReachable(const String& hostname) { } if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - addLogMove(LOG_LEVEL_ERROR, concat(F("Hostname cannot be resolved: "), hostname)); + addLogMove(LOG_LEVEL_ERROR, concat(F("Hostname cannot be resolved: "), hostname)); } return false; } @@ -1388,6 +1424,7 @@ String extractParam(const String& authReq, const String& param, const char delim } #if FEATURE_HTTP_CLIENT + String getCNonce(const int len) { static const char alphanum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -1437,11 +1474,11 @@ String getDigestAuth(const String& authReq, // return authorization return strformat( F("Digest username=\"%s\"" - ", realm=\"%s\"" - ", nonce=\"%s\"" - ", uri=\"%s\"" - ", algorithm=\"MD5\", qop=auth, nc=%s, cnonce=\"%s\"" - ", response=\"%s\""), + ", realm=\"%s\"" + ", nonce=\"%s\"" + ", uri=\"%s\"" + ", algorithm=\"MD5\", qop=auth, nc=%s, cnonce=\"%s\"" + ", response=\"%s\""), username.c_str(), realm.c_str(), nonce.c_str(), @@ -1451,7 +1488,8 @@ String getDigestAuth(const String& authReq, md5.toString().c_str()); // response } -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG + void log_http_result(const HTTPClient& http, const String & logIdentifier, const String & host, @@ -1471,8 +1509,8 @@ void log_http_result(const HTTPClient& http, } if (loglevelActiveFor(loglevel)) { - String log = strformat(F("HTTP : %s %s %s"), - logIdentifier.c_str(), host.c_str(), HttpMethod.c_str()); + String log = strformat(F("HTTP : %s %s %s"), + logIdentifier.c_str(), host.c_str(), HttpMethod.c_str()); if (!success) { log += F("failed "); @@ -1490,7 +1528,8 @@ void log_http_result(const HTTPClient& http, addLogMove(loglevel, log); } } -#endif + +# endif // ifndef BUILD_NO_DEBUG int http_authenticate(const String& logIdentifier, WiFiClient & client, @@ -1522,17 +1561,17 @@ int http_authenticate(const String& logIdentifier, postStr, must_check_reply); } - int httpCode = 0; + int httpCode = 0; const bool hasCredentials = !user.isEmpty() && !pass.isEmpty(); if (hasCredentials) { must_check_reply = true; http.setAuthorization(user.c_str(), pass.c_str()); } else { - http.setAuthorization(""); // Clear Basic authorization -#ifdef ESP32 + http.setAuthorization(""); // Clear Basic authorization +# ifdef ESP32 http.setAuthorizationType(""); // Default type is "Basic" -#endif +# endif } http.setTimeout(timeout); http.setUserAgent(get_user_agent_string()); @@ -1542,31 +1581,31 @@ int http_authenticate(const String& logIdentifier, http.setRedirectLimit(2); } - #ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS + # ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS // See: https://github.com/espressif/arduino-esp32/pull/6676 client.setTimeout((timeout + 500) / 1000); // in seconds!!!! Client *pClient = &client; pClient->setTimeout(timeout); - #else // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS - client.setTimeout(timeout); // in msec as it should be! - #endif // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS + # else // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS + client.setTimeout(timeout); // in msec as it should be! + # endif // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS // Add request header as fall back. // When adding another "accept" header, it may be interpreted as: // "if you have XXX, send it; or failing that, just give me what you've got." - http.addHeader(F("Accept"), F("*/*;q=0.1")); + http.addHeader(F("Accept"), F("*/*;q=0.1")); // Add client IP http.addHeader(F("X-Forwarded-For"), formatIP(NetworkLocalIP())); delay(0); scrubDNS(); -#if defined(CORE_POST_2_6_0) || defined(ESP32) +# if defined(CORE_POST_2_6_0) || defined(ESP32) http.begin(client, host, port, uri, false); // HTTP -#else // if defined(CORE_POST_2_6_0) || defined(ESP32) +# else // if defined(CORE_POST_2_6_0) || defined(ESP32) http.begin(client, host, port, uri); -#endif // if defined(CORE_POST_2_6_0) || defined(ESP32) +# endif // if defined(CORE_POST_2_6_0) || defined(ESP32) const char *keys[] = { "WWW-Authenticate" }; http.collectHeaders(keys, 1); @@ -1576,17 +1615,18 @@ int http_authenticate(const String& logIdentifier, String name, value; while (splitHeaders(headerpos, header, name, value)) { - // Disabled the check to exclude "Authorization", due to: + // Disabled the check to exclude "Authorization", due to: // https://github.com/letscontrolit/ESPEasy/issues/4364 // Check was added for: https://github.com/letscontrolit/ESPEasy/issues/4355 // However, I doubt this was the actual bug. More likely the supplied credential strings were not entirely empty for whatever reason. // // Work-around to not add Authorization header since the HTTPClient code // only ignores this when base64Authorication is set. - -// if (!name.equalsIgnoreCase(F("Authorization"))) { - http.addHeader(name, value); -// } + + // if (!name.equalsIgnoreCase(F("Authorization"))) { + http.addHeader(name, value); + + // } } } @@ -1607,18 +1647,18 @@ int http_authenticate(const String& logIdentifier, addLogMove(LOG_LEVEL_INFO, concat(F("HTTP : Start Digest Authorization for "), host)); } - http.setAuthorization(""); // Clear Basic authorization -#ifdef ESP32 + http.setAuthorization(""); // Clear Basic authorization +# ifdef ESP32 http.setAuthorizationType(""); // Default type is "Basic" and "Digest" is already part of the string generated by getDigestAuth() -#endif +# endif const String authorization = getDigestAuth(authReq, user, pass, F("GET"), uri, 1); http.end(); -#if defined(CORE_POST_2_6_0) || defined(ESP32) +# if defined(CORE_POST_2_6_0) || defined(ESP32) http.begin(client, host, port, uri, false); // HTTP, not HTTPS -#else // if defined(CORE_POST_2_6_0) || defined(ESP32) +# else // if defined(CORE_POST_2_6_0) || defined(ESP32) http.begin(client, host, port, uri); -#endif // if defined(CORE_POST_2_6_0) || defined(ESP32) +# endif // if defined(CORE_POST_2_6_0) || defined(ESP32) http.addHeader(F("Authorization"), authorization); @@ -1643,50 +1683,58 @@ int http_authenticate(const String& logIdentifier, // Generate event with the HTTP return code // e.g. http#hostname=401 eventQueue.addMove(strformat(F("http#%s=%d"), host.c_str(), httpCode)); - - #if FEATURE_THINGSPEAK_EVENT - // Generate event with the response of a - // thingspeak request (https://de.mathworks.com/help/thingspeak/readlastfieldentry.html & - // https://de.mathworks.com/help/thingspeak/readdata.html) - // e.g. command for a specific field: "sendToHTTP,api.thingspeak.com,80,/channels/1637928/fields/5/last.csv" - // command for all fields: "sendToHTTP,api.thingspeak.com,80,/channels/1637928/feeds/last.csv" - // where first eventvalue is the channel number and the second to the nineth event values - // are the field values - // Example of the event: "EVENT: ThingspeakReply=1637928,5,24.2,12,900,..." - // ^ ^ └------┬------┘ - // channel number ┘ | └ received values - // field number (only available for a "single-value-event") - // In rules you can grep the reply by "On ThingspeakReply Do ..." - //----------------------------------------------------------------------------------------------------------------------------- - // 2024-02-05 - Added the option to get a single value of a field or all values of a channel at a certain time (not only the last entry) - // Examples: - // Single channel: "sendtohttp,api.thingspeak.com,80,channels/1637928/fields/1.csv?end=2024-01-01%2023:59:00&results=1" - // => gets the value of field 1 at (or the last entry before) 23:59:00 of the channel 1637928 - // All channels: "sendtohttp,api.thingspeak.com,80,channels/1637928/feeds.csv?end=2024-01-01%2023:59:00&results=1" - // => gets the value of each field of the channel 1637928 at (or the last entry before) 23:59:00 - //----------------------------------------------------------------------------------------------------------------------------- - if (httpCode == 200 && equals(host, F("api.thingspeak.com")) && (uri.endsWith(F("/last.csv")) || (uri.indexOf(F("results=1")) >= 0 && uri.indexOf(F(".csv")) >= 0))){ + # if FEATURE_THINGSPEAK_EVENT + + // Generate event with the response of a + // thingspeak request (https://de.mathworks.com/help/thingspeak/readlastfieldentry.html & + // https://de.mathworks.com/help/thingspeak/readdata.html) + // e.g. command for a specific field: "sendToHTTP,api.thingspeak.com,80,/channels/1637928/fields/5/last.csv" + // command for all fields: "sendToHTTP,api.thingspeak.com,80,/channels/1637928/feeds/last.csv" + // where first eventvalue is the channel number and the second to the nineth event values + // are the field values + // Example of the event: "EVENT: ThingspeakReply=1637928,5,24.2,12,900,..." + // ^ ^ └------┬------┘ + // channel number ┘ | └ received values + // field number (only available for a "single-value-event") + // In rules you can grep the reply by "On ThingspeakReply Do ..." + // ----------------------------------------------------------------------------------------------------------------------------- + // 2024-02-05 - Added the option to get a single value of a field or all values of a channel at a certain time (not only the last entry) + // Examples: + // Single channel: "sendtohttp,api.thingspeak.com,80,channels/1637928/fields/1.csv?end=2024-01-01%2023:59:00&results=1" + // => gets the value of field 1 at (or the last entry before) 23:59:00 of the channel 1637928 + // All channels: "sendtohttp,api.thingspeak.com,80,channels/1637928/feeds.csv?end=2024-01-01%2023:59:00&results=1" + // => gets the value of each field of the channel 1637928 at (or the last entry before) 23:59:00 + // ----------------------------------------------------------------------------------------------------------------------------- + + if ((httpCode == 200) && equals(host, + F("api.thingspeak.com")) && + (uri.endsWith(F("/last.csv")) || ((uri.indexOf(F("results=1")) >= 0) && (uri.indexOf(F(".csv")) >= 0)))) { String result = http.getString(); result.replace(' ', '_'); // if using a single field with a certain time, the result contains a space and would break the code const int posTimestamp = result.lastIndexOf(':'); - if (posTimestamp >= 0){ + + if (posTimestamp >= 0) { result = parseStringToEndKeepCase(result.substring(posTimestamp), 3); - if (uri.indexOf(F("fields")) >= 0){ // when there is a single field call add the field number before the value - result = parseStringKeepCase(uri, 4, '/').substring(0, 1) + "," + result; // since the field number is always the fourth part of the url and is always a single digit, we can use this to extact the fieldnumber + + if (uri.indexOf(F("fields")) >= 0) { // when there is a single field call add the field + // number before the value + result = parseStringKeepCase(uri, 4, '/').substring(0, 1) + "," + result; // since the field number is always the fourth part of + // the url and is always a single digit, we can use this + // to extact the fieldnumber } eventQueue.addMove(strformat( - F("ThingspeakReply=%s,%s"), - parseStringKeepCase(uri, 2, '/').c_str(), - result.c_str())); + F("ThingspeakReply=%s,%s"), + parseStringKeepCase(uri, 2, '/').c_str(), + result.c_str())); } } - #endif + # endif // if FEATURE_THINGSPEAK_EVENT } -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG log_http_result(http, logIdentifier, host + ':' + port, HttpMethod, httpCode, EMPTY_STRING); -#endif +# endif return httpCode; } @@ -1704,6 +1752,7 @@ String send_via_http(const String& logIdentifier, bool must_check_reply) { WiFiClient client; HTTPClient http; + http.setReuse(false); httpCode = http_authenticate( @@ -1725,19 +1774,22 @@ String send_via_http(const String& logIdentifier, if ((httpCode > 0) && must_check_reply) { response = http.getString(); -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG + if (!response.isEmpty()) { log_http_result(http, logIdentifier, host, HttpMethod, httpCode, response); } -#endif +# endif // ifndef BUILD_NO_DEBUG } http.end(); + // http.end() does not call client.stop() if it is no longer connected. - // However the client may still keep its internal state which may prevent + // However the client may still keep its internal state which may prevent // future connections to the same host until there has been a connection to another host inbetween. - client.stop(); + client.stop(); return response; } + #endif // FEATURE_HTTP_CLIENT #if FEATURE_DOWNLOAD @@ -1779,7 +1831,7 @@ bool start_downloadFile(WiFiClient & client, # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - addLogMove(LOG_LEVEL_DEBUG, strformat(F("downloadFile: URL: %s decoded: %s:%d%s"), + addLogMove(LOG_LEVEL_DEBUG, strformat(F("downloadFile: URL: %s decoded: %s:%d%s"), url.c_str(), host.c_str(), port, uri.c_str())); } # endif // ifndef BUILD_NO_DEBUG @@ -1807,7 +1859,7 @@ bool start_downloadFile(WiFiClient & client, ); if (httpCode != HTTP_CODE_OK) { - error = strformat(F("HTTP code: %d %s"), httpCode, url.c_str()); + error = strformat(F("HTTP code: %d %s"), httpCode, url.c_str()); addLog(LOG_LEVEL_ERROR, error); http.end(); @@ -1820,6 +1872,7 @@ bool start_downloadFile(WiFiClient & client, bool downloadFile(const String& url, String file_save, const String& user, const String& pass, String& error) { WiFiClient client; HTTPClient http; + http.setReuse(false); if (!start_downloadFile(client, http, url, file_save, user, pass, error)) { @@ -1827,7 +1880,7 @@ bool downloadFile(const String& url, String file_save, const String& user, const } if (fileExists(file_save)) { - error = concat(F("File exists: "), file_save); + error = concat(F("File exists: "), file_save); addLog(LOG_LEVEL_ERROR, error); http.end(); client.stop(); @@ -1860,7 +1913,7 @@ bool downloadFile(const String& url, String file_save, const String& user, const timeout = millis() + DOWNLOAD_FILE_TIMEOUT; if (f.write(buff, c) != c) { - error = strformat(F("Error saving file: %s %d Bytes written"), file_save.c_str(), bytesWritten); + error = strformat(F("Error saving file: %s %d Bytes written"), file_save.c_str(), bytesWritten); addLog(LOG_LEVEL_ERROR, error); http.end(); client.stop(); @@ -1872,7 +1925,7 @@ bool downloadFile(const String& url, String file_save, const String& user, const } if (timeOutReached(timeout)) { - error = concat(F("Timeout: "), file_save); + error = concat(F("Timeout: "), file_save); addLog(LOG_LEVEL_ERROR, error); delay(0); http.end(); @@ -1892,7 +1945,7 @@ bool downloadFile(const String& url, String file_save, const String& user, const } http.end(); client.stop(); - error = concat(F("Failed to open file for writing: "), file_save); + error = concat(F("Failed to open file for writing: "), file_save); addLog(LOG_LEVEL_ERROR, error); return false; } @@ -1900,18 +1953,20 @@ bool downloadFile(const String& url, String file_save, const String& user, const bool downloadFirmware(String filename, String& error) { String baseurl, user, pass; + # if FEATURE_CUSTOM_PROVISIONING MakeProvisioningSettings(ProvisioningSettings); if (ProvisioningSettings.get()) { loadProvisioningSettings(*ProvisioningSettings); + if (!ProvisioningSettings->allowedFlags.allowFetchFirmware) { error = F("Not Allowed"); return false; } baseurl = ProvisioningSettings->url; - user = ProvisioningSettings->user; - pass = ProvisioningSettings->pass; + user = ProvisioningSettings->user; + pass = ProvisioningSettings->pass; } # endif // if FEATURE_CUSTOM_PROVISIONING @@ -1924,6 +1979,7 @@ bool downloadFirmware(const String& url, String& file_save, String& user, String { WiFiClient client; HTTPClient http; + error.clear(); if (!start_downloadFile(client, http, url, file_save, user, pass, error)) { @@ -1954,8 +2010,8 @@ bool downloadFirmware(const String& url, String& file_save, String& user, String timeout = millis() + DOWNLOAD_FILE_TIMEOUT; if (Update.write(buff, c) != c) { - error = strformat(F("Error saving firmware update: %s %d Bytes written"), - file_save.c_str(), bytesWritten); + error = strformat(F("Error saving firmware update: %s %d Bytes written"), + file_save.c_str(), bytesWritten); break; } bytesWritten += c; @@ -1964,7 +2020,7 @@ bool downloadFirmware(const String& url, String& file_save, String& user, String } if (timeOutReached(timeout)) { - error = concat(F("Timeout: "), file_save); + error = concat(F("Timeout: "), file_save); break; } @@ -1983,29 +2039,45 @@ bool downloadFirmware(const String& url, String& file_save, String& user, String } uint8_t errorcode = 0; + if (!Update.end()) { errorcode = Update.getError(); -#ifdef ESP32 - const __FlashStringHelper * err_fstr = F("Unknown"); - switch (errorcode) { - case UPDATE_ERROR_OK: err_fstr = F("OK"); break; - case UPDATE_ERROR_WRITE: err_fstr = F("WRITE"); break; - case UPDATE_ERROR_ERASE: err_fstr = F("ERASE"); break; - case UPDATE_ERROR_READ: err_fstr = F("READ"); break; - case UPDATE_ERROR_SPACE: err_fstr = F("SPACE"); break; - case UPDATE_ERROR_SIZE: err_fstr = F("SIZE"); break; - case UPDATE_ERROR_STREAM: err_fstr = F("STREAM"); break; - case UPDATE_ERROR_MD5: err_fstr = F("MD5"); break; - case UPDATE_ERROR_MAGIC_BYTE: err_fstr = F("MAGIC_BYTE"); break; - case UPDATE_ERROR_ACTIVATE: err_fstr = F("ACTIVATE"); break; - case UPDATE_ERROR_NO_PARTITION: err_fstr = F("NO_PARTITION"); break; - case UPDATE_ERROR_BAD_ARGUMENT: err_fstr = F("BAD_ARGUMENT"); break; - case UPDATE_ERROR_ABORT: err_fstr = F("ABORT"); break; +# ifdef ESP32 + const __FlashStringHelper *err_fstr = F("Unknown"); + + switch (errorcode) + { + case UPDATE_ERROR_OK: err_fstr = F("OK"); + break; + case UPDATE_ERROR_WRITE: err_fstr = F("WRITE"); + break; + case UPDATE_ERROR_ERASE: err_fstr = F("ERASE"); + break; + case UPDATE_ERROR_READ: err_fstr = F("READ"); + break; + case UPDATE_ERROR_SPACE: err_fstr = F("SPACE"); + break; + case UPDATE_ERROR_SIZE: err_fstr = F("SIZE"); + break; + case UPDATE_ERROR_STREAM: err_fstr = F("STREAM"); + break; + case UPDATE_ERROR_MD5: err_fstr = F("MD5"); + break; + case UPDATE_ERROR_MAGIC_BYTE: err_fstr = F("MAGIC_BYTE"); + break; + case UPDATE_ERROR_ACTIVATE: err_fstr = F("ACTIVATE"); + break; + case UPDATE_ERROR_NO_PARTITION: err_fstr = F("NO_PARTITION"); + break; + case UPDATE_ERROR_BAD_ARGUMENT: err_fstr = F("BAD_ARGUMENT"); + break; + case UPDATE_ERROR_ABORT: err_fstr = F("ABORT"); + break; } error += concat(F(" Error: "), err_fstr); -#else +# else // ifdef ESP32 error += concat(F(" Error: "), errorcode); -#endif +# endif // ifdef ESP32 } else { if (Settings.UseRules) { eventQueue.addMove(concat(F("ProvisionFirmware#success="), file_save)); @@ -2014,6 +2086,7 @@ bool downloadFirmware(const String& url, String& file_save, String& user, String } backgroundtasks(); + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { addLog(LOG_LEVEL_ERROR, concat(F("Failed update firmware: "), error)); } @@ -2048,4 +2121,3 @@ String joinUrlFilename(const String& url, String& filename) } #endif // if FEATURE_DOWNLOAD - From 3741f7f24f8e97c3c26445e07445240b5ebf942f Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 6 Jan 2025 17:27:28 +0100 Subject: [PATCH 018/564] [WiFi] Fix start AP for setup --- .../ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 73 +++++++++++++-- .../ESPEasyWifi_abstracted_ESP8266.cpp | 93 ------------------- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 1 + 3 files changed, 66 insertions(+), 101 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index 16ce48675..3c1d10172 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -25,6 +25,7 @@ namespace wifi { # define WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT 10000 # define WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT 10000 # define WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT 10000 + # define WIFI_STATE_MACHINE_AP_ONLY_TIMEOUT 60000 void ESPEasyWiFi_t::setup() { // TODO TD-er: Must maybe also call 'disable()' first? @@ -74,6 +75,12 @@ void ESPEasyWiFi_t::loop() // setState(WiFiState_e::IdleWaiting, 100); break; case WiFiState_e::AP_only: + + if (WiFi_AP_Candidates.hasCandidates() || + (_state_timeout.timeReached() && + (WiFi.softAPgetStationNum() == 0))) { + setState(WiFiState_e::IdleWaiting, 100); + } break; case WiFiState_e::IdleWaiting: @@ -81,25 +88,68 @@ void ESPEasyWiFi_t::loop() // Do we have candidate to connect to ? if (WiFi_AP_Candidates.hasCandidates()) { setState(WiFiState_e::STA_Connecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); - } else if (WifiIsAP(WiFi.getMode())) { - // TODO TD-er: Must check if any client is connected. - // If not, then we can disable AP mode and switch to WiFiState_e::STA_Scanning - setState(WiFiState_e::STA_AP_Scanning, WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT); - } else { - setState(WiFiState_e::STA_Scanning, WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT); + } else if (WiFi_AP_Candidates.scanComplete() == 0) { + if (WifiIsAP(WiFi.getMode())) { + // TODO TD-er: Must check if any client is connected. + // If not, then we can disable AP mode and switch to WiFiState_e::STA_Scanning + setState(WiFiState_e::STA_AP_Scanning, WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT); + } else { + setState(WiFiState_e::STA_Scanning, WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT); + } + } else if (!WiFi_AP_Candidates.hasCandidateCredentials() || + !Settings.DoNotStartAP()) { + if (!WiFi_AP_Candidates.hasCandidateCredentials() && + !WiFiEventData.warnedNoValidWiFiSettings) + { + addLog(LOG_LEVEL_ERROR, F("WIFI : No valid wifi settings")); + WiFiEventData.warnedNoValidWiFiSettings = true; + } + + WiFiEventData.last_wifi_connect_attempt_moment.clear(); + WiFiEventData.wifi_connect_attempt = 1; + WiFiEventData.wifiConnectAttemptNeeded = false; + setState(WiFiState_e::AP_only, WIFI_STATE_MACHINE_AP_ONLY_TIMEOUT); } } break; case WiFiState_e::STA_Scanning: case WiFiState_e::STA_AP_Scanning: + { + auto scanCompleteStatus = WiFi.scanComplete(); - if (_state_timeout.timeReached() || (WiFi.scanComplete() >= 0)) { + if (scanCompleteStatus >= 0) { + WiFi_AP_Candidates.load_knownCredentials(); +# if !FEATURE_ESP8266_DIRECT_WIFI_SCAN + WiFi_AP_Candidates.process_WiFiscan(scanCompleteStatus); +# endif + addLog(LOG_LEVEL_INFO, strformat( + F("WiFi : Scan done, found %d APs"), + WiFi_AP_Candidates.scanComplete())); + } else if (scanCompleteStatus == -2) { // WIFI_SCAN_FAILED + addLog(LOG_LEVEL_ERROR, F("WiFi : Scan failed")); + WiFi.scanDelete(); setState(WiFiState_e::WiFiOFF, 100); + WiFiEventData.processedScanDone = true; } + if (_state_timeout.timeReached() || (scanCompleteStatus >= 0)) { + WiFi.scanDelete(); + + setState(WiFiState_e::WiFiOFF, 100); + + if (_state_timeout.timeReached()) { +# ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_ERROR, F("WiFi : Scan Running Timeout")); +# endif + } + WiFiEventData.processedScanDone = true; + + } + break; + // Check if scanning is finished // When scanning per channel, call for scanning next channel - break; + } case WiFiState_e::STA_Connecting: case WiFiState_e::STA_Reconnecting: @@ -154,6 +204,11 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { concat(F(" timeout: "), timeout)); } + if (_state == WiFiState_e::AP_only) { + setAPinternal(false); + setAP(false); + } + if (timeout == 0) { _state_timeout.clear(); @@ -173,8 +228,10 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { break; case WiFiState_e::WiFiOFF: // TODO TD-er: Must cancel all and turn off WiFi. + setSTA_AP(false, false); break; case WiFiState_e::AP_only: + setAPinternal(true); break; case WiFiState_e::IdleWaiting: // Do nothing here as we're waiting till the timeout is over diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp index ceb659e7b..361441c1a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp @@ -112,99 +112,6 @@ bool setWifiMode(WiFiMode_t new_mode) } - /* - if (cur_mode == WIFI_OFF) { - #if defined(ESP32) - // Needs to be set while WiFi is off - WiFi.hostname(NetworkCreateRFCCompliantHostname()); - #endif - WiFiEventData.markWiFiTurnOn(); - } - if (new_mode != WIFI_OFF) { - #ifdef ESP8266 - // See: https://github.com/esp8266/Arduino/issues/6172#issuecomment-500457407 - WiFi.forceSleepWake(); // Make sure WiFi is really active. - #endif - delay(100); - } else { - WifiDisconnect(); - // delay(100); - processDisconnect(); - WiFiEventData.clear_processed_flags(); - } - - addLog(LOG_LEVEL_INFO, concat(F("WIFI : Set WiFi to "), getWifiModeString(new_mode))); - - int retry = 2; - while (!WiFi.mode(new_mode) && retry > 0) { - delay(100); - --retry; - } - retry = 2; - while (WiFi.getMode() != new_mode && retry > 0) { - addLog(LOG_LEVEL_INFO, F("WIFI : mode not yet set")); - delay(100); - --retry; - } - if (WiFi.getMode() != new_mode) { - addLog(LOG_LEVEL_ERROR, F("WIFI : Cannot set mode!!!!!")); - return false; - } - - - if (new_mode == WIFI_OFF) { - - // FIXME TD-er: Is this correct to mark Turn ON ???? - WiFiEventData.markWiFiTurnOn(); - #if defined(ESP32) - // Needs to be set while WiFi is off - WiFi.hostname(NetworkCreateRFCCompliantHostname()); - #endif - delay(100); - #if defined(ESP32) - esp_wifi_set_ps(WIFI_PS_NONE); - // esp_wifi_set_ps(WIFI_PS_MAX_MODEM); - #endif - #ifdef ESP8266 - WiFi.forceSleepBegin(); - #endif // ifdef ESP8266 - delay(1); - } else { - if (cur_mode == WIFI_OFF) { - registerWiFiEventHandler(); - } - // Only set power mode when AP is not enabled - // When AP is enabled, the sleep mode is already set to WIFI_NONE_SLEEP - if (! WifiIsAP(new_mode)) { - if (Settings.WifiNoneSleep()) { - setWiFiNoneSleep(); - } else if (Settings.EcoPowerMode()) { - setWiFiEcoPowerMode(); - } else { - // Default - setWiFiDefaultPowerMode(); - } - } - #if FEATURE_SET_WIFI_TX_PWR - SetWiFiTXpower(); - #endif - if ( WifiIsSTA(new_mode)) { - // WiFi.setAutoConnect(Settings.SDK_WiFi_autoreconnect()); - WiFi.setAutoReconnect(Settings.SDK_WiFi_autoreconnect()); - } - delay(100); // Must allow for some time to init. - } - const bool new_mode_AP_enabled = WifiIsAP(new_mode); - - if ( WifiIsAP(cur_mode) && !new_mode_AP_enabled) { - eventQueue.add(F("WiFi#APmodeDisabled")); - } - - if ( WifiIsAP(cur_mode) != new_mode_AP_enabled) { - // Mode has changed - setAPinternal(new_mode_AP_enabled); - } - */ # if FEATURE_MDNS # ifdef ESP8266 diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 15681f954..5c3dbe156 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -92,6 +92,7 @@ void WiFi_AP_CandidatesList::force_reload() { clearCache(); RTC.clearLastWiFi(); // Invalidate the RTC WiFi data. candidates.clear(); + load_knownCredentials(); loadCandidatesFromScanned(); } From bbc99e2c051eeab1ef0ae6de5b59712c7c14e77a Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 6 Jan 2025 18:04:57 +0100 Subject: [PATCH 019/564] [WiFi] Call WiFi_AP_Candidates.force_reload() on saving security setting --- src/src/Helpers/ESPEasy_Storage.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index fb6c949f6..59bc4eddf 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -708,12 +708,14 @@ String SaveSecuritySettings(bool forFactoryReset) { sizeof(SecuritySettings)); // Security settings are saved, may be update of WiFi settings or hostname. - if (!forFactoryReset && !NetworkConnected()) { + if (!forFactoryReset) { if (SecuritySettings.hasWiFiCredentials() && (active_network_medium == NetworkMedium_t::WIFI)) { - WiFiEventData.wifiConnectAttemptNeeded = true; WiFi_AP_Candidates.force_reload(); // Force reload of the credentials and found APs from the last scan - resetWiFi(); - AttemptWiFiConnect(); + if (!NetworkConnected()) { + WiFiEventData.wifiConnectAttemptNeeded = true; + resetWiFi(); + AttemptWiFiConnect(); + } } } } From 079d58d779e776f00aa382a7897def78979e0ab9 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 28 Jan 2025 02:38:55 +0100 Subject: [PATCH 020/564] [PSRAM] Use PSRAM for logs, events and controller queues --- src/src/DataStructs/EventQueue.cpp | 13 ++++-- src/src/DataStructs/LogEntry.cpp | 2 +- src/src/Helpers/Memory.cpp | 70 +++++++++++++++++++++++++++++ src/src/Helpers/Memory.h | 5 ++- src/src/Helpers/StringConverter.cpp | 21 ++------- 5 files changed, 88 insertions(+), 23 deletions(-) diff --git a/src/src/DataStructs/EventQueue.cpp b/src/src/DataStructs/EventQueue.cpp index 0b975046f..06a0b4e54 100644 --- a/src/src/DataStructs/EventQueue.cpp +++ b/src/src/DataStructs/EventQueue.cpp @@ -11,18 +11,21 @@ void EventQueueStruct::add(const String& event, bool deduplicate) { if (!deduplicate || !isDuplicate(event)) { - #ifdef USE_SECOND_HEAP +#if defined(USE_SECOND_HEAP) || defined(ESP32) String tmp; reserve_special(tmp, event.length()); tmp = event; +#ifdef USE_SECOND_HEAP // Do not add to the list while on 2nd heap HeapSelectDram ephemeral; +#endif + _eventQueue.emplace_back(std::move(tmp)); - #else +#else _eventQueue.push_back(event); - #endif // ifdef USE_SECOND_HEAP +#endif } } @@ -38,12 +41,14 @@ void EventQueueStruct::addMove(String&& event, bool deduplicate) if (!event.length()) { return; } if (!deduplicate || !isDuplicate(event)) { - #ifdef USE_SECOND_HEAP + #if defined(USE_SECOND_HEAP) || defined(ESP32) String tmp; move_special(tmp, std::move(event)); + #ifdef USE_SECOND_HEAP // Do not add to the list while on 2nd heap HeapSelectDram ephemeral; + #endif _eventQueue.emplace_back(std::move(tmp)); #else _eventQueue.emplace_back(std::move(event)); diff --git a/src/src/DataStructs/LogEntry.cpp b/src/src/DataStructs/LogEntry.cpp index 90cb825dc..99348ce80 100644 --- a/src/src/DataStructs/LogEntry.cpp +++ b/src/src/DataStructs/LogEntry.cpp @@ -48,7 +48,7 @@ bool LogEntry_t::add(const uint8_t loglevel, String&& line) // Need to make a substring, which is a new allocation, on the 2nd heap HeapSelectIram ephemeral; #endif // ifdef USE_SECOND_HEAP - _message = std::move(line.substring(0, LOG_STRUCT_MESSAGE_SIZE - 1)); + _message = move_special(line.substring(0, LOG_STRUCT_MESSAGE_SIZE - 1)); } else { move_special(_message, std::move(line)); } diff --git a/src/src/Helpers/Memory.cpp b/src/src/Helpers/Memory.cpp index b4749f11c..173e49e94 100644 --- a/src/src/Helpers/Memory.cpp +++ b/src/src/Helpers/Memory.cpp @@ -197,3 +197,73 @@ void* special_calloc(size_t num, size_t size) { return res; } + + +#ifdef ESP8266 +bool String_reserve_special(String& str, size_t size) { + if (str.length() >= size) { + // Nothing needs to be done + return true; + } + #ifdef USE_SECOND_HEAP + if (size >= 32) { + // Only try to store larger strings here as those tend to be kept for a longer period. + HeapSelectIram ephemeral; + // String does round up to nearest multiple of 16 bytes, so no need to round up to multiples of 32 bit here + if (str.reserve(size)) { + return true; + } + } + #endif + return str.reserve(size); +} +#endif + +#ifdef ESP32 + +// Special class to get access to the protected String functions +// This class only has a constructor which will perform +// the requested allocation in PSRAM when possible +class PSRAM_String : public String { + public: + PSRAM_String(size_t size) : String() { + if (size > capacity() && UsePSRAM()) { + size_t newSize = (size + 16) & (~0xf); + void *ptr = special_calloc(1, newSize); + if (ptr != nullptr) { + setSSO(false); + setBuffer((char *)ptr); + setCapacity(newSize - 1); + setLen(newSize - 1); // TD-er: Not sure if needed? + } + } + } +}; + + +bool String_reserve_special(String& str, size_t size) { + if (str.length() < size) { + // As we like to move this to PSRAM, it also makes sense + // to do this when the length equals size + PSRAM_String psram_str(size); + + if (psram_str.length() == 0) { + return str.reserve(size); + } + + // Copy any existing content + String tmp(std::move(str)); + + // Move the newly allocated buffer to a tmp String object. + // Needs to be empty, so the buffer is moved. + // N.B. String::clear() = String::setlen(0)) + str = std::move(psram_str); + str.clear(); + + if (tmp.length()) { + str = tmp; + } + } + return true; +} +#endif diff --git a/src/src/Helpers/Memory.h b/src/src/Helpers/Memory.h index e09ce027d..06d1a3045 100644 --- a/src/src/Helpers/Memory.h +++ b/src/src/Helpers/Memory.h @@ -55,4 +55,7 @@ unsigned long getMaxFreeBlock(); void *special_malloc(uint32_t size); void *special_realloc(void *ptr, size_t size); -void *special_calloc(size_t num, size_t size); \ No newline at end of file +void *special_calloc(size_t num, size_t size); + + +bool String_reserve_special(String& str, size_t size); \ No newline at end of file diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index 7f312beaf..6fb63f445 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -90,6 +90,9 @@ void move_special(String& dest, String&& source) { } #endif // ifdef USE_SECOND_HEAP dest = std::move(source); + #ifdef ESP32 + reserve_special(dest, dest.length()); + #endif } String move_special(String&& source) { @@ -100,23 +103,7 @@ String move_special(String&& source) { bool reserve_special(String& str, size_t size) { - if (str.length() >= size) { - // Nothing needs to be done - return true; - } - // FIXME TD-er: Should also use this for ESP32 with PSRAM to allocate on PSRAM - #ifdef USE_SECOND_HEAP - if (size >= 32) { - // Only try to store larger strings here as those tend to be kept for a longer period. - HeapSelectIram ephemeral; - // String does round up to nearest multiple of 16 bytes, so no need to round up to multiples of 32 bit here - if (str.reserve(size)) { - return true; - } - } - #endif - return str.reserve(size); - // TD-er: should we also log here? + return String_reserve_special(str, size); } From 02f070c9e97ad40e06db5c1ca045c240e37b179e Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 28 Jan 2025 14:49:27 +0100 Subject: [PATCH 021/564] [Memory] Fix freeing of allocated strings --- src/_C008.cpp | 2 +- src/_C010.cpp | 2 +- src/_C015.cpp | 2 +- src/_C016.cpp | 4 +-- src/_P055_Chiming.ino | 2 +- src/src/Commands/InternalCommands.cpp | 2 +- .../Controller_struct/C018_data_struct.cpp | 10 ++++---- .../ExtendedControllerCredentialsStruct.cpp | 3 ++- src/src/DataStructs/LogEntry.cpp | 7 +++--- src/src/DataStructs/LogStruct.h | 2 +- src/src/DataStructs/Modbus.cpp | 3 ++- src/src/DataStructs/RulesEventCache.cpp | 4 +++ src/src/DataStructs/Web_StreamingBuffer.cpp | 2 +- src/src/ESPEasyCore/ESPEasy_Log.cpp | 25 ++++++++++++------- src/src/Globals/RamTracker.cpp | 6 ++--- src/src/Helpers/Audio.cpp | 3 ++- src/src/Helpers/ESPEasy_checks.cpp | 2 +- src/src/Helpers/Memory.h | 6 ++++- src/src/Helpers/Modbus_RTU.cpp | 2 +- src/src/Helpers/StringConverter.cpp | 10 ++++++-- src/src/Helpers/StringConverter.h | 4 +++ src/src/Helpers/StringParser.cpp | 4 +-- src/src/Helpers/WebServer_commandHelper.cpp | 2 +- src/src/Helpers/_CPlugin_Helper.cpp | 3 ++- src/src/PluginStructs/P020_data_struct.cpp | 2 +- src/src/PluginStructs/P044_data_struct.cpp | 2 +- src/src/PluginStructs/P073_data_struct.cpp | 2 +- src/src/PluginStructs/P082_data_struct.cpp | 2 +- src/src/PluginStructs/P094_data_struct.cpp | 3 +-- src/src/PluginStructs/P104_data_struct.cpp | 4 +-- src/src/PluginStructs/P165_data_struct.cpp | 2 +- src/src/WebServer/ControlPage.cpp | 2 +- src/src/WebServer/RootPage.cpp | 4 +-- src/src/WebServer/ToolsPage.cpp | 4 +-- src/src/WebServer/UploadPage.cpp | 4 +-- src/src/WebServer/WebTemplateParser.cpp | 2 +- 36 files changed, 87 insertions(+), 58 deletions(-) diff --git a/src/_C008.cpp b/src/_C008.cpp index d7eb87dff..4383f382f 100644 --- a/src/_C008.cpp +++ b/src/_C008.cpp @@ -49,7 +49,7 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: { - event->String1 = String(); + free_string(event->String1); event->String2 = F("demo.php?name=%sysname%&task=%tskname%&valuename=%valname%&value=%value%"); break; } diff --git a/src/_C010.cpp b/src/_C010.cpp index c12ff0e60..ec65589ad 100644 --- a/src/_C010.cpp +++ b/src/_C010.cpp @@ -35,7 +35,7 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: { - event->String1 = String(); + free_string(event->String1); event->String2 = F("%sysname%_%tskname%_%valname%=%value%"); break; } diff --git a/src/_C015.cpp b/src/_C015.cpp index e06d6edda..5269e4973 100644 --- a/src/_C015.cpp +++ b/src/_C015.cpp @@ -202,7 +202,7 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& if (!isvalid) { // send empty string to Blynk in case of error - formattedValue = String(); + free_string(formattedValue); } const String valueName = Cache.getTaskDeviceValueName(event->TaskIndex, x); diff --git a/src/_C016.cpp b/src/_C016.cpp index 625c377b0..899446b43 100644 --- a/src/_C016.cpp +++ b/src/_C016.cpp @@ -104,8 +104,8 @@ bool CPlugin_016(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: { - event->String1 = String(); - event->String2 = String(); + free_string(event->String1); + free_string(event->String2); break; } diff --git a/src/_P055_Chiming.ino b/src/_P055_Chiming.ino index 1a45df5cb..629b698d7 100644 --- a/src/_P055_Chiming.ino +++ b/src/_P055_Chiming.ino @@ -529,7 +529,7 @@ uint8_t Plugin_055_ReadChime(const String& name, String& tokens) log = strformat(F("Chime: read %s "), fileName.c_str()); } - tokens = String(); + free_string(tokens); fs::File f = tryOpenFile(fileName, "r"); if (f) diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index 17d794620..f9a8b631a 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -175,7 +175,7 @@ bool do_command_case_check(command_case_data & data, // The data struct is re-used on each attempt to process an internal command. // Re-initialize the only two members that may have been altered by a previous call. data.retval = false; - data.status = String(); + free_string(data.status); if (!checkSourceFlags(data.event->Source, group)) { data.status = return_incorrect_source(); diff --git a/src/src/Controller_struct/C018_data_struct.cpp b/src/src/Controller_struct/C018_data_struct.cpp index 16e1ce911..91b3adb3b 100644 --- a/src/src/Controller_struct/C018_data_struct.cpp +++ b/src/src/Controller_struct/C018_data_struct.cpp @@ -25,9 +25,9 @@ void C018_data_struct::reset() { delete C018_easySerial; C018_easySerial = nullptr; } - cacheDevAddr = String(); - cacheHWEUI = String(); - cacheSysVer = String(); + free_string(cacheDevAddr); + free_string(cacheHWEUI); + free_string(cacheSysVer); autobaud_success = false; } @@ -157,7 +157,7 @@ bool C018_data_struct::initOTAA(const String& AppEUI, const String& AppKey, cons if (myLora == nullptr) { return false; } bool success = myLora->initOTAA(AppEUI, AppKey, DevEUI); - cacheDevAddr = String(); + free_string(cacheDevAddr); C018_logError(F("initOTAA()")); updateCacheOnInit(); @@ -334,7 +334,7 @@ void C018_data_struct::updateCacheOnInit() { cacheDevAddr = myLora->sendRawCommand(F("mac get devaddr")); if (cacheDevAddr == F("00000000")) { - cacheDevAddr = String(); + free_string(cacheDevAddr); } } } diff --git a/src/src/DataStructs/ExtendedControllerCredentialsStruct.cpp b/src/src/DataStructs/ExtendedControllerCredentialsStruct.cpp index b53681679..2834cb750 100644 --- a/src/src/DataStructs/ExtendedControllerCredentialsStruct.cpp +++ b/src/src/DataStructs/ExtendedControllerCredentialsStruct.cpp @@ -1,6 +1,7 @@ #include "../DataStructs/ExtendedControllerCredentialsStruct.h" #include "../Helpers/ESPEasy_Storage.h" +#include "../Helpers/StringConverter.h" #define EXT_CONTR_CRED_USER_OFFSET 0 #define EXT_CONTR_CRED_PASS_OFFSET 1 @@ -24,7 +25,7 @@ bool ExtendedControllerCredentialsStruct::validateChecksum() const void ExtendedControllerCredentialsStruct::clear() { for (size_t i = 0; i < CONTROLLER_MAX * 2; ++i) { - _strings[i] = String(); + free_string(_strings[i]); } } diff --git a/src/src/DataStructs/LogEntry.cpp b/src/src/DataStructs/LogEntry.cpp index 99348ce80..0dffb03f9 100644 --- a/src/src/DataStructs/LogEntry.cpp +++ b/src/src/DataStructs/LogEntry.cpp @@ -26,8 +26,9 @@ bool LogEntry_t::add(const uint8_t loglevel, const String& line) #endif // ifdef USE_SECOND_HEAP if (line.length() > LOG_STRUCT_MESSAGE_SIZE - 1) { - _message = std::move(line.substring(0, LOG_STRUCT_MESSAGE_SIZE - 1)); + move_special(_message, line.substring(0, LOG_STRUCT_MESSAGE_SIZE - 1)); } else { + reserve_special(_message, line.length()); _message = line; } } @@ -48,7 +49,7 @@ bool LogEntry_t::add(const uint8_t loglevel, String&& line) // Need to make a substring, which is a new allocation, on the 2nd heap HeapSelectIram ephemeral; #endif // ifdef USE_SECOND_HEAP - _message = move_special(line.substring(0, LOG_STRUCT_MESSAGE_SIZE - 1)); + move_special(_message, line.substring(0, LOG_STRUCT_MESSAGE_SIZE - 1)); } else { move_special(_message, std::move(line)); } @@ -59,7 +60,7 @@ bool LogEntry_t::add(const uint8_t loglevel, String&& line) void LogEntry_t::clear() { - _message = String(); + free_string(_message); _timestamp = 0; _loglevel = 0; } diff --git a/src/src/DataStructs/LogStruct.h b/src/src/DataStructs/LogStruct.h index 40930d22a..4e3c64490 100644 --- a/src/src/DataStructs/LogStruct.h +++ b/src/src/DataStructs/LogStruct.h @@ -10,7 +10,7 @@ * LogStruct \*********************************************************************************************/ #ifdef ESP32 - #define LOG_STRUCT_MESSAGE_LINES 60 + #define LOG_STRUCT_MESSAGE_LINES 120 #else #ifdef USE_SECOND_HEAP #define LOG_STRUCT_MESSAGE_LINES 60 diff --git a/src/src/DataStructs/Modbus.cpp b/src/src/DataStructs/Modbus.cpp index 6c2e46ced..a83796fbe 100644 --- a/src/src/DataStructs/Modbus.cpp +++ b/src/src/DataStructs/Modbus.cpp @@ -4,6 +4,7 @@ #include "../DataStructs/ControllerSettingsStruct.h" #include "../ESPEasyCore/ESPEasy_Log.h" +#include "../Helpers/StringConverter.h" Modbus::Modbus() : ModbusClient(nullptr), errcnt(0), timeout(0), @@ -108,7 +109,7 @@ bool Modbus::handle() { unsigned int RXavailable = 0; #ifndef BUILD_NO_DEBUG - LogString = String(); + free_string(LogString); #endif int64_t rxValue = 0; diff --git a/src/src/DataStructs/RulesEventCache.cpp b/src/src/DataStructs/RulesEventCache.cpp index 743ad2703..e221c027c 100644 --- a/src/src/DataStructs/RulesEventCache.cpp +++ b/src/src/DataStructs/RulesEventCache.cpp @@ -41,6 +41,10 @@ bool RulesEventCache::addLine(const String& line, const String& filename, size_t # ifdef USE_SECOND_HEAP HeapSelectDram ephemeral; # endif // ifdef USE_SECOND_HEAP + #ifdef ESP32 + reserve_special(event, event.length()); + reserve_special(action, action.length()); + #endif _eventCache.emplace_back(filename, pos, std::move(event), std::move(action)); return true; diff --git a/src/src/DataStructs/Web_StreamingBuffer.cpp b/src/src/DataStructs/Web_StreamingBuffer.cpp index 41203f8d7..24e4905d6 100644 --- a/src/src/DataStructs/Web_StreamingBuffer.cpp +++ b/src/src/DataStructs/Web_StreamingBuffer.cpp @@ -336,7 +336,7 @@ void Web_StreamingBuffer::sendContentBlocking(String& data) { web_server.sendContent(data); if (data.length() > (CHUNKED_BUFFER_SIZE + 1)) { - data = String(); // Clear also allocated memory + free_string(data); // Clear also allocated memory } else { data.clear(); } diff --git a/src/src/ESPEasyCore/ESPEasy_Log.cpp b/src/src/ESPEasyCore/ESPEasy_Log.cpp index eade2faa6..fe82f366c 100644 --- a/src/src/ESPEasyCore/ESPEasy_Log.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Log.cpp @@ -17,6 +17,8 @@ #include "../Helpers/ESPEasy_Storage.h" #endif +#define UPDATE_LOGLEVEL_ACTIVE_CACHE_INTERVAL 5000 + /********************************************************************************************\ Init critical variables for logging (important during initial factory reset stuff ) \*********************************************************************************************/ @@ -124,6 +126,13 @@ bool loglevelActiveFor(uint8_t logLevel) { return false; } #endif + static uint32_t lastUpdateLogLevelCache = 0; + if (lastUpdateLogLevelCache == 0 || + timePassedSince(lastUpdateLogLevelCache) > UPDATE_LOGLEVEL_ACTIVE_CACHE_INTERVAL) + { + lastUpdateLogLevelCache = millis(); + updateLogLevelCache(); + } return logLevel <= highest_active_log_level; } @@ -143,15 +152,13 @@ uint8_t getSerialLogLevel() { } uint8_t getWebLogLevel() { - uint8_t logLevelSettings = 0; if (Logging.logActiveRead()) { - logLevelSettings = Settings.WebLogLevel; - } else { - if (Settings.WebLogLevel != 0) { - updateLogLevelCache(); - } + return Settings.WebLogLevel; + } + if (Settings.WebLogLevel != LOG_LEVEL_NONE) { + updateLogLevelCache(); } - return logLevelSettings; + return LOG_LEVEL_NONE; } bool loglevelActiveFor(uint8_t destination, uint8_t logLevel) { @@ -245,7 +252,7 @@ void addLog(uint8_t logLevel, const char *line) } } #else - if (!copy.reserve(strlen_P((PGM_P)line))) { + if (!reserve_special(copy, strlen_P((PGM_P)line))) { return; } copy = line; @@ -353,5 +360,5 @@ void addToLogMove(uint8_t logLevel, String&& string) Logging.add(logLevel, std::move(string)); } // Make sure the string may no longer keep up memory - string = String(); + free_string(string); } diff --git a/src/src/Globals/RamTracker.cpp b/src/src/Globals/RamTracker.cpp index 2e8ce55af..874bfee83 100644 --- a/src/src/Globals/RamTracker.cpp +++ b/src/src/Globals/RamTracker.cpp @@ -156,7 +156,7 @@ RamTracker::RamTracker(void) { writePtr = 0; for (int i = 0; i < TRACES; i++) { - traces[i] = String(); + free_string(traces[i]); tracesMemory[i] = 0xffffffff; // init with best case memory values, so they get replaced if memory goes lower } @@ -172,7 +172,7 @@ void RamTracker::registerRamState(const String& s) { // store function int bestCase = bestCaseTrace(); // find best case memory trace if (ESP.getFreeHeap() < tracesMemory[bestCase]) { // compare to current memory value - traces[bestCase] = String(); + free_string(traces[bestCase]); readPtr = writePtr + 1; // read out buffer, oldest value first if (readPtr >= TRACEENTRIES) { @@ -210,7 +210,7 @@ void RamTracker::getTraceBuffer() { retval += ' '; retval += traces[i]; addLogMove(LOG_LEVEL_DEBUG_DEV, retval); - retval = String(); + retval.clear(); } } #endif // ifndef BUILD_NO_DEBUG diff --git a/src/src/Helpers/Audio.cpp b/src/src/Helpers/Audio.cpp index e7e8d115f..1ee71cda5 100644 --- a/src/src/Helpers/Audio.cpp +++ b/src/src/Helpers/Audio.cpp @@ -5,6 +5,7 @@ #include "../Globals/RamTracker.h" #include "../Helpers/Hardware_GPIO.h" #include "../Helpers/Hardware_PWM.h" +#include "../Helpers/StringConverter.h" /********************************************************************************************\ @@ -53,7 +54,7 @@ void clear_rtttl_melody() { # endif // if FEATURE_RTTTL_EVENTS } - rtttlMelody = String(); + free_string(rtttlMelody); } void set_rtttl_melody(String& melody) { diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 8a86e2544..1af488d4e 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -211,7 +211,7 @@ String ReportOffsetErrorInStruct(const String& structname, size_t offset) { * Not a member function to be able to use the F-macro \*********************************************************************************************/ bool SettingsCheck(String& error) { - error = String(); + free_string(error); #ifndef LIMIT_BUILD_SIZE #ifdef esp8266 size_t offset = offsetof(SettingsStruct, ResetFactoryDefaultPreference); diff --git a/src/src/Helpers/Memory.h b/src/src/Helpers/Memory.h index 06d1a3045..9f7faab34 100644 --- a/src/src/Helpers/Memory.h +++ b/src/src/Helpers/Memory.h @@ -58,4 +58,8 @@ void *special_realloc(void *ptr, size_t size); void *special_calloc(size_t num, size_t size); -bool String_reserve_special(String& str, size_t size); \ No newline at end of file +// Perform a special memory allocate for the buffer pointer in the String object +// Allocation is tried either on 2nd heap (ESP8266) or PSRAM (ESP32) +// when possible. +bool String_reserve_special(String& str, size_t size); + diff --git a/src/src/Helpers/Modbus_RTU.cpp b/src/src/Helpers/Modbus_RTU.cpp index 7b3ac05ec..7e452360c 100644 --- a/src/src/Helpers/Modbus_RTU.cpp +++ b/src/src/Helpers/Modbus_RTU.cpp @@ -19,7 +19,7 @@ void ModbusRTU_struct::reset() { delete easySerial; easySerial = nullptr; } - detected_device_description = String(); + free_string(detected_device_description); for (int i = 0; i < 8; ++i) { _sendframe[i] = 0; diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index 6fb63f445..eb4415a6b 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -83,7 +83,7 @@ void move_special(String& dest, String&& source) { HeapSelectIram ephemeral; if (dest.reserve(source.length())) { dest = source; - source = String(); + free_string(source); return; } // Could not allocate on 2nd heap, so just move existing string @@ -106,6 +106,12 @@ bool reserve_special(String& str, size_t size) { return String_reserve_special(str, size); } +void free_string(String& str) { + // This is a call specifically tailored to what is done in: + // void String::move(String &rhs) + + String tmp(std::move(str)); +} /********************************************************************************************\ Format string using vsnprintf @@ -1515,7 +1521,7 @@ bool GetArgv(const char *string, String& argvString, unsigned int argc, char sep int pos_begin, pos_end; bool hasArgument = GetArgvBeginEnd(string, argc, pos_begin, pos_end, separator); - argvString = String(); + free_string(argvString); if (!hasArgument) { return false; } diff --git a/src/src/Helpers/StringConverter.h b/src/src/Helpers/StringConverter.h index de1ebfc58..61472b954 100644 --- a/src/src/Helpers/StringConverter.h +++ b/src/src/Helpers/StringConverter.h @@ -58,6 +58,10 @@ String move_special(String&& source); // Try to reserve on the heap with the most space available bool reserve_special(String& str, size_t size); +// Arduino String does not have a function to de-allocate its internal buffer +// This is a special trick to de-allocate its internal buffer and thus free up memory. +void free_string(String& str); + /* template bool equals(const String& str, const T &val) { diff --git a/src/src/Helpers/StringParser.cpp b/src/src/Helpers/StringParser.cpp index 6f1eff763..1a0e7b0f5 100644 --- a/src/src/Helpers/StringParser.cpp +++ b/src/src/Helpers/StringParser.cpp @@ -420,7 +420,7 @@ void transformValue( } if (equals(value, '0')) { - value = String(); + free_string(value); } else { const int valueLength = value.length(); @@ -769,7 +769,7 @@ bool findNextDevValNameInString(const String& input, int& startpos, int& endpos, move_special(format, valueName.substring(hashpos + 1)); move_special(valueName, valueName.substring(0, hashpos)); } else { - format = String(); + free_string(format); } deviceName.toLowerCase(); valueName.toLowerCase(); diff --git a/src/src/Helpers/WebServer_commandHelper.cpp b/src/src/Helpers/WebServer_commandHelper.cpp index 1a9092d22..d8f37ded5 100644 --- a/src/src/Helpers/WebServer_commandHelper.cpp +++ b/src/src/Helpers/WebServer_commandHelper.cpp @@ -23,7 +23,7 @@ HandledWebCommand_result handle_command_from_web(EventValueSource::Enum source, bool handledCmd = false; bool sendOK = false; - printWebString = String(); + free_string(printWebString); printToWeb = false; printToWebJSON = false; diff --git a/src/src/Helpers/_CPlugin_Helper.cpp b/src/src/Helpers/_CPlugin_Helper.cpp index 3d97c3b58..347ff2e57 100644 --- a/src/src/Helpers/_CPlugin_Helper.cpp +++ b/src/src/Helpers/_CPlugin_Helper.cpp @@ -42,7 +42,8 @@ bool safeReadStringUntil(Stream & input, const unsigned long timer = start + timeout; unsigned long backgroundtasks_timer = start + 10; - str = String(); + // FIXME TD-er: Should this also de-allocate internal buffer? + str.clear(); do { // read character diff --git a/src/src/PluginStructs/P020_data_struct.cpp b/src/src/PluginStructs/P020_data_struct.cpp index 5b1b2bfca..3129576c6 100644 --- a/src/src/PluginStructs/P020_data_struct.cpp +++ b/src/src/PluginStructs/P020_data_struct.cpp @@ -136,7 +136,7 @@ void P020_Task::discardClientIn() { } void P020_Task::clearBuffer() { - serial_buffer = String(); + free_string(serial_buffer); _maxDataGramSize = serial_processing == P020_Events::P1WiFiGateway ? P020_P1_DATAGRAM_MAX_SIZE : P020_DATAGRAM_MAX_SIZE; diff --git a/src/src/PluginStructs/P044_data_struct.cpp b/src/src/PluginStructs/P044_data_struct.cpp index 6db208ad2..f61fe04bb 100644 --- a/src/src/PluginStructs/P044_data_struct.cpp +++ b/src/src/PluginStructs/P044_data_struct.cpp @@ -154,7 +154,7 @@ void P044_Task::clearBuffer() { maxMessageSize = _min(serial_buffer.length(), P044_DATAGRAM_MAX_SIZE); } - serial_buffer = String(); + free_string(serial_buffer); serial_buffer.reserve(maxMessageSize); } diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index 52daaa878..008722e1b 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -498,7 +498,7 @@ bool P073_data_struct::NextScroll() { } void P073_data_struct::setTextToScroll(const String& text) { - _textToScroll = String(); + free_string(_textToScroll); if (!text.isEmpty()) { const int bufToFill = getBufferLength(displayModel); diff --git a/src/src/PluginStructs/P082_data_struct.cpp b/src/src/PluginStructs/P082_data_struct.cpp index 354455ca8..c51b682bf 100644 --- a/src/src/PluginStructs/P082_data_struct.cpp +++ b/src/src/PluginStructs/P082_data_struct.cpp @@ -342,7 +342,7 @@ bool P082_data_struct::loop() { // Full sentence received # ifdef P082_SEND_GPS_TO_LOG _lastSentence = _currentSentence; - _currentSentence = String(); + free_string(_currentSentence); # endif // ifdef P082_SEND_GPS_TO_LOG completeSentence = true; available = easySerial->available(); diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 268807bfc..f0695bd37 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -594,7 +594,7 @@ bool P094_data_struct::loop() { for (size_t i = 0; i < length && valid; ++i) { if ((sentence_part[i] > 127) || (sentence_part[i] < 32)) { - sentence_part = String(); + free_string(sentence_part); ++sentences_received_error; valid = false; } @@ -653,7 +653,6 @@ const String& P094_data_struct::peekSentence() const { void P094_data_struct::getSentence(String& string, bool appendSysTime) { string = std::move(sentence_part); - sentence_part = String(); // FIXME TD-er: Should not be needed as move already cleared it. if (appendSysTime) { // Unix timestamp = 10 decimals + separator diff --git a/src/src/PluginStructs/P104_data_struct.cpp b/src/src/PluginStructs/P104_data_struct.cpp index 1b7e34e33..2f6e51a80 100644 --- a/src/src/PluginStructs/P104_data_struct.cpp +++ b/src/src/PluginStructs/P104_data_struct.cpp @@ -268,7 +268,7 @@ void P104_data_struct::loadSettings() { # endif // ifdef P104_DEBUG } - buffer = String(); // Free some memory + free_string(buffer); // Free some memory } delete[] settingsBuffer; // Release allocated buffer @@ -1676,7 +1676,7 @@ void P104_data_struct::checkRepeatTimer(uint8_t z) { * saveSettings gather the zones data from the UI and store in customsettings **************************************/ bool P104_data_struct::saveSettings() { - error = String(); // Clear + free_string(error); // Clear # ifdef P104_DEBUG_DEV diff --git a/src/src/PluginStructs/P165_data_struct.cpp b/src/src/PluginStructs/P165_data_struct.cpp index a7ceb8e1f..c10cf930e 100644 --- a/src/src/PluginStructs/P165_data_struct.cpp +++ b/src/src/PluginStructs/P165_data_struct.cpp @@ -2220,7 +2220,7 @@ bool P165_data_struct::nextScroll() { * Set up the string to scroll across the display, with optional prefixed spaces **********************************************************************************/ void P165_data_struct::setTextToScroll(const String& text) { - _textToScroll = String(); + free_string(_textToScroll); if (!text.isEmpty()) { const int bufToFill = calculateDisplayDigits(); diff --git a/src/src/WebServer/ControlPage.cpp b/src/src/WebServer/ControlPage.cpp index 5848d7d48..55efaaa81 100644 --- a/src/src/WebServer/ControlPage.cpp +++ b/src/src/WebServer/ControlPage.cpp @@ -41,7 +41,7 @@ void handle_control() { TXBuffer.endStream(); - printWebString = String(); + free_string(printWebString); printToWeb = false; printToWebJSON = false; } diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index a489a1e4f..1e6085f3a 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -274,7 +274,7 @@ void handle_root() { addHtml(F("Command Output
")); - printWebString = String(); + free_string(printWebString); } } html_end_table(); @@ -460,7 +460,7 @@ void handle_root() { # endif // if FEATURE_ESPEASY_P2P html_end_form(); - printWebString = String(); + free_string(printWebString); printToWeb = false; sendHeadandTail_stdtemplate(_TAIL); } diff --git a/src/src/WebServer/ToolsPage.cpp b/src/src/WebServer/ToolsPage.cpp index 26a861639..908f8f971 100644 --- a/src/src/WebServer/ToolsPage.cpp +++ b/src/src/WebServer/ToolsPage.cpp @@ -56,7 +56,7 @@ void handle_tools() { addHtml(F("Command Output
")); - printWebString = String(); + free_string(printWebString); } @@ -198,7 +198,7 @@ void handle_tools() { html_end_form(); sendHeadandTail_stdtemplate(_TAIL); TXBuffer.endStream(); - printWebString = String(); + free_string(printWebString); printToWeb = false; } diff --git a/src/src/WebServer/UploadPage.cpp b/src/src/WebServer/UploadPage.cpp index 072ba1a46..bb2a2e869 100644 --- a/src/src/WebServer/UploadPage.cpp +++ b/src/src/WebServer/UploadPage.cpp @@ -35,7 +35,7 @@ void handle_upload() { "

Upload settings file:

")); sendHeadandTail_stdtemplate(_TAIL); TXBuffer.endStream(); - printWebString = String(); + free_string(printWebString); printToWeb = false; } @@ -87,7 +87,7 @@ void handle_upload_post() { addHtml(F("Upload finished")); sendHeadandTail_stdtemplate(_TAIL); TXBuffer.endStream(); - printWebString = String(); + free_string(printWebString); printToWeb = false; } diff --git a/src/src/WebServer/WebTemplateParser.cpp b/src/src/WebServer/WebTemplateParser.cpp index 3bc338c55..afa20831d 100644 --- a/src/src/WebServer/WebTemplateParser.cpp +++ b/src/src/WebServer/WebTemplateParser.cpp @@ -159,7 +159,7 @@ bool WebTemplateParser::process(const char c) { } else if (Tail == contentVarFound) { processVarName(); } - varName = String(); + free_string(varName); } } break; From 50a404427ea3e56559876ba53ca1ef18d2684af8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 28 Jan 2025 15:12:29 +0100 Subject: [PATCH 022/564] [Memory] Add small optimization in free_string() to prevent copying --- src/src/Helpers/StringConverter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index eb4415a6b..091bb87dc 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -109,7 +109,8 @@ bool reserve_special(String& str, size_t size) { void free_string(String& str) { // This is a call specifically tailored to what is done in: // void String::move(String &rhs) - + + str.clear(); // Prevent any unneeded copying String tmp(std::move(str)); } From 6d15414fb921e831e55526bd44d34a4b66517b3a Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 13 Feb 2025 16:22:48 +0100 Subject: [PATCH 023/564] [ESP-IDF] Update to latest Arduino 3.1.2 for LittleFS builds --- platformio_core_defs.ini | 2 +- platformio_esp32_solo1.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 5d8408882..85ed9d1cf 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -198,7 +198,7 @@ lib_extra_dirs = ; ESP_IDF 5.3.1 [core_esp32_IDF5_3_2__3_1_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3203/framework-arduinoespressif32-all-release_v5.3-ddc10306.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3385/framework-arduinoespressif32-all-release_v5.3-742cdfce.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 diff --git a/platformio_esp32_solo1.ini b/platformio_esp32_solo1.ini index 4da44943c..5042599aa 100644 --- a/platformio_esp32_solo1.ini +++ b/platformio_esp32_solo1.ini @@ -4,7 +4,7 @@ extends = esp32_base_idf5 board = esp32_solo1_4M platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF53 -platform_packages = framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3204/framework-arduinoespressif32-solo1-release_v5.3-ddc10306.zip +platform_packages = framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3386/framework-arduinoespressif32-solo1-release_v5.3-742cdfce.zip build_flags = ${esp32_base_idf5.build_flags} -DFEATURE_ARDUINO_OTA=1 -DUSE_LITTLEFS From a6fc7283973f33fce8b5d2f63052bf3a0bbf304a Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 Feb 2025 16:29:27 +0100 Subject: [PATCH 024/564] [ESP-SDK] Update to ESP32/Arduino 3.1.3 --- platformio_core_defs.ini | 2 +- platformio_esp32_solo1.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index b408f5bdf..89fe27caf 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -198,7 +198,7 @@ lib_extra_dirs = ; ESP_IDF 5.3.1 [core_esp32_IDF5_3_2__3_1_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3385/framework-arduinoespressif32-all-release_v5.3-742cdfce.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3395/framework-arduinoespressif32-all-release_v5.3-9f9a0e25.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 diff --git a/platformio_esp32_solo1.ini b/platformio_esp32_solo1.ini index 5042599aa..1ab94d4bd 100644 --- a/platformio_esp32_solo1.ini +++ b/platformio_esp32_solo1.ini @@ -4,7 +4,7 @@ extends = esp32_base_idf5 board = esp32_solo1_4M platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF53 -platform_packages = framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3386/framework-arduinoespressif32-solo1-release_v5.3-742cdfce.zip +platform_packages = framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3396/framework-arduinoespressif32-solo1-release_v5.3-9f9a0e25.zip build_flags = ${esp32_base_idf5.build_flags} -DFEATURE_ARDUINO_OTA=1 -DUSE_LITTLEFS From ce69d379721fd163f0ef6da66c6f836de7fec435 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 Feb 2025 16:30:36 +0100 Subject: [PATCH 025/564] [ESPEasy p2p] Add node-IDs for new Espressif SoC models --- src/src/DataTypes/NodeTypeID.cpp | 27 ++++++++++--------- src/src/DataTypes/NodeTypeID.h | 46 ++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/src/DataTypes/NodeTypeID.cpp b/src/src/DataTypes/NodeTypeID.cpp index 6e4bd9bfa..ea80827b9 100644 --- a/src/src/DataTypes/NodeTypeID.cpp +++ b/src/src/DataTypes/NodeTypeID.cpp @@ -4,18 +4,21 @@ const __FlashStringHelper* toNodeTypeDisplayString(uint8_t nodeType) { switch (nodeType) { - case NODE_TYPE_ID_ESP_EASY_STD: return F("ESP Easy"); - case NODE_TYPE_ID_ESP_EASYM_STD: return F("ESP Easy Mega"); - case NODE_TYPE_ID_ESP_EASY32_STD: return F("ESP Easy 32"); - case NODE_TYPE_ID_ESP_EASY32S2_STD: return F("ESP Easy 32-S2"); - case NODE_TYPE_ID_ESP_EASY32S3_STD: return F("ESP Easy 32-S3"); - case NODE_TYPE_ID_ESP_EASY32C2_STD: return F("ESP Easy 32-C2"); - case NODE_TYPE_ID_ESP_EASY32C3_STD: return F("ESP Easy 32-C3"); - case NODE_TYPE_ID_ESP_EASY32H2_STD: return F("ESP Easy 32-H2"); - case NODE_TYPE_ID_ESP_EASY32C6_STD: return F("ESP Easy 32-C6"); - case NODE_TYPE_ID_RPI_EASY_STD: return F("RPI Easy"); - case NODE_TYPE_ID_ARDUINO_EASY_STD: return F("Arduino Easy"); - case NODE_TYPE_ID_NANO_EASY_STD: return F("Nano Easy"); + case NODE_TYPE_ID_ESP_EASY_STD: return F("ESP Easy"); + case NODE_TYPE_ID_ESP_EASYM_STD: return F("ESP Easy Mega"); + case NODE_TYPE_ID_ESP_EASY32_STD: return F("ESP Easy 32"); + case NODE_TYPE_ID_ESP_EASY32S2_STD: return F("ESP Easy 32-S2"); + case NODE_TYPE_ID_ESP_EASY32S3_STD: return F("ESP Easy 32-S3"); + case NODE_TYPE_ID_ESP_EASY32C2_STD: return F("ESP Easy 32-C2"); + case NODE_TYPE_ID_ESP_EASY32C3_STD: return F("ESP Easy 32-C3"); + case NODE_TYPE_ID_ESP_EASY32C5_STD: return F("ESP Easy 32-C5"); + case NODE_TYPE_ID_ESP_EASY32C6_STD: return F("ESP Easy 32-C6"); + case NODE_TYPE_ID_ESP_EASY32C61_STD: return F("ESP Easy 32-C61"); + case NODE_TYPE_ID_ESP_EASY32H2_STD: return F("ESP Easy 32-H2"); + case NODE_TYPE_ID_ESP_EASY32P4_STD: return F("ESP Easy 32-P4"); + case NODE_TYPE_ID_RPI_EASY_STD: return F("RPI Easy"); + case NODE_TYPE_ID_ARDUINO_EASY_STD: return F("Arduino Easy"); + case NODE_TYPE_ID_NANO_EASY_STD: return F("Nano Easy"); } return F(""); } \ No newline at end of file diff --git a/src/src/DataTypes/NodeTypeID.h b/src/src/DataTypes/NodeTypeID.h index d3378e2cd..d448efa7f 100644 --- a/src/src/DataTypes/NodeTypeID.h +++ b/src/src/DataTypes/NodeTypeID.h @@ -3,6 +3,8 @@ #include "../../ESPEasy_common.h" +// These defines are used to identify other ESPEasy build platforms via ESPEasy p2p +// So don't ever change already assigned values as there might be older builds which rely on these. #define NODE_TYPE_ID_ESP_EASY_STD 1 #define NODE_TYPE_ID_RPI_EASY_STD 5 // https://github.com/enesbcs/rpieasy #define NODE_TYPE_ID_ESP_EASYM_STD 17 @@ -13,37 +15,47 @@ #define NODE_TYPE_ID_ESP_EASY32C2_STD 37 #define NODE_TYPE_ID_ESP_EASY32H2_STD 38 #define NODE_TYPE_ID_ESP_EASY32C6_STD 39 +#define NODE_TYPE_ID_ESP_EASY32C61_STD 40 +#define NODE_TYPE_ID_ESP_EASY32C5_STD 41 +#define NODE_TYPE_ID_ESP_EASY32P4_STD 42 #define NODE_TYPE_ID_ARDUINO_EASY_STD 65 #define NODE_TYPE_ID_NANO_EASY_STD 81 #if defined(ESP8266) - #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD #endif #if defined(ESP32) - #ifdef ESP32S2 - #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32S2_STD - #elif defined(ESP32S3) - #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32S3_STD - #elif defined(ESP32C6) - #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32C6_STD - #elif defined(ESP32C3) - #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32C3_STD - #elif defined(ESP32C2) - #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32C2_STD + # ifdef ESP32S2 + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32S2_STD + # elif defined(ESP32S3) + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32S3_STD + # elif defined(ESP32C2) + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32C2_STD + # elif defined(ESP32C3) + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32C3_STD + # elif defined(ESP32C5) + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32C5_STD + # elif defined(ESP32C6) + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32C6_STD + # elif defined(ESP32C61) + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32C61_STD + # elif defined(ESP32H2) + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32H2_STD + # elif defined(ESP32P4) + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32P4_STD # elif defined(ESP32_CLASSIC) - #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32_STD - # else + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32_STD + # else - static_assert(false, "Implement processor architecture"); +static_assert(false, "Implement processor architecture"); - #endif + # endif #endif - const __FlashStringHelper* toNodeTypeDisplayString(uint8_t nodeType); -#endif // ifndef DATATYPES_NODETYPEID_H \ No newline at end of file +#endif // ifndef DATATYPES_NODETYPEID_H From 3f2ac690fb14c4de6087039183f9f801cf60b7bc Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 Feb 2025 16:31:13 +0100 Subject: [PATCH 026/564] [WiFi] Fix processing connected event --- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 25ff3edfe..ce3d0886c 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -51,14 +51,13 @@ void handle_unprocessedNetworkEvents() #endif if (active_network_medium == NetworkMedium_t::WIFI) { - if (WiFiConnected() && !WiFiEventData.WiFiServicesInitialized()) { - WiFiEventData.processedConnect = false; - WiFiEventData.processedGotIP = false; + bool processedSomething = false; if (!WiFiEventData.processedConnect) { #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); #endif // ifndef BUILD_NO_DEBUG processConnect(); + processedSomething = true; // FIXME TD-er: Forcefully set the connected flag for now WiFiEventData.setWiFiConnected(); @@ -70,12 +69,14 @@ void handle_unprocessedNetworkEvents() #endif // ifndef BUILD_NO_DEBUG processGotIP(); + processedSomething = true; + // FIXME TD-er: Forcefully set the GotIP flag for now WiFiEventData.setWiFiGotIP(); } WiFiEventData.setWiFiServicesInitialized(); - if (WiFiEventData.WiFiServicesInitialized()) { + if (WiFiEventData.WiFiServicesInitialized() && processedSomething) { // #ifdef ESP32 setWebserverRunning(false); @@ -89,7 +90,6 @@ void handle_unprocessedNetworkEvents() #endif */ } - } } #if FEATURE_ETHERNET From e6957bd0f94d2f6d5fd31b1561f6f827fadbe76b Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 Feb 2025 17:43:05 +0100 Subject: [PATCH 027/564] [ESP8266] Fix crash on processing log with weblog enabled. --- src/src/ESPEasyCore/ESPEasy_Log.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasy_Log.cpp b/src/src/ESPEasyCore/ESPEasy_Log.cpp index fe82f366c..b02ce2ca9 100644 --- a/src/src/ESPEasyCore/ESPEasy_Log.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Log.cpp @@ -358,7 +358,8 @@ void addToLogMove(uint8_t logLevel, String&& string) // May clear the string, so call as last one. if (loglevelActiveFor(LOG_TO_WEBLOG, logLevel)) { Logging.add(logLevel, std::move(string)); + } else { + // Make sure the string may no longer keep up memory + free_string(string); } - // Make sure the string may no longer keep up memory - free_string(string); } From 115e8a571d27fdb5f524432788433cf16ac4034b Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 Feb 2025 17:47:47 +0100 Subject: [PATCH 028/564] [Cleanup] Simplify generating sysinfo page --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 1 - .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 22 ++++---- src/src/WebServer/SysInfoPage.cpp | 53 +++++++++++++------ 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 19feae0f7..78ae3b9e6 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -104,7 +104,6 @@ // - Start/stop of AP mode // ******************************************************************************** bool WiFiConnected() { - START_TIMER; static uint32_t lastCheckedTime = 0; const int32_t timePassed = timePassedSince(lastCheckedTime); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index ce3d0886c..085486bd2 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -213,11 +213,12 @@ void processGotIP() { if (!useStaticIP()) { #ifdef ESP8266 - if (!ip.isSet()) { + if (!ip.isSet()) #else // ifdef ESP8266 - if ((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0)) { + if ((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0)) #endif // ifdef ESP8266 + { return; } } @@ -313,11 +314,10 @@ void processDisconnectAPmode() { #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { - const int nrStationsConnected = WiFi.softAPgetStationNum(); - String log = F("AP Mode: Client disconnected: "); - log += WiFiEventData.lastMacDisconnectedAPmode.toString(); - log += F(" Connected devices: "); - log += nrStationsConnected; + String log(strformat( + F("AP Mode: Client disconnected: %s Connected devices: %u"), + WiFiEventData.lastMacDisconnectedAPmode.toString().c_str(), + WiFi.softAPgetStationNum())); addLogMove(LOG_LEVEL_INFO, log); } #endif // ifndef BUILD_NO_DEBUG @@ -333,10 +333,10 @@ void processConnectAPmode() { #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("AP Mode: Client connected: "); - log += WiFiEventData.lastMacConnectedAPmode.toString(); - log += F(" Connected devices: "); - log += WiFi.softAPgetStationNum(); + String log(strformat( + F("AP Mode: Client connected: %s Connected devices: %u"), + WiFiEventData.lastMacConnectedAPmode.toString().c_str(), + WiFi.softAPgetStationNum())); addLogMove(LOG_LEVEL_INFO, log); } #endif // ifndef BUILD_NO_DEBUG diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index 232d16665..0ffd9b76d 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -334,12 +334,21 @@ void handle_sysinfo_basicInfo() { getCPUload(), getLoopCountPerSec())); } + + static const LabelType::Enum labels[] PROGMEM = + { #if FEATURE_INTERNAL_TEMPERATURE - addRowLabelValue(LabelType::INTERNAL_TEMPERATURE); + LabelType::INTERNAL_TEMPERATURE, #endif - addRowLabelValue(LabelType::CPU_ECO_MODE); + LabelType::CPU_ECO_MODE, + LabelType::RESET_REASON, + LabelType::LAST_TASK_BEFORE_REBOOT, + LabelType::SW_WD_COUNT, + LabelType::MAX_LABEL + }; + addRowLabelValues(labels); addRowLabel(F("Boot")); { @@ -347,9 +356,6 @@ void handle_sysinfo_basicInfo() { addHtml(strformat( F(" (%d)"), static_cast(RTC.bootCounter))); } - addRowLabelValue(LabelType::RESET_REASON); - addRowLabelValue(LabelType::LAST_TASK_BEFORE_REBOOT); - addRowLabelValue(LabelType::SW_WD_COUNT); } #ifndef WEBSERVER_SYSINFO_MINIMAL @@ -408,9 +414,14 @@ void handle_sysinfo_memory() { addRowLabelValue(LabelType::PSRAM_SIZE); if (UsePSRAM()) { - addRowLabelValue(LabelType::PSRAM_FREE); - addRowLabelValue(LabelType::PSRAM_MIN_FREE); - addRowLabelValue(LabelType::PSRAM_MAX_FREE_BLOCK); + static const LabelType::Enum labels[] PROGMEM = + { + LabelType::PSRAM_FREE, + LabelType::PSRAM_MIN_FREE, + LabelType::PSRAM_MAX_FREE_BLOCK, + LabelType::MAX_LABEL + }; + addRowLabelValues(labels); } # endif // if defined(ESP32) && defined(BOARD_HAS_PSRAM) } @@ -665,22 +676,30 @@ void handle_sysinfo_ESP_Board() { chipID, formatToHex(chipID, 6).c_str())); - addRowLabelValue(LabelType::ESP_CHIP_FREQ); + static const LabelType::Enum labels[] PROGMEM = + { + LabelType::ESP_CHIP_FREQ, # ifdef ESP32 - addRowLabelValue(LabelType::ESP_CHIP_XTAL_FREQ); - addRowLabelValue(LabelType::ESP_CHIP_APB_FREQ); + LabelType::ESP_CHIP_XTAL_FREQ, + LabelType::ESP_CHIP_APB_FREQ, # endif // ifdef ESP32 - addRowLabelValue(LabelType::ESP_CHIP_MODEL); + LabelType::ESP_CHIP_MODEL, # if defined(ESP32) + LabelType::ESP_CHIP_REVISION, +# endif // if defined(ESP32) + LabelType::ESP_CHIP_CORES, + LabelType::BOARD_NAME, + LabelType::MAX_LABEL + }; + addRowLabelValues(labels); + + +#if defined(ESP32) addRowLabel(F("ESP Chip Features")); addHtml(getChipFeaturesString()); - - addRowLabelValue(LabelType::ESP_CHIP_REVISION); -# endif // if defined(ESP32) - addRowLabelValue(LabelType::ESP_CHIP_CORES); - addRowLabelValue(LabelType::BOARD_NAME); +#endif } # endif // ifndef WEBSERVER_SYSINFO_MINIMAL From 9d57e8b6efd542c20ff4955abf528c5c804eeb75 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 Feb 2025 22:06:35 +0100 Subject: [PATCH 029/564] [ESP8266] Fix crash on ESP8266 SDK 2.7.4 --- src/src/Helpers/StringConverter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index 6f71b78e4..ec3375cc7 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -109,9 +109,12 @@ bool reserve_special(String& str, size_t size) { void free_string(String& str) { // This is a call specifically tailored to what is done in: // void String::move(String &rhs) - + #if defined(ESP32) || defined(CORE_POST_3_0_0) str.clear(); // Prevent any unneeded copying String tmp(std::move(str)); + #else + str = String(); + #endif } /********************************************************************************************\ From fac4d97ca3319584105b4a3b96679700568ee8fc Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 18 Feb 2025 17:26:52 +0100 Subject: [PATCH 030/564] [ESP8266] Balance more what should be allocated on 2nd heap --- src/_P082_GPS.ino | 11 +++-- src/src/Commands/InternalCommands.cpp | 2 +- src/src/CustomBuild/define_plugin_sets.h | 4 +- src/src/DataStructs/LogEntry.cpp | 11 ++--- src/src/DataStructs/NodeStruct.cpp | 38 +++++++-------- src/src/DataStructs/NodesHandler.cpp | 2 +- src/src/DataStructs/PluginStats_array.cpp | 6 +-- src/src/DataStructs/ProvisioningStruct.cpp | 2 +- src/src/DataStructs/ProvisioningStruct.h | 26 ++++++---- src/src/DataStructs/Web_StreamingBuffer.cpp | 12 ++++- src/src/DataStructs/WiFi_AP_Candidate.cpp | 48 ++++++++++++------- src/src/DataStructs/WiFi_AP_Candidate.h | 33 +++++++------ src/src/ESPEasyCore/ESPEasy_Log.cpp | 13 +++-- src/src/ESPEasyCore/ESPEasy_setup.cpp | 28 +++++------ src/src/Globals/Plugins.cpp | 24 ++++++---- src/src/Helpers/Memory.cpp | 14 ++++-- src/src/Helpers/RulesHelper.cpp | 3 +- src/src/Helpers/SerialWriteBuffer.cpp | 6 +-- src/src/Helpers/StringConverter.cpp | 10 ++-- src/src/Helpers/StringConverter.h | 4 +- src/src/Helpers/StringGenerator_GPIO.cpp | 14 +++--- .../Helpers/_Internal_GPIO_pulseHelper.cpp | 2 +- src/src/PluginStructs/P036_data_struct.cpp | 36 +++++++------- src/src/PluginStructs/P037_data_struct.cpp | 11 +++-- src/src/WebServer/ESPEasy_WebServer.cpp | 14 +++--- src/src/WebServer/Markup_Buttons.cpp | 12 ++--- 26 files changed, 210 insertions(+), 176 deletions(-) diff --git a/src/_P082_GPS.ino b/src/_P082_GPS.ino index d5bf404bb..1df45035c 100644 --- a/src/_P082_GPS.ino +++ b/src/_P082_GPS.ino @@ -314,11 +314,14 @@ boolean Plugin_082(uint8_t function, struct EventStruct *event, String& string) const int16_t serial_tx = CONFIG_PIN2; const int16_t pps_pin = CONFIG_PIN3; - # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP + // Try to allocate in PSRAM or 2nd heap if possible + constexpr unsigned size = sizeof(P082_data_struct); + void *ptr = special_calloc(1, size); + if (!ptr) { + return success; + } - initPluginTaskData(event->TaskIndex, new (std::nothrow) P082_data_struct()); + initPluginTaskData(event->TaskIndex, new (ptr) P082_data_struct()); P082_data_struct *P082_data = static_cast(getPluginTaskData(event->TaskIndex)); diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index f9a8b631a..f1337f2ae 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -66,7 +66,7 @@ bool checkNrArguments(const char *cmd, const String& Line, int nrArguments) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; - if (log.reserve(128)) { + if (reserve_special(log, 128)) { log += F("Too many arguments: cmd="); log += cmd; diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index d3f2b000a..78c7c0563 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -55,7 +55,9 @@ To create/register a plugin, you have to : #define WEBSERVER_LOG #endif #ifndef WEBSERVER_GITHUB_COPY - #define WEBSERVER_GITHUB_COPY + #ifndef USE_SECOND_HEAP + #define WEBSERVER_GITHUB_COPY + #endif #endif #ifndef WEBSERVER_ROOT #define WEBSERVER_ROOT diff --git a/src/src/DataStructs/LogEntry.cpp b/src/src/DataStructs/LogEntry.cpp index 0dffb03f9..ac45bfd01 100644 --- a/src/src/DataStructs/LogEntry.cpp +++ b/src/src/DataStructs/LogEntry.cpp @@ -19,13 +19,12 @@ bool LogEntry_t::add(const uint8_t loglevel, const String& line) } { - #ifdef USE_SECOND_HEAP - - // Need to make a substring or a copy, which is a new allocation, on the 2nd heap - HeapSelectIram ephemeral; - #endif // ifdef USE_SECOND_HEAP - if (line.length() > LOG_STRUCT_MESSAGE_SIZE - 1) { + #ifdef USE_SECOND_HEAP + + // Need to make a substring or a copy, which is a new allocation, on the 2nd heap + HeapSelectIram ephemeral; + #endif // ifdef USE_SECOND_HEAP move_special(_message, line.substring(0, LOG_STRUCT_MESSAGE_SIZE - 1)); } else { reserve_special(_message, line.length()); diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 99a8ac800..a7ab9af70 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -138,10 +138,10 @@ String NodeStruct::getNodeName() const { String res; size_t length = strnlen(reinterpret_cast(nodeName), sizeof(nodeName)); - res.reserve(length); - - for (size_t i = 0; i < length; ++i) { - res += static_cast(nodeName[i]); + if (reserve_special(res, length)) { + for (size_t i = 0; i < length; ++i) { + res += static_cast(nodeName[i]); + } } return res; } @@ -212,21 +212,21 @@ float NodeStruct::getLoad() const { String NodeStruct::getSummary() const { String res; - - res.reserve(48); - res = F("Unit: "); - res += unit; - res += F(" \""); - res += getNodeName(); - res += '"'; - res += F(" load: "); - res += String(getLoad(), 1); - res += F(" RSSI: "); - res += getRSSI(); - res += F(" ch: "); - res += channel; - res += F(" dst: "); - res += distance; + if (reserve_special(res, 48)) { + res = F("Unit: "); + res += unit; + res += F(" \""); + res += getNodeName(); + res += '"'; + res += F(" load: "); + res += String(getLoad(), 1); + res += F(" RSSI: "); + res += getRSSI(); + res += F(" ch: "); + res += channel; + res += F(" dst: "); + res += distance; + } return res; } diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 0c3bd500e..14728d2f0 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -141,7 +141,7 @@ bool NodesHandler::addNode(const NodeStruct& node, const ESPEasy_now_traceroute_ if (traceRoute.getDistance() != 255) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; - if (log.reserve(80)) { + if (reserve_special(log, 80)) { log = F(ESPEASY_NOW_NAME); log += F(": Node: "); log += String(node.unit); diff --git a/src/src/DataStructs/PluginStats_array.cpp b/src/src/DataStructs/PluginStats_array.cpp index f23524f53..37141eedf 100644 --- a/src/src/DataStructs/PluginStats_array.cpp +++ b/src/src/DataStructs/PluginStats_array.cpp @@ -40,11 +40,7 @@ void PluginStats_array::initPluginStats(taskIndex_t taskIndex, taskVarIndex_t ta } if (ExtraTaskSettings.enabledPluginStats(taskVarIndex)) { - # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP - - // Try to allocate in PSRAM if possible + // Try to allocate in PSRAM or 2nd heap if possible constexpr unsigned size = sizeof(PluginStats); void *ptr = special_calloc(1, size); diff --git a/src/src/DataStructs/ProvisioningStruct.cpp b/src/src/DataStructs/ProvisioningStruct.cpp index e923975d1..839e84989 100644 --- a/src/src/DataStructs/ProvisioningStruct.cpp +++ b/src/src/DataStructs/ProvisioningStruct.cpp @@ -6,7 +6,7 @@ # include "../Helpers/Hardware.h" ProvisioningStruct::ProvisioningStruct() { - memset(this, 0, sizeof(ProvisioningStruct)); + _allBits = 0u; } void ProvisioningStruct::validate() { diff --git a/src/src/DataStructs/ProvisioningStruct.h b/src/src/DataStructs/ProvisioningStruct.h index 25a959721..f88a8b143 100644 --- a/src/src/DataStructs/ProvisioningStruct.h +++ b/src/src/DataStructs/ProvisioningStruct.h @@ -39,20 +39,26 @@ struct ProvisioningStruct char pass[64] = { 0 }; char url[128] = { 0 }; - struct { - uint16_t allowFetchFirmware :1; - uint16_t allowFetchConfigDat :1; - uint16_t allowFetchSecurityDat :1; - uint16_t allowFetchNotificationDat :1; - uint16_t allowFetchProvisioningDat :1; - uint16_t allowFetchRules :4; + union { + struct { + uint16_t allowFetchFirmware :1; + uint16_t allowFetchConfigDat :1; + uint16_t allowFetchSecurityDat :1; + uint16_t allowFetchNotificationDat :1; + uint16_t allowFetchProvisioningDat :1; + uint16_t allowFetchRules :4; - uint16_t unused :7; // Add to use full 16 bit. - } allowedFlags; + uint16_t unused :7; // Add to use full 16 bit. + } allowedFlags; + uint16_t _allBits; + }; }; typedef std::shared_ptr ProvisioningStruct_ptr_type; -# define MakeProvisioningSettings(T) ProvisioningStruct_ptr_type T(new (std::nothrow) ProvisioningStruct()); +//# define MakeProvisioningSettings(T) ProvisioningStruct_ptr_type T(new (std::nothrow) ProvisioningStruct()); + +#define MakeProvisioningSettings(T) void * calloc_ptr = special_calloc(1,sizeof(ProvisioningStruct)); ProvisioningStruct_ptr_type T(new (calloc_ptr) ProvisioningStruct()); + #endif // if FEATURE_CUSTOM_PROVISIONING diff --git a/src/src/DataStructs/Web_StreamingBuffer.cpp b/src/src/DataStructs/Web_StreamingBuffer.cpp index 24e4905d6..09313bf4c 100644 --- a/src/src/DataStructs/Web_StreamingBuffer.cpp +++ b/src/src/DataStructs/Web_StreamingBuffer.cpp @@ -294,7 +294,10 @@ void Web_StreamingBuffer::endStream() { lowMemorySkip = false; } delay(5); -// web_server.client().stop(); + #ifdef ESP8266 + web_server.client().stop(); + tcpCleanup(); + #endif } @@ -333,7 +336,14 @@ void Web_StreamingBuffer::sendContentBlocking(String& data) { if (length > 0) { web_server.sendContent(data); } web_server.sendContent("\r\n"); #else // ESP8266 2.4.0rc2 and higher and the ESP32 webserver supports chunked http transfer + #if defined(ESP8266) && defined(USE_SECOND_HEAP) + { + HeapSelectIram ephemeral; + web_server.sendContent(data); + } + #else web_server.sendContent(data); + #endif if (data.length() > (CHUNKED_BUFFER_SIZE + 1)) { free_string(data); // Clear also allocated memory diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index bf3738363..ce94585c4 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -32,18 +32,24 @@ country({ #endif last_seen(0), rssi(0), channel(0), index(0), enc_type(0) { - memset(&bits, 0, sizeof(bits)); + _allBits = 0u; } WiFi_AP_Candidate::WiFi_AP_Candidate(const WiFi_AP_Candidate& other) +: ssid(other.ssid), + last_seen(other.last_seen), + bssid(other.bssid), + rssi(other.rssi), + channel(other.channel), + index(other.index), + enc_type(other.enc_type) { - // All members other than ssid can be mem-copied - memcpy(this, &other, sizeof(WiFi_AP_Candidate)); - - // Make sure ssid isn't some kind of valid String with heap allocated memory - memset(&ssid, 0, sizeof(ssid)); - // Now copy the ssid String - ssid = other.ssid; + _allBits = other._allBits; + #ifdef ESP32 + # if ESP_IDF_VERSION_MAJOR >= 5 + memcpy(&this.country, &other.country, sizeof(wifi_country_t)); + #endif + #endif } WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t index_c, const String& ssid_c) : @@ -59,7 +65,7 @@ country({ #endif last_seen(0), rssi(0), channel(0), index(index_c), enc_type(0) { - memset(&bits, 0, sizeof(bits)); + _allBits = 0u; const size_t ssid_length = ssid_c.length(); @@ -76,7 +82,7 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { // Need to make sure the phy isn't known as we can't get this information from the AP // See: https://github.com/letscontrolit/ESPEasy/issues/4996 // Not sure why this makes any difference as the flags should already have been set to 0. - memset(&bits, 0, sizeof(bits)); + _allBits = 0u; ssid = WiFi.SSID(networkItem); rssi = WiFi.RSSI(networkItem); @@ -129,8 +135,7 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(const bss_info& ap) : phy_11b(ap.phy_11b), phy_11g(ap.phy_11g), phy_11n(ap.phy_11n), wps(ap.wps) { - memset(&bits, 0, sizeof(bits)); - + _allBits = 0u; last_seen = millis(); switch (ap.authmode) { @@ -180,13 +185,20 @@ bool WiFi_AP_Candidate::operator<(const WiFi_AP_Candidate& other) const { WiFi_AP_Candidate& WiFi_AP_Candidate::operator=(const WiFi_AP_Candidate& other) { - // All members other than ssid can be mem-copied - memcpy(this, &other, sizeof(WiFi_AP_Candidate)); - - // Make sure ssid isn't some kind of valid String with heap allocated memory - memset(&ssid, 0, sizeof(ssid)); - // Now copy the ssid String ssid = other.ssid; + last_seen = other.last_seen; + bssid = other.bssid; + rssi = other.rssi; + channel = other.channel; + index = other.index; + enc_type = other.enc_type; + _allBits = other._allBits; + #ifdef ESP32 + # if ESP_IDF_VERSION_MAJOR >= 5 + memcpy(&this.country, &other.country, sizeof(wifi_country_t)); + #endif + #endif + return *this; } diff --git a/src/src/DataStructs/WiFi_AP_Candidate.h b/src/src/DataStructs/WiFi_AP_Candidate.h index 82766ca51..970afe8f6 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.h +++ b/src/src/DataStructs/WiFi_AP_Candidate.h @@ -68,7 +68,7 @@ struct WiFi_AP_Candidate { return bits.phy_11b || bits.phy_11g || bits.phy_11n; } - String ssid; + String ssid; // String key; @@ -84,21 +84,24 @@ struct WiFi_AP_Candidate { uint8_t channel{}; uint8_t index{}; // Index of the matching credentials uint8_t enc_type{}; // Encryption used (e.g. WPA2) - struct { - uint16_t isHidden : 1; // Hidden SSID - uint16_t lowPriority : 1; // Try as last attempt - uint16_t isEmergencyFallback : 1; - uint16_t phy_11b : 1; - uint16_t phy_11g : 1; - uint16_t phy_11n : 1; - uint16_t phy_lr : 1; - uint16_t phy_11ax : 1; - uint16_t wps : 1; - uint16_t ftm_responder : 1; - uint16_t ftm_initiator : 1; + union { + struct { + uint16_t isHidden : 1; // Hidden SSID + uint16_t lowPriority : 1; // Try as last attempt + uint16_t isEmergencyFallback : 1; + uint16_t phy_11b : 1; + uint16_t phy_11g : 1; + uint16_t phy_11n : 1; + uint16_t phy_lr : 1; + uint16_t phy_11ax : 1; + uint16_t wps : 1; + uint16_t ftm_responder : 1; + uint16_t ftm_initiator : 1; - uint16_t unused : 5; - } bits; + uint16_t unused : 5; + } bits; + uint16_t _allBits; + }; }; #endif // ifndef DATASTRUCTS_WIFI_AP_CANDIDATES_H diff --git a/src/src/ESPEasyCore/ESPEasy_Log.cpp b/src/src/ESPEasyCore/ESPEasy_Log.cpp index b02ce2ca9..bcf69137e 100644 --- a/src/src/ESPEasyCore/ESPEasy_Log.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Log.cpp @@ -351,15 +351,14 @@ void addToLogMove(uint8_t logLevel, String&& string) #endif if (string.isEmpty()) return; - addToSerialLog(logLevel, string); - addToSysLog(logLevel, string); - addToSDLog(logLevel, string); + String tmp; + move_special(tmp, std::move(string)); + addToSerialLog(logLevel, tmp); + addToSysLog(logLevel, tmp); + addToSDLog(logLevel, tmp); // May clear the string, so call as last one. if (loglevelActiveFor(LOG_TO_WEBLOG, logLevel)) { - Logging.add(logLevel, std::move(string)); - } else { - // Make sure the string may no longer keep up memory - free_string(string); + Logging.add(logLevel, std::move(tmp)); } } diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 85043c42e..0f092f664 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -303,8 +303,7 @@ void ESPEasy_setup() readBootCause(); { - String log = F("INIT : "); - log += getLastBootCauseString(); + String log; if (readFromRTC()) { @@ -312,9 +311,8 @@ void ESPEasy_setup() RTC.bootCounter++; lastMixedSchedulerId_beforereboot.mixed_id = RTC.lastMixedSchedulerId; readUserVarFromRTC(); - - log += F(" #"); - log += RTC.bootCounter; + log = concat(F("INIT : "), getLastBootCauseString()) + + concat(F(" #"), RTC.bootCounter); #ifndef BUILD_NO_DEBUG log += F(" Last Action before Reboot: "); @@ -336,8 +334,7 @@ void ESPEasy_setup() log = F("INIT : Cold Boot"); } - log += F(" - Restart Reason: "); - log += getResetReasonString(); + log += concat(F(" - Restart Reason: "), getResetReasonString()); RTC.deepSleepState = 0; saveToRTC(); @@ -543,14 +540,15 @@ void ESPEasy_setup() if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; - log.reserve(80); - log += concat(F("INFO : Plugins: "), getDeviceCount() + 1); - log += ' '; - log += getPluginDescriptionString(); - log += F(" ("); - log += getSystemLibraryString(); - log += ')'; - addLogMove(LOG_LEVEL_INFO, log); + if (reserve_special(log, 80)) { + log += concat(F("INFO : Plugins: "), getDeviceCount() + 1); + log += ' '; + log += getPluginDescriptionString(); + log += F(" ("); + log += getSystemLibraryString(); + log += ')'; + addLogMove(LOG_LEVEL_INFO, log); + } } /* diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index 632d2ef3f..242cbb245 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -419,11 +419,14 @@ bool PluginCallForTask(taskIndex_t taskIndex, uint8_t Function, EventStruct *Tem LoadTaskSettings(taskIndex); if (ExtraTaskSettings.anyEnabledPluginStats()) { - # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP - initPluginTaskData(taskIndex, new (std::nothrow) _StatsOnly_data_struct()); + // Try to allocate in PSRAM or 2nd heap if possible + constexpr unsigned size = sizeof(_StatsOnly_data_struct); + void *ptr = special_calloc(1, size); + + if (ptr) { + initPluginTaskData(taskIndex, new (ptr) _StatsOnly_data_struct()); + } } } } @@ -448,10 +451,13 @@ bool PluginCallForTask(taskIndex_t taskIndex, uint8_t Function, EventStruct *Tem LoadTaskSettings(taskIndex); if (ExtraTaskSettings.anyEnabledPluginStats()) { - # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP - initPluginTaskData(taskIndex, new (std::nothrow) _StatsOnly_data_struct()); + // Try to allocate in PSRAM or 2nd heap if possible + constexpr unsigned size = sizeof(_StatsOnly_data_struct); + void *ptr = special_calloc(1, size); + + if (ptr) { + initPluginTaskData(taskIndex, new (std::nothrow) _StatsOnly_data_struct()); + } } } } @@ -700,7 +706,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) const int freemem_end = ESP.getFreeHeap(); String log; - if (log.reserve(128)) { + if (reserve_special(log, 128)) { log = F("After PLUGIN_INIT "); log += F(" task: "); diff --git a/src/src/Helpers/Memory.cpp b/src/src/Helpers/Memory.cpp index 3a6432ff2..e7420f77a 100644 --- a/src/src/Helpers/Memory.cpp +++ b/src/src/Helpers/Memory.cpp @@ -176,10 +176,10 @@ void* special_calloc(size_t num, size_t size) { res = heap_caps_calloc(num, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); } #else // ifdef ESP32 - { + if (size > 64) { # ifdef USE_SECOND_HEAP - // Try allocating on ESP8266 2nd heap + // Try allocating on ESP8266 2nd heap, only when sufficiently large data is needed HeapSelectIram ephemeral; # endif // ifdef USE_SECOND_HEAP res = calloc(num, size); @@ -194,7 +194,13 @@ void* special_calloc(size_t num, size_t size) { #endif // ifdef USE_SECOND_HEAP res = calloc(num, size); } - +#if defined(ESP8266) && defined(USE_SECOND_HEAP) + if (res == nullptr) { + // Not successful, try allocating on (ESP8266) 2nd heap + HeapSelectIram ephemeral; + res = calloc(num, size); + } +#endif return res; } @@ -206,7 +212,7 @@ bool String_reserve_special(String& str, size_t size) { return true; } #ifdef USE_SECOND_HEAP - if (size >= 32) { + if (size >= 48) { // Only try to store larger strings here as those tend to be kept for a longer period. HeapSelectIram ephemeral; // String does round up to nearest multiple of 16 bytes, so no need to round up to multiples of 32 bit here diff --git a/src/src/Helpers/RulesHelper.cpp b/src/src/Helpers/RulesHelper.cpp index 3c9fafa92..bb969823e 100644 --- a/src/src/Helpers/RulesHelper.cpp +++ b/src/src/Helpers/RulesHelper.cpp @@ -18,8 +18,7 @@ bool rules_replace_common_mistakes(const String& from, const String& to, String& if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; - - if (log.reserve(32 + from.length() + to.length() + line.length())) { + if (reserve_special(log, 32 + from.length() + to.length() + line.length())) { log = F("Rules (Syntax Error, auto-corrected): '"); log += from; log += F("' => '"); diff --git a/src/src/Helpers/SerialWriteBuffer.cpp b/src/src/Helpers/SerialWriteBuffer.cpp index 750a6c4bb..9321136f6 100644 --- a/src/src/Helpers/SerialWriteBuffer.cpp +++ b/src/src/Helpers/SerialWriteBuffer.cpp @@ -10,7 +10,7 @@ void SerialWriteBuffer_t::add(const String& line) #ifdef USE_SECOND_HEAP // Do not store in 2nd heap, std::dequeue cannot handle 2nd heap well - HeapSelectDram ephemeral; + HeapSelectIram ephemeral; #endif // ifdef USE_SECOND_HEAP int roomLeft = getRoomLeft(); @@ -37,7 +37,7 @@ void SerialWriteBuffer_t::add(char c) #ifdef USE_SECOND_HEAP // Do not store in 2nd heap, std::dequeue cannot handle 2nd heap well - HeapSelectDram ephemeral; + HeapSelectIram ephemeral; #endif // ifdef USE_SECOND_HEAP if (_buffer.size() > _maxSize) { @@ -118,7 +118,7 @@ int SerialWriteBuffer_t::getRoomLeft() const { #ifdef USE_SECOND_HEAP // Do not store in 2nd heap, std::dequeue cannot handle 2nd heap well - HeapSelectDram ephemeral; + HeapSelectIram ephemeral; #endif // ifdef USE_SECOND_HEAP int roomLeft = getMaxFreeBlock(); diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index ec3375cc7..a6ea8b0db 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -78,7 +78,7 @@ bool equals(const String& str, const char& c) { void move_special(String& dest, String&& source) { #ifdef USE_SECOND_HEAP // Only try to store larger strings here as those tend to be kept for a longer period. - if ((source.length() >= 32) && mmu_is_dram(&(source[0]))) { + if ((source.length() >= 64) && mmu_is_dram(&(source[0]))) { // The string was not allocated on the 2nd heap, so copy instead of move HeapSelectIram ephemeral; if (dest.reserve(source.length())) { @@ -734,11 +734,9 @@ String stripWrappingChar(const String& text, char wrappingChar) { const unsigned int length = text.length(); if ((length >= 2) && stringWrappedWithChar(text, wrappingChar)) { - # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP - - return text.substring(1, length - 1); + String dest; + move_special(dest,text.substring(1, length - 1)); + return dest; } return text; } diff --git a/src/src/Helpers/StringConverter.h b/src/src/Helpers/StringConverter.h index 61472b954..a8766e1f5 100644 --- a/src/src/Helpers/StringConverter.h +++ b/src/src/Helpers/StringConverter.h @@ -29,7 +29,7 @@ String concat(const char& str, const String &val); template String concat(const __FlashStringHelper * str, const T &val) { # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; + HeapSelectDram ephemeral; # endif // ifdef USE_SECOND_HEAP String res(str); @@ -40,7 +40,7 @@ String concat(const __FlashStringHelper * str, const T &val) { template String concat(const String& str, const T &val) { # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; + HeapSelectDram ephemeral; # endif // ifdef USE_SECOND_HEAP String res(str); diff --git a/src/src/Helpers/StringGenerator_GPIO.cpp b/src/src/Helpers/StringGenerator_GPIO.cpp index e33823d1a..29ceef03c 100644 --- a/src/src/Helpers/StringGenerator_GPIO.cpp +++ b/src/src/Helpers/StringGenerator_GPIO.cpp @@ -39,14 +39,14 @@ String formatGpioName(const __FlashStringHelper * label, gpio_direction directio reserveLength += 11; } String result; + if (reserve_special(result, reserveLength)) { + result += F("GPIO "); + result += formatGpioDirection(direction); + result += label; - result.reserve(reserveLength); - result += F("GPIO "); - result += formatGpioDirection(direction); - result += label; - - if (optional) { - result += F("(optional)"); + if (optional) { + result += F("(optional)"); + } } return result; } diff --git a/src/src/Helpers/_Internal_GPIO_pulseHelper.cpp b/src/src/Helpers/_Internal_GPIO_pulseHelper.cpp index ccba8caa8..35aa0c805 100644 --- a/src/src/Helpers/_Internal_GPIO_pulseHelper.cpp +++ b/src/src/Helpers/_Internal_GPIO_pulseHelper.cpp @@ -461,7 +461,7 @@ void Internal_GPIO_pulseHelper::doTimingLogging(uint8_t logLevel) // Timer to logfile. E.g: ... [4|12000|13444|12243|3244] String log; - if (log.reserve(120)) { + if (reserve_special(log, 120)) { log = strformat(F("Pulse:OverDueStats (GPIO) [dbTim] {step0OdCnt} [maxOdTimeStep0|1|2|3]= (%d) [%d] {%d} ["), config.gpio, config.debounceTime, diff --git a/src/src/PluginStructs/P036_data_struct.cpp b/src/src/PluginStructs/P036_data_struct.cpp index 1af417957..8ade3e86e 100644 --- a/src/src/PluginStructs/P036_data_struct.cpp +++ b/src/src/PluginStructs/P036_data_struct.cpp @@ -51,15 +51,12 @@ String P036_LineContent::saveDisplayLines(taskIndex_t taskIndex) { if (FreeMem() > 8000) { // Write in one single chunk. tDisplayLines_storage_full *tmp = nullptr; - # ifdef USE_SECOND_HEAP - { - HeapSelectIram ephemeral; - tmp = new (std::nothrow) tDisplayLines_storage_full; - } - # endif // ifdef USE_SECOND_HEAP - if (tmp == nullptr) { - tmp = new (std::nothrow) tDisplayLines_storage_full; + // Try to allocate in PSRAM or 2nd heap if possible + constexpr unsigned size = sizeof(tDisplayLines_storage_full); + void *ptr = special_calloc(1, size); + if (ptr) { + tmp = new (ptr) tDisplayLines_storage_full; } if (tmp != nullptr) { @@ -231,10 +228,13 @@ bool P036_data_struct::init(taskIndex_t taskIndex, } { - # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP - LineContent = new (std::nothrow) P036_LineContent(); + // Try to allocate in PSRAM or 2nd heap if possible + constexpr unsigned size = sizeof(P036_LineContent); + void *ptr = special_calloc(1, size); + + if (ptr) { + LineContent = new (ptr) P036_LineContent(); + } } if (isInitialized()) { @@ -723,11 +723,15 @@ void P036_data_struct::setOrientationRotated(bool rotated) { void P036_data_struct::RestoreLineContent(taskIndex_t taskIndex, uint8_t LoadVersion, uint8_t LineNo) { - # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP + // Try to allocate in PSRAM or 2nd heap if possible + constexpr unsigned size = sizeof(P036_LineContent); + void *ptr = special_calloc(1, size); - P036_LineContent *TempContent = new (std::nothrow) P036_LineContent(); + if (!ptr) { + return; + } + + P036_LineContent *TempContent = new (ptr) P036_LineContent(); if (TempContent != nullptr) { TempContent->loadDisplayLines(taskIndex, LoadVersion); diff --git a/src/src/PluginStructs/P037_data_struct.cpp b/src/src/PluginStructs/P037_data_struct.cpp index cbc56046b..2722d0ddf 100644 --- a/src/src/PluginStructs/P037_data_struct.cpp +++ b/src/src/PluginStructs/P037_data_struct.cpp @@ -973,11 +973,12 @@ bool P037_data_struct::parseJSONMessage(const String& message) { } if (nullptr == root) { - # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP - - root = new (std::nothrow) DynamicJsonDocument(lastJsonMessageLength); // Dynamic allocation + // Try to allocate in PSRAM or 2nd heap if possible + constexpr unsigned size = sizeof(DynamicJsonDocument); + void *ptr = special_calloc(1, size); + if (ptr) { + root = new (ptr) DynamicJsonDocument(lastJsonMessageLength); // Dynamic allocation + } } if (nullptr != root) { diff --git a/src/src/WebServer/ESPEasy_WebServer.cpp b/src/src/WebServer/ESPEasy_WebServer.cpp index b5311c349..ad7fa2294 100644 --- a/src/src/WebServer/ESPEasy_WebServer.cpp +++ b/src/src/WebServer/ESPEasy_WebServer.cpp @@ -166,8 +166,8 @@ void sendHeadandTail_stdtemplate(bool Tail, bool rebooting) { // We have sent a lot of data at once. // try to flush it to the connected client to free up some RAM // from pending transfers - TXBuffer.flush(); - delay(10); +// TXBuffer.flush(); +// delay(10); } bool captivePortal() { @@ -1093,12 +1093,10 @@ void getStorageTableSVG(SettingsType::Enum settingsType) { float textYoffset = yOffset + 0.9f * SVG_BAR_HEIGHT; if (struct_size != 0) { - String text; - text.reserve(32); - text += formatHumanReadable(struct_size, 1024); - text += '/'; - text += formatHumanReadable(max_size, 1024); - text += F(" per item"); + String text = strformat( + F("%s/%s per item"), + formatHumanReadable(struct_size, 1024).c_str(), + formatHumanReadable(max_size, 1024).c_str()); createSvgTextElement(text, textXoffset, textYoffset); } else { createSvgTextElement(F("Variable size"), textXoffset, textYoffset); diff --git a/src/src/WebServer/Markup_Buttons.cpp b/src/src/WebServer/Markup_Buttons.cpp index 220cb1734..0b074508c 100644 --- a/src/src/WebServer/Markup_Buttons.cpp +++ b/src/src/WebServer/Markup_Buttons.cpp @@ -3,6 +3,8 @@ #include "../WebServer/common.h" #include "../WebServer/HTML_wrappers.h" +#include "../Helpers/StringConverter.h" + #include "../Static/WebStaticData.h" @@ -153,15 +155,7 @@ void addSubmitButton(const String& value, const String& name, const String& clas { addHtml(F(" 0) { - fullClasses += ' '; - fullClasses += classes; - } - addHtmlAttribute(F("class"), fullClasses); + addHtmlAttribute(F("class"), concat(F("button link "), classes)); } addHtmlAttribute(F("type"), F("submit")); addHtmlAttribute(F("value"), value); From e84d07fba624bb27331357d358e22a3fe18ce860 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 18 Feb 2025 23:08:51 +0100 Subject: [PATCH 031/564] [Build] Fix build issues on ESP32-xx --- src/src/DataStructs/NodeStruct.cpp | 6 ++++++ src/src/DataStructs/WiFi_AP_Candidate.cpp | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index a7ab9af70..d7297dc71 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -2,11 +2,17 @@ #if FEATURE_ESPEASY_P2P #include "../../ESPEasy-Globals.h" + #include "../DataTypes/NodeTypeID.h" + #include "../ESPEasyCore/ESPEasyNetwork.h" + #include "../Globals/SecuritySettings.h" #include "../Globals/Settings.h" + #include "../Helpers/ESPEasy_time_calc.h" +#include "../Helpers/StringConverter.h" + #define NODE_STRUCT_AGE_TIMEOUT 300000 // 5 minutes diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index ce94585c4..a286b8cea 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -47,7 +47,7 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(const WiFi_AP_Candidate& other) _allBits = other._allBits; #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 - memcpy(&this.country, &other.country, sizeof(wifi_country_t)); + memcpy(&this->country, &other.country, sizeof(wifi_country_t)); #endif #endif } @@ -195,7 +195,7 @@ WiFi_AP_Candidate& WiFi_AP_Candidate::operator=(const WiFi_AP_Candidate& other) _allBits = other._allBits; #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 - memcpy(&this.country, &other.country, sizeof(wifi_country_t)); + memcpy(&this->country, &other.country, sizeof(wifi_country_t)); #endif #endif From e94cbce20d46e32e617d3e6e4c12546153762517 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 19 Feb 2025 17:44:03 +0100 Subject: [PATCH 032/564] [Memory] Make memory allocation on ESP8266 2nd heap more stable --- platformio_esp82xx_base.ini | 8 + platformio_esp82xx_envs.ini | 20 ++ src/_N001_Email.cpp | 19 +- src/_N002_Buzzer.cpp | 12 +- src/_P002_ADC.ino | 9 +- src/_P036_FrameOLED.ino | 11 +- .../DataStructs/NotificationSettingsStruct.h | 8 +- src/src/Helpers/Memory.cpp | 6 +- src/src/PluginStructs/P036_data_struct.cpp | 3 + src/src/WebServer/NotificationPage.cpp | 300 +++++++++--------- 10 files changed, 231 insertions(+), 165 deletions(-) diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index c64d7e285..bc45ac8b5 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -107,6 +107,14 @@ build_flags = ${beta_platform.build_flags} lib_ignore = ${beta_platform.lib_ignore} ${no_ir.lib_ignore} +[normal_beta_2ndheap] +platform = ${beta_platform_2ndheap.platform} +platform_packages = ${beta_platform_2ndheap.platform_packages} +build_flags = ${beta_platform_2ndheap.build_flags} + -DBUILD_NO_DEBUG +lib_ignore = ${beta_platform.lib_ignore} + ${no_ir.lib_ignore} + ;;; COLLECTION ******************************************************** ; additional plugins (and dependend code) that is marked as COLLECTION ; ; Includes "normal" + "collection" plugins ; diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index e33f76713..a51d074c3 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -300,6 +300,26 @@ build_flags = ${normal.build_flags} -D NO_LIMIT_BUILD_SIZE lib_ignore = ${normal.lib_ignore} +[env:normal_beta_2ndheap_ESP8266_4M1M] +extends = esp8266_4M1M +platform = ${normal_beta_2ndheap.platform} +platform_packages = ${normal_beta_2ndheap.platform_packages} +build_flags = ${normal_beta_2ndheap.build_flags} + ${esp8266_4M1M.build_flags} + -D NO_LIMIT_BUILD_SIZE +lib_ignore = ${normal_beta_2ndheap.lib_ignore} + + +[env:normal_beta_2ndheap_ESP8266_4M1M_VCC] +extends = esp8266_4M1M +platform = ${normal_beta_2ndheap.platform} +platform_packages = ${normal_beta_2ndheap.platform_packages} +build_flags = ${normal_beta_2ndheap.build_flags} + ${esp8266_4M1M.build_flags} + -D FEATURE_ADC_VCC=1 + -D NO_LIMIT_BUILD_SIZE +lib_ignore = ${normal_beta_2ndheap.lib_ignore} + ; NORMAL: 16M version --- LittleFS -------------- ; LittleFS is determined by using "LittleFS" in the pio env name diff --git a/src/_N001_Email.cpp b/src/_N001_Email.cpp index 4bc89182d..30a652bc8 100644 --- a/src/_N001_Email.cpp +++ b/src/_N001_Email.cpp @@ -56,9 +56,9 @@ bool NPlugin_001(NPlugin::Function function, struct EventStruct *event, String& // if (command == F("email")) // { // MakeNotificationSettings(NotificationSettings); - // LoadNotificationSettings(event->NotificationIndex, (uint8_t*)&NotificationSettings, sizeof(NotificationSettingsStruct)); - // NPlugin_001_send(NotificationSettings.Domain, NotificationSettings.Receiver, NotificationSettings.Sender, - // NotificationSettings.Subject, NotificationSettings.Body, NotificationSettings.Server, NotificationSettings.Port); + // LoadNotificationSettings(event->NotificationIndex, (uint8_t *)NotificationSettings.get(), sizeof(NotificationSettingsStruct)); + // NPlugin_001_send(NotificationSettings->Domain, NotificationSettings->Receiver, NotificationSettings->Sender, + // NotificationSettings->Subject, NotificationSettings->Body, NotificationSettings->Server, NotificationSettings->Port); // success = true; // } // break; @@ -67,11 +67,14 @@ bool NPlugin_001(NPlugin::Function function, struct EventStruct *event, String& case NPlugin::Function::NPLUGIN_NOTIFY: { MakeNotificationSettings(NotificationSettings); - LoadNotificationSettings(event->NotificationIndex, (uint8_t *)&NotificationSettings, sizeof(NotificationSettingsStruct)); - NotificationSettings.validate(); + if (!AllocatedNotificationSettings()) { + break; + } + LoadNotificationSettings(event->NotificationIndex, (uint8_t *)NotificationSettings.get(), sizeof(NotificationSettingsStruct)); + NotificationSettings->validate(); - String subject = NotificationSettings.Subject; - String body = NotificationSettings.Body; + String subject = NotificationSettings->Subject; + String body = NotificationSettings->Body; if (!event->String1.isEmpty()) { body = event->String1; @@ -80,7 +83,7 @@ bool NPlugin_001(NPlugin::Function function, struct EventStruct *event, String& if (!event->String2.isEmpty()) { subject = event->String2; } - NPlugin_001_send(NotificationSettings, subject, body); + NPlugin_001_send(*NotificationSettings, subject, body); success = true; break; } diff --git a/src/_N002_Buzzer.cpp b/src/_N002_Buzzer.cpp index 008d213c9..1bcd867c0 100644 --- a/src/_N002_Buzzer.cpp +++ b/src/_N002_Buzzer.cpp @@ -46,7 +46,7 @@ bool NPlugin_002(NPlugin::Function function, struct EventStruct *event, String& // if (command == F("buzzer")) // { // MakeNotificationSettings(NotificationSettings); - // LoadNotificationSettings(event->NotificationIndex, (uint8_t*)&NotificationSettings, sizeof(NotificationSettingsStruct)); + // LoadNotificationSettings(event->NotificationIndex, (uint8_t *)NotificationSettings.get(), sizeof(NotificationSettingsStruct)); // success = true; // } // break; @@ -55,10 +55,14 @@ bool NPlugin_002(NPlugin::Function function, struct EventStruct *event, String& case NPlugin::Function::NPLUGIN_NOTIFY: { MakeNotificationSettings(NotificationSettings); - LoadNotificationSettings(event->NotificationIndex, (uint8_t*)&NotificationSettings, sizeof(NotificationSettingsStruct)); - NotificationSettings.validate(); + if (!AllocatedNotificationSettings()) { + break; + } + + LoadNotificationSettings(event->NotificationIndex, (uint8_t *)NotificationSettings.get(), sizeof(NotificationSettingsStruct)); + NotificationSettings->validate(); //this reserves IRAM and uninitialized RAM - tone_espEasy(NotificationSettings.Pin1, 440, 500); + tone_espEasy(NotificationSettings->Pin1, 440, 500); success = true; } diff --git a/src/_P002_ADC.ino b/src/_P002_ADC.ino index 21fa91268..920213d51 100644 --- a/src/_P002_ADC.ino +++ b/src/_P002_ADC.ino @@ -57,7 +57,14 @@ boolean Plugin_002(uint8_t function, struct EventStruct *event, String& string) P002_data->webformLoad(event); success = true; } else { - P002_data = new (std::nothrow) P002_data_struct(); + constexpr unsigned size = sizeof(P002_data_struct); + void *ptr = special_calloc(1, size); + + if (ptr == nullptr) { + break; + } + + P002_data = new (ptr) P002_data_struct(); if (nullptr != P002_data) { P002_data->init(event); diff --git a/src/_P036_FrameOLED.ino b/src/_P036_FrameOLED.ino index 6070a3337..0beba24f2 100644 --- a/src/_P036_FrameOLED.ino +++ b/src/_P036_FrameOLED.ino @@ -711,11 +711,12 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string) P036_CheckHeap(F("_INIT: Entering")); # endif // P036_CHECK_HEAP { - # ifdef USE_SECOND_HEAP - HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP - - initPluginTaskData(event->TaskIndex, new (std::nothrow) P036_data_struct()); + constexpr unsigned size = sizeof(P036_data_struct); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + initPluginTaskData(event->TaskIndex, new (ptr) P036_data_struct()); + } } # ifdef P036_CHECK_HEAP P036_CheckHeap(F("_INIT: Before (*P036_data = static_cast)")); diff --git a/src/src/DataStructs/NotificationSettingsStruct.h b/src/src/DataStructs/NotificationSettingsStruct.h index 58827fcc7..4684bbeaf 100644 --- a/src/src/DataStructs/NotificationSettingsStruct.h +++ b/src/src/DataStructs/NotificationSettingsStruct.h @@ -36,8 +36,12 @@ struct NotificationSettingsStruct }; typedef std::shared_ptr NotificationSettingsStruct_ptr_type; -#define MakeNotificationSettings(T) NotificationSettingsStruct_ptr_type NotificationSettingsStruct_ptr(new (std::nothrow) NotificationSettingsStruct());\ - NotificationSettingsStruct& T = *NotificationSettingsStruct_ptr; + +#define MakeNotificationSettings(T) void * calloc_ptr = special_calloc(1,sizeof(NotificationSettingsStruct)); NotificationSettingsStruct_ptr_type T(new (calloc_ptr) NotificationSettingsStruct()); + +// Check to see if MakeNotificationSettings was successful +#define AllocatedNotificationSettings() (NotificationSettings.get() != nullptr) + // Need to make sure every byte between the members is also zero // Otherwise the checksum will fail and settings will be saved too often. diff --git a/src/src/Helpers/Memory.cpp b/src/src/Helpers/Memory.cpp index e7420f77a..2096a86e2 100644 --- a/src/src/Helpers/Memory.cpp +++ b/src/src/Helpers/Memory.cpp @@ -176,14 +176,14 @@ void* special_calloc(size_t num, size_t size) { res = heap_caps_calloc(num, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); } #else // ifdef ESP32 - if (size > 64) { # ifdef USE_SECOND_HEAP + if (size > 64 || FreeMem() < 5000) { // Try allocating on ESP8266 2nd heap, only when sufficiently large data is needed HeapSelectIram ephemeral; -# endif // ifdef USE_SECOND_HEAP res = calloc(num, size); } +# endif // ifdef USE_SECOND_HEAP #endif // ifdef ESP32 if (res == nullptr) { @@ -212,7 +212,7 @@ bool String_reserve_special(String& str, size_t size) { return true; } #ifdef USE_SECOND_HEAP - if (size >= 48) { + if (size >= 48 || FreeMem() < 5000) { // Only try to store larger strings here as those tend to be kept for a longer period. HeapSelectIram ephemeral; // String does round up to nearest multiple of 16 bytes, so no need to round up to multiples of 32 bit here diff --git a/src/src/PluginStructs/P036_data_struct.cpp b/src/src/PluginStructs/P036_data_struct.cpp index 8ade3e86e..a7bd15c3c 100644 --- a/src/src/PluginStructs/P036_data_struct.cpp +++ b/src/src/PluginStructs/P036_data_struct.cpp @@ -19,6 +19,9 @@ # include void P036_LineContent::loadDisplayLines(taskIndex_t taskIndex, uint8_t LoadVersion) { + #ifdef USE_SECOND_HEAP + HeapSelectIram ephemeral; + #endif if (LoadVersion == 0) { // read data of version 0 (up to 22.11.2019) String DisplayLinesV0[P36_Nlines]; // used to load the CustomTaskSettings for V0 diff --git a/src/src/WebServer/NotificationPage.cpp b/src/src/WebServer/NotificationPage.cpp index f5e830901..7852bd71a 100644 --- a/src/src/WebServer/NotificationPage.cpp +++ b/src/src/WebServer/NotificationPage.cpp @@ -34,7 +34,6 @@ # include "../Globals/NPlugins.h" - void handle_notifications() { # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_notifications")); @@ -67,43 +66,51 @@ void handle_notifications() { } else { MakeNotificationSettings(NotificationSettings); - if (Settings.Notification[notificationindex] != notification.value) - { - Settings.Notification[notificationindex] = notification.value; - } - else - { - if (Settings.Notification[notificationindex] != INVALID_N_PLUGIN_ID.value) + if (!AllocatedNotificationSettings()) { + addHtmlError(F("Out of memory!")); + } else { + + if (Settings.Notification[notificationindex] != notification.value) { - nprotocolIndex_t NotificationProtocolIndex = getNProtocolIndex_from_NotifierIndex(notificationindex); + Settings.Notification[notificationindex] = notification.value; + } + else + { + if (Settings.Notification[notificationindex] != INVALID_N_PLUGIN_ID.value) + { + nprotocolIndex_t NotificationProtocolIndex = getNProtocolIndex_from_NotifierIndex(notificationindex); - if (validNProtocolIndex(NotificationProtocolIndex)) { - String dummyString; - NPlugin_ptr[NotificationProtocolIndex](NPlugin::Function::NPLUGIN_WEBFORM_SAVE, 0, dummyString); + if (validNProtocolIndex(NotificationProtocolIndex)) { + String dummyString; + NPlugin_ptr[NotificationProtocolIndex](NPlugin::Function::NPLUGIN_WEBFORM_SAVE, 0, dummyString); + } + + // Reload & overwrite + LoadNotificationSettings(notificationindex, reinterpret_cast(NotificationSettings.get()), + sizeof(NotificationSettingsStruct)); + NotificationSettings->validate(); + NotificationSettings->Port = getFormItemInt(F("port"), 0); + + NotificationSettings->Timeout_ms = getFormItemInt(F("timeout"), NPLUGIN_001_DEF_TM); + NotificationSettings->Pin1 = getFormItemInt(F("pin1"), -1); + NotificationSettings->Pin2 = getFormItemInt(F("pin2"), -1); + Settings.NotificationEnabled[notificationindex] = isFormItemChecked(F("notificationenabled")); + strncpy_webserver_arg(NotificationSettings->Domain, F("domain")); + strncpy_webserver_arg(NotificationSettings->Server, F("server")); + strncpy_webserver_arg(NotificationSettings->Sender, F("sender")); + strncpy_webserver_arg(NotificationSettings->Receiver, F("receiver")); + strncpy_webserver_arg(NotificationSettings->Subject, F("subject")); + strncpy_webserver_arg(NotificationSettings->User, F("username")); + strncpy_webserver_arg(NotificationSettings->Body, F("body")); + + copyFormPassword(F("password"), NotificationSettings->Pass, sizeof(NotificationSettings->Pass)); } - - // Reload & overwrite - LoadNotificationSettings(notificationindex, reinterpret_cast(&NotificationSettings), sizeof(NotificationSettingsStruct)); - NotificationSettings.validate(); - NotificationSettings.Port = getFormItemInt(F("port"), 0); - - NotificationSettings.Timeout_ms = getFormItemInt(F("timeout"), NPLUGIN_001_DEF_TM); - NotificationSettings.Pin1 = getFormItemInt(F("pin1"), -1); - NotificationSettings.Pin2 = getFormItemInt(F("pin2"), -1); - Settings.NotificationEnabled[notificationindex] = isFormItemChecked(F("notificationenabled")); - strncpy_webserver_arg(NotificationSettings.Domain, F("domain")); - strncpy_webserver_arg(NotificationSettings.Server, F("server")); - strncpy_webserver_arg(NotificationSettings.Sender, F("sender")); - strncpy_webserver_arg(NotificationSettings.Receiver, F("receiver")); - strncpy_webserver_arg(NotificationSettings.Subject, F("subject")); - strncpy_webserver_arg(NotificationSettings.User, F("username")); - strncpy_webserver_arg(NotificationSettings.Body, F("body")); - - copyFormPassword(F("password"), NotificationSettings.Pass, sizeof(NotificationSettings.Pass)); } } - addHtmlError(SaveNotificationSettings(notificationindex, reinterpret_cast(&NotificationSettings), - sizeof(NotificationSettingsStruct))); + addHtmlError(SaveNotificationSettings( + notificationindex, + reinterpret_cast(NotificationSettings.get()), + sizeof(NotificationSettingsStruct))); } // Save the settings. @@ -138,51 +145,55 @@ void handle_notifications() { MakeNotificationSettings(NotificationSettings); - for (uint8_t x = 0; x < NOTIFICATION_MAX; x++) - { - LoadNotificationSettings(x, reinterpret_cast(&NotificationSettings), sizeof(NotificationSettingsStruct)); - NotificationSettings.validate(); - html_TR_TD(); - html_add_button_prefix(); - addHtml(F("notifications?index=")); - addHtmlInt(x + 1); - addHtml(F("'>Edit")); - html_TD(); - addHtmlInt(x + 1); - html_TD(); - - if (Settings.Notification[x] != INVALID_N_PLUGIN_ID.value) + if (!AllocatedNotificationSettings()) { + addHtmlError(F("Out of memory!")); + } else { + for (uint8_t x = 0; x < NOTIFICATION_MAX; x++) { - addEnabled(Settings.NotificationEnabled[x]); - + LoadNotificationSettings(x, reinterpret_cast(NotificationSettings.get()), sizeof(NotificationSettingsStruct)); + NotificationSettings->validate(); + html_TR_TD(); + html_add_button_prefix(); + addHtml(F("notifications?index=")); + addHtmlInt(x + 1); + addHtml(F("'>Edit")); + html_TD(); + addHtmlInt(x + 1); html_TD(); - uint8_t NotificationProtocolIndex = getNProtocolIndex(npluginID_t::toPluginID(Settings.Notification[x])); - String NotificationName = F("(plugin not found?)"); - if (validNProtocolIndex(NotificationProtocolIndex)) + if (Settings.Notification[x] != INVALID_N_PLUGIN_ID.value) { - NPlugin_ptr[NotificationProtocolIndex](NPlugin::Function::NPLUGIN_GET_DEVICENAME, 0, NotificationName); - } - addHtml(NotificationName); - html_TD(); - addHtml(NotificationSettings.Server); - html_TD(); + addEnabled(Settings.NotificationEnabled[x]); - if (NotificationSettings.Port) { - addHtmlInt(NotificationSettings.Port); - } else { - // MFD: we display the GPIO - addGpioHtml(NotificationSettings.Pin1); + html_TD(); + uint8_t NotificationProtocolIndex = getNProtocolIndex(npluginID_t::toPluginID(Settings.Notification[x])); + String NotificationName = F("(plugin not found?)"); - if (NotificationSettings.Pin2 >= 0) + if (validNProtocolIndex(NotificationProtocolIndex)) { - html_BR(); - addGpioHtml(NotificationSettings.Pin2); + NPlugin_ptr[NotificationProtocolIndex](NPlugin::Function::NPLUGIN_GET_DEVICENAME, 0, NotificationName); + } + addHtml(NotificationName); + html_TD(); + addHtml(NotificationSettings->Server); + html_TD(); + + if (NotificationSettings->Port) { + addHtmlInt(NotificationSettings->Port); + } else { + // MFD: we display the GPIO + addGpioHtml(NotificationSettings->Pin1); + + if (NotificationSettings->Pin2 >= 0) + { + html_BR(); + addGpioHtml(NotificationSettings->Pin2); + } } } - } - else { - html_TD(3); + else { + html_TD(3); + } } } html_end_table(); @@ -213,88 +224,93 @@ void handle_notifications() { if (Settings.Notification[notificationindex] != INVALID_N_PLUGIN_ID.value) { MakeNotificationSettings(NotificationSettings); - LoadNotificationSettings(notificationindex, reinterpret_cast(&NotificationSettings), sizeof(NotificationSettingsStruct)); - NotificationSettings.validate(); - nprotocolIndex_t NotificationProtocolIndex = getNProtocolIndex_from_NotifierIndex(notificationindex); + if (!AllocatedNotificationSettings()) { + addHtmlError(F("Out of memory!")); + } else { + LoadNotificationSettings(notificationindex, reinterpret_cast(NotificationSettings.get()), sizeof(NotificationSettingsStruct)); + NotificationSettings->validate(); - if (validNProtocolIndex(NotificationProtocolIndex)) - { - if (Notification[NotificationProtocolIndex].usesMessaging) + nprotocolIndex_t NotificationProtocolIndex = getNProtocolIndex_from_NotifierIndex(notificationindex); + + if (validNProtocolIndex(NotificationProtocolIndex)) { - if (NotificationSettings.Port == 0) { -# if FEATURE_EMAIL_TLS - NotificationSettings.Port = 465; -# else // if FEATURE_EMAIL_TLS - NotificationSettings.Port = 25; -# endif // if FEATURE_EMAIL_TLS - } - - addFormSubHeader(F("SMTP Server Settings")); - addFormTextBox(F("Domain"), F("domain"), NotificationSettings.Domain, sizeof(NotificationSettings.Domain) - 1); - addFormTextBox(F("Server"), F("server"), NotificationSettings.Server, sizeof(NotificationSettings.Server) - 1); - addFormNumericBox( - F("Port"), F("port"), - NotificationSettings.Port, - 1, - 65535); -# if FEATURE_EMAIL_TLS - addFormNote(F("default port SSL: 465")); -# else // if FEATURE_EMAIL_TLS - addFormNote(F("default port: 25, SSL/TLS servers NOT supported!")); -# endif // if FEATURE_EMAIL_TLS - - if ((NotificationSettings.Timeout_ms < NPLUGIN_001_MIN_TM) || - (NotificationSettings.Timeout_ms > NPLUGIN_001_MAX_TM)) + if (Notification[NotificationProtocolIndex].usesMessaging) { - NotificationSettings.Timeout_ms = NPLUGIN_001_DEF_TM; + if (NotificationSettings->Port == 0) { +# if FEATURE_EMAIL_TLS + NotificationSettings->Port = 465; +# else // if FEATURE_EMAIL_TLS + NotificationSettings->Port = 25; +# endif // if FEATURE_EMAIL_TLS + } + + addFormSubHeader(F("SMTP Server Settings")); + addFormTextBox(F("Domain"), F("domain"), NotificationSettings->Domain, sizeof(NotificationSettings->Domain) - 1); + addFormTextBox(F("Server"), F("server"), NotificationSettings->Server, sizeof(NotificationSettings->Server) - 1); + addFormNumericBox( + F("Port"), F("port"), + NotificationSettings->Port, + 1, + 65535); +# if FEATURE_EMAIL_TLS + addFormNote(F("default port SSL: 465")); +# else // if FEATURE_EMAIL_TLS + addFormNote(F("default port: 25, SSL/TLS servers NOT supported!")); +# endif // if FEATURE_EMAIL_TLS + + if ((NotificationSettings->Timeout_ms < NPLUGIN_001_MIN_TM) || + (NotificationSettings->Timeout_ms > NPLUGIN_001_MAX_TM)) + { + NotificationSettings->Timeout_ms = NPLUGIN_001_DEF_TM; + } + + addFormNumericBox( + F("Timeout"), F("timeout"), + NotificationSettings->Timeout_ms, + NPLUGIN_001_MIN_TM, + NPLUGIN_001_MAX_TM +# if FEATURE_TOOLTIPS + , F("Maximum Server Response Time") +# endif // if FEATURE_TOOLTIPS + ); + + addUnit(F("ms")); + + ZERO_TERMINATE(NotificationSettings->Pass); + addFormSubHeader(F("Credentials")); + + addFormTextBox(F("Username"), F("username"), NotificationSettings->User, sizeof(NotificationSettings->User) - 1); + addFormPasswordBox(F("Password"), F("password"), NotificationSettings->Pass, sizeof(NotificationSettings->Pass) - 1); + + addFormSubHeader(F("Email Attributes")); + + addFormTextBox(F("Sender"), F("sender"), NotificationSettings->Sender, sizeof(NotificationSettings->Sender) - 1); + addFormTextBox(F("Receiver"), F("receiver"), NotificationSettings->Receiver, sizeof(NotificationSettings->Receiver) - 1); + addFormTextBox(F("Subject"), F("subject"), NotificationSettings->Subject, sizeof(NotificationSettings->Subject) - 1); + + addRowLabel(F("Body")); + addHtml(F("")); } - addFormNumericBox( - F("Timeout"), F("timeout"), - NotificationSettings.Timeout_ms, - NPLUGIN_001_MIN_TM, - NPLUGIN_001_MAX_TM -# if FEATURE_TOOLTIPS - , F("Maximum Server Response Time") -# endif // if FEATURE_TOOLTIPS - ); + if (Notification[NotificationProtocolIndex].usesGPIO > 0) + { + addRowLabel(F("1st GPIO")); + addPinSelect(PinSelectPurpose::Generic, F("pin1"), NotificationSettings->Pin1); + } - addUnit(F("ms")); + addRowLabel(F("Enabled")); + addCheckBox(F("notificationenabled"), Settings.NotificationEnabled[notificationindex]); - ZERO_TERMINATE(NotificationSettings.Pass); - addFormSubHeader(F("Credentials")); + TempEvent.NotificationIndex = notificationindex; + String webformLoadString; + NPlugin_ptr[NotificationProtocolIndex](NPlugin::Function::NPLUGIN_WEBFORM_LOAD, &TempEvent, webformLoadString); - addFormTextBox(F("Username"), F("username"), NotificationSettings.User, sizeof(NotificationSettings.User) - 1); - addFormPasswordBox(F("Password"), F("password"), NotificationSettings.Pass, sizeof(NotificationSettings.Pass) - 1); - - addFormSubHeader(F("Email Attributes")); - - addFormTextBox(F("Sender"), F("sender"), NotificationSettings.Sender, sizeof(NotificationSettings.Sender) - 1); - addFormTextBox(F("Receiver"), F("receiver"), NotificationSettings.Receiver, sizeof(NotificationSettings.Receiver) - 1); - addFormTextBox(F("Subject"), F("subject"), NotificationSettings.Subject, sizeof(NotificationSettings.Subject) - 1); - - addRowLabel(F("Body")); - addHtml(F("")); - } - - if (Notification[NotificationProtocolIndex].usesGPIO > 0) - { - addRowLabel(F("1st GPIO")); - addPinSelect(PinSelectPurpose::Generic, F("pin1"), NotificationSettings.Pin1); - } - - addRowLabel(F("Enabled")); - addCheckBox(F("notificationenabled"), Settings.NotificationEnabled[notificationindex]); - - TempEvent.NotificationIndex = notificationindex; - String webformLoadString; - NPlugin_ptr[NotificationProtocolIndex](NPlugin::Function::NPLUGIN_WEBFORM_LOAD, &TempEvent, webformLoadString); - - if (webformLoadString.length() > 0) { - addHtmlError(F("Bug in NPlugin::Function::NPLUGIN_WEBFORM_LOAD, should not append to string, use addHtml() instead")); + if (webformLoadString.length() > 0) { + addHtmlError(F("Bug in NPlugin::Function::NPLUGIN_WEBFORM_LOAD, should not append to string, use addHtml() instead")); + } } } } From 64eff226d68beab6b2d3b78ab1f3a1f589c6fb1b Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 19 Feb 2025 18:03:48 +0100 Subject: [PATCH 033/564] [Memory] Move C001 and C002 queue elements to 2nd heap (ESP8266) --- src/_C001.cpp | 9 +++++-- src/src/ESPEasyCore/Controller.cpp | 41 ++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/_C001.cpp b/src/_C001.cpp index 46ce884e6..445177d35 100644 --- a/src/_C001.cpp +++ b/src/_C001.cpp @@ -100,9 +100,14 @@ bool CPlugin_001(CPlugin::Function function, struct EventStruct *event, String& url += mapVccToDomoticz(); # endif // if FEATURE_ADC_VCC - std::unique_ptr element(new (std::nothrow) C001_queue_element(event->ControllerIndex, event->TaskIndex, std::move(url))); + constexpr unsigned size = sizeof(C001_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + std::unique_ptr element(new (ptr) C001_queue_element(event->ControllerIndex, event->TaskIndex, std::move(url))); - success = C001_DelayHandler->addToQueue(std::move(element)); + success = C001_DelayHandler->addToQueue(std::move(element)); + } Scheduler.scheduleNextDelayQueue(SchedulerIntervalTimer_e::TIMER_C001_DELAY_QUEUE, C001_DelayHandler->getNextScheduleTime()); } diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 2d953a24e..f8aa316e2 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -838,12 +838,22 @@ bool MQTTpublish(controllerIndex_t controller_idx, } topic_str = topic; payload_str = payload; - const bool success = - MQTTDelayHandler->addToQueue(std::unique_ptr(new (std::nothrow) MQTT_queue_element( - controller_idx, taskIndex, - std::move(topic_str), - std::move(payload_str), retained, - callbackTask))); + + bool success = false; + + constexpr unsigned size = sizeof(MQTT_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + success = + MQTTDelayHandler->addToQueue( + std::unique_ptr( + new (ptr) MQTT_queue_element( + controller_idx, taskIndex, + std::move(topic_str), + std::move(payload_str), retained, + callbackTask))); + } scheduleNextMQTTdelayQueue(); return success; @@ -863,12 +873,21 @@ bool MQTTpublish(controllerIndex_t controller_idx, return false; } - const bool success = - MQTTDelayHandler->addToQueue(std::unique_ptr(new (std::nothrow) MQTT_queue_element(controller_idx, taskIndex, - std::move(topic), - std::move(payload), retained, - callbackTask))); + bool success = false; + constexpr unsigned size = sizeof(MQTT_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + success = + MQTTDelayHandler->addToQueue( + std::unique_ptr( + new (ptr) MQTT_queue_element( + controller_idx, taskIndex, + std::move(topic), + std::move(payload), retained, + callbackTask))); + } scheduleNextMQTTdelayQueue(); return success; } From 5c9d7be604ea4374ef706971551dd6e564b8bb9c Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 19 Feb 2025 22:58:06 +0100 Subject: [PATCH 034/564] [Memory] Move other controller queue elements to 2nd heap (ESP8266) --- src/_C003.cpp | 138 ++++++------ src/_C004.cpp | 12 +- src/_C007.cpp | 56 ++--- src/_C008.cpp | 71 ++++--- src/_C009.cpp | 198 +++++++++--------- src/_C010.cpp | 108 +++++----- src/_C011.cpp | 155 ++++++++------ src/_C012.cpp | 10 +- src/_C015.cpp | 135 ++++++------ src/_C017.cpp | 9 +- src/_C018.cpp | 48 ++++- .../DataStructs/ESPeasyControllerCache.cpp | 11 +- src/src/DataStructs/PluginTaskData_base.cpp | 7 +- src/src/DataStructs/ProvisioningStruct.h | 1 - src/src/Globals/Plugins.cpp | 2 +- src/src/Helpers/Networking.cpp | 18 +- src/src/WebServer/UploadPage.cpp | 7 +- 17 files changed, 574 insertions(+), 412 deletions(-) diff --git a/src/_C003.cpp b/src/_C003.cpp index 0405f090b..3a96f7678 100644 --- a/src/_C003.cpp +++ b/src/_C003.cpp @@ -49,6 +49,7 @@ bool CPlugin_003(CPlugin::Function function, struct EventStruct *event, String& if (C003_DelayHandler == nullptr) { break; } + if (C003_DelayHandler->queueFull(event->ControllerIndex)) { break; } @@ -58,13 +59,18 @@ bool CPlugin_003(CPlugin::Function function, struct EventStruct *event, String& F("variableset %d,%s\n"), event->idx, formatUserVarNoCheck(event, 0).c_str()); - std::unique_ptr element( - new (std::nothrow) C003_queue_element( - event->ControllerIndex, - event->TaskIndex, - std::move(url))); + constexpr unsigned size = sizeof(C003_queue_element); + void *ptr = special_calloc(1, size); - success = C003_DelayHandler->addToQueue(std::move(element)); + if (ptr != nullptr) { + std::unique_ptr element( + new (ptr) C003_queue_element( + event->ControllerIndex, + event->TaskIndex, + std::move(url))); + + success = C003_DelayHandler->addToQueue(std::move(element)); + } Scheduler.scheduleNextDelayQueue(SchedulerIntervalTimer_e::TIMER_C003_DELAY_QUEUE, C003_DelayHandler->getNextScheduleTime()); break; @@ -88,69 +94,69 @@ bool CPlugin_003(CPlugin::Function function, struct EventStruct *event, String& bool do_process_c003_delay_queue(cpluginID_t cpluginID, const Queue_element_base& element_base, ControllerSettingsStruct& ControllerSettings) { const C003_queue_element& element = static_cast(element_base); // *INDENT-ON* - bool success = false; +bool success = false; - // Use WiFiClient class to create TCP connections - WiFiClient client; +// Use WiFiClient class to create TCP connections +WiFiClient client; - if (!try_connect_host(cpluginID, client, ControllerSettings, F("TELNT: "))) - { - return success; - } - - // strcpy_P(log, PSTR("TELNT: Sending enter")); - // addLog(LOG_LEVEL_ERROR, log); - client.print(" \n"); - - unsigned long timer = millis() + 200; - - while (!client_available(client) && !timeOutReached(timer)) { - delay(1); - } - - timer = millis() + 1000; - - while (client_available(client) && !timeOutReached(timer) && !success) - { - // String line = client.readStringUntil('\n'); - String line; - safeReadStringUntil(client, line, '\n'); - - if (line.startsWith(F("Enter your password:"))) - { - success = true; - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("TELNT: Password request ok")); - #endif - } - delay(1); - } - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("TELNT: Sending pw")); - #endif - client.println(getControllerPass(element._controller_idx, ControllerSettings)); - delay(100); - - while (client_available(client)) { - client.read(); - } - - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("TELNT: Sending cmd")); - #endif - client.print(element.txt); - delay(10); - - while (client_available(client)) { - client.read(); - } - - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("TELNT: closing connection")); - #endif - - client.stop(); +if (!try_connect_host(cpluginID, client, ControllerSettings, F("TELNT: "))) +{ return success; } +// strcpy_P(log, PSTR("TELNT: Sending enter")); +// addLog(LOG_LEVEL_ERROR, log); +client.print(" \n"); + +unsigned long timer = millis() + 200; + +while (!client_available(client) && !timeOutReached(timer)) { + delay(1); +} + +timer = millis() + 1000; + +while (client_available(client) && !timeOutReached(timer) && !success) +{ + // String line = client.readStringUntil('\n'); + String line; + safeReadStringUntil(client, line, '\n'); + + if (line.startsWith(F("Enter your password:"))) + { + success = true; + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("TELNT: Password request ok")); + # endif + } + delay(1); +} + # ifndef BUILD_NO_DEBUG +addLog(LOG_LEVEL_DEBUG, F("TELNT: Sending pw")); + # endif +client.println(getControllerPass(element._controller_idx, ControllerSettings)); +delay(100); + +while (client_available(client)) { + client.read(); +} + + # ifndef BUILD_NO_DEBUG +addLog(LOG_LEVEL_DEBUG, F("TELNT: Sending cmd")); + # endif +client.print(element.txt); +delay(10); + +while (client_available(client)) { + client.read(); +} + + # ifndef BUILD_NO_DEBUG +addLog(LOG_LEVEL_DEBUG, F("TELNT: closing connection")); + # endif + +client.stop(); +return success; +} + #endif // ifdef USES_C003 diff --git a/src/_C004.cpp b/src/_C004.cpp index d9903d9b1..a450f0da9 100644 --- a/src/_C004.cpp +++ b/src/_C004.cpp @@ -48,7 +48,8 @@ bool CPlugin_004(CPlugin::Function function, struct EventStruct *event, String& { success = true; - switch (event->idx) { + switch (event->idx) + { case ControllerSettingsStruct::CONTROLLER_USER: string = F("ThingHTTP Name"); break; @@ -72,9 +73,14 @@ bool CPlugin_004(CPlugin::Function function, struct EventStruct *event, String& break; } - std::unique_ptr element(new (std::nothrow) C004_queue_element(event)); + constexpr unsigned size = sizeof(C004_queue_element); + void *ptr = special_calloc(1, size); - success = C004_DelayHandler->addToQueue(std::move(element)); + if (ptr != nullptr) { + std::unique_ptr element(new (ptr) C004_queue_element(event)); + + success = C004_DelayHandler->addToQueue(std::move(element)); + } Scheduler.scheduleNextDelayQueue(SchedulerIntervalTimer_e::TIMER_C004_DELAY_QUEUE, C004_DelayHandler->getNextScheduleTime()); break; diff --git a/src/_C007.cpp b/src/_C007.cpp index 1cf062e58..f4de2157d 100644 --- a/src/_C007.cpp +++ b/src/_C007.cpp @@ -77,8 +77,13 @@ bool CPlugin_007(CPlugin::Function function, struct EventStruct *event, String& break; } - std::unique_ptr element(new (std::nothrow) C007_queue_element(event)); - success = C007_DelayHandler->addToQueue(std::move(element)); + constexpr unsigned size = sizeof(C007_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + std::unique_ptr element(new (ptr) C007_queue_element(event)); + success = C007_DelayHandler->addToQueue(std::move(element)); + } Scheduler.scheduleNextDelayQueue(SchedulerIntervalTimer_e::TIMER_C007_DELAY_QUEUE, C007_DelayHandler->getNextScheduleTime()); break; @@ -101,35 +106,36 @@ bool CPlugin_007(CPlugin::Function function, struct EventStruct *event, String& // *INDENT-OFF* bool do_process_c007_delay_queue(cpluginID_t cpluginID, const Queue_element_base& element_base, ControllerSettingsStruct& ControllerSettings) { const C007_queue_element& element = static_cast(element_base); -// *INDENT-ON* - if (ControllerSettings.Publish[0] == '\0') { - strcpy_P(ControllerSettings.Publish, PSTR(C007_DEFAULT_URL)); - } - String url = strformat(F("%s?node=%d&json="), ControllerSettings.Publish, Settings.Unit); - for (uint8_t i = 0; i < element.valueCount; ++i) { - url += strformat(F("%cfield%d:%s"), (i == 0) ? '{' : ',', element.idx + i, element.txt[i].c_str()); - } - url += strformat(F("}&apikey=%s"), getControllerPass(element._controller_idx, ControllerSettings).c_str()); // "0UDNN17RW6XAS2E5" // api key +// *INDENT-ON* +if (ControllerSettings.Publish[0] == '\0') { + strcpy_P(ControllerSettings.Publish, PSTR(C007_DEFAULT_URL)); +} +String url = strformat(F("%s?node=%d&json="), ControllerSettings.Publish, Settings.Unit); + +for (uint8_t i = 0; i < element.valueCount; ++i) { + url += strformat(F("%cfield%d:%s"), (i == 0) ? '{' : ',', element.idx + i, element.txt[i].c_str()); +} +url += strformat(F("}&apikey=%s"), getControllerPass(element._controller_idx, ControllerSettings).c_str()); // "0UDNN17RW6XAS2E5" // api key # ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { - addLog(LOG_LEVEL_DEBUG_MORE, url); - } +if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { + addLog(LOG_LEVEL_DEBUG_MORE, url); +} # endif // ifndef BUILD_NO_DEBUG - int httpCode = -1; - send_via_http( - cpluginID, - ControllerSettings, - element._controller_idx, - url, - F("GET"), - EMPTY_STRING, - EMPTY_STRING, - httpCode); - return (httpCode >= 100) && (httpCode < 300); +int httpCode = -1; +send_via_http( + cpluginID, + ControllerSettings, + element._controller_idx, + url, + F("GET"), + EMPTY_STRING, + EMPTY_STRING, + httpCode); +return (httpCode >= 100) && (httpCode < 300); } #endif // ifdef USES_C007 diff --git a/src/_C008.cpp b/src/_C008.cpp index 4383f382f..761850332 100644 --- a/src/_C008.cpp +++ b/src/_C008.cpp @@ -59,6 +59,7 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& if (C008_DelayHandler == nullptr) { break; } + if (C008_DelayHandler->queueFull(event->ControllerIndex)) { break; } @@ -67,7 +68,7 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& String pubname; { // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. - MakeControllerSettings(ControllerSettings); //-V522 + MakeControllerSettings(ControllerSettings); // -V522 if (!AllocatedControllerSettings()) { addLog(LOG_LEVEL_ERROR, F("C008 : Generic HTTP - Cannot send, out of RAM")); @@ -79,8 +80,14 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& const bool contains_valname = pubname.indexOf(F("%valname%")) != -1; uint8_t valueCount = getValueCountForTask(event->TaskIndex); - std::unique_ptr element(new (std::nothrow) C008_queue_element(event, valueCount)); - success = C008_DelayHandler->addToQueue(std::move(element)); + + constexpr unsigned size = sizeof(C008_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + std::unique_ptr element(new (ptr) C008_queue_element(event, valueCount)); + success = C008_DelayHandler->addToQueue(std::move(element)); + } if (success) { // Element was added. @@ -89,35 +96,38 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& C008_queue_element& element = static_cast(*(C008_DelayHandler->sendQueue.back())); // Collect the values at the same run, to make sure all are from the same sample - //LoadTaskSettings(event->TaskIndex); // FIXME TD-er: This can probably be removed + // LoadTaskSettings(event->TaskIndex); // FIXME TD-er: This can probably be removed for (uint8_t x = 0; x < valueCount; x++) { - bool isvalid; - const String formattedValue = formatUserVar(event, x , isvalid); + bool isvalid; + const String formattedValue = formatUserVar(event, x, isvalid); if (isvalid) { // First store in a temporary string, so we can use move_special to allocate on the best heap String txt; txt += '/'; txt += pubname; + if (contains_valname) { parseSingleControllerVariable(txt, event, x, true); } parseControllerVariables(txt, event, true); # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { addLog(LOG_LEVEL_DEBUG, strformat( - F("C008 : pubname: %s value: %s"), - pubname.c_str(), - formattedValue.c_str() - )); + F("C008 : pubname: %s value: %s"), + pubname.c_str(), + formattedValue.c_str() + )); } -#endif +# endif // ifndef BUILD_NO_DEBUG txt.replace(F("%value%"), formattedValue); move_special(element.txt[x], std::move(txt)); # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { addLog(LOG_LEVEL_DEBUG_MORE, concat(F("C008 : "), element.txt[x])); } @@ -150,26 +160,27 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& // *INDENT-OFF* bool do_process_c008_delay_queue(cpluginID_t cpluginID, const Queue_element_base& element_base, ControllerSettingsStruct& ControllerSettings) { const C008_queue_element& element = static_cast(element_base); -// *INDENT-ON* - while (element.txt[element.valuesSent].isEmpty()) { - // A non valid value, which we are not going to send. - // Increase sent counter until a valid value is found. - if (element.checkDone(true)) { - return true; - } - } - int httpCode = -1; - send_via_http( - cpluginID, - ControllerSettings, - element._controller_idx, - element.txt[element.valuesSent], - F("GET"), - EMPTY_STRING, - EMPTY_STRING, - httpCode); - return element.checkDone((httpCode >= 100) && (httpCode < 300)); +// *INDENT-ON* +while (element.txt[element.valuesSent].isEmpty()) { + // A non valid value, which we are not going to send. + // Increase sent counter until a valid value is found. + if (element.checkDone(true)) { + return true; + } +} + +int httpCode = -1; +send_via_http( + cpluginID, + ControllerSettings, + element._controller_idx, + element.txt[element.valuesSent], + F("GET"), + EMPTY_STRING, + EMPTY_STRING, + httpCode); +return element.checkDone((httpCode >= 100) && (httpCode < 300)); } #endif // ifdef USES_C008 diff --git a/src/_C009.cpp b/src/_C009.cpp index bcca8adf5..0b5e1a191 100644 --- a/src/_C009.cpp +++ b/src/_C009.cpp @@ -1,9 +1,9 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C009 -#include "src/DataTypes/NodeTypeID.h" -#include "src/Helpers/StringProvider.h" -#include "src/CustomBuild/ESPEasy_buildinfo.h" +# include "src/DataTypes/NodeTypeID.h" +# include "src/Helpers/StringProvider.h" +# include "src/CustomBuild/ESPEasy_buildinfo.h" // ####################################################################################################### // ########################### Controller Plugin 009: FHEM HTTP ########################################## @@ -80,8 +80,13 @@ bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String& break; } - std::unique_ptr element(new (std::nothrow) C009_queue_element(event)); - success = C009_DelayHandler->addToQueue(std::move(element)); + constexpr unsigned size = sizeof(C009_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + std::unique_ptr element(new (ptr) C009_queue_element(event)); + success = C009_DelayHandler->addToQueue(std::move(element)); + } Scheduler.scheduleNextDelayQueue(SchedulerIntervalTimer_e::TIMER_C009_DELAY_QUEUE, C009_DelayHandler->getNextScheduleTime()); } break; @@ -109,109 +114,110 @@ bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String& bool do_process_c009_delay_queue(cpluginID_t cpluginID, const Queue_element_base& element_base, ControllerSettingsStruct& ControllerSettings) { const C009_queue_element& element = static_cast(element_base); // *INDENT-ON* - String jsonString; - // Make an educated guess on the actual length, based on earlier requests. - static size_t expectedJsonLength = 100; - { - // Reserve on the heap with most space - if (!reserve_special(jsonString, expectedJsonLength)) { - // Not enough free memory - return false; - } +String jsonString; + +// Make an educated guess on the actual length, based on earlier requests. +static size_t expectedJsonLength = 100; +{ + // Reserve on the heap with most space + if (!reserve_special(jsonString, expectedJsonLength)) { + // Not enough free memory + return false; } +} +{ + jsonString += '{'; { - jsonString += '{'; + jsonString += to_json_object_value(F("module"), F("ESPEasy")); + jsonString += ','; + jsonString += to_json_object_value(F("version"), F("1.04")); + + // Create nested object "ESP" inside "data" + jsonString += ','; + jsonString += F("\"data\":{"); { - jsonString += to_json_object_value(F("module"), F("ESPEasy")); - jsonString += ','; - jsonString += to_json_object_value(F("version"), F("1.04")); - - // Create nested object "ESP" inside "data" - jsonString += ','; - jsonString += F("\"data\":{"); + jsonString += F("\"ESP\":{"); { - jsonString += F("\"ESP\":{"); - { - // Create nested objects in "ESP": - jsonString += to_json_object_value(F("name"), Settings.getName()); - jsonString += ','; - jsonString += to_json_object_value(F("unit"), static_cast(Settings.Unit)); - jsonString += ','; - jsonString += to_json_object_value(F("version"), static_cast(Settings.Version)); - jsonString += ','; - jsonString += to_json_object_value(F("build"), static_cast(Settings.Build)); - jsonString += ','; - jsonString += to_json_object_value(F("build_notes"), F(BUILD_NOTES)); - jsonString += ','; - jsonString += to_json_object_value(F("build_git"), getValue(LabelType::GIT_BUILD)); - jsonString += ','; - jsonString += to_json_object_value(F("node_type_id"), static_cast(NODE_TYPE_ID)); - jsonString += ','; - jsonString += to_json_object_value(F("sleep"), static_cast(Settings.deepSleep_wakeTime)); - - // embed IP, important if there is NAT/PAT - // char ipStr[20]; - // IPAddress ip = NetworkLocalIP(); - // sprintf_P(ipStr, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]); - jsonString += ','; - jsonString += to_json_object_value(F("ip"), formatIP(NetworkLocalIP())); - } - jsonString += '}'; // End "ESP" - + // Create nested objects in "ESP": + jsonString += to_json_object_value(F("name"), Settings.getName()); jsonString += ','; + jsonString += to_json_object_value(F("unit"), static_cast(Settings.Unit)); + jsonString += ','; + jsonString += to_json_object_value(F("version"), static_cast(Settings.Version)); + jsonString += ','; + jsonString += to_json_object_value(F("build"), static_cast(Settings.Build)); + jsonString += ','; + jsonString += to_json_object_value(F("build_notes"), F(BUILD_NOTES)); + jsonString += ','; + jsonString += to_json_object_value(F("build_git"), getValue(LabelType::GIT_BUILD)); + jsonString += ','; + jsonString += to_json_object_value(F("node_type_id"), static_cast(NODE_TYPE_ID)); + jsonString += ','; + jsonString += to_json_object_value(F("sleep"), static_cast(Settings.deepSleep_wakeTime)); - // Create nested object "SENSOR" json object inside "data" - jsonString += F("\"SENSOR\":{"); - { - // char itemNames[valueCount][2]; - for (uint8_t x = 0; x < element.valueCount; x++) - { - // Each sensor value get an own object (0..n) - // sprintf(itemNames[x],"%d",x); - if (x != 0) { - jsonString += ','; - } - - jsonString += '"'; - jsonString += x; - jsonString += F("\":{"); - { - jsonString += to_json_object_value(F("deviceName"), getTaskDeviceName(element._taskIndex)); - jsonString += ','; - jsonString += to_json_object_value(F("valueName"), Cache.getTaskDeviceValueName(element._taskIndex, x)); - jsonString += ','; - jsonString += to_json_object_value(F("type"), static_cast(element.sensorType)); - jsonString += ','; - jsonString += to_json_object_value(F("value"), element.txt[x]); - } - jsonString += '}'; // End "sensor value N" - } - } - jsonString += '}'; // End "SENSOR" + // embed IP, important if there is NAT/PAT + // char ipStr[20]; + // IPAddress ip = NetworkLocalIP(); + // sprintf_P(ipStr, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]); + jsonString += ','; + jsonString += to_json_object_value(F("ip"), formatIP(NetworkLocalIP())); } - jsonString += '}'; // End "data" + jsonString += '}'; // End "ESP" + + jsonString += ','; + + // Create nested object "SENSOR" json object inside "data" + jsonString += F("\"SENSOR\":{"); + { + // char itemNames[valueCount][2]; + for (uint8_t x = 0; x < element.valueCount; x++) + { + // Each sensor value get an own object (0..n) + // sprintf(itemNames[x],"%d",x); + if (x != 0) { + jsonString += ','; + } + + jsonString += '"'; + jsonString += x; + jsonString += F("\":{"); + { + jsonString += to_json_object_value(F("deviceName"), getTaskDeviceName(element._taskIndex)); + jsonString += ','; + jsonString += to_json_object_value(F("valueName"), Cache.getTaskDeviceValueName(element._taskIndex, x)); + jsonString += ','; + jsonString += to_json_object_value(F("type"), static_cast(element.sensorType)); + jsonString += ','; + jsonString += to_json_object_value(F("value"), element.txt[x]); + } + jsonString += '}'; // End "sensor value N" + } + } + jsonString += '}'; // End "SENSOR" } - jsonString += '}'; // End JSON structure + jsonString += '}'; // End "data" } + jsonString += '}'; // End JSON structure +} - if (expectedJsonLength < jsonString.length()) { - expectedJsonLength = jsonString.length(); - } +if (expectedJsonLength < jsonString.length()) { + expectedJsonLength = jsonString.length(); +} - // addLog(LOG_LEVEL_INFO, F("C009 Test JSON:")); - // addLog(LOG_LEVEL_INFO, jsonString); +// addLog(LOG_LEVEL_INFO, F("C009 Test JSON:")); +// addLog(LOG_LEVEL_INFO, jsonString); - int httpCode = -1; - send_via_http( - cpluginID, - ControllerSettings, - element._controller_idx, - F("/ESPEasy"), - F("POST"), - EMPTY_STRING, - jsonString, - httpCode); - return (httpCode >= 100) && (httpCode < 300); +int httpCode = -1; +send_via_http( + cpluginID, + ControllerSettings, + element._controller_idx, + F("/ESPEasy"), + F("POST"), + EMPTY_STRING, + jsonString, + httpCode); +return (httpCode >= 100) && (httpCode < 300); } #endif // ifdef USES_C009 diff --git a/src/_C010.cpp b/src/_C010.cpp index ec65589ad..7322233ef 100644 --- a/src/_C010.cpp +++ b/src/_C010.cpp @@ -57,6 +57,7 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String& if (C010_DelayHandler == nullptr) { break; } + if (C010_DelayHandler->queueFull(event->ControllerIndex)) { break; } @@ -67,47 +68,53 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String& break; } - //LoadTaskSettings(event->TaskIndex); // FIXME TD-er: This can probably be removed + // LoadTaskSettings(event->TaskIndex); // FIXME TD-er: This can probably be removed - std::unique_ptr element(new (std::nothrow) C010_queue_element(event, valueCount)); + constexpr unsigned size = sizeof(C010_queue_element); + void *ptr = special_calloc(1, size); - - { - String pubname; + if (ptr != nullptr) { + std::unique_ptr element(new (ptr) C010_queue_element(event, valueCount)); { - MakeControllerSettings(ControllerSettings); //-V522 + String pubname; + { + MakeControllerSettings(ControllerSettings); // -V522 - if (!AllocatedControllerSettings()) { - break; + if (!AllocatedControllerSettings()) { + break; + } + LoadControllerSettings(event->ControllerIndex, *ControllerSettings); + pubname = ControllerSettings->Publish; } - LoadControllerSettings(event->ControllerIndex, *ControllerSettings); - pubname = ControllerSettings->Publish; - } - const bool contains_valname = pubname.indexOf(F("%valname%")) != -1; + const bool contains_valname = pubname.indexOf(F("%valname%")) != -1; - for (uint8_t x = 0; x < valueCount; x++) - { - bool isvalid; - const String formattedValue = formatUserVar(event, x, isvalid); + for (uint8_t x = 0; x < valueCount; x++) + { + bool isvalid; + const String formattedValue = formatUserVar(event, x, isvalid); - if (isvalid) { - String txt; - txt = pubname; - if (contains_valname) { - parseSingleControllerVariable(txt, event, x, false); + if (isvalid) { + String txt; + txt = pubname; + + if (contains_valname) { + parseSingleControllerVariable(txt, event, x, false); + } + parseControllerVariables(txt, event, false); + txt.replace(F("%value%"), formattedValue); + move_special(element->txt[x], std::move(txt)); +# ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { + addLog(LOG_LEVEL_DEBUG_MORE, element->txt[x]); + } +# endif // ifndef BUILD_NO_DEBUG } - parseControllerVariables(txt, event, false); - txt.replace(F("%value%"), formattedValue); - move_special(element->txt[x], std::move(txt)); -#ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) - addLog(LOG_LEVEL_DEBUG_MORE, element->txt[x]); -#endif } } - } - success = C010_DelayHandler->addToQueue(std::move(element)); + success = C010_DelayHandler->addToQueue(std::move(element)); + } Scheduler.scheduleNextDelayQueue(SchedulerIntervalTimer_e::TIMER_C010_DELAY_QUEUE, C010_DelayHandler->getNextScheduleTime()); break; } @@ -133,33 +140,34 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String& // *INDENT-OFF* bool do_process_c010_delay_queue(cpluginID_t cpluginID, const Queue_element_base& element_base, ControllerSettingsStruct& ControllerSettings) { const C010_queue_element& element = static_cast(element_base); + // *INDENT-ON* - while (element.txt[element.valuesSent].isEmpty()) { - // A non valid value, which we are not going to send. - // Increase sent counter until a valid value is found. - if (element.checkDone(true)) { - return true; - } +while (element.txt[element.valuesSent].isEmpty()) { + // A non valid value, which we are not going to send. + // Increase sent counter until a valid value is found. + if (element.checkDone(true)) { + return true; } - WiFiUDP C010_portUDP; +} +WiFiUDP C010_portUDP; - if (!beginWiFiUDP_randomPort(C010_portUDP)) { return false; } +if (!beginWiFiUDP_randomPort(C010_portUDP)) { return false; } - if (!try_connect_host(cpluginID, C010_portUDP, ControllerSettings)) { - return false; - } +if (!try_connect_host(cpluginID, C010_portUDP, ControllerSettings)) { + return false; +} - C010_portUDP.write( - reinterpret_cast(element.txt[element.valuesSent].c_str()), - element.txt[element.valuesSent].length()); - bool reply = C010_portUDP.endPacket(); +C010_portUDP.write( + reinterpret_cast(element.txt[element.valuesSent].c_str()), + element.txt[element.valuesSent].length()); +bool reply = C010_portUDP.endPacket(); - C010_portUDP.stop(); +C010_portUDP.stop(); - if (ControllerSettings.MustCheckReply) { - return element.checkDone(reply); - } - return element.checkDone(true); +if (ControllerSettings.MustCheckReply) { + return element.checkDone(reply); +} +return element.checkDone(true); } #endif // ifdef USES_C010 diff --git a/src/_C011.cpp b/src/_C011.cpp index ef641abd6..c29756c32 100644 --- a/src/_C011.cpp +++ b/src/_C011.cpp @@ -19,6 +19,7 @@ bool C011_sendBinary = false; struct C011_ConfigStruct { + void zero_last() { HttpMethod[C011_HTTP_METHOD_MAX_LEN - 1] = 0; HttpUri[C011_HTTP_URI_MAX_LEN - 1] = 0; @@ -30,16 +31,22 @@ struct C011_ConfigStruct char HttpUri[C011_HTTP_URI_MAX_LEN] = { 0 }; char HttpHeader[C011_HTTP_HEADER_MAX_LEN] = { 0 }; char HttpBody[C011_HTTP_BODY_MAX_LEN] = { 0 }; + }; // Forward declarations -bool load_C011_ConfigStruct(controllerIndex_t ControllerIndex, String& HttpMethod, String& HttpUri, String& HttpHeader, String& HttpBody); +bool load_C011_ConfigStruct(controllerIndex_t ControllerIndex, + String & HttpMethod, + String & HttpUri, + String & HttpHeader, + String & HttpBody); boolean Create_schedule_HTTP_C011(struct EventStruct *event); -void DeleteNotNeededValues(String& s, uint8_t numberOfValuesWanted); -void ReplaceTokenByValue(String& s, struct EventStruct *event, bool sendBinary); - - +void DeleteNotNeededValues(String& s, + uint8_t numberOfValuesWanted); +void ReplaceTokenByValue(String & s, + struct EventStruct *event, + bool sendBinary); bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -68,7 +75,7 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_INIT: { { - MakeControllerSettings(ControllerSettings); //-V522 + MakeControllerSettings(ControllerSettings); // -V522 if (AllocatedControllerSettings()) { LoadControllerSettings(event->ControllerIndex, *ControllerSettings); @@ -99,8 +106,8 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& } addTableSeparator(F("HTTP Config"), 2, 3); { - uint8_t choice = 0; - const __FlashStringHelper * methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") }; + uint8_t choice = 0; + const __FlashStringHelper *methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") }; constexpr int nrOptions = NR_ELEMENTS(methods); @@ -127,7 +134,7 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& } { // Place in scope to delete ControllerSettings as soon as it is no longer needed - MakeControllerSettings(ControllerSettings); //-V522 + MakeControllerSettings(ControllerSettings); // -V522 if (!AllocatedControllerSettings()) { addHtmlError(F("Out of memory, cannot load page")); @@ -142,30 +149,37 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_WEBFORM_SAVE: { - std::shared_ptr customConfig(new (std::nothrow) C011_ConfigStruct); + constexpr unsigned size = sizeof(C011_ConfigStruct); + void *ptr = special_calloc(1, size); - if (customConfig) { - uint8_t choice = 0; - String methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") }; + if (ptr != nullptr) { + std::shared_ptr customConfig(new (ptr) C011_ConfigStruct); - for (uint8_t i = 0; i < 5; i++) - { - if (methods[i].equals(customConfig->HttpMethod)) { - choice = i; + if (customConfig) { + uint8_t choice = 0; + String methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") }; + + for (uint8_t i = 0; i < 5; i++) + { + if (methods[i].equals(customConfig->HttpMethod)) { + choice = i; + } } + + int httpmethod = getFormItemInt(F("P011httpmethod"), choice); + String httpuri = webArg(F("P011httpuri")); + String httpheader = webArg(F("P011httpheader")); + String httpbody = webArg(F("P011httpbody")); + + strlcpy(customConfig->HttpMethod, methods[httpmethod].c_str(), sizeof(customConfig->HttpMethod)); + strlcpy(customConfig->HttpUri, httpuri.c_str(), sizeof(customConfig->HttpUri)); + strlcpy(customConfig->HttpHeader, httpheader.c_str(), sizeof(customConfig->HttpHeader)); + strlcpy(customConfig->HttpBody, httpbody.c_str(), sizeof(customConfig->HttpBody)); + customConfig->zero_last(); + SaveCustomControllerSettings(event->ControllerIndex, + reinterpret_cast(customConfig.get()), + sizeof(C011_ConfigStruct)); } - - int httpmethod = getFormItemInt(F("P011httpmethod"), choice); - String httpuri = webArg(F("P011httpuri")); - String httpheader = webArg(F("P011httpheader")); - String httpbody = webArg(F("P011httpbody")); - - strlcpy(customConfig->HttpMethod, methods[httpmethod].c_str(), sizeof(customConfig->HttpMethod)); - strlcpy(customConfig->HttpUri, httpuri.c_str(), sizeof(customConfig->HttpUri)); - strlcpy(customConfig->HttpHeader, httpheader.c_str(), sizeof(customConfig->HttpHeader)); - strlcpy(customConfig->HttpBody, httpbody.c_str(), sizeof(customConfig->HttpBody)); - customConfig->zero_last(); - SaveCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C011_ConfigStruct)); } break; } @@ -202,29 +216,36 @@ bool do_process_c011_delay_queue(cpluginID_t cpluginID, const Queue_element_base const C011_queue_element& element = static_cast(element_base); // *INDENT-ON* - if (!NetworkConnected()) { return false; } +if (!NetworkConnected()) { return false; } - int httpCode = -1; +int httpCode = -1; - send_via_http( - cpluginID, - ControllerSettings, - element._controller_idx, - element.uri, - element.HttpMethod, - element.header, - element.postStr, - httpCode); +send_via_http( + cpluginID, + ControllerSettings, + element._controller_idx, + element.uri, + element.HttpMethod, + element.header, + element.postStr, + httpCode); - // HTTP codes: - // 1xx Informational response - // 2xx Success - return httpCode >= 100 && httpCode < 300; +// HTTP codes: +// 1xx Informational response +// 2xx Success +return httpCode >= 100 && httpCode < 300; } bool load_C011_ConfigStruct(controllerIndex_t ControllerIndex, String& HttpMethod, String& HttpUri, String& HttpHeader, String& HttpBody) { // Just copy the needed strings and destruct the C011_ConfigStruct as soon as possible - std::shared_ptr customConfig(new (std::nothrow) C011_ConfigStruct); + constexpr unsigned size = sizeof(C011_ConfigStruct); + void *ptr = special_calloc(1, size); + + if (ptr == nullptr) { + return false; + } + + std::shared_ptrcustomConfig(new (ptr) C011_ConfigStruct); if (!customConfig) { return false; @@ -232,9 +253,9 @@ bool load_C011_ConfigStruct(controllerIndex_t ControllerIndex, String& HttpMetho LoadCustomControllerSettings(ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C011_ConfigStruct)); customConfig->zero_last(); move_special(HttpMethod, String(customConfig->HttpMethod)); - move_special(HttpUri , String(customConfig->HttpUri)); + move_special(HttpUri, String(customConfig->HttpUri)); move_special(HttpHeader, String(customConfig->HttpHeader)); - move_special(HttpBody , String(customConfig->HttpBody)); + move_special(HttpBody, String(customConfig->HttpBody)); return true; } @@ -247,10 +268,19 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) addLog(LOG_LEVEL_ERROR, F("No C011_DelayHandler")); return false; } - //LoadTaskSettings(event->TaskIndex); // FIXME TD-er: This can probably be removed + + // LoadTaskSettings(event->TaskIndex); // FIXME TD-er: This can probably be removed + + constexpr unsigned size = sizeof(C011_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr == nullptr) { + return false; + } + // Add a new element to the queue with the minimal payload - std::unique_ptr element(new (std::nothrow) C011_queue_element(event)); + std::unique_ptrelement(new (ptr) C011_queue_element(event)); bool success = C011_DelayHandler->addToQueue(std::move(element)); if (success) { @@ -264,11 +294,11 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { addLogMove(LOG_LEVEL_ERROR, strformat( - F("C011 : %s %s %s %s"), - element.HttpMethod.c_str(), - element.uri.c_str(), - element.header.c_str(), - element.postStr.c_str())); + F("C011 : %s %s %s %s"), + element.HttpMethod.c_str(), + element.uri.c_str(), + element.header.c_str(), + element.postStr.c_str())); } C011_DelayHandler->sendQueue.pop_back(); return false; @@ -305,7 +335,7 @@ void DeleteNotNeededValues(String& s, uint8_t numberOfValuesWanted) { // yes, so just remove the tokens s.replace(startToken, EMPTY_STRING); - s.replace(endToken, EMPTY_STRING); + s.replace(endToken, EMPTY_STRING); } else { @@ -344,31 +374,34 @@ void ReplaceTokenByValue(String& s, struct EventStruct *event, bool sendBinary) // write?db=testdb&type=%1%%vname1%%/1%%2%;%vname2%%/2%%3%;%vname3%%/3%%4%;%vname4%%/4%&value=%1%%val1%%/1%%2%;%val2%%/2%%3%;%val3%%/3%%4%;%val4%%/4% // %1%%vname1%,Standort=%tskname% Wert=%val1%%/1%%2%%LF%%vname2%,Standort=%tskname% Wert=%val2%%/2%%3%%LF%%vname3%,Standort=%tskname% // Wert=%val3%%/3%%4%%LF%%vname4%,Standort=%tskname% Wert=%val4%%/4% - #ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP before parsing: ")); addLog(LOG_LEVEL_DEBUG_MORE, s); } - #endif + # endif // ifndef BUILD_NO_DEBUG const uint8_t valueCount = getValueCountForTask(event->TaskIndex); DeleteNotNeededValues(s, valueCount); - #ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after parsing: ")); addLog(LOG_LEVEL_DEBUG_MORE, s); } - #endif + # endif // ifndef BUILD_NO_DEBUG parseControllerVariables(s, event, !sendBinary); - #ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after replacements: ")); addLog(LOG_LEVEL_DEBUG_MORE, s); } - #endif + # endif // ifndef BUILD_NO_DEBUG } #endif // ifdef USES_C011 diff --git a/src/_C012.cpp b/src/_C012.cpp index 94d639cf6..e4053f668 100644 --- a/src/_C012.cpp +++ b/src/_C012.cpp @@ -59,7 +59,15 @@ bool CPlugin_012(CPlugin::Function function, struct EventStruct *event, String& // Collect the values at the same run, to make sure all are from the same sample uint8_t valueCount = getValueCountForTask(event->TaskIndex); - std::unique_ptr element(new (std::nothrow) C012_queue_element(event, valueCount)); + + constexpr unsigned size = sizeof(C012_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr == nullptr) { + break; + } + + std::unique_ptr element(new (ptr) C012_queue_element(event, valueCount)); for (uint8_t x = 0; x < valueCount; x++) { diff --git a/src/_C015.cpp b/src/_C015.cpp index 5269e4973..c0d8869e0 100644 --- a/src/_C015.cpp +++ b/src/_C015.cpp @@ -30,32 +30,35 @@ # define CPLUGIN_015_RECONNECT_INTERVAL 60000 # ifdef CPLUGIN_015_SSL - #ifdef ESP8266 - # include - #endif - #ifdef ESP32 - # include - #endif + # ifdef ESP8266 + # include + # endif + # ifdef ESP32 + # include + # endif # define CPLUGIN_NAME_015 "Blynk SSL" // Current official blynk server thumbprint # define CPLUGIN_015_DEFAULT_THUMBPRINT "FD C0 7D 8D 47 97 F7 E3 07 05 D3 4E E3 BB 8E 3D C0 EA BE 1C" # define C015_LOG_PREFIX "BL (ssl): " # else // ifdef CPLUGIN_015_SSL - #ifdef ESP8266 - # include - #endif - #ifdef ESP32 - # include - #endif + # ifdef ESP8266 + # include + # endif + # ifdef ESP32 + # include + # endif # define CPLUGIN_NAME_015 "Blynk" # define C015_LOG_PREFIX "BL: " # endif // ifdef CPLUGIN_015_SSL // Forward declarations: -boolean Blynk_send_c015(const String& value, int vPin, unsigned int clientTimeout); -boolean Blynk_keep_connection_c015(int controllerIndex, ControllerSettingsStruct& ControllerSettings); +boolean Blynk_send_c015(const String& value, + int vPin, + unsigned int clientTimeout); +boolean Blynk_keep_connection_c015(int controllerIndex, + ControllerSettingsStruct& ControllerSettings); static unsigned long _C015_LastConnectAttempt[CONTROLLER_MAX] = { 0, 0, 0 }; @@ -119,7 +122,7 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& # ifdef CPLUGIN_015_SSL case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: { - char thumbprint[60] = {0}; + char thumbprint[60] = { 0 }; LoadCustomControllerSettings(event->ControllerIndex, reinterpret_cast(&thumbprint), sizeof(thumbprint)); if (strlen(thumbprint) != 59) { @@ -141,6 +144,7 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& if (validProtocolIndex(ProtocolIndex)) { const cpluginID_t number = getCPluginID_from_ProtocolIndex(ProtocolIndex); + if ((i != event->ControllerIndex) && (number == 15) && Settings.ControllerEnabled[i]) { success = false; @@ -156,8 +160,8 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& _C015_LastConnectAttempt[event->ControllerIndex] = 0; # ifdef CPLUGIN_015_SSL - char thumbprint[60] = {0}; - String error = F("Specify server thumbprint with exactly 59 symbols string like " CPLUGIN_015_DEFAULT_THUMBPRINT); + char thumbprint[60] = { 0 }; + String error = F("Specify server thumbprint with exactly 59 symbols string like " CPLUGIN_015_DEFAULT_THUMBPRINT); if (!safe_strncpy(thumbprint, webArg("c015_thumbprint"), 60) || (strlen(thumbprint) != 59)) { addHtmlError(error); @@ -173,6 +177,7 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& if (C015_DelayHandler == nullptr) { break; } + if (C015_DelayHandler->queueFull(event->ControllerIndex)) { break; } @@ -184,8 +189,13 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& // Collect the values at the same run, to make sure all are from the same sample uint8_t valueCount = getValueCountForTask(event->TaskIndex); - std::unique_ptr element(new (std::nothrow) C015_queue_element(event, valueCount)); - success = C015_DelayHandler->addToQueue(std::move(element)); + constexpr unsigned size = sizeof(C015_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + std::unique_ptr element(new (ptr) C015_queue_element(event, valueCount)); + success = C015_DelayHandler->addToQueue(std::move(element)); + } if (success) { // Element was added. @@ -205,19 +215,20 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& free_string(formattedValue); } - const String valueName = Cache.getTaskDeviceValueName(event->TaskIndex, x); + const String valueName = Cache.getTaskDeviceValueName(event->TaskIndex, x); const String valueFullName = strformat( - F("%s.%s"), + F("%s.%s"), taskDeviceName.c_str(), valueName.c_str()); const String vPinNumberStr = valueName.substring(1, 4); - int vPinNumber = vPinNumberStr.toInt(); + int vPinNumber = vPinNumberStr.toInt(); if ((vPinNumber < 0) || (vPinNumber > 255)) { vPinNumber = -1; } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F(C015_LOG_PREFIX); + String log = F(C015_LOG_PREFIX); log += Blynk.connected() ? F("(online): ") : F("(offline): "); if ((vPinNumber > 0) && (vPinNumber < 256)) { @@ -228,9 +239,9 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& vPinNumber); } else { log += strformat( - F("error got vPin number for %s, got not valid value: %s"), - valueFullName.c_str(), - vPinNumberStr.c_str()); + F("error got vPin number for %s, got not valid value: %s"), + valueFullName.c_str(), + vPinNumberStr.c_str()); } addLogMove(LOG_LEVEL_INFO, log); } @@ -257,34 +268,35 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& // *INDENT-OFF* bool do_process_c015_delay_queue(cpluginID_t cpluginID, const Queue_element_base& element_base, ControllerSettingsStruct& ControllerSettings) { const C015_queue_element& element = static_cast(element_base); + // *INDENT-ON* - if (!Settings.ControllerEnabled[element._controller_idx]) { - // controller has been disabled. Answer true to flush queue. +if (!Settings.ControllerEnabled[element._controller_idx]) { + // controller has been disabled. Answer true to flush queue. + return true; +} + +if (!NetworkConnected()) { + return false; +} + +if (!Blynk_keep_connection_c015(element._controller_idx, ControllerSettings)) { + return false; +} + +while (element.vPin[element.valuesSent] == -1) { + // A non valid value, which we are not going to send. + // answer ok and skip real sending + if (element.checkDone(true)) { return true; } +} - if (!NetworkConnected()) { - return false; - } +bool sendSuccess = Blynk_send_c015( + element.txt[element.valuesSent], + element.vPin[element.valuesSent], + ControllerSettings.ClientTimeout); - if (!Blynk_keep_connection_c015(element._controller_idx, ControllerSettings)) { - return false; - } - - while (element.vPin[element.valuesSent] == -1) { - // A non valid value, which we are not going to send. - // answer ok and skip real sending - if (element.checkDone(true)) { - return true; - } - } - - bool sendSuccess = Blynk_send_c015( - element.txt[element.valuesSent], - element.vPin[element.valuesSent], - ControllerSettings.ClientTimeout); - - return element.checkDone(sendSuccess); +return element.checkDone(sendSuccess); } boolean Blynk_keep_connection_c015(int controllerIndex, ControllerSettingsStruct& ControllerSettings) { @@ -303,7 +315,7 @@ boolean Blynk_keep_connection_c015(int controllerIndex, ControllerSettingsStruct _C015_LastConnectAttempt[controllerIndex] = millis(); # ifdef CPLUGIN_015_SSL - char thumbprint[60] = {0}; + char thumbprint[60] = { 0 }; LoadCustomControllerSettings(controllerIndex, reinterpret_cast(&thumbprint), sizeof(thumbprint)); if (strlen(thumbprint) != 59) { @@ -312,6 +324,7 @@ boolean Blynk_keep_connection_c015(int controllerIndex, ControllerSettingsStruct addLog(LOG_LEVEL_INFO, thumbprint); } strcpy(thumbprint, CPLUGIN_015_DEFAULT_THUMBPRINT); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "using default one:")); addLog(LOG_LEVEL_INFO, thumbprint); @@ -421,9 +434,9 @@ String Command_Blynk_Set_c015(struct EventStruct *event, const char *Line) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, strformat( - F(C015_LOG_PREFIX "(online): send blynk pin v%d = %s"), - vPin, - data.c_str())); + F(C015_LOG_PREFIX "(online): send blynk pin v%d = %s"), + vPin, + data.c_str())); } Blynk.virtualWrite(vPin, data); @@ -449,16 +462,16 @@ BLYNK_WRITE_DEFAULT() { if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, strformat( - F(C015_LOG_PREFIX "server set v%u to %f"), - vPin, - pinValue)); + F(C015_LOG_PREFIX "server set v%u to %f"), + vPin, + pinValue)); } if (Settings.UseRules) { - eventQueue.addMove(strformat( - F("blynkv%d=%f"), - vPin, - pinValue)); + eventQueue.addMove(strformat( + F("blynkv%d=%f"), + vPin, + pinValue)); } } @@ -491,4 +504,4 @@ BLYNK_APP_DISCONNECTED() { // addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "app disconnected handler")); } -#endif // ifdef USES_C015 \ No newline at end of file +#endif // ifdef USES_C015 diff --git a/src/_C017.cpp b/src/_C017.cpp index fc8f5131d..be1180826 100644 --- a/src/_C017.cpp +++ b/src/_C017.cpp @@ -67,8 +67,13 @@ bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String& break; } - std::unique_ptr element(new (std::nothrow) C017_queue_element(event)); - success = C017_DelayHandler->addToQueue(std::move(element)); + constexpr unsigned size = sizeof(C017_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + std::unique_ptr element(new (ptr) C017_queue_element(event)); + success = C017_DelayHandler->addToQueue(std::move(element)); + } Scheduler.scheduleNextDelayQueue(SchedulerIntervalTimer_e::TIMER_C017_DELAY_QUEUE, C017_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/_C018.cpp b/src/_C018.cpp index 6642609dc..cd47ed974 100644 --- a/src/_C018.cpp +++ b/src/_C018.cpp @@ -127,7 +127,14 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& { // Keep this object in a small scope so we can destruct it as soon as possible again. - std::shared_ptr customConfig(new (std::nothrow) C018_ConfigStruct); + + constexpr unsigned size = sizeof(C018_ConfigStruct); + void *ptr = special_calloc(1, size); + + if (ptr == nullptr) { + break; + } + std::shared_ptr customConfig(new (ptr) C018_ConfigStruct); if (!customConfig) { break; @@ -140,7 +147,13 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& } case CPlugin::Function::CPLUGIN_WEBFORM_SAVE: { - std::shared_ptr customConfig(new (std::nothrow) C018_ConfigStruct); + constexpr unsigned size = sizeof(C018_ConfigStruct); + void *ptr = special_calloc(1, size); + + if (ptr == nullptr) { + break; + } + std::shared_ptr customConfig(new (ptr) C018_ConfigStruct); if (customConfig) { customConfig->webform_save(); @@ -186,7 +199,14 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& if (C018_data != nullptr) { { - std::unique_ptr element(new (std::nothrow) C018_queue_element(event, C018_data->getSampleSetCount(event->TaskIndex))); + constexpr unsigned size = sizeof(C018_queue_element); + void *ptr = special_calloc(1, size); + + if (ptr == nullptr) { + break; + } + + std::unique_ptr element(new (ptr) C018_queue_element(event, C018_data->getSampleSetCount(event->TaskIndex))); success = C018_DelayHandler->addToQueue(std::move(element)); Scheduler.scheduleNextDelayQueue(SchedulerIntervalTimer_e::TIMER_C018_DELAY_QUEUE, C018_DelayHandler->getNextScheduleTime()); @@ -274,11 +294,19 @@ bool C018_init(struct EventStruct *event) { C018_data = nullptr; } + { + constexpr unsigned size = sizeof(C018_data_struct); + void *ptr = special_calloc(1, size); - C018_data = new (std::nothrow) C018_data_struct; + if (ptr == nullptr) { + return false; + } - if (C018_data == nullptr) { - return false; + C018_data = new (ptr) C018_data_struct; + + if (C018_data == nullptr) { + return false; + } } { // Allocate ControllerSettings object in a scope, so we can destruct it as soon as possible. @@ -296,7 +324,13 @@ bool C018_init(struct EventStruct *event) { Port = ControllerSettings->Port; } - std::shared_ptr customConfig(new (std::nothrow) C018_ConfigStruct); + constexpr unsigned size = sizeof(C018_ConfigStruct); + void *ptr = special_calloc(1, size); + + if (ptr == nullptr) { + return false; + } + std::shared_ptr customConfig(new (ptr) C018_ConfigStruct); if (!customConfig) { return false; diff --git a/src/src/DataStructs/ESPeasyControllerCache.cpp b/src/src/DataStructs/ESPeasyControllerCache.cpp index 1654e40c7..bae5fbee6 100644 --- a/src/src/DataStructs/ESPeasyControllerCache.cpp +++ b/src/src/DataStructs/ESPeasyControllerCache.cpp @@ -2,6 +2,8 @@ #if FEATURE_RTC_CACHE_STORAGE +#include "../Helpers/Memory.h" + ControllerCache_struct::~ControllerCache_struct() { if (_RTC_cache_handler != nullptr) { delete _RTC_cache_handler; @@ -33,11 +35,12 @@ bool ControllerCache_struct::flush() { void ControllerCache_struct::init() { if (_RTC_cache_handler == nullptr) { - # ifdef USE_SECOND_HEAP -// HeapSelectIram ephemeral; - # endif // ifdef USE_SECOND_HEAP + constexpr unsigned size = sizeof(RTC_cache_handler_struct); + void *ptr = special_calloc(1, size); - _RTC_cache_handler = new (std::nothrow) RTC_cache_handler_struct; + if (ptr != nullptr) { + _RTC_cache_handler = new (ptr) RTC_cache_handler_struct; + } if (_RTC_cache_handler != nullptr) { _RTC_cache_handler->init(); } diff --git a/src/src/DataStructs/PluginTaskData_base.cpp b/src/src/DataStructs/PluginTaskData_base.cpp index 28428100f..99e8346f4 100644 --- a/src/src/DataStructs/PluginTaskData_base.cpp +++ b/src/src/DataStructs/PluginTaskData_base.cpp @@ -60,7 +60,12 @@ void PluginTaskData_base::initPluginStats(taskIndex_t taskIndex, taskVarIndex_t { if (taskVarIndex < VARS_PER_TASK) { if (_plugin_stats_array == nullptr) { - _plugin_stats_array = new (std::nothrow) PluginStats_array(); + constexpr unsigned size = sizeof(PluginStats_array); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + _plugin_stats_array = new (ptr) PluginStats_array(); + } } if (_plugin_stats_array != nullptr) { diff --git a/src/src/DataStructs/ProvisioningStruct.h b/src/src/DataStructs/ProvisioningStruct.h index f88a8b143..5d0589928 100644 --- a/src/src/DataStructs/ProvisioningStruct.h +++ b/src/src/DataStructs/ProvisioningStruct.h @@ -55,7 +55,6 @@ struct ProvisioningStruct }; typedef std::shared_ptr ProvisioningStruct_ptr_type; -//# define MakeProvisioningSettings(T) ProvisioningStruct_ptr_type T(new (std::nothrow) ProvisioningStruct()); #define MakeProvisioningSettings(T) void * calloc_ptr = special_calloc(1,sizeof(ProvisioningStruct)); ProvisioningStruct_ptr_type T(new (calloc_ptr) ProvisioningStruct()); diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index 242cbb245..d3a856e48 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -456,7 +456,7 @@ bool PluginCallForTask(taskIndex_t taskIndex, uint8_t Function, EventStruct *Tem void *ptr = special_calloc(1, size); if (ptr) { - initPluginTaskData(taskIndex, new (std::nothrow) _StatsOnly_data_struct()); + initPluginTaskData(taskIndex, new (ptr) _StatsOnly_data_struct()); } } } diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index b7eaa510f..32b2fac50 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -685,7 +685,12 @@ bool SSDP_begin() { _server = nullptr; } - _server = new (std::nothrow) UdpContext; + constexpr unsigned size = sizeof(UdpContext); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + _server = new (ptr) UdpContext; + } if (_server == nullptr) { return false; @@ -770,7 +775,16 @@ void SSDP_send(uint8_t method) { (uint16_t)((chipId >> 8) & 0xff), (uint16_t)chipId & 0xff); - char *buffer = new (std::nothrow) char[1460](); + char *buffer = nullptr; + # ifdef USE_SECOND_HEAP + { + HeapSelectIram ephemeral; + buffer = new (std::nothrow) char[1460](); + } + # endif // ifdef USE_SECOND_HEAP + if (buffer == nullptr) { + buffer = new (std::nothrow) char[1460](); + } if (buffer == nullptr) { return; } int len = snprintf(buffer, 1460, diff --git a/src/src/WebServer/UploadPage.cpp b/src/src/WebServer/UploadPage.cpp index bb2a2e869..74ae84ca7 100644 --- a/src/src/WebServer/UploadPage.cpp +++ b/src/src/WebServer/UploadPage.cpp @@ -174,7 +174,12 @@ void handleFileUploadBase(bool toSDcard) { # if FEATURE_TARSTREAM_SUPPORT if ((upload.filename.length() > 3) && upload.filename.substring(upload.filename.length() - 4).equalsIgnoreCase(F(".tar"))) { - tarStream = new (std::nothrow) TarStream(upload.filename, destination); + constexpr unsigned size = sizeof(TarStream); + void *ptr = special_calloc(1, size); + + if (ptr != nullptr) { + tarStream = new (ptr) TarStream(upload.filename, destination); + } # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { From 130d297fe55f2b25fe63aea3004e5a5a53448eb8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 20 Feb 2025 17:02:56 +0100 Subject: [PATCH 035/564] [ESP32S3] Fix bootloop on ESP32S3 with OPI PSRAM --- boards/esp32s3cdc-qio_opi-16M.json | 3 ++- boards/esp8266_160MHz_4M1M_board.json | 31 +++++++++++++++++++++++++++ platformio_esp32s3_envs.ini | 6 +++--- platformio_esp82xx_envs.ini | 2 ++ src/src/ESPEasyCore/ESPEasy_setup.cpp | 7 +++--- 5 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 boards/esp8266_160MHz_4M1M_board.json diff --git a/boards/esp32s3cdc-qio_opi-16M.json b/boards/esp32s3cdc-qio_opi-16M.json index 05b680768..964cb33ef 100644 --- a/boards/esp32s3cdc-qio_opi-16M.json +++ b/boards/esp32s3cdc-qio_opi-16M.json @@ -5,10 +5,11 @@ "memory_type": "qio_opi" }, "core": "esp32", - "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_16M -DESP32S3 -DARDUINO_USB_CDC_ON_BOOT=1", "f_cpu": "240000000L", "f_flash": "80000000L", + "boot": "opi", "flash_mode": "qio", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_16M -DESP32S3 -DARDUINO_USB_CDC_ON_BOOT=1", "hwids": [ [ "0x303A", diff --git a/boards/esp8266_160MHz_4M1M_board.json b/boards/esp8266_160MHz_4M1M_board.json new file mode 100644 index 000000000..01bddc562 --- /dev/null +++ b/boards/esp8266_160MHz_4M1M_board.json @@ -0,0 +1,31 @@ +{ + "build": { + "arduino": { + "ldscript": "eagle.flash.4m1m.ld" + }, + "core": "esp8266", + "extra_flags": "-DARDUINO_TASMOTA -DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01 -DESP8266_4M -DESP8266_4M1M", + "f_cpu": "120000000L", + "f_flash": "40000000L", + "flash_mode": "dout", + "mcu": "esp8266", + "variant": "generic" + }, + "connectivity": [ + "wifi" + ], + "frameworks": [ + "arduino" + ], + "name": "Espressif Generic ESP8266 ESPEasy 4M Flash 1M FS", + "upload": { + "maximum_ram_size": 81920, + "maximum_size": 1040316, + "require_upload_port": true, + "resetmethod": "nodemcu", + "speed": 115200 + }, + "url": "http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family", + "vendor": "Espressif" + } + \ No newline at end of file diff --git a/platformio_esp32s3_envs.ini b/platformio_esp32s3_envs.ini index 55019ee6e..abc5bb7a0 100644 --- a/platformio_esp32s3_envs.ini +++ b/platformio_esp32s3_envs.ini @@ -217,9 +217,9 @@ build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_BUILD_IR_EXTENDED -DCONFIG_PM_LIGHTSLEEP_RTC_OSC_CAL_INTERVAL=1 extra_scripts = ${esp32s3_common_LittleFS.extra_scripts} -custom_sdkconfig = - CONFIG_RMT_ISR_CACHE_SAFE=y - CONFIG_PM_LIGHTSLEEP_RTC_OSC_CAL_INTERVAL=1 +;custom_sdkconfig = +; CONFIG_RMT_ISR_CACHE_SAFE=y +; CONFIG_PM_LIGHTSLEEP_RTC_OSC_CAL_INTERVAL=1 diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index a51d074c3..3e8246a42 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -302,6 +302,7 @@ lib_ignore = ${normal.lib_ignore} [env:normal_beta_2ndheap_ESP8266_4M1M] extends = esp8266_4M1M +board = esp8266_160MHz_4M1M_board platform = ${normal_beta_2ndheap.platform} platform_packages = ${normal_beta_2ndheap.platform_packages} build_flags = ${normal_beta_2ndheap.build_flags} @@ -312,6 +313,7 @@ lib_ignore = ${normal_beta_2ndheap.lib_ignore} [env:normal_beta_2ndheap_ESP8266_4M1M_VCC] extends = esp8266_4M1M +board = esp8266_160MHz_4M1M_board platform = ${normal_beta_2ndheap.platform} platform_packages = ${normal_beta_2ndheap.platform_packages} build_flags = ${normal_beta_2ndheap.build_flags} diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 0f092f664..c956a8640 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -129,6 +129,10 @@ void sw_watchdog_callback(void *arg) \*********************************************************************************************/ void ESPEasy_setup() { +# ifdef BOARD_HAS_PSRAM + psramInit(); +# endif // ifdef BOARD_HAS_PSRAM + #if defined(ESP8266_DISABLE_EXTRA4K) || defined(USE_SECOND_HEAP) // disable_extra4k_at_link_time(); @@ -144,9 +148,6 @@ void ESPEasy_setup() DisableBrownout(); // Workaround possible weak LDO resulting in brownout detection during Wifi connection # endif // DISABLE_ESP32_BROWNOUT -# ifdef BOARD_HAS_PSRAM - psramInit(); -# endif // ifdef BOARD_HAS_PSRAM # if CONFIG_IDF_TARGET_ESP32 From bf300aa177448437f846d7606667e198e54fa560 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 20 Feb 2025 17:03:42 +0100 Subject: [PATCH 036/564] [WiFi] Fix not setting wifi as initialized too often --- src/src/DataStructs/WiFiEventData.cpp | 2 +- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index e8bf8be67..0790640f8 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -182,7 +182,7 @@ void WiFiEventData_t::setWiFiServicesInitialized() { if (/*!unprocessedWifiEvents() && */ WiFiConnected() && WiFiGotIP()) { #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WiFi : WiFi services initialized")); +// addLog(LOG_LEVEL_DEBUG, F("WiFi : WiFi services initialized")); #endif bitSet(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); wifiConnectInProgress = false; diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 085486bd2..3f19bf7b6 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -74,7 +74,9 @@ void handle_unprocessedNetworkEvents() // FIXME TD-er: Forcefully set the GotIP flag for now WiFiEventData.setWiFiGotIP(); } - WiFiEventData.setWiFiServicesInitialized(); + if (!WiFiEventData.WiFiServicesInitialized()) { + WiFiEventData.setWiFiServicesInitialized(); + } if (WiFiEventData.WiFiServicesInitialized() && processedSomething) { From c391ad8a3bfe4e780e7463e7ae270c1ceee2d0e8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 20 Feb 2025 17:04:42 +0100 Subject: [PATCH 037/564] [Memory] Improve memory usage on Strings and task data --- src/_P002_ADC.ino | 2 +- src/_P023_OLED.ino | 5 +++- src/_P036_FrameOLED.ino | 9 +------ src/_P037_MQTTImport.ino | 18 +++++++++++--- src/_P082_GPS.ino | 9 +------ src/_P092_DLbus.ino | 2 ++ src/_Plugin_Helper.h | 3 +++ src/src/Globals/Plugins.cpp | 18 +++----------- src/src/Helpers/ESPEasy_Storage.cpp | 6 ++++- src/src/Helpers/RulesHelper.cpp | 9 ++++--- src/src/Helpers/StringConverter.cpp | 29 +++++++++++----------- src/src/PluginStructs/P037_data_struct.cpp | 4 +++ 12 files changed, 59 insertions(+), 55 deletions(-) diff --git a/src/_P002_ADC.ino b/src/_P002_ADC.ino index 920213d51..56a572765 100644 --- a/src/_P002_ADC.ino +++ b/src/_P002_ADC.ino @@ -99,7 +99,7 @@ boolean Plugin_002(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { - initPluginTaskData(event->TaskIndex, new (std::nothrow) P002_data_struct()); + special_initPluginTaskData(event->TaskIndex, P002_data_struct); P002_data_struct *P002_data = static_cast(getPluginTaskData(event->TaskIndex)); diff --git a/src/_P023_OLED.ino b/src/_P023_OLED.ino index eae8fb7be..97cfda340 100644 --- a/src/_P023_OLED.ino +++ b/src/_P023_OLED.ino @@ -183,7 +183,10 @@ boolean Plugin_023(uint8_t function, struct EventStruct *event, String& string) font_spacing = static_cast(PCONFIG(4)); } - initPluginTaskData(event->TaskIndex, new (std::nothrow) P023_data_struct(PCONFIG(0), type, font_spacing, PCONFIG(2), PCONFIG(5))); + void * ptr = special_calloc(1, sizeof(P023_data_struct)); + if (ptr) { + initPluginTaskData(event->TaskIndex, new (ptr) P023_data_struct(PCONFIG(0), type, font_spacing, PCONFIG(2), PCONFIG(5))); + } P023_data_struct *P023_data = static_cast(getPluginTaskData(event->TaskIndex)); if (nullptr != P023_data) { diff --git a/src/_P036_FrameOLED.ino b/src/_P036_FrameOLED.ino index 0beba24f2..3ea0e4396 100644 --- a/src/_P036_FrameOLED.ino +++ b/src/_P036_FrameOLED.ino @@ -710,14 +710,7 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string) # ifdef P036_CHECK_HEAP P036_CheckHeap(F("_INIT: Entering")); # endif // P036_CHECK_HEAP - { - constexpr unsigned size = sizeof(P036_data_struct); - void *ptr = special_calloc(1, size); - - if (ptr != nullptr) { - initPluginTaskData(event->TaskIndex, new (ptr) P036_data_struct()); - } - } + special_initPluginTaskData(event->TaskIndex, P036_data_struct); # ifdef P036_CHECK_HEAP P036_CheckHeap(F("_INIT: Before (*P036_data = static_cast)")); # endif // P036_CHECK_HEAP diff --git a/src/_P037_MQTTImport.ino b/src/_P037_MQTTImport.ino index 3d5980a3d..8e47eb746 100644 --- a/src/_P037_MQTTImport.ino +++ b/src/_P037_MQTTImport.ino @@ -200,7 +200,12 @@ boolean Plugin_037(uint8_t function, struct EventStruct *event, String& string) # endif // if P037_REPLACE_BY_COMMA_SUPPORT { - P037_data_struct *P037_data = new (std::nothrow) P037_data_struct(event->TaskIndex); + P037_data_struct *P037_data = nullptr; + constexpr size_t size = sizeof(P037_data_struct); + void * ptr = special_calloc(1, size); + if (ptr) { + P037_data = new (ptr) P037_data_struct(event->TaskIndex); + } if (nullptr == P037_data) { return success; @@ -229,7 +234,11 @@ boolean Plugin_037(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_SAVE: { - P037_data_struct *P037_data = new (std::nothrow) P037_data_struct(event->TaskIndex); + P037_data_struct *P037_data = nullptr; + void * ptr = special_calloc(1, sizeof(P037_data_struct)); + if (ptr) { + P037_data = new (ptr) P037_data_struct(event->TaskIndex); + } if (nullptr == P037_data) { return success; @@ -271,7 +280,10 @@ boolean Plugin_037(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { - initPluginTaskData(event->TaskIndex, new (std::nothrow) P037_data_struct(event->TaskIndex)); + void * ptr = special_calloc(1, sizeof(P037_data_struct)); + if (ptr) { + initPluginTaskData(event->TaskIndex, new (ptr) P037_data_struct(event->TaskIndex)); + } P037_data_struct *P037_data = static_cast(getPluginTaskData(event->TaskIndex)); diff --git a/src/_P082_GPS.ino b/src/_P082_GPS.ino index 1df45035c..6237fc3b6 100644 --- a/src/_P082_GPS.ino +++ b/src/_P082_GPS.ino @@ -314,14 +314,7 @@ boolean Plugin_082(uint8_t function, struct EventStruct *event, String& string) const int16_t serial_tx = CONFIG_PIN2; const int16_t pps_pin = CONFIG_PIN3; - // Try to allocate in PSRAM or 2nd heap if possible - constexpr unsigned size = sizeof(P082_data_struct); - void *ptr = special_calloc(1, size); - if (!ptr) { - return success; - } - - initPluginTaskData(event->TaskIndex, new (ptr) P082_data_struct()); + special_initPluginTaskData(event->TaskIndex, P082_data_struct); P082_data_struct *P082_data = static_cast(getPluginTaskData(event->TaskIndex)); diff --git a/src/_P092_DLbus.ino b/src/_P092_DLbus.ino index 4a8a0e06e..63aa79e3f 100644 --- a/src/_P092_DLbus.ino +++ b/src/_P092_DLbus.ino @@ -411,6 +411,8 @@ boolean Plugin_092(uint8_t function, struct EventStruct *event, String& string) addLog(LOG_LEVEL_INFO, F("Create P092_data_struct ...")); # endif // ifndef P092_LIMIT_BUILD_SIZE + // FIXME TD-er: This is a really odd and overly complex way to handle this. + P092_data = new (std::nothrow) P092_data_struct(); initPluginTaskData(event->TaskIndex, P092_data); diff --git a/src/_Plugin_Helper.h b/src/_Plugin_Helper.h index 8acf57fac..d00edfd46 100644 --- a/src/_Plugin_Helper.h +++ b/src/_Plugin_Helper.h @@ -92,6 +92,9 @@ extern PluginTaskData_base *Plugin_task_data[TASKS_MAX]; +// Try to allocate in PSRAM or 2nd heap if possible +#define special_initPluginTaskData(I, T) void * ptr = special_calloc(1, sizeof(T)); if (ptr) { initPluginTaskData(I, new (ptr) T()); } + String PCONFIG_LABEL(int n); // ============================================== diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index d3a856e48..a20eec4bd 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -419,14 +419,7 @@ bool PluginCallForTask(taskIndex_t taskIndex, uint8_t Function, EventStruct *Tem LoadTaskSettings(taskIndex); if (ExtraTaskSettings.anyEnabledPluginStats()) { - - // Try to allocate in PSRAM or 2nd heap if possible - constexpr unsigned size = sizeof(_StatsOnly_data_struct); - void *ptr = special_calloc(1, size); - - if (ptr) { - initPluginTaskData(taskIndex, new (ptr) _StatsOnly_data_struct()); - } + special_initPluginTaskData(taskIndex, _StatsOnly_data_struct); } } } @@ -452,12 +445,7 @@ bool PluginCallForTask(taskIndex_t taskIndex, uint8_t Function, EventStruct *Tem if (ExtraTaskSettings.anyEnabledPluginStats()) { // Try to allocate in PSRAM or 2nd heap if possible - constexpr unsigned size = sizeof(_StatsOnly_data_struct); - void *ptr = special_calloc(1, size); - - if (ptr) { - initPluginTaskData(taskIndex, new (ptr) _StatsOnly_data_struct()); - } + special_initPluginTaskData(taskIndex, _StatsOnly_data_struct); } } } @@ -931,7 +919,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) LoadTaskSettings(event->TaskIndex); if (ExtraTaskSettings.anyEnabledPluginStats()) { - initPluginTaskData(event->TaskIndex, new (std::nothrow) _StatsOnly_data_struct()); + special_initPluginTaskData(event->TaskIndex, _StatsOnly_data_struct); } } } diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index b4010bda3..4d93ca8a7 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -1061,7 +1061,11 @@ String LoadStringArray(SettingsType::Enum settingsType, // Specific string length, so we have to set the next string position. nextStringPos += maxStringLength; } - move_special(strings[stringCount], std::move(tmpString)); + if (!tmpString.isEmpty()) { + move_special(strings[stringCount], std::move(tmpString)); + } else { + free_string(strings[stringCount]); + } // Do not allocate tmpString on 2nd heap as byte access on 2nd heap is much slower // We're appending per byte, so better prefer speed for short lived objects diff --git a/src/src/Helpers/RulesHelper.cpp b/src/src/Helpers/RulesHelper.cpp index bb969823e..41b2ce958 100644 --- a/src/src/Helpers/RulesHelper.cpp +++ b/src/src/Helpers/RulesHelper.cpp @@ -293,7 +293,7 @@ String RulesHelperClass::readLn(const String& filename, while (f.available()) { if (addChar(char(f.read()), tmpStr, firstNonSpaceRead)) { - lines.push_back(move_special(std::move(tmpStr))); + lines.push_back(std::move(move_special(std::move(tmpStr)))); ++readPos; firstNonSpaceRead = false; @@ -304,7 +304,7 @@ String RulesHelperClass::readLn(const String& filename, if (tmpStr.length() > 0) { rules_strip_trailing_comments(tmpStr); check_rules_line_user_errors(tmpStr); - lines.push_back(move_special(std::move(tmpStr))); + lines.push_back(std::move(move_special(std::move(tmpStr)))); tmpStr.clear(); } # ifndef BUILD_NO_DEBUG @@ -404,7 +404,10 @@ String RulesHelperClass::readLn(const String& filename, } rules_strip_trailing_comments(line); check_rules_line_user_errors(line); - return line; + + // Make sure there is no left-over reserved data + // and allocate it to the appropriate memory area. + return move_special(std::move(line)); } #endif // ifdef CACHE_RULES_IN_MEMORY diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index a6ea8b0db..4e8ea1f4f 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -76,23 +76,24 @@ bool equals(const String& str, const char& c) { } void move_special(String& dest, String&& source) { - #ifdef USE_SECOND_HEAP // Only try to store larger strings here as those tend to be kept for a longer period. - if ((source.length() >= 64) && mmu_is_dram(&(source[0]))) { + if ((source.length() >= 64) +#ifdef USE_SECOND_HEAP + && mmu_is_dram(&(source[0])) +#endif + ) { // The string was not allocated on the 2nd heap, so copy instead of move - HeapSelectIram ephemeral; - if (dest.reserve(source.length())) { - dest = source; - free_string(source); + if (!reserve_special(dest, source.length())) { + // Could not allocate on 2nd heap or PSRAM, so just move existing string + dest = std::move(source); return; } - // Could not allocate on 2nd heap, so just move existing string } - #endif // ifdef USE_SECOND_HEAP - dest = std::move(source); - #ifdef ESP32 - reserve_special(dest, dest.length()); - #endif + + // Try to avoid keeping reserved memory on empty strings + // So just copy the data, not move + dest = source; + free_string(source); } String move_special(String&& source) { @@ -734,9 +735,7 @@ String stripWrappingChar(const String& text, char wrappingChar) { const unsigned int length = text.length(); if ((length >= 2) && stringWrappedWithChar(text, wrappingChar)) { - String dest; - move_special(dest,text.substring(1, length - 1)); - return dest; + return move_special(text.substring(1, length - 1)); } return text; } diff --git a/src/src/PluginStructs/P037_data_struct.cpp b/src/src/PluginStructs/P037_data_struct.cpp index 2722d0ddf..269216848 100644 --- a/src/src/PluginStructs/P037_data_struct.cpp +++ b/src/src/PluginStructs/P037_data_struct.cpp @@ -30,7 +30,11 @@ P037_data_struct::~P037_data_struct() { * Load the settings from file */ bool P037_data_struct::loadSettings() { + if (_taskIndex < TASKS_MAX) { + # ifdef USE_SECOND_HEAP +// HeapSelectIram ephemeral; + #endif size_t offset = 0; LoadCustomTaskSettings(_taskIndex, mqttTopics, VARS_PER_TASK, 41, offset); From 78c2c04ae6611edcb2bfab0766e4d7945bc56ccc Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 21 Feb 2025 16:33:46 +0100 Subject: [PATCH 038/564] [Memory] Fix crashes on ESP32-S2 with 8M PSRAM --- src/src/Helpers/Memory.cpp | 9 ++++++++- src/src/Helpers/StringConverter.cpp | 13 ++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/src/Helpers/Memory.cpp b/src/src/Helpers/Memory.cpp index 2096a86e2..3fd4a35ad 100644 --- a/src/src/Helpers/Memory.cpp +++ b/src/src/Helpers/Memory.cpp @@ -233,7 +233,11 @@ bool String_reserve_special(String& str, size_t size) { class PSRAM_String : public String { public: PSRAM_String(size_t size) : String() { - init(); + sso.isSSO = 0; // setSSO(false); + ptr.buff = nullptr; // setBuffer(nullptr); + ptr.cap = 0; // setCapacity(0); + ptr.len = 0; // setLen(0); + if (size != 0 && size > capacity() && UsePSRAM()) { size_t newSize = (size + 16) & (~0xf); void *ptr = special_calloc(1, newSize); @@ -249,6 +253,9 @@ class PSRAM_String : public String { bool String_reserve_special(String& str, size_t size) { + if (size == 0) { + return true; + } if (!UsePSRAM()) { return str.reserve(size); } diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index 4e8ea1f4f..4afdd7362 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -110,12 +110,15 @@ bool reserve_special(String& str, size_t size) { void free_string(String& str) { // This is a call specifically tailored to what is done in: // void String::move(String &rhs) - #if defined(ESP32) || defined(CORE_POST_3_0_0) - str.clear(); // Prevent any unneeded copying - String tmp(std::move(str)); - #else + +#if defined(ESP32) || defined(CORE_POST_3_0_0) + // Use current implementation of String::copy as this + // invalidates and thus deallocates current buffer + str = (const char*)nullptr; + str = String(); // No idea why this is needed, without it, some ESP32's may bootloop +#else str = String(); - #endif +#endif } /********************************************************************************************\ From c58ac90c8c90da8aba8a5d77514261b2f2217496 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 10 Mar 2025 12:18:44 +0100 Subject: [PATCH 039/564] [WiFi] Fix setting dynamic WiFi TX power --- src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 3 +++ src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp | 7 +++---- tools/pio/pre_custom_esp32.py | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index 3c1d10172..cb1ea480d 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -177,6 +177,9 @@ void ESPEasyWiFi_t::loop() } else { // Else mark last timestamp seen as connected _last_seen_connected.setNow(); + # if FEATURE_SET_WIFI_TX_PWR + SetWiFiTXpower(); + # endif } break; } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index 919f57745..03b48ac1f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -271,10 +271,9 @@ void doSetWiFiTXpower(float& dBm) { int8_t power = dBm * 4; - if (esp_wifi_set_max_tx_power(power) == ESP_OK) { - if (esp_wifi_get_max_tx_power(&power) == ESP_OK) { - dBm = static_cast(power) / 4.0f; - } + esp_wifi_set_max_tx_power(power); + if (esp_wifi_get_max_tx_power(&power) == ESP_OK) { + dBm = static_cast(power) / 4.0f; } } diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index 6c642b9b3..c43244b73 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -57,7 +57,7 @@ else: "-DUSES_P131", # NeoPixelMatrix "-DUSES_P146", # Cache Reader - "-DUSES_P123", # AS3935 Lightning Detector + "-DUSES_P169", # AS3935 Lightning Detector "-DUSES_C016", # Cache Controller "-DUSES_C018", # TTN/RN2483 From 3d62e87fab045ba7d09b87301d5fef73bcdeb2c3 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 10 Mar 2025 18:01:51 +0100 Subject: [PATCH 040/564] [Cleanup] Optimize parsing system variables --- src/src/Commands/Tasks.cpp | 4 -- src/src/ESPEasyCore/Controller.cpp | 6 ++- src/src/Helpers/Networking.cpp | 1 + src/src/Helpers/Scheduler_TaskDeviceTimer.cpp | 3 -- src/src/Helpers/StringConverter.cpp | 5 +- src/src/Helpers/SystemVariables.cpp | 47 ++++++++++++++++--- src/src/Helpers/SystemVariables.h | 4 +- src/src/Helpers/_CPlugin_Helper_mqtt.cpp | 22 ++++++++- src/src/Helpers/_CPlugin_Helper_mqtt.h | 2 +- 9 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/src/Commands/Tasks.cpp b/src/src/Commands/Tasks.cpp index 21782e3a5..1ac31846c 100644 --- a/src/src/Commands/Tasks.cpp +++ b/src/src/Commands/Tasks.cpp @@ -266,11 +266,9 @@ const __FlashStringHelper * Command_Task_ValueSetAndRun(struct EventStruct *even const __FlashStringHelper * returnvalue = taskValueSet(event, Line, taskIndex, success); if (success) { - START_TIMER; struct EventStruct TempEvent(taskIndex); TempEvent.Source = event->Source; SensorSendTask(&TempEvent); - STOP_TIMER(SENSOR_SEND_TASK); return return_command_success_flashstr(); } @@ -315,11 +313,9 @@ const __FlashStringHelper * Command_Task_Run(struct EventStruct *event, const ch validUIntFromString(par3, unixTime); } - START_TIMER; struct EventStruct TempEvent(taskIndex); TempEvent.Source = event->Source; SensorSendTask(&TempEvent, unixTime); - STOP_TIMER(SENSOR_SEND_TASK); return return_command_success_flashstr(); } diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index f8aa316e2..313053677 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -1006,7 +1006,9 @@ void SensorSendTask(struct EventStruct *event, unsigned long timestampUnixTime) void SensorSendTask(struct EventStruct *event, unsigned long timestampUnixTime, unsigned long lasttimer) { - if (!validTaskIndex(event->TaskIndex)) { return; } + if (!validTaskIndex(event->TaskIndex)) { + return; + } // FIXME TD-er: Should a 'disabled' task be rescheduled? // If not, then it should be rescheduled after the check to see if it is enabled. @@ -1018,6 +1020,7 @@ void SensorSendTask(struct EventStruct *event, unsigned long timestampUnixTime, if (Settings.TaskDeviceEnabled[event->TaskIndex]) { + START_TIMER; const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(event->TaskIndex); if (!validDeviceIndex(DeviceIndex)) { return; } @@ -1032,5 +1035,6 @@ void SensorSendTask(struct EventStruct *event, unsigned long timestampUnixTime, if (PluginCall(PLUGIN_READ, &TempEvent, dummy)) { sendData(&TempEvent); } + STOP_TIMER(SENSOR_SEND_TASK); } } diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 32b2fac50..feaa17a57 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -1043,6 +1043,7 @@ bool useStaticIP() { // Check connection. Maximum timeout 500 msec. bool NetworkConnected(uint32_t timeout_ms) { + if (NetworkConnected()) return true; #ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/Scheduler_TaskDeviceTimer.cpp b/src/src/Helpers/Scheduler_TaskDeviceTimer.cpp index dcf3747f9..6f1aa9864 100644 --- a/src/src/Helpers/Scheduler_TaskDeviceTimer.cpp +++ b/src/src/Helpers/Scheduler_TaskDeviceTimer.cpp @@ -85,9 +85,6 @@ void ESPEasy_Scheduler::process_task_device_timer(SchedulerTimerID timerID, unsi const taskIndex_t task_index = tmp->getTaskIndex(); if (!validTaskIndex(task_index)) { return; } - START_TIMER; struct EventStruct TempEvent(task_index); - SensorSendTask(&TempEvent, 0, lasttimer); - STOP_TIMER(SENSOR_SEND_TASK); } diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index 4afdd7362..0b8af08ec 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -545,10 +545,7 @@ String get_formatted_Controller_number(cpluginID_t cpluginID) { if (!validCPluginID(cpluginID)) { return F("C---"); } - String result; - result += 'C'; - result += formatIntLeadingZeroes(cpluginID, 3); - return result; + return strformat(F("C%03d"), cpluginID); } String get_formatted_Plugin_number(pluginID_t pluginID) diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index c5db8bf9a..bfb488bf6 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -230,7 +230,7 @@ String SystemVariables::getSystemVariable(SystemVariables::Enum enumval) { case SYSYEAR_0: case SYSYEAR: intvalue = node_time.year(); break; case SYSYEARS: return timeReplacement_leadZero(node_time.year() % 100); - case SYS_MONTH_0: return timeReplacement_leadZero(node_time.month()); + case SYSMONTH_0: return timeReplacement_leadZero(node_time.month()); case S_CR: return F("\\r"); case S_LF: return F("\\n"); case UNIXDAY: intvalue = node_time.getUnixTime() / 86400; break; @@ -407,7 +407,7 @@ SystemVariables::Enum SystemVariables::nextReplacementEnum(const String& str, Sy return Enum::UNKNOWN; } - nextTested = SystemVariables::startIndex_beginWith(str[percent_pos + 1]); + nextTested = SystemVariables::startIndex_beginWith(str.c_str() + percent_pos + 1); } while (Enum::UNKNOWN == nextTested); if (last_percent_pos < percent_pos) { @@ -435,7 +435,7 @@ SystemVariables::Enum SystemVariables::nextReplacementEnum(const String& str, Sy return Enum::UNKNOWN; } last_percent_pos = percent_pos; - return SystemVariables::startIndex_beginWith(str[percent_pos + 1]); + return SystemVariables::startIndex_beginWith(str.c_str() + percent_pos + 1); } const __FlashStringHelper *fstr_sysvar = SystemVariables::toFlashString(nextTested); @@ -474,9 +474,44 @@ String SystemVariables::toString(Enum enumval) return wrap_String(SystemVariables::toFlashString(enumval), '%'); } -SystemVariables::Enum SystemVariables::startIndex_beginWith(char beginchar) +SystemVariables::Enum SystemVariables::startIndex_beginWith(const char* beginchar) { - switch (tolower(beginchar)) + if (beginchar == nullptr || *beginchar == '\0') + { + return Enum::UNKNOWN; + } + + const char ch = tolower(*beginchar); + if (ch == 's') { + // Lots of system variables start with "%sys" + const char sys_str[] = {'s', 'y', 's'}; + bool found = true; + const char* cur = beginchar; + for (size_t i = 0; found && i < NR_ELEMENTS(sys_str); ++i, ++cur) { + if (tolower(*cur) != sys_str[i]) { + found = false; + } + } + if (found) { + const char next_ch = tolower(*cur); + if (next_ch != '\0') { + switch (next_ch) { + case 'b': return Enum::SYSBUILD_DATE; + case 'd': return Enum::SYSDAY; + case 'h': return Enum::SYSHEAP; + case 'l': return Enum::SYSLOAD; + case 'm': return Enum::SYSMIN; + case 'n': return Enum::SYSNAME; + case 's': return Enum::SYSSEC; + case 't': return Enum::SYSTIME; + case 'w': return Enum::SYSWEEKDAY; + case 'y': return Enum::SYSYEAR; + } + } + } + } + + switch (ch) { case 'b': return Enum::BOARD_NAME; case 'c': return Enum::CLIENTIP; @@ -584,6 +619,7 @@ const __FlashStringHelper * SystemVariables::toFlashString(SystemVariables::Enum case Enum::SYSMIN_0: return F("sysmin_0"); case Enum::SYSMONTH: return F("sysmonth"); case Enum::SYSMONTH_S: return F("sysmonth_s"); + case Enum::SYSMONTH_0: return F("sysmonth_0"); case Enum::SYSNAME: return F("sysname"); case Enum::SYSSEC: return F("syssec"); case Enum::SYSSEC_0: return F("syssec_0"); @@ -605,7 +641,6 @@ const __FlashStringHelper * SystemVariables::toFlashString(SystemVariables::Enum case Enum::SYSYEAR: return F("sysyear"); case Enum::SYSYEARS: return F("sysyears"); case Enum::SYSYEAR_0: return F("sysyear_0"); - case Enum::SYS_MONTH_0: return F("sysmonth_0"); case Enum::UNIT_sysvar: return F("unit"); #if FEATURE_ZEROFILLED_UNITNUMBER case Enum::UNIT_0_sysvar: return F("unit_0"); diff --git a/src/src/Helpers/SystemVariables.h b/src/src/Helpers/SystemVariables.h index d061f7a88..c2cc302a1 100644 --- a/src/src/Helpers/SystemVariables.h +++ b/src/src/Helpers/SystemVariables.h @@ -84,6 +84,7 @@ public: SYSMIN_0, SYSMONTH, SYSMONTH_S, + SYSMONTH_0, SYSNAME, SYSSEC, SYSSEC_0, @@ -105,7 +106,6 @@ public: SYSYEAR, SYSYEARS, SYSYEAR_0, - SYS_MONTH_0, UNIT_sysvar, #if FEATURE_ZEROFILLED_UNITNUMBER UNIT_0_sysvar, @@ -132,7 +132,7 @@ public: static String toString(SystemVariables::Enum enumval); - static SystemVariables::Enum startIndex_beginWith(char beginchar); + static SystemVariables::Enum startIndex_beginWith(const char* beginchar); static const __FlashStringHelper* toFlashString(SystemVariables::Enum enumval); static String getSystemVariable(SystemVariables::Enum enumval); diff --git a/src/src/Helpers/_CPlugin_Helper_mqtt.cpp b/src/src/Helpers/_CPlugin_Helper_mqtt.cpp index 318523672..f48a5f402 100644 --- a/src/src/Helpers/_CPlugin_Helper_mqtt.cpp +++ b/src/src/Helpers/_CPlugin_Helper_mqtt.cpp @@ -4,6 +4,9 @@ #if FEATURE_MQTT # include "../Commands/ExecuteCommand.h" +#include "../Helpers/SystemVariables.h" + + /*************************************************************************************** * Parse MQTT topic for /cmd and /set ending to handle commands or TaskValueSet * Special C014 case: handleCmd = false and handleSet is true, so *only* pluginID 33 & 86 are accepted @@ -186,11 +189,22 @@ void MQTT_execute_command(String& cmd, } bool MQTT_protocol_send(EventStruct *event, - String pubname, + String pubname, bool retainFlag) { bool success = false; + + // Check for %valname% const bool contains_valname = pubname.indexOf(F("%valname%")) != -1; + // Small speed-up as there are lots of system variables starting with "%sys" and this is used in quite a lot of MQTT topics. + if (pubname.indexOf(F("%sysname%")) != -1) { + pubname.replace(F("%sysname%"), SystemVariables::getSystemVariable(SystemVariables::SYSNAME)); + } + // %tskname% will not change per taskvalue, so replace now + if (pubname.indexOf(F("%tskname%")) != -1) { + pubname.replace(F("%tskname%"), getTaskDeviceName(event->TaskIndex)); + } + const uint8_t valueCount = getValueCountForTask(event->TaskIndex); for (uint8_t x = 0; x < valueCount; ++x) { @@ -214,7 +228,11 @@ bool MQTT_protocol_send(EventStruct *event, # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - addLog(LOG_LEVEL_DEBUG, strformat(F("MQTT C%03d : %s %s"), event->ControllerIndex, tmppubname.c_str(), value.c_str())); + addLog(LOG_LEVEL_DEBUG, strformat( + F("MQTT %s : %s %s"), + get_formatted_Controller_number(getCPluginID_from_ControllerIndex(event->ControllerIndex)).c_str(), + tmppubname.c_str(), + value.c_str())); } # endif // ifndef BUILD_NO_DEBUG diff --git a/src/src/Helpers/_CPlugin_Helper_mqtt.h b/src/src/Helpers/_CPlugin_Helper_mqtt.h index f4f056385..51222a2b6 100644 --- a/src/src/Helpers/_CPlugin_Helper_mqtt.h +++ b/src/src/Helpers/_CPlugin_Helper_mqtt.h @@ -11,7 +11,7 @@ bool MQTT_handle_topic_commands(struct EventStruct *event, void MQTT_execute_command(String& command, bool tryRemoteConfig = false); bool MQTT_protocol_send(EventStruct *event, - String pubname, + String pubname, bool retainFlag); #endif // if FEATURE_MQTT From c969cd00121adcb3b33a8aef9d83e7b37a0fdd02 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 10 Mar 2025 21:26:53 +0100 Subject: [PATCH 041/564] [Rules] Fix broken math parsing As reported on the [forum](https://www.letscontrolit.com/forum/viewtopic.php?p=73218#p73218) --- src/src/Helpers/Rules_calculate.cpp | 2 +- src/src/Helpers/SystemVariables.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/src/Helpers/Rules_calculate.cpp b/src/src/Helpers/Rules_calculate.cpp index 9d48102f0..dfa39a4c3 100644 --- a/src/src/Helpers/Rules_calculate.cpp +++ b/src/src/Helpers/Rules_calculate.cpp @@ -572,7 +572,7 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL } } } - // else + else { *TokenPos = sc; ++TokenPos; diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index bfb488bf6..b832281ae 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -53,11 +53,10 @@ String getReplacementString(const String& format, const String& s) { #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - String log = F("ReplacementString SunTime: "); - log += R; - log += F(" offset: "); - log += ESPEasy_time::getSecOffset(R); - addLogMove(LOG_LEVEL_DEBUG, log); + addLogMove(LOG_LEVEL_DEBUG, strformat( + F("ReplacementString SunTime: %s offset: %d"), + R.c_str(), + ESPEasy_time::getSecOffset(R))); } #endif // ifndef BUILD_NO_DEBUG return R; From 99ec939cefe975f75bb83adffc091be42131e20d Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 11 Mar 2025 22:20:33 +0100 Subject: [PATCH 042/564] [WiFi] Fix (re-)connecting after WiFi connection lost --- src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp | 38 +++++++++++++++---- .../ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 17 ++++++++- .../ESPEasyWiFi_state_machine_ESP32.cpp | 2 +- .../ESPEasyWifi_abstracted_ESP32.cpp | 3 ++ src/src/Helpers/WiFi_AP_CandidatesList.cpp | 14 +++---- 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp index becbf000c..168c9eab7 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp @@ -91,8 +91,30 @@ void NetworkConnectRelaxed() { WiFiConnectRelaxed(); } -bool NetworkConnected() { + +// Forward declaration to access internal function in NetworkInterface.cpp +// as we don't have a public function in NetworkInterface to access the +// Network_Interface_ID +NetworkInterface *getNetifByID(Network_Interface_ID id); + +NetworkInterface * getDefaultNonAP_interface() +{ auto network_if = Network.getDefaultInterface(); + if (network_if != nullptr) { + auto ap_if = getNetifByID(ESP_NETIF_ID_AP); + if (ap_if != nullptr) { + if (network_if->netif() == ap_if->netif()) { + // This is the AP interface, which we do not want + return nullptr; + } + } + } + return network_if; +} + + +bool NetworkConnected() { + auto network_if = getDefaultNonAP_interface(); if (network_if == nullptr) { return false; @@ -101,7 +123,7 @@ bool NetworkConnected() { } IPAddress NetworkLocalIP() { - auto network_if = Network.getDefaultInterface(); + auto network_if = getDefaultNonAP_interface(); if (network_if == nullptr) { return IPAddress(); @@ -110,7 +132,7 @@ IPAddress NetworkLocalIP() { } IPAddress NetworkSubnetMask() { - auto network_if = Network.getDefaultInterface(); + auto network_if = getDefaultNonAP_interface(); if (network_if == nullptr) { return IPAddress(); @@ -119,7 +141,7 @@ IPAddress NetworkSubnetMask() { } IPAddress NetworkGatewayIP() { - auto network_if = Network.getDefaultInterface(); + auto network_if = getDefaultNonAP_interface(); if (network_if == nullptr) { return IPAddress(); @@ -128,7 +150,7 @@ IPAddress NetworkGatewayIP() { } IPAddress NetworkDnsIP(uint8_t dns_no) { - auto network_if = Network.getDefaultInterface(); + auto network_if = getDefaultNonAP_interface(); if (network_if == nullptr) { return IPAddress(); @@ -139,7 +161,7 @@ IPAddress NetworkDnsIP(uint8_t dns_no) { #if FEATURE_USE_IPV6 IPAddress NetworkLocalIP6() { - auto network_if = Network.getDefaultInterface(); + auto network_if = getDefaultNonAP_interface(); if (network_if == nullptr) { return IN6ADDR_ANY; @@ -148,7 +170,7 @@ IPAddress NetworkLocalIP6() { } IPAddress NetworkGlobalIP6() { - auto network_if = Network.getDefaultInterface(); + auto network_if = getDefaultNonAP_interface(); if (network_if == nullptr) { return IN6ADDR_ANY; @@ -158,7 +180,7 @@ IPAddress NetworkGlobalIP6() { IP6Addresses_t NetworkAllIPv6() { IP6Addresses_t addresses; - auto network_if = Network.getDefaultInterface(); + auto network_if = getDefaultNonAP_interface(); if (network_if != nullptr) { esp_ip6_addr_t esp_ip6_addr[LWIP_IPV6_NUM_ADDRESSES]{}; diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index cb1ea480d..f0a96c286 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -88,7 +88,11 @@ void ESPEasyWiFi_t::loop() // Do we have candidate to connect to ? if (WiFi_AP_Candidates.hasCandidates()) { setState(WiFiState_e::STA_Connecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); - } else if (WiFi_AP_Candidates.scanComplete() == 0) { + } else if (WiFi_AP_Candidates.scanComplete() == 0 +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) + || WiFi.status() == WL_STOPPED +#endif + ) { if (WifiIsAP(WiFi.getMode())) { // TODO TD-er: Must check if any client is connected. // If not, then we can disable AP mode and switch to WiFiState_e::STA_Scanning @@ -128,7 +132,7 @@ void ESPEasyWiFi_t::loop() } else if (scanCompleteStatus == -2) { // WIFI_SCAN_FAILED addLog(LOG_LEVEL_ERROR, F("WiFi : Scan failed")); WiFi.scanDelete(); - setState(WiFiState_e::WiFiOFF, 100); + setState(WiFiState_e::WiFiOFF, 1000); WiFiEventData.processedScanDone = true; } @@ -211,6 +215,11 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { setAPinternal(false); setAP(false); } + if (_state == WiFiState_e::STA_AP_Scanning || + _state == WiFiState_e::STA_Scanning) + { + WiFi.scanDelete(); + } if (timeout == 0) { @@ -257,6 +266,10 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { } break; case WiFiState_e::STA_Connected: + #ifdef ESP32 + // FIXME TD-er: Must move to ESP32-specific cpp file + WiFi.STA.setDefault(); + #endif _last_seen_connected.setNow(); _state_timeout.clear(); break; diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp index 1e2066d3a..4bb82251f 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp @@ -45,7 +45,7 @@ STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() const switch (WiFi.status()) { case WL_CONNECTED: - return STA_connected_state::Connected; + break; // return STA_connected_state::Connected; case WL_NO_SSID_AVAIL: return STA_connected_state::Error_Not_Found; diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index 03b48ac1f..b67da31ca 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -141,6 +141,9 @@ bool setWifiMode(WiFiMode_t new_mode) // esp_wifi_set_ps(WIFI_PS_MAX_MODEM); delay(1); + #ifdef ESP32 + WiFi.STA.end(); + #endif } else { /* if (cur_mode == WIFI_OFF) { diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 5c3dbe156..48f8daeb7 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -251,6 +251,11 @@ void WiFi_AP_CandidatesList::markCurrentConnectionStable() { } int8_t WiFi_AP_CandidatesList::scanComplete() const { + const int8_t scanCompleteStatus = WiFi.scanComplete(); + if (scanCompleteStatus <= 0) { + return scanCompleteStatus; + } + size_t found = 0; for (auto scan = scanned.begin(); scan != scanned.end(); ++scan) { if (!scan->expired()) { @@ -262,14 +267,7 @@ int8_t WiFi_AP_CandidatesList::scanComplete() const { ++found; } } - if (found > 0) { - return found; - } - const int8_t scanCompleteStatus = WiFi.scanComplete(); - if (scanCompleteStatus <= 0) { - return scanCompleteStatus; - } - return 0; + return found; } bool WiFi_AP_CandidatesList::SettingsIndexMatchCustomCredentials(uint8_t index) From 3d2b15ff8d46a24f8a89375f62c04bdc4549458b Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 11 Mar 2025 22:59:02 +0100 Subject: [PATCH 043/564] [WiFi] Fix build error on ESP8266 --- src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index f0a96c286..984591422 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -89,10 +89,12 @@ void ESPEasyWiFi_t::loop() if (WiFi_AP_Candidates.hasCandidates()) { setState(WiFiState_e::STA_Connecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); } else if (WiFi_AP_Candidates.scanComplete() == 0 -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) - || WiFi.status() == WL_STOPPED -#endif - ) { +# ifdef ESP32 +# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 2) + || WiFi.status() == WL_STOPPED +# endif +# endif // ifdef ESP32 + ) { if (WifiIsAP(WiFi.getMode())) { // TODO TD-er: Must check if any client is connected. // If not, then we can disable AP mode and switch to WiFiState_e::STA_Scanning From 48d3b7d02da54e9b1ecf010e90a06cb88cca9629 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 11 Mar 2025 23:01:27 +0100 Subject: [PATCH 044/564] [Cleanup] Uncrustify WiFi/Network code --- src/src/DataStructs/WiFi_AP_Candidate.cpp | 96 ++++++++++--------- src/src/DataStructs/WiFi_AP_Candidate.h | 15 +-- src/src/DataTypes/WiFiConnectionProtocol.cpp | 17 ++-- src/src/DataTypes/WiFi_State.h | 2 +- src/src/ESPEasyCore/ESPEasyNetwork.h | 63 ++++++------ src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp | 14 +-- .../ESPEasyCore/ESPEasyNetwork_ESP8266.cpp | 6 +- .../ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp | 8 +- .../ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 10 +- .../ESPEasyWiFi_state_machine_ESP32.cpp | 1 - .../ESPEasyWiFi_state_machine_ESP8266.cpp | 6 +- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 82 ++++++++-------- .../ESPEasyCore/ESPEasyWifi_abstracted.cpp | 2 +- src/src/ESPEasyCore/ESPEasyWifi_abstracted.h | 8 +- .../ESPEasyWifi_abstracted_ESP32.cpp | 35 +++---- .../ESPEasyWifi_abstracted_ESP8266.cpp | 22 ++--- 16 files changed, 206 insertions(+), 181 deletions(-) diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index a286b8cea..bab5c2fa0 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -16,53 +16,53 @@ # include #endif // if defined(ESP32) -#define WIFI_AP_CANDIDATE_MAX_AGE 300000 // 5 minutes in msec +#define WIFI_AP_CANDIDATE_MAX_AGE 300000 // 5 minutes in msec WiFi_AP_Candidate::WiFi_AP_Candidate() : #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 -country({ - .cc = "01", - .schan = 1, - .nchan = 14, - .policy = WIFI_COUNTRY_POLICY_AUTO, + country({ + .cc = "01", + .schan = 1, + .nchan = 14, + .policy = WIFI_COUNTRY_POLICY_AUTO, }), -#endif -#endif +# endif // if ESP_IDF_VERSION_MAJOR >= 5 +#endif // ifdef ESP32 last_seen(0), rssi(0), channel(0), index(0), enc_type(0) { _allBits = 0u; } WiFi_AP_Candidate::WiFi_AP_Candidate(const WiFi_AP_Candidate& other) -: ssid(other.ssid), - last_seen(other.last_seen), + : ssid(other.ssid), + last_seen(other.last_seen), bssid(other.bssid), - rssi(other.rssi), - channel(other.channel), - index(other.index), + rssi(other.rssi), + channel(other.channel), + index(other.index), enc_type(other.enc_type) { _allBits = other._allBits; #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 memcpy(&this->country, &other.country, sizeof(wifi_country_t)); - #endif - #endif + # endif + #endif // ifdef ESP32 } WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t index_c, const String& ssid_c) : #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 -country({ - .cc = "01", - .schan = 1, - .nchan = 14, - .policy = WIFI_COUNTRY_POLICY_AUTO, + country({ + .cc = "01", + .schan = 1, + .nchan = 14, + .policy = WIFI_COUNTRY_POLICY_AUTO, }), -#endif -#endif +# endif // if ESP_IDF_VERSION_MAJOR >= 5 +#endif // ifdef ESP32 last_seen(0), rssi(0), channel(0), index(index_c), enc_type(0) { _allBits = 0u; @@ -121,7 +121,7 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { // FIXME TD-er: Maybe also add other info like 2nd channel, ftm and phy_lr support? # if ESP_IDF_VERSION_MAJOR >= 5 memcpy(&country, &(it->country), sizeof(wifi_country_t)); -#endif +# endif } #endif // ifdef ESP32 last_seen = millis(); @@ -135,15 +135,21 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(const bss_info& ap) : phy_11b(ap.phy_11b), phy_11g(ap.phy_11g), phy_11n(ap.phy_11n), wps(ap.wps) { - _allBits = 0u; + _allBits = 0u; last_seen = millis(); - switch (ap.authmode) { - case AUTH_OPEN: enc_type = ENC_TYPE_NONE; break; - case AUTH_WEP: enc_type = ENC_TYPE_WEP; break; - case AUTH_WPA_PSK: enc_type = ENC_TYPE_TKIP; break; - case AUTH_WPA2_PSK: enc_type = ENC_TYPE_CCMP; break; - case AUTH_WPA_WPA2_PSK: enc_type = ENC_TYPE_AUTO; break; + switch (ap.authmode) + { + case AUTH_OPEN: enc_type = ENC_TYPE_NONE; + break; + case AUTH_WEP: enc_type = ENC_TYPE_WEP; + break; + case AUTH_WPA_PSK: enc_type = ENC_TYPE_TKIP; + break; + case AUTH_WPA2_PSK: enc_type = ENC_TYPE_CCMP; + break; + case AUTH_WPA_WPA2_PSK: enc_type = ENC_TYPE_AUTO; + break; case AUTH_MAX: break; } @@ -185,19 +191,19 @@ bool WiFi_AP_Candidate::operator<(const WiFi_AP_Candidate& other) const { WiFi_AP_Candidate& WiFi_AP_Candidate::operator=(const WiFi_AP_Candidate& other) { - ssid = other.ssid; + ssid = other.ssid; last_seen = other.last_seen; - bssid = other.bssid; - rssi = other.rssi; - channel = other.channel; - index = other.index; - enc_type = other.enc_type; - _allBits = other._allBits; + bssid = other.bssid; + rssi = other.rssi; + channel = other.channel; + index = other.index; + enc_type = other.enc_type; + _allBits = other._allBits; #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 memcpy(&this->country, &other.country, sizeof(wifi_country_t)); - #endif - #endif + # endif + #endif // ifdef ESP32 return *this; } @@ -256,10 +262,13 @@ String WiFi_AP_Candidate::toString(const String& separator) const { #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 + // Country code string - if (country.cc[0] != '\0' && country.cc[1] != '\0') { + if ((country.cc[0] != '\0') && (country.cc[1] != '\0')) { result += strformat(F(" '%c%c'"), country.cc[0], country.cc[1]); - switch (country.cc[2]) { + + switch (country.cc[2]) + { case 'O': // Outdoor case 'I': // Indoor case 'X': // "non-country" @@ -267,11 +276,12 @@ String WiFi_AP_Candidate::toString(const String& separator) const { break; } } + if (country.nchan > 0) { result += strformat(F(" ch: %d..%d"), country.schan, country.schan + country.nchan - 1); } -#endif -#endif +# endif // if ESP_IDF_VERSION_MAJOR >= 5 +#endif // ifdef ESP32 if (phy_known()) { String phy_str; diff --git a/src/src/DataStructs/WiFi_AP_Candidate.h b/src/src/DataStructs/WiFi_AP_Candidate.h index 970afe8f6..8dda8a5ab 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.h +++ b/src/src/DataStructs/WiFi_AP_Candidate.h @@ -68,22 +68,22 @@ struct WiFi_AP_Candidate { return bits.phy_11b || bits.phy_11g || bits.phy_11n; } - String ssid; + String ssid; // String key; #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 wifi_country_t country; - #endif - #endif + # endif + #endif // ifdef ESP32 unsigned long last_seen = 0u; MAC_address bssid; int8_t rssi{}; uint8_t channel{}; - uint8_t index{}; // Index of the matching credentials - uint8_t enc_type{}; // Encryption used (e.g. WPA2) + uint8_t index{}; // Index of the matching credentials + uint8_t enc_type{}; // Encryption used (e.g. WPA2) union { struct { uint16_t isHidden : 1; // Hidden SSID @@ -99,9 +99,12 @@ struct WiFi_AP_Candidate { uint16_t ftm_initiator : 1; uint16_t unused : 5; - } bits; + + } bits; uint16_t _allBits; + }; + }; #endif // ifndef DATASTRUCTS_WIFI_AP_CANDIDATES_H diff --git a/src/src/DataTypes/WiFiConnectionProtocol.cpp b/src/src/DataTypes/WiFiConnectionProtocol.cpp index c5a72595f..909973dd1 100644 --- a/src/src/DataTypes/WiFiConnectionProtocol.cpp +++ b/src/src/DataTypes/WiFiConnectionProtocol.cpp @@ -1,7 +1,8 @@ #include "../DataTypes/WiFiConnectionProtocol.h" -const __FlashStringHelper * toString(WiFiConnectionProtocol proto) { - switch (proto) { +const __FlashStringHelper* toString(WiFiConnectionProtocol proto) { + switch (proto) + { case WiFiConnectionProtocol::WiFi_Protocol_11b: return F("802.11b"); case WiFiConnectionProtocol::WiFi_Protocol_11g: @@ -9,7 +10,7 @@ const __FlashStringHelper * toString(WiFiConnectionProtocol proto) { #ifdef ESP8266 case WiFiConnectionProtocol::WiFi_Protocol_11n: return F("802.11n"); -#endif +#endif // ifdef ESP8266 #ifdef ESP32 case WiFiConnectionProtocol::WiFi_Protocol_HT20: return F("802.11n (HT20)"); @@ -17,18 +18,18 @@ const __FlashStringHelper * toString(WiFiConnectionProtocol proto) { return F("802.11n (HT40)"); case WiFiConnectionProtocol::WiFi_Protocol_HE20: return F("802.11ax (HE20)"); -#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) +# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) case WiFiConnectionProtocol::WiFi_Protocol_11a: return F("802.11a"); case WiFiConnectionProtocol::WiFi_Protocol_VHT20: return F("802.11ac (VHT20)"); -#endif +# endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) case WiFiConnectionProtocol::WiFi_Protocol_LR: return F("802.11lr"); -#endif +#endif // ifdef ESP32 case WiFiConnectionProtocol::Unknown: - break;; + break; } return F("-"); -} \ No newline at end of file +} diff --git a/src/src/DataTypes/WiFi_State.h b/src/src/DataTypes/WiFi_State.h index 794ecdc17..dade05ef6 100644 --- a/src/src/DataTypes/WiFi_State.h +++ b/src/src/DataTypes/WiFi_State.h @@ -85,7 +85,7 @@ enum class WiFiState_e }; -const __FlashStringHelper * toString(WiFiState_e state); +const __FlashStringHelper* toString(WiFiState_e state); } // namespace wifi diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.h b/src/src/ESPEasyCore/ESPEasyNetwork.h index 436fab792..9b1cea915 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.h +++ b/src/src/ESPEasyCore/ESPEasyNetwork.h @@ -8,50 +8,53 @@ #include #if FEATURE_USE_IPV6 -#include -//typedef uint8_t ip6_addr_type_t; -//typedef std::vector> IP6Addresses_t; +# include + +// typedef uint8_t ip6_addr_type_t; +// typedef std::vector> IP6Addresses_t; typedef std::vector IP6Addresses_t; -#endif +#endif // if FEATURE_USE_IPV6 -void setNetworkMedium(NetworkMedium_t medium); +void setNetworkMedium(NetworkMedium_t medium); -void NetworkConnectRelaxed(); -bool NetworkConnected(); -IPAddress NetworkLocalIP(); -IPAddress NetworkSubnetMask(); -IPAddress NetworkGatewayIP(); -IPAddress NetworkDnsIP (uint8_t dns_no); +void NetworkConnectRelaxed(); +bool NetworkConnected(); +IPAddress NetworkLocalIP(); +IPAddress NetworkSubnetMask(); +IPAddress NetworkGatewayIP(); +IPAddress NetworkDnsIP(uint8_t dns_no); #if FEATURE_USE_IPV6 -IPAddress NetworkLocalIP6(); -IPAddress NetworkGlobalIP6(); +IPAddress NetworkLocalIP6(); +IPAddress NetworkGlobalIP6(); IP6Addresses_t NetworkAllIPv6(); -bool IPv6_link_local_from_MAC(const MAC_address& mac, IPAddress &ipv6); -bool is_IPv6_link_local_from_MAC(const MAC_address& mac); +bool IPv6_link_local_from_MAC(const MAC_address& mac, + IPAddress & ipv6); +bool is_IPv6_link_local_from_MAC(const MAC_address& mac); // Assume we're in the same subnet, thus use our own IPv6 global address -bool IPv6_global_from_MAC(const MAC_address& mac, IPAddress &ipv6); -bool is_IPv6_global_from_MAC(const MAC_address& mac); +bool IPv6_global_from_MAC(const MAC_address& mac, + IPAddress & ipv6); +bool is_IPv6_global_from_MAC(const MAC_address& mac); -#endif -MAC_address NetworkMacAddress(); -String NetworkGetHostNameFromSettings(bool force_add_unitnr = false); -String NetworkGetHostname(); -String NetworkCreateRFCCompliantHostname(bool force_add_unitnr = false); +#endif // if FEATURE_USE_IPV6 +MAC_address NetworkMacAddress(); +String NetworkGetHostNameFromSettings(bool force_add_unitnr = false); +String NetworkGetHostname(); +String NetworkCreateRFCCompliantHostname(bool force_add_unitnr = false); #if FEATURE_WIFI -MAC_address WifiSoftAPmacAddress(); -MAC_address WifiSTAmacAddress(); -#endif +MAC_address WifiSoftAPmacAddress(); +MAC_address WifiSTAmacAddress(); +#endif // if FEATURE_WIFI -void CheckRunningServices(); +void CheckRunningServices(); #if FEATURE_ETHERNET -bool EthFullDuplex(); -bool EthLinkUp(); -uint8_t EthLinkSpeed(); +bool EthFullDuplex(); +bool EthLinkUp(); +uint8_t EthLinkSpeed(); #endif // if FEATURE_ETHERNET -#endif \ No newline at end of file +#endif // ifndef ESPEASY_NETWORK_H diff --git a/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp index 168c9eab7..38186bdb9 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp @@ -91,17 +91,18 @@ void NetworkConnectRelaxed() { WiFiConnectRelaxed(); } - // Forward declaration to access internal function in NetworkInterface.cpp -// as we don't have a public function in NetworkInterface to access the +// as we don't have a public function in NetworkInterface to access the // Network_Interface_ID -NetworkInterface *getNetifByID(Network_Interface_ID id); +NetworkInterface* getNetifByID(Network_Interface_ID id); -NetworkInterface * getDefaultNonAP_interface() +NetworkInterface* getDefaultNonAP_interface() { auto network_if = Network.getDefaultInterface(); + if (network_if != nullptr) { auto ap_if = getNetifByID(ESP_NETIF_ID_AP); + if (ap_if != nullptr) { if (network_if->netif() == ap_if->netif()) { // This is the AP interface, which we do not want @@ -112,7 +113,6 @@ NetworkInterface * getDefaultNonAP_interface() return network_if; } - bool NetworkConnected() { auto network_if = getDefaultNonAP_interface(); @@ -273,6 +273,7 @@ String NetworkGetHostname() { } #if FEATURE_WIFI + MAC_address WifiSoftAPmacAddress() { MAC_address mac; @@ -286,7 +287,8 @@ MAC_address WifiSTAmacAddress() { WiFi.macAddress(mac.mac); return mac; } -#endif + +#endif // if FEATURE_WIFI #if FEATURE_ETHERNET diff --git a/src/src/ESPEasyCore/ESPEasyNetwork_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyNetwork_ESP8266.cpp index f31ea0c89..d6d89e306 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork_ESP8266.cpp @@ -66,9 +66,10 @@ MAC_address NetworkMacAddress() { return mac; } -String NetworkGetHostname() { return String(WiFi.hostname()); } +String NetworkGetHostname() { return String(WiFi.hostname()); } #if FEATURE_WIFI + MAC_address WifiSoftAPmacAddress() { MAC_address mac; @@ -82,6 +83,7 @@ MAC_address WifiSTAmacAddress() { WiFi.macAddress(mac.mac); return mac; } -#endif + +#endif // if FEATURE_WIFI #endif // ifdef ESP8266 diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp index c3720b8bc..52535cfef 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent_ESP32.cpp @@ -131,10 +131,10 @@ void WiFiEvent(WiFiEvent_t event_id, arduino_event_info_t info) { { // FIXME TD-er: Must also check event->esp_netif to see which interface got this event. ignoreDisconnectEvent = false; - ip_event_got_ip_t *event = static_cast(&info.got_ip); - const IPAddress ip(event->ip_info.ip.addr); - const IPAddress netmask(event->ip_info.netmask.addr); - const IPAddress gw(event->ip_info.gw.addr); + ip_event_got_ip_t *event = static_cast(&info.got_ip); + const IPAddress ip(event->ip_info.ip.addr); + const IPAddress netmask(event->ip_info.netmask.addr); + const IPAddress gw(event->ip_info.gw.addr); WiFiEventData.markGotIP(ip, netmask, gw); break; } diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index 984591422..68e4e8461 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -217,8 +217,9 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { setAPinternal(false); setAP(false); } - if (_state == WiFiState_e::STA_AP_Scanning || - _state == WiFiState_e::STA_Scanning) + + if ((_state == WiFiState_e::STA_AP_Scanning) || + (_state == WiFiState_e::STA_Scanning)) { WiFi.scanDelete(); } @@ -268,10 +269,11 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) { } break; case WiFiState_e::STA_Connected: - #ifdef ESP32 + # ifdef ESP32 + // FIXME TD-er: Must move to ESP32-specific cpp file WiFi.STA.setDefault(); - #endif + # endif // ifdef ESP32 _last_seen_connected.setNow(); _state_timeout.clear(); break; diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp index 4bb82251f..0f38b7432 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP32.cpp @@ -19,7 +19,6 @@ namespace ESPEasy { namespace net { namespace wifi { - IPAddress ESPEasyWiFi_t::getIP() const { if (WiFi.STA.hasIP()) { diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp index ff8de9bb8..373afebbe 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine_ESP8266.cpp @@ -3,27 +3,27 @@ #ifdef ESP8266 # if FEATURE_WIFI -#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" +# include "../ESPEasyCore/ESPEasyWifi_abstracted.h" namespace ESPEasy { namespace net { namespace wifi { - IPAddress ESPEasyWiFi_t::getIP() const { IPAddress ip = WiFi.localIP(); + if (ip.isSet()) { return ip; } ip = WiFi.softAPIP(); + if (ip.isSet()) { return ip; } return IPAddress(); } - STA_connected_state ESPEasyWiFi_t::getSTA_connected_state() const { // Perform check on SDK function, see: https://github.com/esp8266/Arduino/issues/7432 diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 3f19bf7b6..f45ac4e4f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -52,46 +52,48 @@ void handle_unprocessedNetworkEvents() if (active_network_medium == NetworkMedium_t::WIFI) { bool processedSomething = false; - if (!WiFiEventData.processedConnect) { + + if (!WiFiEventData.processedConnect) { #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); + addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); #endif // ifndef BUILD_NO_DEBUG - processConnect(); - processedSomething = true; + processConnect(); + processedSomething = true; -// FIXME TD-er: Forcefully set the connected flag for now - WiFiEventData.setWiFiConnected(); - } + // FIXME TD-er: Forcefully set the connected flag for now + WiFiEventData.setWiFiConnected(); + } - if (!WiFiEventData.processedGotIP) { + if (!WiFiEventData.processedGotIP) { #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processGotIP()")); + addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processGotIP()")); #endif // ifndef BUILD_NO_DEBUG - processGotIP(); + processGotIP(); - processedSomething = true; + processedSomething = true; - // FIXME TD-er: Forcefully set the GotIP flag for now - WiFiEventData.setWiFiGotIP(); - } - if (!WiFiEventData.WiFiServicesInitialized()) { - WiFiEventData.setWiFiServicesInitialized(); - } + // FIXME TD-er: Forcefully set the GotIP flag for now + WiFiEventData.setWiFiGotIP(); + } - if (WiFiEventData.WiFiServicesInitialized() && processedSomething) { + if (!WiFiEventData.WiFiServicesInitialized()) { + WiFiEventData.setWiFiServicesInitialized(); + } - // #ifdef ESP32 - setWebserverRunning(false); - delay(1); - setWebserverRunning(true); - delay(1); + if (WiFiEventData.WiFiServicesInitialized() && processedSomething) { - /* - #else - CheckRunningServices(); - #endif - */ - } + // #ifdef ESP32 + setWebserverRunning(false); + delay(1); + setWebserverRunning(true); + delay(1); + + /* + #else + CheckRunningServices(); + #endif + */ + } } #if FEATURE_ETHERNET @@ -107,9 +109,7 @@ void handle_unprocessedNetworkEvents() // Functions to process the data gathered from the events. // These functions are called from Setup() or Loop() and thus may call delay() or yield() // ******************************************************************************** -void processDisconnect() { - -} +void processDisconnect() {} void processConnect() { if (WiFiEventData.processedConnect) { return; } @@ -122,7 +122,7 @@ void processConnect() { */ WiFiEventData.processedConnect = true; - /* + /* if (WiFi.status() == WL_DISCONNECTED) { // Apparently not really connected return; @@ -215,10 +215,10 @@ void processGotIP() { if (!useStaticIP()) { #ifdef ESP8266 - if (!ip.isSet()) + if (!ip.isSet()) #else // ifdef ESP8266 - if ((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0)) + if ((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0)) #endif // ifdef ESP8266 { return; @@ -317,9 +317,9 @@ void processDisconnectAPmode() { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log(strformat( - F("AP Mode: Client disconnected: %s Connected devices: %u"), - WiFiEventData.lastMacDisconnectedAPmode.toString().c_str(), - WiFi.softAPgetStationNum())); + F("AP Mode: Client disconnected: %s Connected devices: %u"), + WiFiEventData.lastMacDisconnectedAPmode.toString().c_str(), + WiFi.softAPgetStationNum())); addLogMove(LOG_LEVEL_INFO, log); } #endif // ifndef BUILD_NO_DEBUG @@ -336,9 +336,9 @@ void processConnectAPmode() { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log(strformat( - F("AP Mode: Client connected: %s Connected devices: %u"), - WiFiEventData.lastMacConnectedAPmode.toString().c_str(), - WiFi.softAPgetStationNum())); + F("AP Mode: Client connected: %s Connected devices: %u"), + WiFiEventData.lastMacConnectedAPmode.toString().c_str(), + WiFi.softAPgetStationNum())); addLogMove(LOG_LEVEL_INFO, log); } #endif // ifndef BUILD_NO_DEBUG diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp index 155e4f63e..3937d3eb2 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp @@ -26,7 +26,7 @@ const __FlashStringHelper* getWifiModeString(WiFiMode_t wifimode) return F("Unknown"); } -bool WiFiConnected() { return ESPEasyWiFi.connected(); } +bool WiFiConnected() { return ESPEasyWiFi.connected(); } bool setSTA(bool enable) { return setSTA_AP(enable, WifiIsAP(WiFi.getMode())); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h index 3fd86c22b..a8a45d4f6 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h @@ -26,14 +26,14 @@ namespace wifi { // Call before starting WiFi -bool WiFi_pre_setup(); +bool WiFi_pre_setup(); // Call before setting WiFi into STA mode -bool WiFi_pre_STA_setup(); +bool WiFi_pre_STA_setup(); -bool WiFiConnected(); +bool WiFiConnected(); -void WiFiDisconnect(); +void WiFiDisconnect(); // ******************************************************************************** // Manage Wifi Modes diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index b67da31ca..18b3cd7fc 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -46,7 +46,7 @@ bool WiFi_pre_STA_setup() } void WiFiDisconnect() { -// removeWiFiEventHandler(); + // removeWiFiEventHandler(); WiFi.disconnect(); delay(100); { @@ -141,15 +141,16 @@ bool setWifiMode(WiFiMode_t new_mode) // esp_wifi_set_ps(WIFI_PS_MAX_MODEM); delay(1); - #ifdef ESP32 + # ifdef ESP32 WiFi.STA.end(); - #endif + # endif } else { -/* - if (cur_mode == WIFI_OFF) { - registerWiFiEventHandler(); - } -*/ + /* + if (cur_mode == WIFI_OFF) { + registerWiFiEventHandler(); + } + */ + // Only set power mode when AP is not enabled // When AP is enabled, the sleep mode is already set to WIFI_NONE_SLEEP if (!WifiIsAP(new_mode)) { @@ -275,6 +276,7 @@ void doSetWiFiTXpower(float& dBm) int8_t power = dBm * 4; esp_wifi_set_max_tx_power(power); + if (esp_wifi_get_max_tx_power(&power) == ESP_OK) { dBm = static_cast(power) / 4.0f; } @@ -358,15 +360,16 @@ void setWiFiDefaultPowerMode() void setWiFiCountryPolicyManual() { -/* wifi_country_t config = { - .cc = "01", - .schan = 1, - .nchan = 14, - .policy = WIFI_COUNTRY_POLICY_MANUAL, - }; + /* wifi_country_t config = { + .cc = "01", + .schan = 1, + .nchan = 14, + .policy = WIFI_COUNTRY_POLICY_MANUAL, + }; - esp_wifi_set_country(&config); - */} + esp_wifi_set_country(&config); + */ +} } // namespace wifi } // namespace net diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp index 361441c1a..349c04831 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp @@ -18,13 +18,13 @@ namespace wifi { bool WiFi_pre_setup() { registerWiFiEventHandler(); - setSTA_AP(false, false); + setSTA_AP(false, false); delay(100); return true; } bool WiFi_pre_STA_setup() { - if (! setSTA(true)) { return false; } + if (!setSTA(true)) { return false; } // Assign to 2 separate bools to make sure both are executed. const bool autoConnect = WiFi.setAutoConnect(false); @@ -39,7 +39,7 @@ bool WiFi_pre_STA_setup() { void WiFiDisconnect() { // Only call disconnect when STA is active - if ( WifiIsSTA(WiFi.getMode())) { + if (WifiIsSTA(WiFi.getMode())) { wifi_station_disconnect(); } station_config conf{}; @@ -49,9 +49,9 @@ void WiFiDisconnect() { ETS_UART_INTR_ENABLE(); } -bool WifiIsAP(WiFiMode_t wifimode) { return (wifimode == WIFI_AP) || (wifimode == WIFI_AP_STA); } +bool WifiIsAP(WiFiMode_t wifimode) { return (wifimode == WIFI_AP) || (wifimode == WIFI_AP_STA); } -bool WifiIsSTA(WiFiMode_t wifimode) { return (wifimode & WIFI_STA) != 0; } +bool WifiIsSTA(WiFiMode_t wifimode) { return (wifimode & WIFI_STA) != 0; } bool setWifiMode(WiFiMode_t new_mode) { @@ -71,12 +71,12 @@ bool setWifiMode(WiFiMode_t new_mode) processing_wifi_mode = static_cast(new_mode); - if (! WifiIsSTA(new_mode)) { - // calls lwIP's dhcp_stop(), - // safe to call even if not started - // See: https://github.com/esp8266/Arduino/pull/5703/files - wifi_station_dhcpc_stop(); - } + if (!WifiIsSTA(new_mode)) { + // calls lwIP's dhcp_stop(), + // safe to call even if not started + // See: https://github.com/esp8266/Arduino/pull/5703/files + wifi_station_dhcpc_stop(); + } if (new_mode != WIFI_OFF) { // See: https://github.com/esp8266/Arduino/issues/6172#issuecomment-500457407 From f6bd2c40dc5d06c428f6faadd855455ce0e15091 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 12 Mar 2025 17:05:09 +0100 Subject: [PATCH 045/564] [WiFi] Fix reconnecting + WiFi scan --- .../ESPEasyCore/ESPEasyWiFi_state_machine.cpp | 11 ++++++-- .../ESPEasyCore/ESPEasyWiFi_state_machine.h | 26 +++++++++---------- src/src/ESPEasyCore/ESPEasyWifi.cpp | 1 + src/src/Helpers/WiFi_AP_CandidatesList.cpp | 10 ++++++- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp index 68e4e8461..c9ae0b751 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.cpp @@ -85,6 +85,13 @@ void ESPEasyWiFi_t::loop() case WiFiState_e::IdleWaiting: if (_state_timeout.timeReached()) { + // This is where we decide what to do next: + // - Reconnect + // - Scan + // + + + // Do we have candidate to connect to ? if (WiFi_AP_Candidates.hasCandidates()) { setState(WiFiState_e::STA_Connecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT); @@ -121,8 +128,8 @@ void ESPEasyWiFi_t::loop() case WiFiState_e::STA_Scanning: case WiFiState_e::STA_AP_Scanning: { + // -1 if scan not finished auto scanCompleteStatus = WiFi.scanComplete(); - if (scanCompleteStatus >= 0) { WiFi_AP_Candidates.load_knownCredentials(); # if !FEATURE_ESP8266_DIRECT_WIFI_SCAN @@ -343,7 +350,7 @@ bool ESPEasyWiFi_t::connectSTA() addLogMove(LOG_LEVEL_INFO, strformat( F("WIFI : Connecting %s attempt #%u"), candidate.toString().c_str(), - _connect_attempt)); + WiFiEventData.wifi_connect_attempt)); } WiFiEventData.markWiFiBegin(); diff --git a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h index f6656cb5f..d64780348 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h +++ b/src/src/ESPEasyCore/ESPEasyWiFi_state_machine.h @@ -73,36 +73,36 @@ private: STA_connected_state getSTA_connected_state() const; - WiFi_AP_Candidate _active_sta; - WiFi_AP_Candidate _AP_conf; +// WiFi_AP_Candidate _active_sta; +// WiFi_AP_Candidate _AP_conf; - String _last_ssid; - MAC_address _last_bssid; - uint8_t _last_channel = 0; +// String _last_ssid; +// MAC_address _last_bssid; +// uint8_t _last_channel = 0; WiFiState_e _state = WiFiState_e::Disabled; LongTermTimer _last_state_change; LongTermTimer _state_timeout; LongTermTimer _last_seen_connected; - LongTermTimer _AP_start_timestamp; +// LongTermTimer _AP_start_timestamp; - uint32_t _connect_attempt = 0; +// uint32_t _connect_attempt = 0; - uint32_t _nrReconnects = 0; +// uint32_t _nrReconnects = 0; bool _callbackError = false; // Special modes for initial setup or re-configuration of a node via serial port/IMPROV - bool _improvActive = false; - bool _setupActive = false; +// bool _improvActive = false; +// bool _setupActive = false; // WiFi settings => Move to separate class/struct bool _disabledAtBoot = false; - bool _passiveScan = false; - bool _includeHiddenSSID = false; - float _TX_power = -1; +// bool _passiveScan = false; +// bool _includeHiddenSSID = false; +// float _TX_power = -1; // Manual IP settings // IP diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 78ae3b9e6..9a018c3a7 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -379,6 +379,7 @@ void WifiScan(bool async, uint8_t channel) { # ifdef ESP32 const bool passive = Settings.PassiveWiFiScan(); const uint32_t max_ms_per_chan = 120; + WiFi.setScanTimeout(14 * max_ms_per_chan * 2); WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan /*, channel */); # endif // ifdef ESP32 diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 48f8daeb7..8195defd4 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -137,6 +137,7 @@ void WiFi_AP_CandidatesList::after_process_WiFiscan() { scanned_new.sort(); scanned_new.unique(); _mustLoadCredentials = true; + load_knownCredentials(); WiFi.scanDelete(); attemptsLeft = WiFi_CONNECT_ATTEMPTS; } @@ -252,7 +253,8 @@ void WiFi_AP_CandidatesList::markCurrentConnectionStable() { int8_t WiFi_AP_CandidatesList::scanComplete() const { const int8_t scanCompleteStatus = WiFi.scanComplete(); - if (scanCompleteStatus <= 0) { + if (scanCompleteStatus == -1) { + // Still scanning return scanCompleteStatus; } @@ -267,6 +269,12 @@ int8_t WiFi_AP_CandidatesList::scanComplete() const { ++found; } } + if (found == 0) { + if (scanCompleteStatus == -2) { + // Not triggered + return scanCompleteStatus; + } + } return found; } From 7e2bce22c05d3ba5249afbd451302421c1c0acd5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 13 Mar 2025 15:48:15 +0100 Subject: [PATCH 046/564] [ESP-IDF5.4] Prepare for ESP-IDF5.4 with Arduino 3.2.0 --- platformio_core_defs.ini | 4 ++-- src/src/Helpers/Hardware_device_info_ESP32C2.cpp | 9 +++++++++ src/src/Helpers/Hardware_device_info_ESP32C3.cpp | 9 +++++++++ src/src/Helpers/Hardware_device_info_ESP32C6.cpp | 9 +++++++++ src/src/Helpers/Hardware_device_info_ESP32S2.cpp | 9 +++++++++ src/src/Helpers/Hardware_device_info_ESP32S3.cpp | 9 +++++++++ 6 files changed, 47 insertions(+), 2 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 220d27851..93da5cf15 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -197,8 +197,8 @@ lib_extra_dirs = ; ESP_IDF 5.3.1 [core_esp32_IDF5_3_2__3_1_0_LittleFS] -platform = https://github.com/Jason2866/platform-espressif32.git -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3427/framework-arduinoespressif32-all-release_v5.3-be550b63.zip +platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF54 +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3443/framework-arduinoespressif32-all-release_v5.4-eb786b90.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 diff --git a/src/src/Helpers/Hardware_device_info_ESP32C2.cpp b/src/src/Helpers/Hardware_device_info_ESP32C2.cpp index 7bae3722b..9ec6d7a4c 100644 --- a/src/src/Helpers/Hardware_device_info_ESP32C2.cpp +++ b/src/src/Helpers/Hardware_device_info_ESP32C2.cpp @@ -16,12 +16,21 @@ bool isFlashInterfacePin_ESPEasy(int gpio) { // For chip variants with a SiP flash built in, GPIO11~ GPIO17 are dedicated to connecting SiP flash, not for other uses // return (gpio) >= 12 && (gpio) <= 17; switch (gpio) { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) case SPI_IOMUX_PIN_NUM_HD: case SPI_IOMUX_PIN_NUM_CS: case SPI_IOMUX_PIN_NUM_MOSI: case SPI_IOMUX_PIN_NUM_CLK: case SPI_IOMUX_PIN_NUM_MISO: case SPI_IOMUX_PIN_NUM_WP: +#else + case SPI2_IOMUX_PIN_NUM_HD: + case SPI2_IOMUX_PIN_NUM_CS: + case SPI2_IOMUX_PIN_NUM_MOSI: + case SPI2_IOMUX_PIN_NUM_CLK: + case SPI2_IOMUX_PIN_NUM_MISO: + case SPI2_IOMUX_PIN_NUM_WP: +#endif return true; } return false; diff --git a/src/src/Helpers/Hardware_device_info_ESP32C3.cpp b/src/src/Helpers/Hardware_device_info_ESP32C3.cpp index ba0bb1198..e923c4664 100644 --- a/src/src/Helpers/Hardware_device_info_ESP32C3.cpp +++ b/src/src/Helpers/Hardware_device_info_ESP32C3.cpp @@ -37,12 +37,21 @@ bool isFlashInterfacePin_ESPEasy(int gpio) { // GPIO-12 ... 17: Connected to flash // return (gpio) >= 12 && (gpio) <= 17; switch (gpio) { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) case SPI_IOMUX_PIN_NUM_HD: case SPI_IOMUX_PIN_NUM_CS: case SPI_IOMUX_PIN_NUM_MOSI: case SPI_IOMUX_PIN_NUM_CLK: case SPI_IOMUX_PIN_NUM_MISO: case SPI_IOMUX_PIN_NUM_WP: +#else + case SPI2_IOMUX_PIN_NUM_HD: + case SPI2_IOMUX_PIN_NUM_CS: + case SPI2_IOMUX_PIN_NUM_MOSI: + case SPI2_IOMUX_PIN_NUM_CLK: + case SPI2_IOMUX_PIN_NUM_MISO: + case SPI2_IOMUX_PIN_NUM_WP: +#endif return true; } return false; diff --git a/src/src/Helpers/Hardware_device_info_ESP32C6.cpp b/src/src/Helpers/Hardware_device_info_ESP32C6.cpp index e88b38e80..b0390de4f 100644 --- a/src/src/Helpers/Hardware_device_info_ESP32C6.cpp +++ b/src/src/Helpers/Hardware_device_info_ESP32C6.cpp @@ -33,12 +33,21 @@ bool isFlashInterfacePin_ESPEasy(int gpio) { // GPIO-24 ... 30: Connected to internal flash (might be available when using external flash???) switch (gpio) { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) case SPI_IOMUX_PIN_NUM_CS: case SPI_IOMUX_PIN_NUM_CLK: case SPI_IOMUX_PIN_NUM_MOSI: case SPI_IOMUX_PIN_NUM_MISO: case SPI_IOMUX_PIN_NUM_WP: case SPI_IOMUX_PIN_NUM_HD: +#else + case SPI2_IOMUX_PIN_NUM_CS: + case SPI2_IOMUX_PIN_NUM_CLK: + case SPI2_IOMUX_PIN_NUM_MOSI: + case SPI2_IOMUX_PIN_NUM_MISO: + case SPI2_IOMUX_PIN_NUM_WP: + case SPI2_IOMUX_PIN_NUM_HD: +#endif return true; } return false; diff --git a/src/src/Helpers/Hardware_device_info_ESP32S2.cpp b/src/src/Helpers/Hardware_device_info_ESP32S2.cpp index 15867ba44..7e7cba83c 100644 --- a/src/src/Helpers/Hardware_device_info_ESP32S2.cpp +++ b/src/src/Helpers/Hardware_device_info_ESP32S2.cpp @@ -31,12 +31,21 @@ bool isFlashInterfacePin_ESPEasy(int gpio) { // GPIO-27 ... 32: SPI 8 ­line mode (OPI) pins for flash or PSRAM (e.g. ESP32-S2FH2 and ESP32-S2FH4) // return (gpio) >= 22 && (gpio) <= 25; switch (gpio) { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) case SPI_IOMUX_PIN_NUM_HD: case SPI_IOMUX_PIN_NUM_CS: case SPI_IOMUX_PIN_NUM_MOSI: case SPI_IOMUX_PIN_NUM_CLK: case SPI_IOMUX_PIN_NUM_MISO: case SPI_IOMUX_PIN_NUM_WP: +#else + case SPI2_IOMUX_PIN_NUM_HD: + case SPI2_IOMUX_PIN_NUM_CS: + case SPI2_IOMUX_PIN_NUM_MOSI: + case SPI2_IOMUX_PIN_NUM_CLK: + case SPI2_IOMUX_PIN_NUM_MISO: + case SPI2_IOMUX_PIN_NUM_WP: +#endif return true; } return false; diff --git a/src/src/Helpers/Hardware_device_info_ESP32S3.cpp b/src/src/Helpers/Hardware_device_info_ESP32S3.cpp index a5abb5058..3f02fde3c 100644 --- a/src/src/Helpers/Hardware_device_info_ESP32S3.cpp +++ b/src/src/Helpers/Hardware_device_info_ESP32S3.cpp @@ -50,12 +50,21 @@ bool isFlashInterfacePin_ESPEasy(int gpio) { // return (gpio) >= 26 && (gpio) <= 32; switch (gpio) { case 26: // SPICS1 Only when PSRAM is present??? +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) case SPI_IOMUX_PIN_NUM_HD: case SPI_IOMUX_PIN_NUM_CS: case SPI_IOMUX_PIN_NUM_MOSI: case SPI_IOMUX_PIN_NUM_CLK: case SPI_IOMUX_PIN_NUM_MISO: case SPI_IOMUX_PIN_NUM_WP: +#else + case SPI2_IOMUX_PIN_NUM_HD: + case SPI2_IOMUX_PIN_NUM_CS: + case SPI2_IOMUX_PIN_NUM_MOSI: + case SPI2_IOMUX_PIN_NUM_CLK: + case SPI2_IOMUX_PIN_NUM_MISO: + case SPI2_IOMUX_PIN_NUM_WP: +#endif return true; } return false; From 853245c0fb1d1328395a162d7c5eda997dbdc31d Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 15 Mar 2025 00:03:54 +0100 Subject: [PATCH 047/564] [Eastron] Speed up parsing Modbus RTU messages --- lib/ESPEasySerial/ESPEasySerial.cpp | 8 ++++++++ lib/ESPEasySerial/ESPeasySerial.h | 1 + lib/SDM_Energy_Meter/SDM.cpp | 21 +++++++++++---------- platformio_core_defs.ini | 7 +++++-- platformio_esp32_solo1.ini | 2 +- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/lib/ESPEasySerial/ESPEasySerial.cpp b/lib/ESPEasySerial/ESPEasySerial.cpp index d8f2f21c9..bda77cdc1 100644 --- a/lib/ESPEasySerial/ESPEasySerial.cpp +++ b/lib/ESPEasySerial/ESPEasySerial.cpp @@ -182,6 +182,14 @@ int ESPeasySerial::read(void) return _serialPort->read(); } +int ESPeasySerial::read(uint8_t *buffer, size_t size) +{ + if (!isValid()) { + return -1; + } + return _serialPort->read(buffer, size); +} + int ESPeasySerial::available(void) { if (!isValid()) { diff --git a/lib/ESPEasySerial/ESPeasySerial.h b/lib/ESPEasySerial/ESPeasySerial.h index 7f9e5ea19..229919025 100644 --- a/lib/ESPEasySerial/ESPeasySerial.h +++ b/lib/ESPEasySerial/ESPeasySerial.h @@ -89,6 +89,7 @@ public: int peek(void); size_t write(uint8_t val) override; int read(void) override; + int read(uint8_t *buffer, size_t size); int available(void) override; int availableForWrite(void); void flush(void) override; diff --git a/lib/SDM_Energy_Meter/SDM.cpp b/lib/SDM_Energy_Meter/SDM.cpp index 8da79aebe..f98b8e2aa 100644 --- a/lib/SDM_Energy_Meter/SDM.cpp +++ b/lib/SDM_Energy_Meter/SDM.cpp @@ -104,19 +104,20 @@ void SDM::startReadVal(uint16_t reg, uint8_t node, uint8_t functionCode) { uint16_t SDM::readValReady(uint8_t node, uint8_t functionCode) { uint16_t readErr = SDM_ERR_NO_ERROR; - if (sdmSer.available() < FRAMESIZE && ((millis() - resptime) < msturnaround)) + int available = sdmSer.available(); + if (available < FRAMESIZE && ((millis() - resptime) < msturnaround)) { return SDM_ERR_STILL_WAITING; } - while (sdmSer.available() < FRAMESIZE) { + while (available < FRAMESIZE) { if ((millis() - resptime) > msturnaround) { readErr = SDM_ERR_TIMEOUT; //err debug (4) - if (sdmSer.available() == 5) { - for(int n=0; n<5; n++) { - sdmarr[n] = sdmSer.read(); - } + if (available == 5) { + memset(sdmarr, 0, NR_ELEMENTS(sdmarr)); + sdmSer.read(sdmarr, available); + if (validChecksum(sdmarr, 5)) { readErr = sdmarr[2]; } @@ -124,15 +125,15 @@ uint16_t SDM::readValReady(uint8_t node, uint8_t functionCode) { break; } delay(1); + available = sdmSer.available(); } if (readErr == SDM_ERR_NO_ERROR) { //if no timeout... - if (sdmSer.available() >= FRAMESIZE) { + if (available >= FRAMESIZE) { - for(int n=0; n Date: Wed, 26 Mar 2025 08:37:19 +0100 Subject: [PATCH 048/564] [Serial] Add setXxBufferSize functions --- lib/ESPEasySerial/ESPEasySerial.cpp | 16 ++++++++++++++++ lib/ESPEasySerial/ESPeasySerial.h | 5 +++++ lib/ESPEasySerial/Port_ESPEasySerial_base.h | 4 +++- src/_P091_SerSwitch.ino | 2 +- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/ESPEasySerial/ESPEasySerial.cpp b/lib/ESPEasySerial/ESPEasySerial.cpp index bda77cdc1..38af845a4 100644 --- a/lib/ESPEasySerial/ESPEasySerial.cpp +++ b/lib/ESPEasySerial/ESPEasySerial.cpp @@ -246,6 +246,22 @@ void ESPeasySerial::setDebugOutput(bool enable) } } +size_t ESPeasySerial::setRxBufferSize(size_t new_size) +{ + if (isValid()) { + return _serialPort->setRxBufferSize(new_size); + } + return 0; +} + +size_t ESPeasySerial::setTxBufferSize(size_t new_size) +{ + if (isValid()) { + return _serialPort->setTxBufferSize(new_size); + } + return 0; +} + bool ESPeasySerial::isTxEnabled(void) { return getTxPin() != -1; diff --git a/lib/ESPEasySerial/ESPeasySerial.h b/lib/ESPEasySerial/ESPeasySerial.h index 229919025..00d766db3 100644 --- a/lib/ESPEasySerial/ESPeasySerial.h +++ b/lib/ESPEasySerial/ESPeasySerial.h @@ -122,6 +122,11 @@ public: void setDebugOutput(bool); + // Set buffer size, should be called before calling begin() + size_t setRxBufferSize(size_t new_size); + size_t setTxBufferSize(size_t new_size); + + bool isTxEnabled(void); bool isRxEnabled(void); diff --git a/lib/ESPEasySerial/Port_ESPEasySerial_base.h b/lib/ESPEasySerial/Port_ESPEasySerial_base.h index e317b6764..c520df617 100644 --- a/lib/ESPEasySerial/Port_ESPEasySerial_base.h +++ b/lib/ESPEasySerial/Port_ESPEasySerial_base.h @@ -45,7 +45,7 @@ public: inline size_t write(const char *s) { - return write((uint8_t *)s, strlen(s)); + return (s) ? write((uint8_t *)s, strlen(s)) : 0; } inline size_t write(unsigned long n) @@ -74,6 +74,8 @@ public: virtual void setDebugOutput(bool) = 0; + + // Set buffer size, should be called before calling begin() virtual size_t setRxBufferSize(size_t new_size) = 0; virtual size_t setTxBufferSize(size_t new_size) = 0; virtual bool setRS485Mode(int8_t rtsPin, bool enableCollisionDetection) = 0; diff --git a/src/_P091_SerSwitch.ino b/src/_P091_SerSwitch.ino index 7cd07b113..304d7ea64 100644 --- a/src/_P091_SerSwitch.ino +++ b/src/_P091_SerSwitch.ino @@ -232,8 +232,8 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) if (PCONFIG(0) == SER_SWITCH_YEWE) { Plugin_091_numrelay = PCONFIG(1); - ESPEASY_SERIAL_0.begin(9600, SERIAL_8N1); ESPEASY_SERIAL_0.setRxBufferSize(BUFFER_SIZE); // Arduino core for ESP8266 WiFi chip 2.4.0 + ESPEASY_SERIAL_0.begin(9600, SERIAL_8N1); delay(1); getmcustate(); // request status on startup log += strformat(F(" Yewe %d btn"), Plugin_091_numrelay); From e7841a2c98b5cf877a3456acc573c409e3c39b34 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 17 Apr 2025 00:49:11 +0200 Subject: [PATCH 049/564] [ESP-IDF5.3] Update to latest Arduino/ESP-IDF5.3 version --- platformio_core_defs.ini | 2 +- platformio_esp32_solo1.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 08e5cc190..49e382365 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -201,7 +201,7 @@ lib_extra_dirs = ;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3443/framework-arduinoespressif32-all-release_v5.4-eb786b90.zip platform = https://github.com/Jason2866/platform-espressif32.git -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3447/framework-arduinoespressif32-all-release_v5.3-a8f33310.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3506/framework-arduinoespressif32-all-release_v5.3-2952ac93.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 diff --git a/platformio_esp32_solo1.ini b/platformio_esp32_solo1.ini index 299f1c144..a1ccd95fa 100644 --- a/platformio_esp32_solo1.ini +++ b/platformio_esp32_solo1.ini @@ -4,7 +4,7 @@ extends = esp32_base_idf5 board = esp32_solo1_4M platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF53 -platform_packages = framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3448/framework-arduinoespressif32-solo1-release_v5.3-a8f33310.zip +platform_packages = framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3507/framework-arduinoespressif32-solo1-release_v5.3-2952ac93.zip build_flags = ${esp32_base_idf5.build_flags} -DFEATURE_ARDUINO_OTA=1 -DUSE_LITTLEFS From a2a0e2c77b24e7362186568a38dfcd70c4bd1aa3 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 17 Apr 2025 00:50:03 +0200 Subject: [PATCH 050/564] [timing stats] Simplify and speedup collecting timing stats --- src/src/DataStructs/TimingStats.cpp | 48 ++++++++++------------ src/src/DataStructs/TimingStats.h | 30 +++++++------- src/src/ESPEasyCore/ESPEasy_loop.cpp | 6 +-- src/src/Globals/Statistics.cpp | 2 +- src/src/Globals/Statistics.h | 2 +- src/src/Helpers/Dallas1WireHelper.h | 2 +- src/src/Helpers/ESPEasyStatistics.cpp | 4 +- src/src/Helpers/msecTimerHandlerStruct.cpp | 4 +- src/src/Helpers/msecTimerHandlerStruct.h | 4 +- src/src/PluginStructs/P005_data_struct.cpp | 14 +++---- src/src/PluginStructs/P025_data_struct.cpp | 4 +- src/src/WebServer/TimingStats.cpp | 14 +++---- src/src/WebServer/TimingStats.h | 6 +-- 13 files changed, 68 insertions(+), 72 deletions(-) diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index fdf943119..d74f1bd24 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -13,45 +13,41 @@ std::map miscStats; unsigned long timingstats_last_reset(0); -TimingStats::TimingStats() : _timeTotal(0.0f), _count(0), _maxVal(0), _minVal(4294967295) {} - -void TimingStats::add(int64_t time) { - _timeTotal += static_cast(time); +void TimingStats::add(int32_t duration_usec) { + // Max duration in usec is roughly 35 minutes. + // For timing stats more than enough + if (duration_usec < 0) return; + _timeTotal += static_cast(duration_usec); ++_count; - if (time > static_cast(_maxVal)) { _maxVal = time; } + if (static_cast(duration_usec) > _maxVal) { _maxVal = duration_usec; } - if (time < static_cast(_minVal)) { _minVal = time; } + if (static_cast(duration_usec) < _minVal) { _minVal = duration_usec; } } void TimingStats::reset() { - _timeTotal = 0.0f; - _count = 0; - _maxVal = 0; - _minVal = 4294967295; + _timeTotal = 0u; + _count = 0u; + _maxVal = 0u; + _minVal = 4294967295u; } bool TimingStats::isEmpty() const { - return _count == 0; + return _count == 0u; } float TimingStats::getAvg() const { if (_count == 0) { return 0.0f; } - return _timeTotal / static_cast(_count); + return static_cast(_timeTotal) / static_cast(_count); } -uint32_t TimingStats::getMinMax(uint64_t& minVal, uint64_t& maxVal) const { - if (_count == 0) { - minVal = 0; - maxVal = 0; - return 0; - } +uint32_t TimingStats::getMinMax(uint32_t& minVal, uint32_t& maxVal) const { minVal = _minVal; maxVal = _maxVal; return _count; } -bool TimingStats::thresholdExceeded(const uint64_t& threshold) const { +bool TimingStats::thresholdExceeded(const uint32_t& threshold) const { if (_count == 0) { return false; } @@ -321,22 +317,22 @@ String getMiscStatsName(TimingStatsElements stat) { return getMiscStatsName_F(static_cast(stat)); } -void stopTimerTask(deviceIndex_t T, int F, uint64_t statisticsTimerStart) +void stopTimerTask(deviceIndex_t T, int F, uint32_t statisticsTimerStart) { - if (mustLogFunction(F)) { pluginStats[static_cast(T.value) * 256 + (F)].add(usecPassedSince(statisticsTimerStart)); } + if (mustLogFunction(F)) { pluginStats[static_cast(T.value) * 256 + (F)].add(usecPassedSince_fast(statisticsTimerStart)); } } -void stopTimerController(protocolIndex_t T, CPlugin::Function F, uint64_t statisticsTimerStart) +void stopTimerController(protocolIndex_t T, CPlugin::Function F, uint32_t statisticsTimerStart) { - if (mustLogCFunction(F)) { controllerStats[static_cast(T) * 256 + static_cast(F)].add(usecPassedSince(statisticsTimerStart)); } + if (mustLogCFunction(F)) { controllerStats[static_cast(T) * 256 + static_cast(F)].add(usecPassedSince_fast(statisticsTimerStart)); } } -void stopTimer(TimingStatsElements L, uint64_t statisticsTimerStart) +void stopTimer(TimingStatsElements L, uint32_t statisticsTimerStart) { - if (Settings.EnableTimingStats()) { miscStats[L].add(usecPassedSince(statisticsTimerStart)); } + if (Settings.EnableTimingStats()) { miscStats[L].add(usecPassedSince_fast(statisticsTimerStart)); } } -void addMiscTimerStat(TimingStatsElements L, int64_t T) +void addMiscTimerStat(TimingStatsElements L, int32_t T) { if (Settings.EnableTimingStats()) { miscStats[L].add(T); } } diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index 41126efef..5d70d5dd5 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -142,22 +142,22 @@ enum class TimingStatsElements { class TimingStats { public: - TimingStats(); + TimingStats() = default; - void add(int64_t time); + void add(int32_t duration_usec); void reset(); bool isEmpty() const; float getAvg() const; - uint32_t getMinMax(uint64_t& minVal, - uint64_t& maxVal) const; - bool thresholdExceeded(const uint64_t& threshold) const; + uint32_t getMinMax(uint32_t& minVal, + uint32_t& maxVal) const; + bool thresholdExceeded(const uint32_t& threshold) const; private: - float _timeTotal; - uint32_t _count; - uint64_t _maxVal; - uint64_t _minVal; + uint64_t _timeTotal{}; + uint32_t _count{}; + uint32_t _maxVal{}; + uint32_t _minVal = 4294967295; }; @@ -169,25 +169,25 @@ String getMiscStatsName(TimingStatsElements stat); void stopTimerTask(deviceIndex_t T, int F, - uint64_t statisticsTimerStart); + uint32_t statisticsTimerStart); void stopTimerController(protocolIndex_t T, CPlugin::Function F, - uint64_t statisticsTimerStart); + uint32_t statisticsTimerStart); void stopTimer(TimingStatsElements L, - uint64_t statisticsTimerStart); + uint32_t statisticsTimerStart); void addMiscTimerStat(TimingStatsElements L, - int64_t T); + int32_t T); extern std::map pluginStats; extern std::map controllerStats; extern std::map miscStats; extern unsigned long timingstats_last_reset; -# define START_TIMER const uint64_t statisticsTimerStart(getMicros64()); +# define START_TIMER const uint32_t statisticsTimerStart(micros()); # define STOP_TIMER_TASK(T, F) stopTimerTask(T, F, statisticsTimerStart); # define STOP_TIMER_CONTROLLER(T, F) stopTimerController(T, F, statisticsTimerStart); -// #define STOP_TIMER_LOADFILE miscStats[LOADFILE_STATS].add(usecPassedSince(statisticsTimerStart)); +// #define STOP_TIMER_LOADFILE miscStats[LOADFILE_STATS].add(usecPassedSince_fast(statisticsTimerStart)); # define STOP_TIMER(L) stopTimer(TimingStatsElements::L, statisticsTimerStart); # define STOP_TIMER_VAR(L) stopTimer(L, statisticsTimerStart); diff --git a/src/src/ESPEasyCore/ESPEasy_loop.cpp b/src/src/ESPEasyCore/ESPEasy_loop.cpp index d157addb6..128acd099 100644 --- a/src/src/ESPEasyCore/ESPEasy_loop.cpp +++ b/src/src/ESPEasyCore/ESPEasy_loop.cpp @@ -31,17 +31,17 @@ void updateLoopStats() { ++loopCounter_full; if (lastLoopStart == 0) { - lastLoopStart = getMicros64(); + lastLoopStart = micros(); return; } - const int64_t usecSince = usecPassedSince(lastLoopStart); + const int32_t usecSince = usecPassedSince_fast(lastLoopStart); #if FEATURE_TIMING_STATS ADD_TIMER_STAT(LOOP_STATS, usecSince); #endif // if FEATURE_TIMING_STATS loop_usec_duration_total += usecSince; - lastLoopStart = getMicros64(); + lastLoopStart = micros(); if ((usecSince <= 0) || (usecSince > 10000000)) { return; // No loop should take > 10 sec. diff --git a/src/src/Globals/Statistics.cpp b/src/src/Globals/Statistics.cpp index a0cdb5385..1dee64440 100644 --- a/src/src/Globals/Statistics.cpp +++ b/src/src/Globals/Statistics.cpp @@ -18,7 +18,7 @@ unsigned long elapsed50ps = 0; unsigned long loopCounter = 0; unsigned long loopCounterLast = 0; unsigned long loopCounterMax = 1; -uint64_t lastLoopStart = 0; +uint32_t lastLoopStart = 0; unsigned long shortestLoop = 10000000; unsigned long longestLoop = 0; unsigned long loopCounter_full = 1; diff --git a/src/src/Globals/Statistics.h b/src/src/Globals/Statistics.h index 10af6129f..1cb45dabb 100644 --- a/src/src/Globals/Statistics.h +++ b/src/src/Globals/Statistics.h @@ -35,7 +35,7 @@ extern SchedulerTimerID lastMixedSchedulerId_beforereboot; extern unsigned long loopCounter; extern unsigned long loopCounterLast; extern unsigned long loopCounterMax; -extern uint64_t lastLoopStart; +extern uint32_t lastLoopStart; extern unsigned long shortestLoop; extern unsigned long longestLoop; extern unsigned long loopCounter_full; diff --git a/src/src/Helpers/Dallas1WireHelper.h b/src/src/Helpers/Dallas1WireHelper.h index fceab3e5b..9ce548b06 100644 --- a/src/src/Helpers/Dallas1WireHelper.h +++ b/src/src/Helpers/Dallas1WireHelper.h @@ -136,7 +136,7 @@ bool Dallas_is_parasite(const uint8_t ROM[8], /*********************************************************************************************\ * Dallas data from scratchpad \*********************************************************************************************/ -enum struct Dallas_read_result { +enum class Dallas_read_result { OK, NoReply, CRCerr, diff --git a/src/src/Helpers/ESPEasyStatistics.cpp b/src/src/Helpers/ESPEasyStatistics.cpp index d4cfafafa..81e8addd6 100644 --- a/src/src/Helpers/ESPEasyStatistics.cpp +++ b/src/src/Helpers/ESPEasyStatistics.cpp @@ -10,8 +10,8 @@ void stream_json_timing_stats(const TimingStats& stats, long timeSinceLastReset) { - uint64_t minVal, maxVal; - uint64_t count = stats.getMinMax(minVal, maxVal); + uint32_t minVal, maxVal; + uint32_t count = stats.getMinMax(minVal, maxVal); float call_per_sec = static_cast(count) / static_cast(timeSinceLastReset) * 1000.0f; json_number(F("count"), ull2String(count)); diff --git a/src/src/Helpers/msecTimerHandlerStruct.cpp b/src/src/Helpers/msecTimerHandlerStruct.cpp index e3f6ce1d5..2a5862e33 100644 --- a/src/src/Helpers/msecTimerHandlerStruct.cpp +++ b/src/src/Helpers/msecTimerHandlerStruct.cpp @@ -146,7 +146,7 @@ void msecTimerHandlerStruct::recordIdle() { if (is_idle) { return; } - last_exec_time_usec = getMicros64(); + last_exec_time_usec = micros(); is_idle = true; delay(0); // Nothing to do, so leave time for backgroundtasks } @@ -154,5 +154,5 @@ void msecTimerHandlerStruct::recordRunning() { if (!is_idle) { return; } is_idle = false; - total_idle_time_usec += usecPassedSince(last_exec_time_usec); + total_idle_time_usec += usecPassedSince_fast(last_exec_time_usec); } diff --git a/src/src/Helpers/msecTimerHandlerStruct.h b/src/src/Helpers/msecTimerHandlerStruct.h index 6897a7110..fcddae316 100644 --- a/src/src/Helpers/msecTimerHandlerStruct.h +++ b/src/src/Helpers/msecTimerHandlerStruct.h @@ -49,8 +49,8 @@ private: unsigned long max_queue_length; // Compute idle system time - uint64_t last_exec_time_usec; - uint64_t total_idle_time_usec; + uint32_t last_exec_time_usec; + uint32_t total_idle_time_usec; uint32_t last_log_start_time; float idle_time_pct; bool is_idle; diff --git a/src/src/PluginStructs/P005_data_struct.cpp b/src/src/PluginStructs/P005_data_struct.cpp index 4429c69ed..f5caadc6d 100644 --- a/src/src/PluginStructs/P005_data_struct.cpp +++ b/src/src/PluginStructs/P005_data_struct.cpp @@ -76,7 +76,7 @@ P005_data_struct::P005_data_struct(struct EventStruct *event) { \*********************************************************************************************/ bool P005_data_struct::waitState(uint32_t state) { - const uint64_t timeout = getMicros64() + 100; + const uint32_t start = micros(); # ifdef DEBUG_LOGIC_ANALYZER_PIN @@ -86,7 +86,7 @@ bool P005_data_struct::waitState(uint32_t state) while (DIRECT_pinRead(DHT_pin) != state) { - if (usecTimeOutReached(timeout)) { return false; } + if (usecPassedSince_fast(start) >= 100) { return false; } } # ifdef DEBUG_LOGIC_ANALYZER_PIN @@ -166,8 +166,8 @@ bool P005_data_struct::readDHT(struct EventStruct *event) { if (receive_start) { // We know we're now at a "low" state. - uint64_t last_micros = getMicros64(); - uint64_t prev_edge = last_micros; + uint32_t last_micros = micros(); + uint32_t prev_edge = last_micros; for (dht_byte = 0; dht_byte < 5 && !readingAborted; ++dht_byte) { @@ -187,16 +187,16 @@ bool P005_data_struct::readDHT(struct EventStruct *event) { // Keep track of last microsecond the state had not yet changed. // This way we are less dependent on any jitter caused by // the delay call or rise times of the voltage on the pin. - last_micros = getMicros64(); + last_micros = micros(); - if (timeDiff64(prev_edge, last_micros) > 100) { + if (timeDiff(prev_edge, last_micros) > 100) { readingAborted = true; } } if (!readingAborted) { // We know it is less than 100 usec, so it does fit in the uint8_t timings array. - timings[t] = usecPassedSince(prev_edge); + timings[t] = usecPassedSince_fast(prev_edge); prev_edge = last_micros; } else { timings[t] = 255; diff --git a/src/src/PluginStructs/P025_data_struct.cpp b/src/src/PluginStructs/P025_data_struct.cpp index d5e33ddf5..c9e3783fd 100644 --- a/src/src/PluginStructs/P025_data_struct.cpp +++ b/src/src/PluginStructs/P025_data_struct.cpp @@ -233,7 +233,7 @@ bool P025_data_struct::startMeasurement(uint8_t i2cAddress, uint16_t configRegis long P025_data_struct::waitReady025(uint8_t i2cAddress) { - const uint64_t start = getMicros64(); + const uint32_t start = micros(); unsigned long timeout = millis(); bool is_ok = false; @@ -257,7 +257,7 @@ long P025_data_struct::waitReady025(uint8_t i2cAddress) const bool ready = reg.operatingStatus == 1; if (ready && is_ok) { - const long res = usecPassedSince(start); + const long res = usecPassedSince_fast(start); const long sps = (res > 0) ? 1000000 / res : 0; # ifndef BUILD_NO_DEBUG diff --git a/src/src/WebServer/TimingStats.cpp b/src/src/WebServer/TimingStats.cpp index 478795bc3..7c6481db7 100644 --- a/src/src/WebServer/TimingStats.cpp +++ b/src/src/WebServer/TimingStats.cpp @@ -44,7 +44,7 @@ void handle_timingstats() { } - const long timeSinceLastReset = stream_timing_statistics(true); + const int32_t timeSinceLastReset = stream_timing_statistics(true); html_end_table(); html_table_class_normal(); @@ -68,7 +68,7 @@ void handle_timingstats() { // ******************************************************************************** // HTML table formatted timing statistics // ******************************************************************************** -void format_using_threshhold(unsigned long value) { +void format_using_threshhold(uint32_t value) { float value_msec = value / 1000.0f; if (value > TIMING_STATS_THRESHOLD) { @@ -78,9 +78,9 @@ void format_using_threshhold(unsigned long value) { } } -void stream_html_timing_stats(const TimingStats& stats, long timeSinceLastReset) { - uint64_t minVal, maxVal; - const uint64_t c = stats.getMinMax(minVal, maxVal); +void stream_html_timing_stats(const TimingStats& stats, int32_t timeSinceLastReset) { + uint32_t minVal, maxVal; + const uint32_t c = stats.getMinMax(minVal, maxVal); html_TD(); addHtmlInt(c); @@ -112,8 +112,8 @@ void stream_html_timing_stats(const TimingStats& stats, long timeSinceLastReset) format_using_threshhold(maxVal); } -long stream_timing_statistics(bool clearStats) { - const long timeSinceLastReset = timePassedSince(timingstats_last_reset); +int32_t stream_timing_statistics(bool clearStats) { + const int32_t timeSinceLastReset = timePassedSince(timingstats_last_reset); for (auto& x: pluginStats) { if (!x.second.isEmpty()) { diff --git a/src/src/WebServer/TimingStats.h b/src/src/WebServer/TimingStats.h index 352bd353e..b416372f6 100644 --- a/src/src/WebServer/TimingStats.h +++ b/src/src/WebServer/TimingStats.h @@ -12,11 +12,11 @@ void handle_timingstats(); // ******************************************************************************** // HTML table formatted timing statistics // ******************************************************************************** -void format_using_threshhold(unsigned long value); +void format_using_threshhold(uint32_t value); -void stream_html_timing_stats(const TimingStats& stats, long timeSinceLastReset); +void stream_html_timing_stats(const TimingStats& stats, int32_t timeSinceLastReset); -long stream_timing_statistics(bool clearStats); +int32_t stream_timing_statistics(bool clearStats); #endif From 02e2f92e296132ca755bb690a6cd517d59f2f677 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 18 Apr 2025 17:11:55 +0200 Subject: [PATCH 051/564] [1-wire] Fix ESP8266 builds not fitting in IRAM --- src/src/Helpers/Dallas1WireHelper.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/src/Helpers/Dallas1WireHelper.cpp b/src/src/Helpers/Dallas1WireHelper.cpp index 99dbe3354..9bf203678 100644 --- a/src/src/Helpers/Dallas1WireHelper.cpp +++ b/src/src/Helpers/Dallas1WireHelper.cpp @@ -49,7 +49,13 @@ int32_t presence_end{}; void DALLAS_IRAM_ATTR Dallas_pinModeInput(uint32_t gpio_pin_rx, uint32_t gpio_pin_tx) { if (gpio_pin_rx == gpio_pin_tx) { - DIRECT_PINMODE_INPUT_ISR(gpio_pin_rx); // let pin float, pull up will raise level + // let pin float, pull up will raise level +#ifdef ESP8266 + // We're running out of IRAM on ESP8266 + DIRECT_PINMODE_INPUT(gpio_pin_rx); +#else + DIRECT_PINMODE_INPUT_ISR(gpio_pin_rx); +#endif } else { DIRECT_pinWrite_ISR(gpio_pin_tx, 1); } @@ -60,7 +66,12 @@ void DALLAS_IRAM_ATTR Dallas_pinWrite(uint32_t gpio_pin_rx, uint32_t gpio_pin_tx DIRECT_pinWrite_ISR(gpio_pin_tx, pinstate); if (gpio_pin_rx == gpio_pin_tx) { +#ifdef ESP8266 + // We're running out of IRAM on ESP8266 + DIRECT_PINMODE_OUTPUT(gpio_pin_rx); +#else DIRECT_PINMODE_OUTPUT_ISR(gpio_pin_rx); +#endif } } From 382dad51a169060e528d51671ad4c78c778c9944 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 24 May 2025 02:24:44 +0200 Subject: [PATCH 052/564] [ESP32-C5] Add preliminary support for ESP32-C5 with dual band WiFi --- boards/esp32c5cdc-8M.json | 40 +++++ boards/esp32c5cdc.json | 40 +++++ lib/ESPEasySerial/ESPEasySerialType.h | 12 +- .../ESPEasySerial_common_defines.h | 4 +- lib/GPIO_DirectAccess/GPIO_Direct_Access.h | 10 +- lib/ImprovWiFi/src/ImprovTypes.h | 2 + .../src/internal/DotStarEsp32DmaSpiMethod.h | 16 +- lib/NeoPixelBus/src/internal/Esp32_i2s.c | 16 +- lib/NeoPixelBus/src/internal/Esp32_i2s.h | 2 +- lib/NeoPixelBus/src/internal/NeoBusChannel.h | 2 +- .../src/internal/NeoEsp32I2sMethod.h | 8 +- .../src/internal/NeoEsp32RmtMethod.h | 16 +- .../src/internal/NeoEsp32RmtMethod_idf5.h | 20 +-- .../src/internal/NeoEsp32SpiMethod_idf5.h | 2 +- .../src/internal/NeoEspBitBangMethod.cpp | 2 +- platformio.ini | 5 +- platformio_core_defs.ini | 40 ++++- platformio_esp32_envs.ini | 46 ++++- platformio_esp32c5_envs..ini | 29 +++ src/include/ESPEasy_config.h | 2 +- src/include/esp32x_fixes.h | 2 +- src/src/CustomBuild/ESPEasy_buildinfo.h | 8 +- src/src/CustomBuild/define_plugin_sets.h | 2 +- src/src/DataStructs/WiFi_AP_Candidate.cpp | 18 +- src/src/DataStructs/WiFi_AP_Candidate.h | 6 +- src/src/DataStructs_templ/SettingsStruct.cpp | 2 +- src/src/DataTypes/SPI_options.cpp | 2 + src/src/DataTypes/SPI_options.h | 4 + src/src/ESPEasyCore/ESPEasyWifi.cpp | 3 + .../ESPEasyWifi_abstracted_ESP32.cpp | 25 ++- src/src/Helpers/ESPEasy_Storage.cpp | 5 +- src/src/Helpers/Hardware.cpp | 26 +++ src/src/Helpers/Hardware_ADC_cali.h | 2 +- src/src/Helpers/Hardware_GPIO_ESP32C5.cpp | 166 ++++++++++++++++++ src/src/Helpers/Hardware_defines.h | 12 +- .../Helpers/Hardware_device_info_ESP32C5.cpp | 77 +++++++- .../Helpers/Hardware_temperature_sensor.cpp | 4 +- src/src/Helpers/StringGenerator_GPIO.cpp | 3 + src/src/Helpers/StringGenerator_System.cpp | 28 +++ tools/pio/copy_files.py | 8 +- tools/pio/generate_web_flasher_manifest.py | 8 + 41 files changed, 637 insertions(+), 88 deletions(-) create mode 100644 boards/esp32c5cdc-8M.json create mode 100644 boards/esp32c5cdc.json create mode 100644 platformio_esp32c5_envs..ini create mode 100644 src/src/Helpers/Hardware_GPIO_ESP32C5.cpp diff --git a/boards/esp32c5cdc-8M.json b/boards/esp32c5cdc-8M.json new file mode 100644 index 000000000..17a802156 --- /dev/null +++ b/boards/esp32c5cdc-8M.json @@ -0,0 +1,40 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32c5_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_TASMOTA -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_8M -DESP32C5 -DARDUINO_USB_CDC_ON_BOOT=1", + "f_cpu": "160000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32c5", + "variant": "esp32c5", + "partitions": "boards/partitions/esp32_partition_app3520k_spiffs1088k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth" + ], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], + "openocd_target": "esp32c5.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "Espressif Generic ESP32-C5 >= 8M Flash, ESPEasy 3520k Code/OTA 1088k FS", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c5/esp32-c5-devkitc-1/index.html", + "vendor": "Espressif" + } diff --git a/boards/esp32c5cdc.json b/boards/esp32c5cdc.json new file mode 100644 index 000000000..312d32556 --- /dev/null +++ b/boards/esp32c5cdc.json @@ -0,0 +1,40 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32c5_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_TASMOTA -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32C5 -DARDUINO_USB_CDC_ON_BOOT=1", + "f_cpu": "160000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32c5", + "variant": "esp32c5", + "partitions": "boards/partitions/esp32_partition_app1810k_spiffs316k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth" + ], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], + "openocd_target": "esp32c5.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "Espressif Generic ESP32-C5 >= 4M Flash, ESPEasy 1810k Code/OTA 316k FS", + "upload": { + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c5/esp32-c5-devkitc-1/index.html", + "vendor": "Espressif" + } diff --git a/lib/ESPEasySerial/ESPEasySerialType.h b/lib/ESPEasySerial/ESPEasySerialType.h index d77ab506b..65d15d5b9 100644 --- a/lib/ESPEasySerial/ESPEasySerialType.h +++ b/lib/ESPEasySerial/ESPEasySerialType.h @@ -22,6 +22,8 @@ # define SOC_RX0 44 # elif CONFIG_IDF_TARGET_ESP32C6 # define SOC_RX0 17 +# elif CONFIG_IDF_TARGET_ESP32C5 +# define SOC_RX0 12 # elif CONFIG_IDF_TARGET_ESP32C3 # define SOC_RX0 20 # elif CONFIG_IDF_TARGET_ESP32C2 @@ -36,6 +38,8 @@ # define SOC_TX0 43 # elif CONFIG_IDF_TARGET_ESP32C6 # define SOC_TX0 16 +# elif CONFIG_IDF_TARGET_ESP32C5 +# define SOC_TX0 11 # elif CONFIG_IDF_TARGET_ESP32C3 # define SOC_TX0 21 # elif CONFIG_IDF_TARGET_ESP32C2 @@ -50,7 +54,7 @@ # define SOC_RX1 13 # elif CONFIG_IDF_TARGET_ESP32S2 # define SOC_RX1 18 -# elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 +# elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 # define SOC_RX1 4 # elif CONFIG_IDF_TARGET_ESP32S3 # define SOC_RX1 15 @@ -62,7 +66,7 @@ # define SOC_TX1 15 # elif CONFIG_IDF_TARGET_ESP32S2 # define SOC_TX1 17 -# elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 +# elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 # define SOC_TX1 5 # elif CONFIG_IDF_TARGET_ESP32S3 # define SOC_TX1 16 @@ -80,6 +84,8 @@ # define SOC_RX2 19 # elif CONFIG_IDF_TARGET_ESP32C6 # define SOC_RX2 6 +# elif CONFIG_IDF_TARGET_ESP32C5 +# define SOC_RX2 6 # else // if CONFIG_IDF_TARGET_ESP32 # define SOC_RX2 -1 # endif // if CONFIG_IDF_TARGET_ESP32 @@ -92,6 +98,8 @@ # define SOC_TX2 20 # elif CONFIG_IDF_TARGET_ESP32C6 # define SOC_TX2 7 +# elif CONFIG_IDF_TARGET_ESP32C5 +# define SOC_TX2 7 # else // if CONFIG_IDF_TARGET_ESP32 # define SOC_TX2 -1 # endif // if CONFIG_IDF_TARGET_ESP32 diff --git a/lib/ESPEasySerial/ESPEasySerial_common_defines.h b/lib/ESPEasySerial/ESPEasySerial_common_defines.h index 88d2a508c..6d8ce15dc 100644 --- a/lib/ESPEasySerial/ESPEasySerial_common_defines.h +++ b/lib/ESPEasySerial/ESPEasySerial_common_defines.h @@ -8,7 +8,7 @@ #ifndef SOC_UART_NUM # ifdef ESP8266 # define SOC_UART_NUM 2 -# elif defined(ESP32_CLASSIC) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C6) +# elif defined(ESP32_CLASSIC) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) # include # else // ifdef ESP8266 static_assert(false, "Implement processor architecture"); @@ -40,7 +40,7 @@ static_assert(false, "Implement processor architecture"); CONFIG_IDF_TARGET_ESP32S2 || // support USB via USBCDC CONFIG_IDF_TARGET_ESP32S3 // support USB via HWCDC using JTAG interface or USBCDC */ -# if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +# if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // #if CONFIG_TINYUSB_CDC_ENABLED // This define is not recognized here so use USE_USB_CDC_CONSOLE # ifdef USE_USB_CDC_CONSOLE diff --git a/lib/GPIO_DirectAccess/GPIO_Direct_Access.h b/lib/GPIO_DirectAccess/GPIO_Direct_Access.h index 36dd37c1f..24d4457af 100644 --- a/lib/GPIO_DirectAccess/GPIO_Direct_Access.h +++ b/lib/GPIO_DirectAccess/GPIO_Direct_Access.h @@ -152,7 +152,7 @@ void DIRECT_PINMODE_INPUT_ISR(IO_REG_TYPE pin); static inline __attribute__((always_inline)) IO_REG_TYPE directRead(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 +#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 return (GPIO.in.val >> pin) & 0x1; #elif CONFIG_IDF_TARGET_ESP32C6 if ( pin < 32 ) @@ -172,7 +172,7 @@ IO_REG_TYPE directRead(IO_REG_TYPE pin) static inline __attribute__((always_inline)) void directWriteLow(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 +#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 GPIO.out_w1tc.val = ((uint32_t)1 << pin); #elif CONFIG_IDF_TARGET_ESP32C6 if ( pin < 32 ) @@ -191,7 +191,7 @@ void directWriteLow(IO_REG_TYPE pin) static inline __attribute__((always_inline)) void directWriteHigh(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 +#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 GPIO.out_w1ts.val = ((uint32_t)1 << pin); #elif CONFIG_IDF_TARGET_ESP32C6 if ( pin < 32 ) @@ -210,7 +210,7 @@ void directWriteHigh(IO_REG_TYPE pin) static inline __attribute__((always_inline)) void directModeInput(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 +#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 GPIO.enable_w1tc.val = ((uint32_t)1 << (pin)); #else if ( GPIO_IS_VALID_GPIO(pin) ) @@ -243,7 +243,7 @@ void directModeInput(IO_REG_TYPE pin) static inline __attribute__((always_inline)) void directModeOutput(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 +#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 GPIO.enable_w1ts.val = ((uint32_t)1 << (pin)); #else if ( GPIO_IS_VALID_GPIO(pin) && pin <= 33 ) // pins above 33 can be only inputs diff --git a/lib/ImprovWiFi/src/ImprovTypes.h b/lib/ImprovWiFi/src/ImprovTypes.h index 3e77a7cf3..bdd43e964 100644 --- a/lib/ImprovWiFi/src/ImprovTypes.h +++ b/lib/ImprovWiFi/src/ImprovTypes.h @@ -87,6 +87,8 @@ struct ImprovWiFiParamsStruct { "ESP32-C2" #elif defined(CONFIG_IDF_TARGET_ESP32C3) "ESP32-C3" +#elif defined(CONFIG_IDF_TARGET_ESP32C5) + "ESP32-C5" #elif defined(CONFIG_IDF_TARGET_ESP32C6) "ESP32-C6" #elif defined(CONFIG_IDF_TARGET_ESP32H2) diff --git a/lib/NeoPixelBus/src/internal/DotStarEsp32DmaSpiMethod.h b/lib/NeoPixelBus/src/internal/DotStarEsp32DmaSpiMethod.h index 953a216e7..398e03344 100644 --- a/lib/NeoPixelBus/src/internal/DotStarEsp32DmaSpiMethod.h +++ b/lib/NeoPixelBus/src/internal/DotStarEsp32DmaSpiMethod.h @@ -29,12 +29,12 @@ License along with NeoPixel. If not, see #include "driver/spi_master.h" -#if (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) && !defined(HSPI_HOST) +#if (defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) && !defined(HSPI_HOST) // HSPI_HOST depreciated in C3 #define HSPI_HOST SPI2_HOST #endif -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) class Esp32VspiBus { public: @@ -52,7 +52,7 @@ public: const static int ParallelBits = 1; }; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) class Esp32Vspi2BitBus { public: @@ -70,7 +70,7 @@ public: const static int ParallelBits = 2; }; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) class Esp32Vspi4BitBus { public: @@ -174,7 +174,7 @@ public: // If pins aren't specified, initialize bus with just the default SCK and MOSI pins for the SPI peripheral (no SS, no >1-bit pins) void Initialize() { -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) if (T_SPIBUS::SpiHostDevice == VSPI_HOST) { Initialize(SCK, -1, MOSI, -1, -1, -1); @@ -277,7 +277,7 @@ private: int8_t _ssPin; }; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) // Clock Speed and Default Definitions for DotStarEsp32DmaVspi typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi40MhzMethod; typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi20MhzMethod; @@ -303,7 +303,7 @@ typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspiHz typedef DotStarEsp32DmaHspi10MhzMethod DotStarEsp32DmaHspiMethod; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) // Clock Speed and Default Definitions for DotStarEsp32DmaVspi2Bit typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit40MhzMethod; typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit20MhzMethod; @@ -329,7 +329,7 @@ typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHsp typedef DotStarEsp32DmaHspi2Bit10MhzMethod DotStarEsp32DmaHspi2BitMethod; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) // Clock Speed and Default Definitions for DotStarEsp32DmaVspi4Bit typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit40MhzMethod; typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit20MhzMethod; diff --git a/lib/NeoPixelBus/src/internal/Esp32_i2s.c b/lib/NeoPixelBus/src/internal/Esp32_i2s.c index 5823b1875..c4ff33239 100644 --- a/lib/NeoPixelBus/src/internal/Esp32_i2s.c +++ b/lib/NeoPixelBus/src/internal/Esp32_i2s.c @@ -21,7 +21,7 @@ // ESP32C3/S3 I2S is not supported yet due to significant changes to interface #ifndef CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP // turn this off with something new from idf5.1 -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C2) +#if !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C2) #include #include @@ -113,7 +113,7 @@ typedef struct { static uint8_t i2s_silence_buf[I2S_DMA_SILENCE_SIZE] = { 0 }; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) // (I2S_NUM_MAX == 2) static i2s_bus_t I2S[I2S_NUM_MAX] = { {&I2S0, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_SIZE, NULL, I2S_DMA_BLOCK_COUNT_DEFAULT, 0, 0, I2s_Is_Idle}, @@ -187,7 +187,7 @@ esp_err_t i2sSetClock(uint8_t bus_num, uint8_t div_num, uint8_t div_b, uint8_t d typeof(i2s->clkm_conf) clkm_conf; clkm_conf.val = 0; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) clkm_conf.clka_en = 0; #else clkm_conf.clk_sel = 2; @@ -222,7 +222,7 @@ void i2sSetPins(uint8_t bus_num, int8_t out, bool invert) { pinMode(out, OUTPUT); int i2sSignal; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) // (I2S_NUM_MAX == 2) if (bus_num == 1) { i2sSignal = I2S1O_DATA_OUT23_IDX; @@ -268,7 +268,7 @@ void i2sInit(uint8_t bus_num, return; } -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) // (I2S_NUM_MAX == 2) if (bus_num) { periph_module_enable(PERIPH_I2S1_MODULE); @@ -310,7 +310,7 @@ void i2sInit(uint8_t bus_num, lc_conf.out_eof_mode = 1; i2s->lc_conf.val = lc_conf.val; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) i2s->pdm_conf.pcm2pdm_conv_en = 0; i2s->pdm_conf.pdm2pcm_conv_en = 0; #endif @@ -341,7 +341,7 @@ void i2sInit(uint8_t bus_num, i2s->fifo_conf.tx_fifo_mod_force_en = 1; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) i2s->pdm_conf.rx_pdm_en = 0; i2s->pdm_conf.tx_pdm_en = 0; #endif @@ -351,7 +351,7 @@ void i2sInit(uint8_t bus_num, // enable intr in cpu // int i2sIntSource; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) // (I2S_NUM_MAX == 2) if (bus_num == 1) { i2sIntSource = ETS_I2S1_INTR_SOURCE; diff --git a/lib/NeoPixelBus/src/internal/Esp32_i2s.h b/lib/NeoPixelBus/src/internal/Esp32_i2s.h index bfc024a8c..b3df5def0 100644 --- a/lib/NeoPixelBus/src/internal/Esp32_i2s.h +++ b/lib/NeoPixelBus/src/internal/Esp32_i2s.h @@ -4,7 +4,7 @@ #ifndef CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP // turn this off with something new from idf5.1 // ESP32C3 I2S is not supported yet due to significant changes to interface -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) #ifdef __cplusplus extern "C" { diff --git a/lib/NeoPixelBus/src/internal/NeoBusChannel.h b/lib/NeoPixelBus/src/internal/NeoBusChannel.h index 5fdb131bf..87f90d614 100644 --- a/lib/NeoPixelBus/src/internal/NeoBusChannel.h +++ b/lib/NeoPixelBus/src/internal/NeoBusChannel.h @@ -12,7 +12,7 @@ enum NeoBusChannel NeoBusChannel_0, NeoBusChannel_1, -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) NeoBusChannel_2, diff --git a/lib/NeoPixelBus/src/internal/NeoEsp32I2sMethod.h b/lib/NeoPixelBus/src/internal/NeoEsp32I2sMethod.h index 2afe6d5aa..374014261 100644 --- a/lib/NeoPixelBus/src/internal/NeoEsp32I2sMethod.h +++ b/lib/NeoPixelBus/src/internal/NeoEsp32I2sMethod.h @@ -28,7 +28,7 @@ License along with NeoPixel. If not, see #if ESP_IDF_VERSION_MAJOR <= 4 // ESP32C3 I2S is not supported yet due to significant changes to interface -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) extern "C" { @@ -305,7 +305,7 @@ typedef NeoEsp32I2sMethodBase NeoEsp32I2s0400KbpsInvertedMethod; typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Apa106InvertedMethod; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) // (I2S_NUM_MAX == 2) typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Ws2812xMethod; @@ -347,7 +347,7 @@ typedef NeoEsp32I2sMethodBase NeoEs typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1800KbpsMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1400KbpsMethod; -#if !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2811Method; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2812xMethod; @@ -765,7 +765,7 @@ typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1800KbpsInvertedMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1400KbpsInvertedMethod; -#if !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2811InvertedMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2812xInvertedMethod; @@ -839,13 +839,13 @@ typedef NeoEsp32RmtMethodBase NeoEs typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1800KbpsMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1400KbpsMethod; -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6) typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2811Method; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2812xMethod; @@ -653,7 +653,7 @@ typedef NeoEsp32RmtMethodBase NeoE typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7400KbpsMethod; #endif // !defined(CONFIG_IDF_TARGET_ESP32S2) -#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) // inverted typedef NeoEsp32RmtMethodBase NeoEsp32RmtNWs2811InvertedMethod; @@ -689,7 +689,7 @@ typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1800KbpsInvertedMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1400KbpsInvertedMethod; -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6) typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2811InvertedMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2812xInvertedMethod; @@ -763,13 +763,13 @@ typedef NeoEsp32RmtMethodBase= 5 -#if (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) && !defined(HSPI_HOST) +#if (defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) && !defined(HSPI_HOST) // HSPI_HOST depreciated in C3 #define HSPI_HOST SPI2_HOST #endif diff --git a/lib/NeoPixelBus/src/internal/NeoEspBitBangMethod.cpp b/lib/NeoPixelBus/src/internal/NeoEspBitBangMethod.cpp index 01499fe13..7c66f7e40 100644 --- a/lib/NeoPixelBus/src/internal/NeoEspBitBangMethod.cpp +++ b/lib/NeoPixelBus/src/internal/NeoEspBitBangMethod.cpp @@ -29,7 +29,7 @@ License along with NeoPixel. If not, see #include // ESP32C3 I2S is not supported yet -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) #if !defined(ARDUINO_ARCH_ESP8266) #include "soc/gpio_periph.h" #endif diff --git a/platformio.ini b/platformio.ini index 0d8b3f33c..6e461dd30 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,16 +22,19 @@ extra_configs = platformio_esp82xx_envs.ini platformio_esp32_envs.ini platformio_esp32_solo1.ini - platformio_esp32c3_envs.ini platformio_esp32s2_envs.ini platformio_esp32s3_envs.ini platformio_special_envs.ini platformio_esp32c2_envs.ini + platformio_esp32c3_envs.ini + platformio_esp32c5_envs.ini platformio_esp32c6_envs.ini ;default_envs = normal_ESP32_4M default_envs = max_ESP32_16M8M_LittleFS_ETH +;default_envs = max_ESP32c5_8M1M_LittleFS_CDC_ETH + ;default_envs = normal_ESP32c6_4M316k_LittleFS_CDC ; default_envs = custom_ESP8266_4M1M diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index a13e8b50e..1591d67d4 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -195,10 +195,12 @@ lib_extra_dirs = lib/lib_ssl -; ESP_IDF 5.3.1 -[core_esp32_IDF5_3_2__3_1_0_LittleFS] -platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF54 -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3538/framework-arduinoespressif32-all-release_v5.4-8f5ad6d7.zip +; ESP_IDF 5.4.1 +[core_esp32_IDF5_4_1__3_2_0_LittleFS] +;platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF54 +;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3538/framework-arduinoespressif32-all-release_v5.4-8f5ad6d7.zip +platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 +platform_packages = build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 @@ -223,6 +225,36 @@ lib_ignore = lib_extra_dirs = lib/lib_ssl + +; ESP_IDF 5.5.0 +[core_esp32_IDF5_5_0__3_2_0_LittleFS] +platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 +platform_packages = +build_flags = -DESP32_STAGE + -DESP_IDF_VERSION_MAJOR=5 + -DLIBRARIES_NO_LOG=1 + -DDISABLE_SC16IS752_SPI +; -DCONFIG_PM_ENABLE=0 + -DETH_TYPE_JL1101_SUPPORTED + ; PR_9453_FLUSH_TO_CLEAR_REVERTED + -DPR_9453_FLUSH_TO_CLEAR=clear +; -DCONFIG_LWIP_L2_TO_L3_COPY +; -DETH_SPI_SUPPORTS_NO_IRQ=1 + -DCONFIG_FREERTOS_USE_TICKLESS_IDLE=1 + -DCONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP=3 + -DNEOPIXEL_ESP32_RMT_DEFAULT + -DCRON_USE_LOCAL_TIME + -I$PROJECT_DIR/src/include + -include "sdkconfig.h" + -include "ESPEasy_config.h" + -include "esp32x_fixes.h" + -DUPDATE_NOCRYPT +; -Wnull-dereference +lib_ignore = +lib_extra_dirs = + lib/lib_ssl + + ; Regarding the define PR_9453_FLUSH_TO_CLEAR ; See: ; https://github.com/espressif/arduino-esp32/pull/8871/files diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index e19c70d5f..bf258e2db 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -36,7 +36,7 @@ lib_ignore = [esp32_base_idf5] -extends = common, core_esp32_IDF5_3_2__3_1_0_LittleFS +extends = common, core_esp32_IDF5_4_1__3_2_0_LittleFS upload_speed = 460800 upload_before_reset = default_reset upload_after_reset = hard_reset @@ -55,7 +55,7 @@ extra_scripts = pre:tools/pio/pre_esp32.py ; However LTO cannot optimize builds with text section literals and thus will result in quite a lot larger builds (80k - 140k larger) build_unflags = -Wall -fno-lto -build_flags = ${core_esp32_IDF5_3_2__3_1_0_LittleFS.build_flags} +build_flags = ${core_esp32_IDF5_4_1__3_2_0_LittleFS.build_flags} ; ${mqtt_flags.build_flags} -DMQTT_MAX_PACKET_SIZE=2048 -DCONFIG_FREERTOS_ASSERT_DISABLE @@ -69,7 +69,45 @@ build_flags = ${core_esp32_IDF5_3_2__3_1_0_LittleFS.build_flags} -DLWIP_IPV6=1 monitor_filters = esp32_exception_decoder lib_ignore = - ${core_esp32_IDF5_3_2__3_1_0_LittleFS.lib_ignore} + ${core_esp32_IDF5_4_1__3_2_0_LittleFS.lib_ignore} + + +[esp32_base_idf5_5] +extends = common, core_esp32_IDF5_5_0__3_2_0_LittleFS +upload_speed = 460800 +upload_before_reset = default_reset +upload_after_reset = hard_reset +extra_scripts = pre:tools/pio/pre_esp32.py + post:tools/pio/post_esp32.py + ${extra_scripts_default.extra_scripts} + post:tools/pio/copy_files.py +; you can disable debug linker flag to reduce binary size (comment out line below), but the backtraces will become less readable +; tools/pio/extra_linker_flags.py +; fix the platform package to use gcc-ar and gcc-ranlib to enable lto linker plugin +; more detail: https://embeddedartistry.com/blog/2020/04/13/prefer-gcc-ar-to-ar-in-your-buildsystems/ +; pre:tools/pio/apply_patches.py + +; When using LTO, make sure NOT to use -mtext-section-literals +; -mtext-section-literals may be required when building large builds +; However LTO cannot optimize builds with text section literals and thus will result in quite a lot larger builds (80k - 140k larger) +build_unflags = -Wall + -fno-lto +build_flags = ${core_esp32_IDF5_5_0__3_2_0_LittleFS.build_flags} +; ${mqtt_flags.build_flags} + -DMQTT_MAX_PACKET_SIZE=2048 + -DCONFIG_FREERTOS_ASSERT_DISABLE + -DCONFIG_LWIP_ESP_GRATUITOUS_ARP + -fno-strict-aliasing + -flto=auto + -Wswitch + -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE +; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO +; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE + -DLWIP_IPV6=1 + -DCONFIG_BT_NIMBLE_NVS_PERSIST=y +monitor_filters = esp32_exception_decoder +lib_ignore = + ${core_esp32_IDF5_5_0__3_2_0_LittleFS.lib_ignore} ; -flto cannot be used for ESP32 C3! @@ -120,7 +158,7 @@ board_build.filesystem = littlefs lib_ignore = ${esp32_always.lib_ignore} ESP32_ping ESP32 BLE Arduino - ${core_esp32_IDF5_3_2__3_1_0_LittleFS.lib_ignore} + ${core_esp32_IDF5_4_1__3_2_0_LittleFS.lib_ignore} [esp32_IRExt] diff --git a/platformio_esp32c5_envs..ini b/platformio_esp32c5_envs..ini new file mode 100644 index 000000000..1322859eb --- /dev/null +++ b/platformio_esp32c5_envs..ini @@ -0,0 +1,29 @@ + + +[esp32c5_common_LittleFS] +extends = esp32_base_idf5 +build_flags = ${esp32_base_idf5.build_flags} + -DFEATURE_ARDUINO_OTA=1 + -DUSE_LITTLEFS + -DESP32C5 +extra_scripts = ${esp32_base_idf5.extra_scripts} +build_unflags = ${esp32_base_idf5.build_unflags} + -fexceptions +board_build.filesystem = littlefs +lib_ignore = ${esp32_base_idf5.lib_ignore} +board = esp32c5cdc + + +[env:max_ESP32c5_8M1M_LittleFS_CDC_ETH] +extends = esp32c5_common_LittleFS +board = esp32c5cdc-8M +build_flags = ${esp32c5_common_LittleFS.build_flags} + -DFEATURE_ETHERNET=1 + -DFEATURE_ARDUINO_OTA=1 + -DPLUGIN_BUILD_MAX_ESP32 + -DPLUGIN_BUILD_IR_EXTENDED + -D ST7789_EXTRA_INIT=1 + -D P116_EXTRA_ST7789=1 +extra_scripts = ${esp32c5_common_LittleFS.extra_scripts} + + diff --git a/src/include/ESPEasy_config.h b/src/include/ESPEasy_config.h index 8ccfe1643..7dce45094 100644 --- a/src/include/ESPEasy_config.h +++ b/src/include/ESPEasy_config.h @@ -149,7 +149,7 @@ constexpr unsigned CEIL_LOG2(unsigned x) # endif // ifdef ESP8266 # ifdef ESP32 - # if defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C6) + # if defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) // (ESP32) FsP: FlashstringHelper to String-Pointer # define FsP diff --git a/src/include/esp32x_fixes.h b/src/include/esp32x_fixes.h index 4c5a5e780..44c3ab47c 100644 --- a/src/include/esp32x_fixes.h +++ b/src/include/esp32x_fixes.h @@ -87,7 +87,7 @@ # endif // REG_SPI_BASE # endif // ESP_IDF_VERSION_MAJOR < 5 -#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 +#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 # define SPI_HOST SPI1_HOST # define HSPI_HOST SPI2_HOST # define VSPI_HOST SPI2_HOST /* No SPI3_host on C2/C6 */ diff --git a/src/src/CustomBuild/ESPEasy_buildinfo.h b/src/src/CustomBuild/ESPEasy_buildinfo.h index 3b203c12f..b6f669d73 100644 --- a/src/src/CustomBuild/ESPEasy_buildinfo.h +++ b/src/src/CustomBuild/ESPEasy_buildinfo.h @@ -34,8 +34,14 @@ # define BUILD_NOTES " - Mega32-s2" #elif defined(ESP32S3) # define BUILD_NOTES " - Mega32-s3" + #elif defined(ESP32H2) + # define BUILD_NOTES " - Mega32-h2" + #elif defined(ESP32P4) + # define BUILD_NOTES " - Mega32-p4" #elif defined(ESP32C6) # define BUILD_NOTES " - Mega32-c6" + #elif defined(ESP32C5) + # define BUILD_NOTES " - Mega32-c5" #elif defined(ESP32C3) # define BUILD_NOTES " - Mega32-c3" #elif defined(ESP32C2) @@ -66,7 +72,7 @@ CONFIG_IDF_TARGET_ESP32S2 || // support USB via USBCDC CONFIG_IDF_TARGET_ESP32S3 // support USB via HWCDC using JTAG interface or USBCDC */ -# if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +# if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // #if CONFIG_TINYUSB_CDC_ENABLED // This define is not recognized here so use USE_USB_CDC_CONSOLE # ifdef USE_USB_CDC_CONSOLE diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index e84d76cc9..53dfb5898 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -3477,7 +3477,7 @@ To create/register a plugin, you have to : #ifndef FEATURE_SET_WIFI_TX_PWR #ifdef ESP32 - #if defined(ESP32S2) || defined(ESP32S3) || defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C6) + #if defined(ESP32S2) || defined(ESP32S3) || defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) #define FEATURE_SET_WIFI_TX_PWR 1 #else // TD-er: Disable setting TX power on ESP32 as it seems to cause issues on IDF4.4 diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index bab5c2fa0..50251e7b8 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -115,6 +115,10 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { bits.phy_11ax = it->phy_11ax; bits.ftm_initiator = it->ftm_initiator; bits.ftm_responder = it->ftm_responder; +#ifdef ESP32C5 + bits.phy_11a = it->phy_11a; + bits.phy_11ac = it->phy_11ac; +#endif # endif // if ESP_IDF_VERSION_MAJOR >= 5 bits.wps = it->wps; @@ -252,6 +256,14 @@ String WiFi_AP_Candidate::toString(const String& separator) const { separator.c_str(), channel); +#ifdef ESP32C5 + if (channel < 36) { + result += F(" 2.4 GHz"); + } else { + result += F(" 5 GHz"); + } +#endif + if (rssi == -1) { result += F(" (RTC) "); } else { @@ -292,7 +304,6 @@ String WiFi_AP_Candidate::toString(const String& separator) const { if (bits.phy_11n) { phy_str += 'n'; } #ifdef ESP32 - if (bits.phy_11ax) { phy_str += F("/ax"); } if (bits.phy_lr) { phy_str += F("/lr"); } @@ -300,6 +311,11 @@ String WiFi_AP_Candidate::toString(const String& separator) const { if (bits.ftm_initiator) { phy_str += F("/FTM_i"); } if (bits.ftm_responder) { phy_str += F("/FTM_r"); } + + // Add 5 GHz WiFi types as last in the list. + if (bits.phy_11a) { phy_str += F("/a"); } + if (bits.phy_11ac) { phy_str += F("/ac"); } + #endif // ifdef ESP32 if (phy_str.length()) { diff --git a/src/src/DataStructs/WiFi_AP_Candidate.h b/src/src/DataStructs/WiFi_AP_Candidate.h index 8dda8a5ab..cfcb2bf1c 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.h +++ b/src/src/DataStructs/WiFi_AP_Candidate.h @@ -93,12 +93,14 @@ struct WiFi_AP_Candidate { uint16_t phy_11g : 1; uint16_t phy_11n : 1; uint16_t phy_lr : 1; - uint16_t phy_11ax : 1; + uint16_t phy_11a : 1; // traditional (old) 5 GHz + uint16_t phy_11ac : 1; // 5 GHz WiFi 5, 802.11ac + uint16_t phy_11ax : 1; // WiFi 6, both bands possible uint16_t wps : 1; uint16_t ftm_responder : 1; uint16_t ftm_initiator : 1; - uint16_t unused : 5; + uint16_t unused : 3; } bits; uint16_t _allBits; diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 5e706b595..7d0aba71d 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -743,7 +743,7 @@ bool SettingsStruct_tmpl::getPinBootStateIndex( index_high = gpio_pin - maxStates; -# if defined(ESP32_CLASSIC) || defined(ESP32C2) || defined(ESP32C3)|| defined(ESP32C6) +# if defined(ESP32_CLASSIC) || defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C5) || defined(ESP32C6) // These can all store in the PinBootStates_ESP32 array return (index_high < maxStatesesp32); diff --git a/src/src/DataTypes/SPI_options.cpp b/src/src/DataTypes/SPI_options.cpp index 575611044..0736a212e 100644 --- a/src/src/DataTypes/SPI_options.cpp +++ b/src/src/DataTypes/SPI_options.cpp @@ -42,6 +42,8 @@ #define VSPI_FSPI_SHORT_STRING "FSPI" # elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 #define VSPI_FSPI_SHORT_STRING "SPI" +# elif CONFIG_IDF_TARGET_ESP32C5 // ESP32-C5 +#define VSPI_FSPI_SHORT_STRING "FSPI" # elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6 #define VSPI_FSPI_SHORT_STRING "FSPI" # elif CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 diff --git a/src/src/DataTypes/SPI_options.h b/src/src/DataTypes/SPI_options.h index b2a8627dc..b70459622 100644 --- a/src/src/DataTypes/SPI_options.h +++ b/src/src/DataTypes/SPI_options.h @@ -51,6 +51,10 @@ #define VSPI_FSPI_SCK 21 #define VSPI_FSPI_MISO 20 #define VSPI_FSPI_MOSI 19 +# elif CONFIG_IDF_TARGET_ESP32C5 // ESP32-C5 +#define VSPI_FSPI_SCK 4 +#define VSPI_FSPI_MISO 5 +#define VSPI_FSPI_MOSI 6 # elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 #define VSPI_FSPI_SCK 4 #define VSPI_FSPI_MISO 5 diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 9a018c3a7..828736fe5 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -379,7 +379,10 @@ void WifiScan(bool async, uint8_t channel) { # ifdef ESP32 const bool passive = Settings.PassiveWiFiScan(); const uint32_t max_ms_per_chan = 120; +#ifndef ESP32C5 + // C5 scans both 2.4 and 5 GHz band, which takes much longer WiFi.setScanTimeout(14 * max_ms_per_chan * 2); +#endif WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan /*, channel */); # endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index 18b3cd7fc..cb83130f1 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -295,14 +295,19 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { // The response speed and stability is better at HT20 for ESP units. esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT20); - uint8_t protocol = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G; // Default to BG + // uint8_t protocol = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G; // Default to BG + uint8_t protocol = 0; if (!ForceWiFi_bg_mode || (WiFiEventData.connectionFailures > 10)) { // Set to use BGN protocol |= WIFI_PROTOCOL_11N; - # ifdef ESP32C6 + # if defined(ESP32C5) || defined(ESP32C6) protocol |= WIFI_PROTOCOL_11AX; # endif + #ifdef ESP32C5 + protocol |= WIFI_PROTOCOL_11A; + protocol |= WIFI_PROTOCOL_11AC; + #endif } const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); @@ -316,13 +321,25 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { protocol |= WIFI_PROTOCOL_11N; addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11n only")); } -# ifdef ESP32C6 +# if defined(ESP32C5) || defined(ESP32C6) if (candidate.bits.phy_11ax) { // Set to use WiFi6 protocol |= WIFI_PROTOCOL_11AX; - addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11ax")); + addLog(LOG_LEVEL_INFO, F("WIFI : AP allows 802.11ax, Wi-Fi 6")); } +#ifdef ESP32C5 + if (candidate.bits.phy_11a) { + // Set to use 5 GHz WiFi + protocol |= WIFI_PROTOCOL_11A; + addLog(LOG_LEVEL_INFO, F("WIFI : AP allows 802.11a, 5 GHz")); + } + if (candidate.bits.phy_11ac) { + // Set to use 5 GHz WiFi-5 + protocol |= WIFI_PROTOCOL_11AC; + addLog(LOG_LEVEL_INFO, F("WIFI : AP allows 802.11ac, 5 GHz Wi-Fi 5")); + } +#endif # endif // ifdef ESP32C6 } } diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 06272a37b..613923cd8 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -17,6 +17,7 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../ESPEasyCore/Serial.h" #include "../Globals/CRCValues.h" @@ -679,7 +680,7 @@ bool check_and_update_WiFi_Calibration() { bool Erase_WiFi_Calibration() { #ifdef ESP8266 WifiDisconnect(); - setWifiMode(WIFI_OFF); + ESPEasy::net::wifi::setWifiMode(WIFI_OFF); if (!ESP.eraseConfig()) return false; #ifndef BUILD_MINIMAL_OTA @@ -689,7 +690,7 @@ bool Erase_WiFi_Calibration() { #ifdef ESP32 WifiDisconnect(); - setWifiMode(WIFI_OFF); + ESPEasy::net::wifi::setWifiMode(WIFI_OFF); // Make sure power is stable, so wait a bit longer delay(1000); esp_phy_erase_cal_data_in_nvs(); diff --git a/src/src/Helpers/Hardware.cpp b/src/src/Helpers/Hardware.cpp index 29281b201..bff72f4c6 100644 --- a/src/src/Helpers/Hardware.cpp +++ b/src/src/Helpers/Hardware.cpp @@ -444,6 +444,8 @@ int getCPU_MaxFreqMHz() return 160; #elif CONFIG_IDF_TARGET_ESP32C6 return 160; +#elif CONFIG_IDF_TARGET_ESP32C5 + return 240; #elif CONFIG_IDF_TARGET_ESP32H2 //IDF-6570 return 96; @@ -673,6 +675,30 @@ void readBootCause() { case POWER_GLITCH_RESET : lastBootCause = BOOT_CAUSE_POWER_UNSTABLE; break; /**<23, power glitch reset digital core and rtc module*/ } +#elif defined(ESP32C5) + switch (rtc_get_reset_reason(0)) { + case NO_MEAN : break; + case POWERON_RESET : lastBootCause = BOOT_CAUSE_MANUAL_REBOOT; break; /**<1, Vbat power on reset*/ + case RTC_SW_SYS_RESET : lastBootCause = BOOT_CAUSE_SOFT_RESTART; break; /**<3, Software reset digital core*/ + case DEEPSLEEP_RESET : lastBootCause = BOOT_CAUSE_DEEP_SLEEP; break; /**<5, Deep Sleep reset digital core*/ +// case SDIO_RESET : lastBootCause = BOOT_CAUSE_MANUAL_REBOOT; break; /**<6, Reset by SLC module, reset digital core (hp system)*/ + case TG0WDT_SYS_RESET : lastBootCause = BOOT_CAUSE_EXT_WD; break; /**<7, Timer Group0 Watch dog reset digital core*/ + case TG1WDT_SYS_RESET : lastBootCause = BOOT_CAUSE_EXT_WD; break; /**<8, Timer Group1 Watch dog reset digital core*/ + case RTCWDT_SYS_RESET : lastBootCause = BOOT_CAUSE_EXT_WD; break; /**<9, RTC Watch dog Reset digital core*/ + case TG0WDT_CPU_RESET : lastBootCause = BOOT_CAUSE_EXT_WD; break; /**<11, Time Group0 reset CPU*/ + case RTC_SW_CPU_RESET : lastBootCause = BOOT_CAUSE_SOFT_RESTART; break; /**<12, Software reset CPU*/ + case RTCWDT_CPU_RESET : lastBootCause = BOOT_CAUSE_EXT_WD; break; /**<13, RTC Watch dog Reset CPU*/ + case RTCWDT_BROWN_OUT_RESET : lastBootCause = BOOT_CAUSE_POWER_UNSTABLE; break; /**<15, Reset when the vdd voltage is not stable*/ + case RTCWDT_RTC_RESET : lastBootCause = BOOT_CAUSE_EXT_WD; break; /**<16, RTC Watch dog reset digital core and rtc module*/ + case TG1WDT_CPU_RESET : lastBootCause = BOOT_CAUSE_EXT_WD; break; /**<17, Time Group1 reset CPU*/ + case SUPER_WDT_RESET : lastBootCause = BOOT_CAUSE_EXT_WD; break; /**<18, super watchdog reset digital core and rtc module*/ + case EFUSE_RESET : lastBootCause = BOOT_CAUSE_MANUAL_REBOOT; break; /**<20, efuse reset digital core*/ + case USB_UART_CHIP_RESET : lastBootCause = BOOT_CAUSE_MANUAL_REBOOT; break; /**<21, usb uart reset digital core */ + case USB_JTAG_CHIP_RESET : lastBootCause = BOOT_CAUSE_MANUAL_REBOOT; break; /**<22, usb jtag reset digital core */ + case JTAG_RESET : lastBootCause = BOOT_CAUSE_MANUAL_REBOOT; break; /**<24, jtag reset CPU*/ + } + + #elif defined(ESP32C6) switch (rtc_get_reset_reason(0)) { case NO_MEAN : break; diff --git a/src/src/Helpers/Hardware_ADC_cali.h b/src/src/Helpers/Hardware_ADC_cali.h index 824ad553d..0972e714c 100644 --- a/src/src/Helpers/Hardware_ADC_cali.h +++ b/src/src/Helpers/Hardware_ADC_cali.h @@ -18,7 +18,7 @@ # include # endif // if ESP_IDF_VERSION_MAJOR >= 5 -# if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 +# if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 /** * On ESP32C3, ADC2 is no longer supported, due to its HW limitation. * Search for errata on espressif website for more details. diff --git a/src/src/Helpers/Hardware_GPIO_ESP32C5.cpp b/src/src/Helpers/Hardware_GPIO_ESP32C5.cpp new file mode 100644 index 000000000..f70b53b27 --- /dev/null +++ b/src/src/Helpers/Hardware_GPIO_ESP32C5.cpp @@ -0,0 +1,166 @@ +#include "../Helpers/Hardware_GPIO.h" + +#ifdef ESP32C5 +# include + +# include "../Helpers/Hardware_device_info.h" + +// ******************************************************************************** +// Get info of a specific GPIO pin +// ******************************************************************************** + +bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) { + pinnr = -1; // ESP32 does not label the pins, they just use the GPIO number. + + input = GPIO_IS_VALID_GPIO(gpio); + output = GPIO_IS_VALID_OUTPUT_GPIO(gpio); + warning = isBootStrapPin(gpio); + + if (!(GPIO_IS_VALID_GPIO(gpio))) { return false; } + + + // FIXME TD-er: Implement for ESP32-C5 + // See: + // - https://docs.espressif.com/projects/esp-idf/en/v5.0/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html + // - https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/gpio.html + // Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf + + if (gpio == 11) { + if (getChipFeatures().embeddedFlash /* || !flashVddPinCanBeUsedAsGPIO() */) { + // See: https://www.letscontrolit.com/forum/viewtopic.php?p=71880#p71874 + // + // By default VDD_SPI is the power supply pin for embedded flash or external flash. + // It can only be used as GPIO11 only when the chip is connected to an + // external flash, and this flash is powered by an external power supply + input = false; + output = false; + } + warning = true; + } + + if (isFlashInterfacePin_ESPEasy(gpio)) { + if (getChipFeatures().embeddedFlash) { + // Connected to the integrated SPI flash. + input = false; + output = false; + } else { + // See: https://www.letscontrolit.com/forum/viewtopic.php?p=71880#p71874 + if ((gpio == 12) || (gpio == 13)) { + // SPIHD/GPIO12 + // SPIWP/GPIO13 + if ((ESP.getFlashChipMode() != FM_DOUT) && + (ESP.getFlashChipMode() != FM_DIO)) { + input = false; + output = false; + } + } + } + warning = true; + } + + if ((gpio == PIN_USB_D_MIN) || (gpio == PIN_USB_D_PLUS)) { + // USB OTG and USB Serial/JTAG function. USB signal is a differential + // signal transmitted over a pair of D+ and D- wires. + warning = true; + } + + // GPIO 18: USB_D- + // GPIO 19: USB_D+ + + // GPIO 20: U0RXD + // GPIO 21: U0TXD + + return (input || output); +} + +bool isBootStrapPin(int gpio) +{ + if (gpio == 2) { + // Strapping pin which must be high during boot + return true; + } + + if (gpio == 8) { + // Strapping pin which must be high during flashing + return true; + } + + if (gpio == 9) { + // Strapping pin to force download mode (like GPIO-0 on ESP8266/ESP32-classic) + return true; + } + return false; +} + +bool getGpioPullResistor(int gpio, bool& hasPullUp, bool& hasPullDown) { + hasPullDown = false; + hasPullUp = false; + + if (validGpio(gpio)) { + hasPullUp = true; + hasPullDown = true; + } + return true; +} + +bool validGpio(int gpio) { + if (!GPIO_IS_VALID_GPIO(gpio)) { return false; } + + int pinnr; + bool input; + bool output; + bool warning; + + return getGpioInfo(gpio, pinnr, input, output, warning); +} + +// Get ADC related info for a given GPIO pin +// @param gpio_pin GPIO pin number +// @param adc Number of ADC unit (0 == Hall effect) +// @param ch Channel number on ADC unit +// @param t index of touch pad ID +bool getADC_gpio_info(int gpio_pin, int& adc, int& ch, int& t) +{ + adc = -1; + ch = -1; + t = -1; + + if ((gpio_pin >= 0) && (gpio_pin <= 4)) { + adc = 1; + ch = gpio_pin; + return true; + } + # if ESP_IDF_VERSION_MAJOR >= 5 + + // Support for ADC2 has been dropped. + # else // if ESP_IDF_VERSION_MAJOR >= 5 + + if (gpio_pin == 5) { + adc = 2; + ch = 0; + return true; + } + # endif // if ESP_IDF_VERSION_MAJOR >= 5 + return false; +} + +#if SOC_TOUCH_SENSOR_SUPPORTED +int touchPinToGpio(int touch_pin) +{ + // No touch pin support + return -1; +} +#endif + +#if SOC_DAC_SUPPORTED +// Get DAC related info for a given GPIO pin +// @param gpio_pin GPIO pin number +// @param dac Number of DAC unit +bool getDAC_gpio_info(int gpio_pin, int& dac) +{ + // ESP32-C5, ESP32-S3, ESP32-C2, ESP32-C6 and ESP32-H2 don't have a DAC onboard + return false; +} +#endif + +#endif // ifdef ESP32C5 diff --git a/src/src/Helpers/Hardware_defines.h b/src/src/Helpers/Hardware_defines.h index bfd7c13a0..e58d72e0a 100644 --- a/src/src/Helpers/Hardware_defines.h +++ b/src/src/Helpers/Hardware_defines.h @@ -55,7 +55,7 @@ # define WIFI_SENSITIVITY_11b -88 # define WIFI_SENSITIVITY_54g -76 # define WIFI_SENSITIVITY_n -72 -#elif defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C6) +#elif defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) # define MAX_TX_PWR_DBM_11b 21.0f # define MAX_TX_PWR_DBM_54g 19.0f # define MAX_TX_PWR_DBM_n 18.5f @@ -81,6 +81,8 @@ static_assert(false, "Implement processor architecture"); # define SOC_RX0 44 # elif CONFIG_IDF_TARGET_ESP32C6 # define SOC_RX0 17 +# elif CONFIG_IDF_TARGET_ESP32C5 +# define SOC_RX0 12 # elif CONFIG_IDF_TARGET_ESP32C3 # define SOC_RX0 20 # elif CONFIG_IDF_TARGET_ESP32C2 @@ -97,6 +99,8 @@ static_assert(false, "Implement processor architecture"); # define SOC_TX0 43 # elif CONFIG_IDF_TARGET_ESP32C6 # define SOC_TX0 16 +# elif CONFIG_IDF_TARGET_ESP32C5 +# define SOC_TX0 11 # elif CONFIG_IDF_TARGET_ESP32C3 # define SOC_TX0 21 # elif CONFIG_IDF_TARGET_ESP32C2 @@ -114,6 +118,9 @@ static_assert(false, "Implement processor architecture"); #ifdef ESP32C6 #define PIN_USB_D_MIN 12 #endif +#ifdef ESP32C5 +#define PIN_USB_D_MIN 13 +#endif #ifdef ESP32C3 #define PIN_USB_D_MIN 18 #endif @@ -127,6 +134,9 @@ static_assert(false, "Implement processor architecture"); #ifdef ESP32C6 #define PIN_USB_D_PLUS 13 #endif +#ifdef ESP32C5 +#define PIN_USB_D_PLUS 14 +#endif #ifdef ESP32C3 #define PIN_USB_D_PLUS 19 #endif diff --git a/src/src/Helpers/Hardware_device_info_ESP32C5.cpp b/src/src/Helpers/Hardware_device_info_ESP32C5.cpp index e9b9148bf..bbed9d264 100644 --- a/src/src/Helpers/Hardware_device_info_ESP32C5.cpp +++ b/src/src/Helpers/Hardware_device_info_ESP32C5.cpp @@ -2,17 +2,78 @@ #ifdef ESP32C5 +# include +# include +# include +# include +# include +# include +# include + + +bool isFlashInterfacePin_ESPEasy(int gpio) { + // FIXME TD-er: Must know whether we have internal or external flash + + // For chip variants with an in-package flash, this pin can not be used. + + + switch (gpio) { + case MSPI_IOMUX_PIN_NUM_HD: + case MSPI_IOMUX_PIN_NUM_WP: + case MSPI_IOMUX_PIN_NUM_CS0: + case MSPI_IOMUX_PIN_NUM_CLK: + case MSPI_IOMUX_PIN_NUM_MOSI: + case MSPI_IOMUX_PIN_NUM_MISO: + return true; + } + return false; + + // return (gpio) >= 24 && (gpio) <= 30 && gpio != 27; +} + +bool flashVddPinCanBeUsedAsGPIO() +{ + return false; +} + +int32_t getEmbeddedFlashSize() +{ + /* + // See: framework-arduinoespressif32\tools\esp32-arduino-libs\esp32c5\include\soc\esp32c5\include\soc\efuse_reg.h + const uint32_t flash_cap = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_4_REG, EFUSE_FLASH_CAP); + + // FIXME TD-er: No idea about meaning of values + switch (flash_cap) { + case 0: return 0; + case 1: return 4; + case 2: return 2; + case 3: return 1; + case 4: return 8; + } + + // Unknown value, thus mark as negative value + return -1 * static_cast(flash_cap); + */ + return 8; +} + +int32_t getEmbeddedPSRAMSize() +{ + // Doesn't have PSRAM + return 0; +} + +# ifndef isPSRAMInterfacePin +bool isPSRAMInterfacePin(int gpio) { + return false; +} + +# endif // ifndef isPSRAMInterfacePin + const __FlashStringHelper* getChipModel(uint32_t chip_model, uint32_t chip_revision, uint32_t pkg_version, bool single_core) { - if (17 == chip_model) { // ESP32-C5 beta3 (MPW) - return F("ESP32-C5 beta3"); - } - else if (23 == chip_model) { // ESP32-C5 MP - return F("ESP32-C5"); - } - - return F("Unknown"); + return F("ESP32-C5"); } #endif // ifdef ESP32C5 diff --git a/src/src/Helpers/Hardware_temperature_sensor.cpp b/src/src/Helpers/Hardware_temperature_sensor.cpp index 6420ca5d6..3104a1abd 100644 --- a/src/src/Helpers/Hardware_temperature_sensor.cpp +++ b/src/src/Helpers/Hardware_temperature_sensor.cpp @@ -17,7 +17,7 @@ extern "C" { uint8_t temprature_sens_read(); } -# elif defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C6) || defined(ESP32S2) || defined(ESP32S3) +# elif defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) || defined(ESP32S2) || defined(ESP32S3) # if ESP_IDF_VERSION_MAJOR < 5 # include @@ -62,7 +62,7 @@ esp_err_t do_read_internal_temperature(float& celsius) { return result; } -# elif defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C6) || defined(ESP32S2) || defined(ESP32S3) +# elif defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) || defined(ESP32S2) || defined(ESP32S3) esp_err_t do_read_internal_temperature(float& celsius) { esp_err_t result = ESP_FAIL; diff --git a/src/src/Helpers/StringGenerator_GPIO.cpp b/src/src/Helpers/StringGenerator_GPIO.cpp index 4841f57ec..36f4cc58c 100644 --- a/src/src/Helpers/StringGenerator_GPIO.cpp +++ b/src/src/Helpers/StringGenerator_GPIO.cpp @@ -195,6 +195,9 @@ const __FlashStringHelper* getConflictingUse(int gpio, PinSelectPurpose purpose, // See Appendix A, page 71: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf + #elif defined(ESP32C5) + // TODO TD-er: Must check if C5 has conflicts here + #elif defined(ESP32C6) if (gpio == 27) { diff --git a/src/src/Helpers/StringGenerator_System.cpp b/src/src/Helpers/StringGenerator_System.cpp index ff7ffd40c..ba59809f2 100644 --- a/src/src/Helpers/StringGenerator_System.cpp +++ b/src/src/Helpers/StringGenerator_System.cpp @@ -19,6 +19,8 @@ #include #elif defined(ESP32C3) #include + #elif defined(ESP32C5) + #include #elif defined(ESP32C6) #include # elif defined(ESP32_CLASSIC) @@ -177,6 +179,32 @@ const __FlashStringHelper * getResetReasonString_f(uint8_t icore, bool& isDEEPSL case POWER_GLITCH_RESET : return F("power glitch reset digital core and rtc module"); } + #elif defined(ESP32C5) + + // See tools\sdk\esp32\include\esp_rom\include\esp32c6\rom\rtc.h + switch (rtc_get_reset_reason(icore)) { + case NO_MEAN : break; + case POWERON_RESET : return F("Vbat power on reset"); + case RTC_SW_SYS_RESET : return F("Software reset digital core (hp system)"); + case DEEPSLEEP_RESET : isDEEPSLEEP_RESET = true; break; + //case DEEPSLEEP_RESET : return F("Deep Sleep reset digital core (hp system)"); +// case SDIO_RESET : return F("Reset by SLC module, reset digital core (hp system)"); + case TG0WDT_SYS_RESET : return F("Timer Group0 Watch dog reset digital core (hp system)"); + case TG1WDT_SYS_RESET : return F("Timer Group1 Watch dog reset digital core (hp system)"); + case RTCWDT_SYS_RESET : return F("RTC Watch dog Reset digital core (hp system)"); + case TG0WDT_CPU_RESET : return F("Time Group0 reset CPU"); + case RTC_SW_CPU_RESET : return F("Software reset CPU"); + case RTCWDT_CPU_RESET : return F("RTC Watch dog Reset CPU"); + case RTCWDT_BROWN_OUT_RESET : return F("Reset when the vdd voltage is not stable"); + case RTCWDT_RTC_RESET : return F("RTC Watch dog reset digital core and rtc module"); + case TG1WDT_CPU_RESET : return F("Time Group1 reset CPU"); + case SUPER_WDT_RESET : return F("super watchdog reset digital core and rtc module"); + case EFUSE_RESET : return F("efuse reset digital core (hp system)"); + case USB_UART_CHIP_RESET : return F("usb uart reset digital core (hp system)"); + case USB_JTAG_CHIP_RESET : return F("usb jtag reset digital core (hp system)"); + case JTAG_RESET : return F("jtag reset CPU"); + } + #elif defined(ESP32C6) // See tools\sdk\esp32\include\esp_rom\include\esp32c6\rom\rtc.h diff --git a/tools/pio/copy_files.py b/tools/pio/copy_files.py index 3aa58d0cf..53aa332ee 100644 --- a/tools/pio/copy_files.py +++ b/tools/pio/copy_files.py @@ -21,11 +21,11 @@ def get_max_bin_size(env_name, file_suffix): if "4M316k" in env_name or "_ESP32_4M2M" in env_name: # ESP32 with 1800k of sketch space. max_bin_size = 1900544 - if "_ESP32_" in env_name or "_ESP32c6_" in env_name or "_ESP32s2_" in env_name or "_ESP32s3_" in env_name: + if "_ESP32_" in env_name or "_ESP32c5_" in env_name or "_ESP32c6_" in env_name or "_ESP32s2_" in env_name or "_ESP32s3_" in env_name: if "_8M1M" in env_name: # ESP32 with 3520k of sketch space. max_bin_size = 3604480 - if "_ESP32_" in env_name or "_ESP32c3_" in env_name or "_ESP32c6_" in env_name or "_ESP32s2_" in env_name or "_ESP32s3_" in env_name: + if "_ESP32_" in env_name or "_ESP32c3_" in env_name or "_ESP32c5_" in env_name or "_ESP32c6_" in env_name or "_ESP32s2_" in env_name or "_ESP32s3_" in env_name: if "_16M8M" in env_name or "_16M2M" in env_name or "_16M1M" in env_name: # ESP32 with 4096k of sketch space. max_bin_size = 4194304 @@ -86,8 +86,12 @@ def generate_webflash_json_manifest(variant, file_suffix): chipFamily = 'ESP32-C2' elif 'ESP32c3' in variant: chipFamily = 'ESP32-C3' + elif 'ESP32c5' in variant: + chipFamily = 'ESP32-C5' elif 'ESP32c6' in variant: chipFamily = 'ESP32-C6' + elif 'ESP32p4' in variant: + chipFamily = 'ESP32-P4' elif 'ESP32h2' in variant: chipFamily = 'ESP32-H2' else: diff --git a/tools/pio/generate_web_flasher_manifest.py b/tools/pio/generate_web_flasher_manifest.py index b0f1cbfad..7ca9e1d5b 100644 --- a/tools/pio/generate_web_flasher_manifest.py +++ b/tools/pio/generate_web_flasher_manifest.py @@ -33,10 +33,14 @@ def create_display_text(description, version, families): esp32_split.append('C2') if 'ESP32-C3' in families: esp32_split.append('C3') + if 'ESP32-C5' in families: + esp32_split.append('C5') if 'ESP32-C6' in families: esp32_split.append('C6') if 'ESP32-H2' in families: esp32_split.append('H2') + if 'ESP32-P4' in families: + esp32_split.append('P4') if len(esp32_split) > 0: fam_split.append('ESP32-' + '/'.join(esp32_split)) @@ -74,10 +78,14 @@ def parse_filename(file, version, variant, file_suffix): chipFamily = 'ESP32-C2' elif 'ESP32c3' in variant: chipFamily = 'ESP32-C3' + elif 'ESP32c5' in variant: + chipFamily = 'ESP32-C5' elif 'ESP32c6' in variant: chipFamily = 'ESP32-C6' elif 'ESP32h2' in variant: chipFamily = 'ESP32-H2' + elif 'ESP32p4' in variant: + chipFamily = 'ESP32-P4' else: chipFamily = 'ESP32' From 732b4ff6229d158eb726e7d0da44466d50ac018a Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 25 May 2025 00:24:22 +0200 Subject: [PATCH 053/564] [ESP32-C5] Minor tweaks formatting used WiFi protocol --- platformio_esp32c6_envs.ini | 29 +++++++++++ src/src/DataStructs/WiFi_AP_Candidate.cpp | 23 ++++++-- src/src/DataTypes/WiFiConnectionProtocol.cpp | 55 +++++++++++++------- src/src/DataTypes/WiFiConnectionProtocol.h | 18 +++++-- 4 files changed, 98 insertions(+), 27 deletions(-) diff --git a/platformio_esp32c6_envs.ini b/platformio_esp32c6_envs.ini index a97e1ac48..1921ee92d 100644 --- a/platformio_esp32c6_envs.ini +++ b/platformio_esp32c6_envs.ini @@ -57,3 +57,32 @@ build_flags = ${esp32c6_common_LittleFS.build_flags} extra_scripts = ${esp32c6_common_LittleFS.extra_scripts} + + + +[esp32c5_common_LittleFS] +extends = esp32_base_idf5 +build_flags = ${esp32_base_idf5.build_flags} + -DFEATURE_ARDUINO_OTA=1 + -DUSE_LITTLEFS + -DESP32C5 +extra_scripts = ${esp32_base_idf5.extra_scripts} +build_unflags = ${esp32_base_idf5.build_unflags} + -fexceptions +board_build.filesystem = littlefs +lib_ignore = ${esp32_base_idf5.lib_ignore} +board = esp32c5cdc + + +[env:max_ESP32c5_8M1M_LittleFS_CDC_ETH] +extends = esp32c5_common_LittleFS +board = esp32c5cdc-8M +build_flags = ${esp32c5_common_LittleFS.build_flags} + -DFEATURE_ETHERNET=1 + -DFEATURE_ARDUINO_OTA=1 + -DPLUGIN_BUILD_MAX_ESP32 + -DPLUGIN_BUILD_IR_EXTENDED + -D ST7789_EXTRA_INIT=1 + -D P116_EXTRA_ST7789=1 +extra_scripts = ${esp32c5_common_LittleFS.extra_scripts} + diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index 50251e7b8..907c3d5d2 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -297,13 +297,32 @@ String WiFi_AP_Candidate::toString(const String& separator) const { if (phy_known()) { String phy_str; + // Order of items is kinda in order of age, oldest first. + // first 2.4 GHz version + // Later called "Wi-Fi 1" if (bits.phy_11b) { phy_str += 'b'; } + // 2nd 2.4 GHz version to adopt the same 54 Mbps bandwidth as used in 802.11a + // Later called "Wi-Fi 3" if (bits.phy_11g) { phy_str += 'g'; } + // 3rd iteration for 2.4 GHz + // Also used for 5 GHz to make it even more confusing + // To top the naming confusion even worse, this is later called "Wi-Fi 4" if (bits.phy_11n) { phy_str += 'n'; } #ifdef ESP32 + // Add 5 GHz WiFi types, oldest first. + + // 802.11a was one of the first WiFi standards, using 5 GHz + // Later called "Wi-Fi 2" + if (bits.phy_11a) { phy_str += F("/a"); } + + // 802.11ac was the significantly faster version for 5 GHz WiFi. + // Later called "Wi-Fi 5" + if (bits.phy_11ac) { phy_str += F("/ac"); } + + // AX is WiFi-6, on both frequencies if (bits.phy_11ax) { phy_str += F("/ax"); } if (bits.phy_lr) { phy_str += F("/lr"); } @@ -312,10 +331,6 @@ String WiFi_AP_Candidate::toString(const String& separator) const { if (bits.ftm_responder) { phy_str += F("/FTM_r"); } - // Add 5 GHz WiFi types as last in the list. - if (bits.phy_11a) { phy_str += F("/a"); } - if (bits.phy_11ac) { phy_str += F("/ac"); } - #endif // ifdef ESP32 if (phy_str.length()) { diff --git a/src/src/DataTypes/WiFiConnectionProtocol.cpp b/src/src/DataTypes/WiFiConnectionProtocol.cpp index 909973dd1..e406df595 100644 --- a/src/src/DataTypes/WiFiConnectionProtocol.cpp +++ b/src/src/DataTypes/WiFiConnectionProtocol.cpp @@ -1,5 +1,7 @@ #include "../DataTypes/WiFiConnectionProtocol.h" +#ifdef ESP8266 + const __FlashStringHelper* toString(WiFiConnectionProtocol proto) { switch (proto) { @@ -7,29 +9,44 @@ const __FlashStringHelper* toString(WiFiConnectionProtocol proto) { return F("802.11b"); case WiFiConnectionProtocol::WiFi_Protocol_11g: return F("802.11g"); -#ifdef ESP8266 case WiFiConnectionProtocol::WiFi_Protocol_11n: return F("802.11n"); -#endif // ifdef ESP8266 -#ifdef ESP32 - case WiFiConnectionProtocol::WiFi_Protocol_HT20: - return F("802.11n (HT20)"); - case WiFiConnectionProtocol::WiFi_Protocol_HT40: - return F("802.11n (HT40)"); - case WiFiConnectionProtocol::WiFi_Protocol_HE20: - return F("802.11ax (HE20)"); -# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) - case WiFiConnectionProtocol::WiFi_Protocol_11a: - return F("802.11a"); - case WiFiConnectionProtocol::WiFi_Protocol_VHT20: - return F("802.11ac (VHT20)"); -# endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) - case WiFiConnectionProtocol::WiFi_Protocol_LR: - return F("802.11lr"); - -#endif // ifdef ESP32 case WiFiConnectionProtocol::Unknown: break; } return F("-"); } + +#endif // ifdef ESP8266 + +#ifdef ESP32 + +const __FlashStringHelper* toString(WiFiConnectionProtocol proto) { + switch (proto) + { + case WiFiConnectionProtocol::WiFi_Protocol_11b: + return F("Wi-Fi 1: 802.11b"); + case WiFiConnectionProtocol::WiFi_Protocol_11g: + return F("Wi-Fi 3: 802.11g"); + case WiFiConnectionProtocol::WiFi_Protocol_HT20: + return F("Wi-Fi 4: 802.11n (HT20)"); + case WiFiConnectionProtocol::WiFi_Protocol_HT40: + return F("Wi-Fi 4: 802.11n (HT40)"); + # if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) + case WiFiConnectionProtocol::WiFi_Protocol_11a: + return F("Wi-Fi 2: 802.11a"); + case WiFiConnectionProtocol::WiFi_Protocol_VHT20: + return F("Wi-Fi 5: 802.11ac (VHT20)"); + # endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) + case WiFiConnectionProtocol::WiFi_Protocol_HE20: + return F("Wi-Fi 6: 802.11ax (HE20)"); + case WiFiConnectionProtocol::WiFi_Protocol_LR: + return F("802.11lr"); + + case WiFiConnectionProtocol::Unknown: + break; + } + return F("-"); +} + +#endif // ifdef ESP32 diff --git a/src/src/DataTypes/WiFiConnectionProtocol.h b/src/src/DataTypes/WiFiConnectionProtocol.h index 54f55bf70..9013ffab3 100644 --- a/src/src/DataTypes/WiFiConnectionProtocol.h +++ b/src/src/DataTypes/WiFiConnectionProtocol.h @@ -3,28 +3,38 @@ #include "../../ESPEasy_common.h" +#ifdef ESP8266 + enum class WiFiConnectionProtocol { Unknown, WiFi_Protocol_11b, WiFi_Protocol_11g, -#ifdef ESP8266 WiFi_Protocol_11n +}; + + #endif + #ifdef ESP32 + +enum class WiFiConnectionProtocol { + Unknown, + WiFi_Protocol_11b, + WiFi_Protocol_11g, WiFi_Protocol_HT20, WiFi_Protocol_HT40, - WiFi_Protocol_HE20, // WiFi 6 # if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, \ 2, \ 0) WiFi_Protocol_11a, // traditional (old) 5 GHz WiFi_Protocol_VHT20, // 5 GHz WiFi 5, 802.11ac # endif // if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 2, 0) + WiFi_Protocol_HE20, // WiFi 6 WiFi_Protocol_LR -#endif // ifdef ESP32 - }; +#endif + const __FlashStringHelper* toString(WiFiConnectionProtocol proto); From 203f476484ff3eb8cd318e445be401df248be34d Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 25 May 2025 15:42:42 +0200 Subject: [PATCH 054/564] [ESP32-C5] Fix file name error for platformio_esp32c5_envs.ini --- ...5_envs..ini => platformio_esp32c5_envs.ini | 58 +++++++++---------- platformio_esp32c6_envs.ini | 27 --------- 2 files changed, 29 insertions(+), 56 deletions(-) rename platformio_esp32c5_envs..ini => platformio_esp32c5_envs.ini (97%) diff --git a/platformio_esp32c5_envs..ini b/platformio_esp32c5_envs.ini similarity index 97% rename from platformio_esp32c5_envs..ini rename to platformio_esp32c5_envs.ini index 1322859eb..ae0a669c8 100644 --- a/platformio_esp32c5_envs..ini +++ b/platformio_esp32c5_envs.ini @@ -1,29 +1,29 @@ - - -[esp32c5_common_LittleFS] -extends = esp32_base_idf5 -build_flags = ${esp32_base_idf5.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DUSE_LITTLEFS - -DESP32C5 -extra_scripts = ${esp32_base_idf5.extra_scripts} -build_unflags = ${esp32_base_idf5.build_unflags} - -fexceptions -board_build.filesystem = littlefs -lib_ignore = ${esp32_base_idf5.lib_ignore} -board = esp32c5cdc - - -[env:max_ESP32c5_8M1M_LittleFS_CDC_ETH] -extends = esp32c5_common_LittleFS -board = esp32c5cdc-8M -build_flags = ${esp32c5_common_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 - -DFEATURE_ARDUINO_OTA=1 - -DPLUGIN_BUILD_MAX_ESP32 - -DPLUGIN_BUILD_IR_EXTENDED - -D ST7789_EXTRA_INIT=1 - -D P116_EXTRA_ST7789=1 -extra_scripts = ${esp32c5_common_LittleFS.extra_scripts} - - + + +[esp32c5_common_LittleFS] +extends = esp32_base_idf5 +build_flags = ${esp32_base_idf5.build_flags} + -DFEATURE_ARDUINO_OTA=1 + -DUSE_LITTLEFS + -DESP32C5 +extra_scripts = ${esp32_base_idf5.extra_scripts} +build_unflags = ${esp32_base_idf5.build_unflags} + -fexceptions +board_build.filesystem = littlefs +lib_ignore = ${esp32_base_idf5.lib_ignore} +board = esp32c5cdc + + +[env:max_ESP32c5_8M1M_LittleFS_CDC_ETH] +extends = esp32c5_common_LittleFS +board = esp32c5cdc-8M +build_flags = ${esp32c5_common_LittleFS.build_flags} + -DFEATURE_ETHERNET=1 + -DFEATURE_ARDUINO_OTA=1 + -DPLUGIN_BUILD_MAX_ESP32 + -DPLUGIN_BUILD_IR_EXTENDED + -D ST7789_EXTRA_INIT=1 + -D P116_EXTRA_ST7789=1 +extra_scripts = ${esp32c5_common_LittleFS.extra_scripts} + + diff --git a/platformio_esp32c6_envs.ini b/platformio_esp32c6_envs.ini index 1921ee92d..b35600630 100644 --- a/platformio_esp32c6_envs.ini +++ b/platformio_esp32c6_envs.ini @@ -59,30 +59,3 @@ extra_scripts = ${esp32c6_common_LittleFS.extra_scripts} - -[esp32c5_common_LittleFS] -extends = esp32_base_idf5 -build_flags = ${esp32_base_idf5.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DUSE_LITTLEFS - -DESP32C5 -extra_scripts = ${esp32_base_idf5.extra_scripts} -build_unflags = ${esp32_base_idf5.build_unflags} - -fexceptions -board_build.filesystem = littlefs -lib_ignore = ${esp32_base_idf5.lib_ignore} -board = esp32c5cdc - - -[env:max_ESP32c5_8M1M_LittleFS_CDC_ETH] -extends = esp32c5_common_LittleFS -board = esp32c5cdc-8M -build_flags = ${esp32c5_common_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 - -DFEATURE_ARDUINO_OTA=1 - -DPLUGIN_BUILD_MAX_ESP32 - -DPLUGIN_BUILD_IR_EXTENDED - -D ST7789_EXTRA_INIT=1 - -D P116_EXTRA_ST7789=1 -extra_scripts = ${esp32c5_common_LittleFS.extra_scripts} - From 398faf185113df730b2b19d91b4e38caf5ecca5e Mon Sep 17 00:00:00 2001 From: Fabio Ancona Date: Tue, 17 Jun 2025 09:49:04 +0200 Subject: [PATCH 055/564] Update LD2410 doc adding info of false positive Update LD2410 doc adding info of avoid false positive --- docs/source/Plugin/P159.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/Plugin/P159.rst b/docs/source/Plugin/P159.rst index 30fd97358..9469c3989 100644 --- a/docs/source/Plugin/P159.rst +++ b/docs/source/Plugin/P159.rst @@ -27,6 +27,8 @@ Description Detecting (human) presence can be achieved in several ways, like via IR detection sensors, or a light-beam that's interrupted by someone passing. But these sensors have quite some limitations, like limited sensitivity, no information about the distance, or weather a person is there but not moving. The limitations of these existing sensors are not applicable when using radar-based presence detection, and since some time, rather affordable radar human-presence detectors are available. These are available with 5 GHz, 10 GHz, 24 GHz and 60 GHz radar frequency transmitter/receiver chips. Because of the accuracy and range, achievable with 24 GHz sensors, these are quite popular, so support has been added to ESPEasy. +Some notes about "false positive" detections: based on our test and experience some false positive presence rilevations can happens. For example if the sensor is near to plant, the movement of leaves can be incorrectly translated as presence detection; also electric cables in front of the sensor can provide noise to the sensor. To avoid false positive presence detection try to leave the sensor as free from obstacles as possible. + Some examples of these sensors: From 7150f9641c0d4cb1e6c6797c635c66ee6a1b5ced Mon Sep 17 00:00:00 2001 From: Fabio Ancona Date: Tue, 17 Jun 2025 10:13:00 +0200 Subject: [PATCH 056/564] Update P159.rst Update wrong translation --- docs/source/Plugin/P159.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Plugin/P159.rst b/docs/source/Plugin/P159.rst index 9469c3989..a79975208 100644 --- a/docs/source/Plugin/P159.rst +++ b/docs/source/Plugin/P159.rst @@ -27,7 +27,7 @@ Description Detecting (human) presence can be achieved in several ways, like via IR detection sensors, or a light-beam that's interrupted by someone passing. But these sensors have quite some limitations, like limited sensitivity, no information about the distance, or weather a person is there but not moving. The limitations of these existing sensors are not applicable when using radar-based presence detection, and since some time, rather affordable radar human-presence detectors are available. These are available with 5 GHz, 10 GHz, 24 GHz and 60 GHz radar frequency transmitter/receiver chips. Because of the accuracy and range, achievable with 24 GHz sensors, these are quite popular, so support has been added to ESPEasy. -Some notes about "false positive" detections: based on our test and experience some false positive presence rilevations can happens. For example if the sensor is near to plant, the movement of leaves can be incorrectly translated as presence detection; also electric cables in front of the sensor can provide noise to the sensor. To avoid false positive presence detection try to leave the sensor as free from obstacles as possible. +Some notes about "false positive" detections: based on our test and experience some false positive presence detections can happens. For example if the sensor is near to plant, the movement of leaves can be incorrectly translated as presence detection; also electric cables in front of the sensor can provide noise to the sensor. To avoid false positive presence detection try to leave the sensor as free from obstacles as possible. Some examples of these sensors: From 7465a2233e2b6a03ab078909963ed9f4fc5d83a4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 20 Jun 2025 11:19:24 +0200 Subject: [PATCH 057/564] [ESP-IDF] Update to latest SDK/IDF --- platformio_core_defs.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 1591d67d4..1a06f5d42 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -229,7 +229,7 @@ lib_extra_dirs = ; ESP_IDF 5.5.0 [core_esp32_IDF5_5_0__3_2_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 -platform_packages = +platform_packages = https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3692/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 From c144a591460f98b41d5f2eafab9a637d6b53cc6c Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 20 Jun 2025 11:20:13 +0200 Subject: [PATCH 058/564] [ESPtool] Prepare use of esptool v5.0.0 --- tools/pio/post_esp32.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/pio/post_esp32.py b/tools/pio/post_esp32.py index d75e918f8..5de862526 100644 --- a/tools/pio/post_esp32.py +++ b/tools/pio/post_esp32.py @@ -26,6 +26,17 @@ from os.path import join sys.path.append(join(platform.get_package_dir("tool-esptoolpy"))) import esptool +def esptool_call(cmd): + try: + esptool.main(cmd) + except SystemExit as e: + # Fetch sys.exit() without leaving the script + if e.code == 0: + return True + else: + print(f"❌ esptool failed with exit code: {e.code}") + return False + def esp32_create_combined_bin(source, target, env): print("Generating combined binary for serial flashing") @@ -66,7 +77,7 @@ def esp32_create_combined_bin(source, target, env): print('Using esptool.py arguments: %s' % ' '.join(cmd)) - esptool.main(cmd) + esptool_call(cmd) env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin) From ee6c6b6bfefbc3572ce329d6ad2a88c283c2cbe3 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 20 Jun 2025 11:21:19 +0200 Subject: [PATCH 059/564] [ESP32-S2] Change ADC for ESP32-S2 back to 13 bit --- src/src/Helpers/Hardware_defines.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/src/Helpers/Hardware_defines.h b/src/src/Helpers/Hardware_defines.h index e58d72e0a..901549f2c 100644 --- a/src/src/Helpers/Hardware_defines.h +++ b/src/src/Helpers/Hardware_defines.h @@ -19,7 +19,11 @@ #if ESP_IDF_VERSION_MAJOR < 5 # define MAX_ADC_VALUE ((1 << SOC_ADC_MAX_BITWIDTH) - 1) #else +#ifdef ESP32S2 + # define MAX_ADC_VALUE ((1 << 13) - 1) + # else # define MAX_ADC_VALUE ((1 << SOC_ADC_DIGI_MAX_BITWIDTH) - 1) + # endif #endif # endif // if CONFIG_IDF_TARGET_ESP32 #endif // ifdef ESP32 From 54e0ad486f9bb7c2443a8b7d8a77452a10547928 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 20 Jun 2025 17:27:53 +0200 Subject: [PATCH 060/564] [ESP-IDF] Revert to older build due to broken UART support --- platformio_core_defs.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 1a06f5d42..00c82440c 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -229,7 +229,7 @@ lib_extra_dirs = ; ESP_IDF 5.5.0 [core_esp32_IDF5_5_0__3_2_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 -platform_packages = https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3692/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3627/framework-arduinoespressif32-all-release_v5.5-5d572003.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 From a9b749c34a20ea17abf2d12cf855929129e9c9ec Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 20 Jun 2025 17:28:41 +0200 Subject: [PATCH 061/564] [ESP32-C5] Add hardware specific info about ESP32-C5 --- boards/esp32c5cdc-8M.json | 2 +- docs/source/ESPEasy/ESPchips.rst | 7 +- docs/source/Reference/GPIO.rst | 15 +++ src/src/DataTypes/SPI_options.h | 94 ++++++++++++------- src/src/Helpers/Hardware_GPIO.h | 1 + src/src/Helpers/Hardware_GPIO_ESP32.cpp | 6 ++ src/src/Helpers/Hardware_GPIO_ESP32C2.cpp | 5 + src/src/Helpers/Hardware_GPIO_ESP32C3.cpp | 9 +- src/src/Helpers/Hardware_GPIO_ESP32C5.cpp | 83 ++++++++-------- src/src/Helpers/Hardware_GPIO_ESP32C6.cpp | 8 ++ src/src/Helpers/Hardware_GPIO_ESP32P4.cpp | 6 ++ src/src/Helpers/Hardware_GPIO_ESP32S2.cpp | 6 ++ src/src/Helpers/Hardware_GPIO_ESP32S3.cpp | 5 + src/src/Helpers/Hardware_GPIO_ESP8266.cpp | 5 + .../Helpers/Hardware_device_info_ESP32C5.cpp | 8 +- src/src/Helpers/StringGenerator_GPIO.cpp | 5 + 16 files changed, 176 insertions(+), 89 deletions(-) diff --git a/boards/esp32c5cdc-8M.json b/boards/esp32c5cdc-8M.json index 17a802156..42ae430a3 100644 --- a/boards/esp32c5cdc-8M.json +++ b/boards/esp32c5cdc-8M.json @@ -4,7 +4,7 @@ "ldscript": "esp32c5_out.ld" }, "core": "esp32", - "extra_flags": "-DARDUINO_TASMOTA -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_8M -DESP32C5 -DARDUINO_USB_CDC_ON_BOOT=1", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_8M -DESP32C5 -DARDUINO_USB_CDC_ON_BOOT=1", "f_cpu": "160000000L", "f_flash": "80000000L", "flash_mode": "qio", diff --git a/docs/source/ESPEasy/ESPchips.rst b/docs/source/ESPEasy/ESPchips.rst index f5cf06b70..f00d235c6 100644 --- a/docs/source/ESPEasy/ESPchips.rst +++ b/docs/source/ESPEasy/ESPchips.rst @@ -593,6 +593,7 @@ Datasheets * `DS:ESP32-S3 `_ * `DS:ESP32-C3 `_ / `DS:ESP8685 `_ * `DS:ESP32-C2 `_ / `DS:ESP8684 `_ +* `DS:ESP32-C5 `_ * `DS:ESP32-C6 `_ * `DS:ESP32-H2 `_ @@ -606,6 +607,7 @@ Technical Reference Manuals * `TR:ESP32-S3 `_ * `TR:ESP32-C3 `_ * `TR:ESP32-C2 `_ +* `TR:ESP32-C5 `_ * `TR:ESP32-C6 `_ * `TR:ESP32-H2 `_ @@ -854,7 +856,7 @@ ESP32-C5 This will be the first Espressif SoC supporting 5 GHz WiFi. -.. note:: Not yet available (as of Dec 2024) +.. note:: Beta silicon is available (as of June 2025), which may change in Q3 or Q4 of 2025. So not yet adviced to be used in real products ESP32-C6 ======== @@ -897,4 +899,5 @@ The CPU is rather powerful and there are versions with quite a large amount of P It does have a RMII interface for Ethernet, like the ESP32-classic does. -.. note:: Not yet supported (as of Dec 2024) +.. note:: Not yet supported. Beta silicon is available (as of June 2025), which may change in Q3 or Q4 of 2025. So not yet adviced to be used in real products + diff --git a/docs/source/Reference/GPIO.rst b/docs/source/Reference/GPIO.rst index fd2fd282f..ca9b50539 100644 --- a/docs/source/Reference/GPIO.rst +++ b/docs/source/Reference/GPIO.rst @@ -614,6 +614,21 @@ ESP32-C2 (ESP8684) The strapping combination of GPIO-8 = 0 and GPIO-9 = 0 is invalid and will trigger unexpected behavior. +ESP32-C5 +~~~~~~~~ + +* GPIO-26 ... 28: "Select Bootloader Mode" pin +* GPIO-27: Enable or disable ROM messages printing +* GPIO-7: JTAG signal source +* GPIO-2: MTMS, used to select crystal frequency in non-standard boot mode + + +GPIO-2 is only used when the crystal frequency isn't explicitly set via efuses (which should not happen). + +GPIO-25 and -3 are used to set SDIO sampling and driving clock edge. +However this is also never used as SDIO mode means no flash and the chip is connected to a CPU and used as WiFi card. + + ESP32-C6 ~~~~~~~~ diff --git a/src/src/DataTypes/SPI_options.h b/src/src/DataTypes/SPI_options.h index b70459622..341695d87 100644 --- a/src/src/DataTypes/SPI_options.h +++ b/src/src/DataTypes/SPI_options.h @@ -16,15 +16,15 @@ // SPI_HOST = SPI1_HOST // Only usable on ESP32 // HSPI_HOST = SPI2_HOST // VSPI_HOST = SPI3_HOST -// +// // ESP32-S2: // FSPI_HOST = SPI2_HOST // HSPI_HOST = SPI3_HOST -// +// // ESP32-S3: // FSPI_HOST = SPI2_HOST // HSPI_HOST = SPI3_HOST -// +// // ESP32-C6: // FSPI_HOST = SPI1_HOST // ESP32-C3: @@ -39,51 +39,72 @@ // HSPI option is disabled for now on other than ESP32_CLASSIC. // Should be added later as "Custom HSPI" when we support multiple SPI busses. #ifdef ESP32 -# if CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3 -#define VSPI_FSPI_SCK 36 -#define VSPI_FSPI_MISO 37 -#define VSPI_FSPI_MOSI 35 -# elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2 -#define VSPI_FSPI_SCK 36 -#define VSPI_FSPI_MISO 37 -#define VSPI_FSPI_MOSI 35 +# if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) +# if CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3 +# define VSPI_FSPI_SCK 36 +# define VSPI_FSPI_MISO 37 +# define VSPI_FSPI_MOSI 35 +# elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2 +# define VSPI_FSPI_SCK 36 +# define VSPI_FSPI_MISO 37 +# define VSPI_FSPI_MOSI 35 # elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6 -#define VSPI_FSPI_SCK 21 -#define VSPI_FSPI_MISO 20 -#define VSPI_FSPI_MOSI 19 +# define VSPI_FSPI_SCK 21 +# define VSPI_FSPI_MISO 20 +# define VSPI_FSPI_MOSI 19 # elif CONFIG_IDF_TARGET_ESP32C5 // ESP32-C5 -#define VSPI_FSPI_SCK 4 -#define VSPI_FSPI_MISO 5 -#define VSPI_FSPI_MOSI 6 +# define VSPI_FSPI_SCK SPI2_IOMUX_PIN_NUM_CLK +# define VSPI_FSPI_MISO SPI2_IOMUX_PIN_NUM_MISO +# define VSPI_FSPI_MOSI SPI2_IOMUX_PIN_NUM_MOSI # elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 -#define VSPI_FSPI_SCK 4 -#define VSPI_FSPI_MISO 5 -#define VSPI_FSPI_MOSI 6 +# define VSPI_FSPI_SCK 4 +# define VSPI_FSPI_MISO 5 +# define VSPI_FSPI_MOSI 6 # elif CONFIG_IDF_TARGET_ESP32C2 // ESP32-C2 -#define VSPI_FSPI_SCK 4 -#define VSPI_FSPI_MISO 5 -#define VSPI_FSPI_MOSI 6 -# elif CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 -#define VSPI_FSPI_SCK 18 -#define VSPI_FSPI_MISO 19 -#define VSPI_FSPI_MOSI 23 +# define VSPI_FSPI_SCK 4 +# define VSPI_FSPI_MISO 5 +# define VSPI_FSPI_MOSI 6 +# elif CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +# define VSPI_FSPI_SCK 18 +# define VSPI_FSPI_MISO 19 +# define VSPI_FSPI_MOSI 23 -# define HSPI_SCLK 14 -# define HSPI_MISO 12 -# define HSPI_MOSI 13 -# define HSPI_SS 15 +# define HSPI_SCLK 14 +# define HSPI_MISO 12 +# define HSPI_MOSI 13 +# define HSPI_SS 15 # else // if CONFIG_IDF_TARGET_ESP32S2 # error Target CONFIG_IDF_TARGET is not supported # endif // if CONFIG_IDF_TARGET_ESP32S2 +# else // if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) +# if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 -#endif +# define VSPI_FSPI_SCK 18 +# define VSPI_FSPI_MISO 19 +# define VSPI_FSPI_MOSI 23 -enum class SPI_Options_e { // Do not change values as this is stored in the settings! - None = 0, - Vspi_Fspi = 1, // Default SPI bus +# define HSPI_SCLK 14 +# define HSPI_MISO 12 +# define HSPI_MOSI 13 +# define HSPI_SS 15 + +# else // if CONFIG_IDF_TARGET_ESP32 +# include + +# define VSPI_FSPI_SCK SPI2_IOMUX_PIN_NUM_CLK +# define VSPI_FSPI_MISO SPI2_IOMUX_PIN_NUM_MISO +# define VSPI_FSPI_MOSI SPI2_IOMUX_PIN_NUM_MOSI + +# endif // if CONFIG_IDF_TARGET_ESP32 +# endif // if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) +#endif // ifdef ESP32 +enum class SPI_Options_e { + // Do not change values as this is stored in the settings! + None = 0, + Vspi_Fspi = 1, // General-purpose SPI (GP-SPI) mode (Default SPI bus) #ifdef ESP32_CLASSIC - Hspi = 2, + Hspi = 2, #endif // UserDefined is using the default SPI bus. @@ -91,6 +112,7 @@ enum class SPI_Options_e { // Do not change values as this is stored in the sett // For later versions it is called FSPI // N.B. the ESP32-C3 does not seem to name these as there is no SPI3_HOST. UserDefined = 9 // Leave some room for other, possible future, hardware-related options + }; #ifdef ESP32 diff --git a/src/src/Helpers/Hardware_GPIO.h b/src/src/Helpers/Hardware_GPIO.h index dd97c5636..e03522aa6 100644 --- a/src/src/Helpers/Hardware_GPIO.h +++ b/src/src/Helpers/Hardware_GPIO.h @@ -17,6 +17,7 @@ bool getGpioInfo(int gpio, bool& input, bool& output, bool& warning); +bool isBootModePin(int gpio); bool isBootStrapPin(int gpio); diff --git a/src/src/Helpers/Hardware_GPIO_ESP32.cpp b/src/src/Helpers/Hardware_GPIO_ESP32.cpp index c7a42abec..1a130f49c 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP32.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP32.cpp @@ -82,6 +82,12 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) return (input || output); } +bool isBootModePin(int gpio) +{ + return gpio == 0; +} + + bool isBootStrapPin(int gpio) { // GPIO 0 & 2 can't be used as an input. State during boot is dependent on boot mode. diff --git a/src/src/Helpers/Hardware_GPIO_ESP32C2.cpp b/src/src/Helpers/Hardware_GPIO_ESP32C2.cpp index 609839052..a5d525d5f 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP32C2.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP32C2.cpp @@ -36,6 +36,11 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) return (input || output); } +bool isBootModePin(int gpio) +{ + return gpio == 9; +} + bool isBootStrapPin(int gpio) { if (gpio == 8) { diff --git a/src/src/Helpers/Hardware_GPIO_ESP32C3.cpp b/src/src/Helpers/Hardware_GPIO_ESP32C3.cpp index 99bfc09ff..daf353e55 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP32C3.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP32C3.cpp @@ -45,9 +45,7 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) output = false; } else { // See: https://www.letscontrolit.com/forum/viewtopic.php?p=71880#p71874 - if ((gpio == 12) || (gpio == 13)) { - // SPIHD/GPIO12 - // SPIWP/GPIO13 + if ((gpio == MSPI_IOMUX_PIN_NUM_HD) || (gpio == MSPI_IOMUX_PIN_NUM_WP)) { if ((ESP.getFlashChipMode() != FM_DOUT) && (ESP.getFlashChipMode() != FM_DIO)) { input = false; @@ -73,6 +71,11 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) return (input || output); } +bool isBootModePin(int gpio) +{ + return gpio == 9; +} + bool isBootStrapPin(int gpio) { if (gpio == 2) { diff --git a/src/src/Helpers/Hardware_GPIO_ESP32C5.cpp b/src/src/Helpers/Hardware_GPIO_ESP32C5.cpp index f70b53b27..6f3e7218a 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP32C5.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP32C5.cpp @@ -2,9 +2,12 @@ #ifdef ESP32C5 # include +# include # include "../Helpers/Hardware_device_info.h" + + // ******************************************************************************** // Get info of a specific GPIO pin // ******************************************************************************** @@ -21,33 +24,18 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) // FIXME TD-er: Implement for ESP32-C5 // See: - // - https://docs.espressif.com/projects/esp-idf/en/v5.0/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html - // - https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/gpio.html + // - https://docs.espressif.com/projects/esp-idf/en/v5.0/esp32c5/hw-reference/esp32c3/user-guide-devkitm-1.html + // - https://docs.espressif.com/projects/esp-idf/en/latest/esp32c5/api-reference/peripherals/gpio.html // Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf - if (gpio == 11) { - if (getChipFeatures().embeddedFlash /* || !flashVddPinCanBeUsedAsGPIO() */) { - // See: https://www.letscontrolit.com/forum/viewtopic.php?p=71880#p71874 - // - // By default VDD_SPI is the power supply pin for embedded flash or external flash. - // It can only be used as GPIO11 only when the chip is connected to an - // external flash, and this flash is powered by an external power supply - input = false; - output = false; - } - warning = true; - } - - if (isFlashInterfacePin_ESPEasy(gpio)) { + if (isFlashInterfacePin_ESPEasy(gpio) || isPSRAMInterfacePin(gpio)) { if (getChipFeatures().embeddedFlash) { // Connected to the integrated SPI flash. input = false; output = false; } else { // See: https://www.letscontrolit.com/forum/viewtopic.php?p=71880#p71874 - if ((gpio == 12) || (gpio == 13)) { - // SPIHD/GPIO12 - // SPIWP/GPIO13 + if ((gpio == MSPI_IOMUX_PIN_NUM_HD) || (gpio == MSPI_IOMUX_PIN_NUM_WP)) { if ((ESP.getFlashChipMode() != FM_DOUT) && (ESP.getFlashChipMode() != FM_DIO)) { input = false; @@ -64,31 +52,44 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) warning = true; } - // GPIO 18: USB_D- - // GPIO 19: USB_D+ - - // GPIO 20: U0RXD - // GPIO 21: U0TXD - return (input || output); } +bool isBootModePin(int gpio) +{ + return gpio == 28; +} + bool isBootStrapPin(int gpio) { - if (gpio == 2) { - // Strapping pin which must be high during boot + // Boot mode | GPIO26 | GPIO27 | GPIO28 + // + // SPI Boot | Any | Any | 1 + // Joint Download Boot 0 | Any | 1 | 0 + // Joint Download Boot 1 | 0 | 0 | 0 +/* + Joint Download Boot 0 mode supports the following download methods: + - USB-Serial-JTAG Download Boot + - UART Download Boot + - SPI Slave Download Boot (chip revision v0.1 only) + + Joint Download Boot 1 mode supports the following download methods: + - UART Download Boot + - SDIO Download Boot +*/ + if (gpio == 26 || gpio == 27 || gpio == 28) { + // Strapping pin setting boot mode return true; } - if (gpio == 8) { - // Strapping pin which must be high during flashing + + if (gpio == 7) { + // Strapping pin JTAG signal source return true; } - if (gpio == 9) { - // Strapping pin to force download mode (like GPIO-0 on ESP8266/ESP32-classic) - return true; - } + // Ignoring strapping pins GPIO-2, -3, 25 + // as they should never cause issues for users. return false; } @@ -125,22 +126,12 @@ bool getADC_gpio_info(int gpio_pin, int& adc, int& ch, int& t) ch = -1; t = -1; - if ((gpio_pin >= 0) && (gpio_pin <= 4)) { + // GPIO 1 ... 6 -> Channel 0 ... 5 + if ((gpio_pin > 0) && (gpio_pin <= 6)) { adc = 1; - ch = gpio_pin; + ch = gpio_pin - 1; return true; } - # if ESP_IDF_VERSION_MAJOR >= 5 - - // Support for ADC2 has been dropped. - # else // if ESP_IDF_VERSION_MAJOR >= 5 - - if (gpio_pin == 5) { - adc = 2; - ch = 0; - return true; - } - # endif // if ESP_IDF_VERSION_MAJOR >= 5 return false; } diff --git a/src/src/Helpers/Hardware_GPIO_ESP32C6.cpp b/src/src/Helpers/Hardware_GPIO_ESP32C6.cpp index b559912c4..bf5a53456 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP32C6.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP32C6.cpp @@ -42,6 +42,11 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) return (input || output); } +bool isBootModePin(int gpio) +{ + return gpio == 9; +} + bool isBootStrapPin(int gpio) { // See: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf @@ -58,12 +63,15 @@ bool isBootStrapPin(int gpio) return true; } + // Ignoring SDIO stapping pins as this will not be used in typical use cases where ESPEasy is used. + /* if (gpio == 4 || gpio == 5) { // SDIO Sampling and Driving Clock Edge // MTMS = GPIO-4 // MTDI = Gpio-5 return true; } + */ if (gpio == 15) { // JTAG signal source diff --git a/src/src/Helpers/Hardware_GPIO_ESP32P4.cpp b/src/src/Helpers/Hardware_GPIO_ESP32P4.cpp index ebfe55994..6e26586a0 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP32P4.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP32P4.cpp @@ -47,6 +47,12 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) return (input || output); } +bool isBootModePin(int gpio) +{ + return gpio == 35; +} + + bool isBootStrapPin(int gpio) { diff --git a/src/src/Helpers/Hardware_GPIO_ESP32S2.cpp b/src/src/Helpers/Hardware_GPIO_ESP32S2.cpp index 4ffe6ab2c..c7337b49b 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP32S2.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP32S2.cpp @@ -45,6 +45,12 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) return (input || output); } +bool isBootModePin(int gpio) +{ + return gpio == 0; +} + + bool isBootStrapPin(int gpio) { if (gpio == 45) { diff --git a/src/src/Helpers/Hardware_GPIO_ESP32S3.cpp b/src/src/Helpers/Hardware_GPIO_ESP32S3.cpp index be747f1f9..1f57ff3ce 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP32S3.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP32S3.cpp @@ -46,6 +46,11 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) return (input || output); } +bool isBootModePin(int gpio) +{ + return gpio == 0; +} + bool isBootStrapPin(int gpio) { if (gpio == 45) { diff --git a/src/src/Helpers/Hardware_GPIO_ESP8266.cpp b/src/src/Helpers/Hardware_GPIO_ESP8266.cpp index 917602466..17a566789 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP8266.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP8266.cpp @@ -66,6 +66,11 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) return input || output; } +bool isBootModePin(int gpio) +{ + return gpio == 0; +} + bool isBootStrapPin(int gpio) { return (gpio == 0 || gpio == 2 || gpio == 15); diff --git a/src/src/Helpers/Hardware_device_info_ESP32C5.cpp b/src/src/Helpers/Hardware_device_info_ESP32C5.cpp index bbed9d264..80440d4d9 100644 --- a/src/src/Helpers/Hardware_device_info_ESP32C5.cpp +++ b/src/src/Helpers/Hardware_device_info_ESP32C5.cpp @@ -25,6 +25,10 @@ bool isFlashInterfacePin_ESPEasy(int gpio) { case MSPI_IOMUX_PIN_NUM_MOSI: case MSPI_IOMUX_PIN_NUM_MISO: return true; + + case 19: + // special pin to power flash + return true; } return false; @@ -63,14 +67,16 @@ int32_t getEmbeddedPSRAMSize() return 0; } + # ifndef isPSRAMInterfacePin bool isPSRAMInterfacePin(int gpio) { - return false; + return FoundPSRAM() ? ((gpio) >= MSPI_IOMUX_PIN_NUM_CS1 && (gpio) <= MSPI_IOMUX_PIN_NUM_MOSI) : false; } # endif // ifndef isPSRAMInterfacePin + const __FlashStringHelper* getChipModel(uint32_t chip_model, uint32_t chip_revision, uint32_t pkg_version, bool single_core) { return F("ESP32-C5"); diff --git a/src/src/Helpers/StringGenerator_GPIO.cpp b/src/src/Helpers/StringGenerator_GPIO.cpp index 36f4cc58c..f71bc8c1b 100644 --- a/src/src/Helpers/StringGenerator_GPIO.cpp +++ b/src/src/Helpers/StringGenerator_GPIO.cpp @@ -373,6 +373,11 @@ const __FlashStringHelper* getConflictingUse(int gpio, PinSelectPurpose purpose, } #endif // if FEATURE_ETHERNET + + if (isBootModePin(gpio)) { + return F("Boot Mode"); + } + if (isBootStrapPin(gpio)) { return F("Boot Strapping"); } From ec4b23a0216415f5b36425dd4e38ffcc3707738f Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 21 Jun 2025 01:03:40 +0200 Subject: [PATCH 062/564] [Build] Get rid of all ESP32-SPIFFS builds --- platformio_core_defs.ini | 34 +- platformio_esp32_envs.ini | 459 +++++----------------- platformio_esp32c3_envs.ini | 127 ++---- platformio_esp32c5_envs.ini | 10 +- platformio_esp32s2_envs.ini | 114 ++---- platformio_esp32s3_envs.ini | 117 ++---- src/src/Helpers/Hardware_GPIO_ESP32C3.cpp | 4 +- tools/pio/post_esp32.py | 8 +- 8 files changed, 213 insertions(+), 660 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 00c82440c..569072a76 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -162,44 +162,12 @@ extra_scripts = ${esp82xx_common.extra_scripts} -; Updated ESP-IDF to the latest stable 4.0.1 -; See: https://github.com/platformio/platform-espressif32/releases -; IDF 4.4 = platform-espressif32 3.4.x = espressif/arduino-esp32 tag 2.0.4 -; Just for those who lost track of the extremely confusing numbering schema. -; For MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS See: https://github.com/espressif/arduino-esp32/pull/6676 -[core_esp32_IDF5_1_4__3_1_0_SPIFFS] -platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.09.10/platform-espressif32.zip -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3202/framework-arduinoespressif32-all-release_v5.1-41a885b.zip -build_flags = -DESP32_STAGE - -DESP_IDF_VERSION_MAJOR=5 - -DLIBRARIES_NO_LOG=1 - -DDISABLE_SC16IS752_SPI - -DCONFIG_PM_ENABLE=0 - -DESP_IDF_STILL_NEEDS_SPI_REGISTERS_FIXED - -DPR_9453_FLUSH_TO_CLEAR=clear - - ;-DETH_TYPE_JL1101_SUPPORTED -; -DCONFIG_LWIP_L2_TO_L3_COPY -; -DETH_SPI_SUPPORTS_NO_IRQ=1 - -DCONFIG_FREERTOS_USE_TICKLESS_IDLE=1 - -DCONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP=3 - -DNEOPIXEL_ESP32_RMT_DEFAULT - -DCRON_USE_LOCAL_TIME - -I$PROJECT_DIR/src/include - -include "sdkconfig.h" - -include "ESPEasy_config.h" - -include "esp32x_fixes.h" - -Wnull-dereference -lib_ignore = -lib_extra_dirs = - lib/lib_ssl - ; ESP_IDF 5.4.1 [core_esp32_IDF5_4_1__3_2_0_LittleFS] ;platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF54 ;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3538/framework-arduinoespressif32-all-release_v5.4-8f5ad6d7.zip -platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 +platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF54 platform_packages = build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index bf258e2db..6670dced5 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -1,40 +1,3 @@ -;;; ESP32 test build ********************************************************************; -; Status of the ESP32 support is still considered "beta" ; -; Most plugins work just fine on ESP32. ; -; Especially some plugins using serial may not run very well (GPS does run fine). ; -; ***************************************************************************************; - - -[esp32_base] -extends = common, core_esp32_IDF5_1_4__3_1_0_SPIFFS -upload_speed = 460800 -upload_before_reset = default_reset -upload_after_reset = hard_reset -extra_scripts = pre:tools/pio/pre_esp32.py - post:tools/pio/post_esp32.py - ${extra_scripts_default.extra_scripts} - post:tools/pio/copy_files.py -; you can disable debug linker flag to reduce binary size (comment out line below), but the backtraces will become less readable -; tools/pio/extra_linker_flags.py -; fix the platform package to use gcc-ar and gcc-ranlib to enable lto linker plugin -; more detail: https://embeddedartistry.com/blog/2020/04/13/prefer-gcc-ar-to-ar-in-your-buildsystems/ -; pre:tools/pio/apply_patches.py -build_unflags = -Wall - -fno-lto -build_flags = ${core_esp32_IDF5_1_4__3_1_0_SPIFFS.build_flags} -; ${mqtt_flags.build_flags} - -DMQTT_MAX_PACKET_SIZE=2048 - -DCONFIG_FREERTOS_ASSERT_DISABLE - -DCONFIG_LWIP_ESP_GRATUITOUS_ARP - -fno-strict-aliasing - -flto=auto - -Wswitch - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE -monitor_filters = esp32_exception_decoder -lib_ignore = - ${core_esp32_IDF5_1_4__3_1_0_SPIFFS.lib_ignore} - - [esp32_base_idf5] extends = common, core_esp32_IDF5_4_1__3_2_0_LittleFS upload_speed = 460800 @@ -110,16 +73,6 @@ lib_ignore = ${core_esp32_IDF5_5_0__3_2_0_LittleFS.lib_ignore} -; -flto cannot be used for ESP32 C3! -; See: https://github.com/letscontrolit/ESPEasy/pull/3845#issuecomment-1014857366 -; TD-er: 2022-01-20: Disabled for now as it also resulted in obscure linker errors on ESP32-S2 and ESP32 running custom builds. -;build_flags = ${esp32_base.build_flags} -; -flto -;build_unflags = ${esp32_base.build_unflags} -; -fexceptions -; -fno-lto - - [esp32_always] lib_ignore = ESP8266Ping ESP8266HTTPUpdateServer @@ -131,20 +84,9 @@ lib_ignore = ESP8266Ping TinyWireM LittleFS_esp32 Adafruit NeoPixel - ${esp32_base.lib_ignore} + ${esp32_base_idf5.lib_ignore} -[esp32_common] -extends = esp32_base -lib_ignore = ${esp32_always.lib_ignore} - ESP32_ping - ${no_ir.lib_ignore} - ESP32 BLE Arduino -build_flags = ${esp32_base.build_flags} - -DESP32_CLASSIC -extra_scripts = ${esp32_base.extra_scripts} -build_unflags = ${esp32_base.build_unflags} - -fexceptions [esp32_common_LittleFS] extends = esp32_base_idf5 @@ -153,7 +95,7 @@ build_flags = ${esp32_base_idf5.build_flags} -DESP32_CLASSIC -DUSE_LITTLEFS build_unflags = ${esp32_base_idf5.build_unflags} -extra_scripts = ${esp32_common.extra_scripts} +extra_scripts = ${esp32_base_idf5.extra_scripts} board_build.filesystem = littlefs lib_ignore = ${esp32_always.lib_ignore} ESP32_ping @@ -161,25 +103,19 @@ lib_ignore = ${esp32_always.lib_ignore} ${core_esp32_IDF5_4_1__3_2_0_LittleFS.lib_ignore} -[esp32_IRExt] -extends = esp32_common +[esp32_IRExt_LittleFS_ETH] +extends = esp32_common_LittleFS lib_ignore = ${esp32_always.lib_ignore} ESP32_ping -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} + -DFEATURE_ETHERNET=1 -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_NORMAL_IRext -DCOLLECTION_FEATURE_RTTTL=1 -extra_scripts = ${esp32_common.extra_scripts} +extra_scripts = ${esp32_common_LittleFS.extra_scripts} pre:tools/pio/ir_build_check.py -[esp32_custom_base] -extends = esp32_common -build_flags = ${esp32_common.build_flags} - -DPLUGIN_BUILD_CUSTOM -extra_scripts = ${esp32_common.extra_scripts} - pre:tools/pio/pre_custom_esp32.py - [esp32_custom_base_LittleFS] extends = esp32_common_LittleFS build_flags = ${esp32_common_LittleFS.build_flags} @@ -188,189 +124,165 @@ extra_scripts = ${esp32_common_LittleFS.extra_scripts} pre:tools/pio/pre_custom_esp32.py -[env:custom_ESP32_4M316k_ETH] -extends = esp32_custom_base -board = esp32_4M -build_flags = ${esp32_custom_base.build_flags} - -DFEATURE_ETHERNET=1 - -; [env:custom_ESP32_4M316k_LittleFS] -; extends = esp32_custom_base_LittleFS -; board = esp32_4M - -[env:custom_ESP32_16M8M_LittleFS_ETH] +[env:custom_ESP32_4M316k_LittleFS_ETH] extends = esp32_custom_base_LittleFS -board = esp32_16M8M -board_upload.flash_size = 16MB +board = esp32_4M build_flags = ${esp32_custom_base_LittleFS.build_flags} -DFEATURE_ETHERNET=1 -[env:custom_IR_ESP32_4M316k_ETH] -extends = esp32_common + +[env:custom_ESP32_16M8M_LittleFS_ETH] +extends = env:custom_ESP32_4M316k_LittleFS_ETH +board = esp32_16M8M +board_upload.flash_size = 16MB +build_flags = ${env:custom_ESP32_4M316k_LittleFS_ETH.build_flags} + + +[env:custom_IR_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DPLUGIN_BUILD_CUSTOM -DPLUGIN_BUILD_IR - -DFEATURE_ETHERNET=1 + lib_ignore = ${esp32_always.lib_ignore} ESP32_ping -extra_scripts = ${esp32_common.extra_scripts} +extra_scripts = ${esp32_common_LittleFS.extra_scripts} pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py [env:custom_ESP32_4M2M_NO_OTA_LittleFS_ETH] -extends = esp32_custom_base_LittleFS +extends = env:custom_ESP32_4M316k_LittleFS_ETH board = esp32_4M2M -build_flags = ${esp32_custom_base_LittleFS.build_flags} +build_flags = ${env:custom_ESP32_4M316k_LittleFS_ETH.build_flags} -DNO_HTTP_UPDATER - -DFEATURE_ETHERNET=1 + -[env:normal_ESP32_4M316k_ETH] -extends = esp32_common +[env:collection_A_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -lib_ignore = ${esp32_common.lib_ignore} - ${no_ir.lib_ignore} -build_flags = ${esp32_common.build_flags} - -DFEATURE_ETHERNET=1 - -; [env:normal_ESP32_4M316k_LittleFS] -; extends = esp32_common_LittleFS -; board = esp32_4M -; lib_ignore = ${esp32_common_LittleFS.lib_ignore} -; ${no_ir.lib_ignore} - -[env:collection_A_ESP32_4M316k_ETH] -extends = esp32_common -board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 - -DFEATURE_ETHERNET=1 + -[env:collection_B_ESP32_4M316k_ETH] -extends = esp32_common +[env:collection_B_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_B_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 - -DFEATURE_ETHERNET=1 + -[env:collection_C_ESP32_4M316k_ETH] -extends = esp32_common +[env:collection_C_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_C_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 - -DFEATURE_ETHERNET=1 + -[env:collection_D_ESP32_4M316k_ETH] -extends = esp32_common +[env:collection_D_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_D_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 - -DFEATURE_ETHERNET=1 + -[env:collection_E_ESP32_4M316k_ETH] -extends = esp32_common +[env:collection_E_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_E_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 - -DFEATURE_ETHERNET=1 + -[env:collection_F_ESP32_4M316k_ETH] -extends = esp32_common +[env:collection_F_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_F_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 - -DFEATURE_ETHERNET=1 + -[env:collection_G_ESP32_4M316k_ETH] -extends = esp32_common +[env:collection_G_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_G_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 - -DFEATURE_ETHERNET=1 + -[env:collection_A_ESP32_IRExt_4M316k] -extends = esp32_IRExt +[env:collection_A_ESP32_IRExt_4M316k_LittleFS_ETH] +extends = esp32_IRExt_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_IRExt.build_flags} +build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} -DPLUGIN_SET_COLLECTION_ESP32 -[env:collection_B_ESP32_IRExt_4M316k] -extends = esp32_IRExt +[env:collection_B_ESP32_IRExt_4M316k_LittleFS_ETH] +extends = esp32_IRExt_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_IRExt.build_flags} +build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} -DPLUGIN_SET_COLLECTION_B_ESP32 -[env:collection_C_ESP32_IRExt_4M316k] -extends = esp32_IRExt +[env:collection_C_ESP32_IRExt_4M316k_LittleFS_ETH] +extends = esp32_IRExt_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_IRExt.build_flags} +build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} -DPLUGIN_SET_COLLECTION_C_ESP32 -[env:collection_D_ESP32_IRExt_4M316k] -extends = esp32_IRExt +[env:collection_D_ESP32_IRExt_4M316k_LittleFS_ETH] +extends = esp32_IRExt_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_IRExt.build_flags} +build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} -DPLUGIN_SET_COLLECTION_D_ESP32 -[env:collection_E_ESP32_IRExt_4M316k] -extends = esp32_IRExt +[env:collection_E_ESP32_IRExt_4M316k_LittleFS_ETH] +extends = esp32_IRExt_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_IRExt.build_flags} +build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} -DPLUGIN_SET_COLLECTION_E_ESP32 -[env:collection_F_ESP32_IRExt_4M316k] -extends = esp32_IRExt +[env:collection_F_ESP32_IRExt_4M316k_LittleFS_ETH] +extends = esp32_IRExt_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_IRExt.build_flags} +build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} -DPLUGIN_SET_COLLECTION_F_ESP32 -[env:collection_G_ESP32_IRExt_4M316k] -extends = esp32_IRExt +[env:collection_G_ESP32_IRExt_4M316k_LittleFS_ETH] +extends = esp32_IRExt_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_IRExt.build_flags} +build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} -DPLUGIN_SET_COLLECTION_G_ESP32 -[env:energy_ESP32_4M316k_ETH] -extends = esp32_common +[env:energy_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_ENERGY_COLLECTION - -DFEATURE_ETHERNET=1 + -[env:display_ESP32_4M316k_ETH] -extends = esp32_common +[env:display_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_DISPLAY_COLLECTION -D ST7789_EXTRA_INIT=1 -D P116_EXTRA_ST7789=1 - -DFEATURE_ETHERNET=1 + -[env:climate_ESP32_4M316k_ETH] -extends = esp32_common -board = esp32_4M -build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DPLUGIN_CLIMATE_COLLECTION - -DFEATURE_ETHERNET=1 [env:climate_ESP32_4M316k_LittleFS_ETH] extends = esp32_common_LittleFS @@ -381,35 +293,18 @@ lib_ignore = ${esp32_always.lib_ignore} ${no_ir.lib_ignore} build_flags = ${esp32_common_LittleFS.build_flags} -DPLUGIN_CLIMATE_COLLECTION - -DFEATURE_ETHERNET=1 + -[env:neopixel_ESP32_4M316k_ETH] -extends = esp32_common +[env:neopixel_ESP32_4M316k_LittleFS_ETH] +extends = esp32_common_LittleFS board = esp32_4M -build_flags = ${esp32_common.build_flags} +build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DFEATURE_SD=1 -D PLUGIN_NEOPIXEL_COLLECTION - -DFEATURE_ETHERNET=1 + -; [env:custom_ESP32_4M316k_ETH] -; extends = env:custom_ESP32_4M316k -; build_flags = ${env:custom_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 - -[env:custom_ESP32_4M316k_LittleFS_ETH] -extends = esp32_custom_base_LittleFS -board = esp32_4M -build_flags = ${esp32_custom_base_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 - - -; [env:custom_IR_ESP32_4M316k_ETH] -; extends = env:custom_IR_ESP32_4M316k -; build_flags = ${env:custom_IR_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 -; extra_scripts = ${env:custom_IR_ESP32_4M316k.extra_scripts} [env:custom_IR_ESP32_16M8M_LittleFS_ETH] extends = esp32_common_LittleFS @@ -418,18 +313,13 @@ board_upload.flash_size = 16MB build_flags = ${esp32_common_LittleFS.build_flags} -DPLUGIN_BUILD_CUSTOM -DPLUGIN_BUILD_IR - -DFEATURE_ETHERNET=1 lib_ignore = ${esp32_always.lib_ignore} ESP32_ping ${esp32_common_LittleFS.lib_ignore} -extra_scripts = ${esp32_common.extra_scripts} +extra_scripts = ${esp32_common_LittleFS.extra_scripts} pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py -; [env:normal_ESP32_4M316k_ETH] -; extends = env:normal_ESP32_4M316k -; build_flags = ${env:normal_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 [env:normal_ESP32_4M316k_LittleFS_ETH] @@ -440,178 +330,19 @@ lib_ignore = ${esp32_always.lib_ignore} ${esp32_common_LittleFS.lib_ignore} ${no_ir.lib_ignore} build_flags = ${esp32_common_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 + -[env:normal_ESP32_IRExt_4M316k_ETH] -extends = esp32_IRExt +[env:normal_ESP32_IRExt_4M316k_LittleFS_ETH] +extends = esp32_IRExt_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_IRExt.build_flags} - -DFEATURE_ETHERNET=1 +build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} + -; [env:collection_A_ESP32_4M316k_ETH] -; extends = env:collection_A_ESP32_4M316k -; build_flags = ${env:collection_A_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 -; -DCOLLECTION_FEATURE_RTTTL=1 - -; [env:collection_B_ESP32_4M316k_ETH] -; extends = env:collection_B_ESP32_4M316k -; build_flags = ${env:collection_B_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 -; -DCOLLECTION_FEATURE_RTTTL=1 - -; [env:collection_C_ESP32_4M316k_ETH] -; extends = env:collection_C_ESP32_4M316k -; build_flags = ${env:collection_C_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 -; -DCOLLECTION_FEATURE_RTTTL=1 - -; [env:collection_D_ESP32_4M316k_ETH] -; extends = env:collection_D_ESP32_4M316k -; build_flags = ${env:collection_D_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 -; -DCOLLECTION_FEATURE_RTTTL=1 - -; [env:collection_E_ESP32_4M316k_ETH] -; extends = env:collection_E_ESP32_4M316k -; build_flags = ${env:collection_E_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 -; -DCOLLECTION_FEATURE_RTTTL=1 - -; [env:collection_F_ESP32_4M316k_ETH] -; extends = env:collection_F_ESP32_4M316k -; build_flags = ${env:collection_F_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 -; -DCOLLECTION_FEATURE_RTTTL=1 - -; [env:collection_G_ESP32_4M316k_ETH] -; extends = env:collection_G_ESP32_4M316k -; build_flags = ${env:collection_G_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 -; -DCOLLECTION_FEATURE_RTTTL=1 - -; [env:energy_ESP32_4M316k_ETH] -; extends = env:energy_ESP32_4M316k -; build_flags = ${env:energy_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 - -; [env:display_ESP32_4M316k_ETH] -; extends = env:display_ESP32_4M316k -; build_flags = ${env:display_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 - -; [env:climate_ESP32_4M316k_ETH] -; extends = env:climate_ESP32_4M316k -; build_flags = ${env:climate_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 - -; [env:neopixel_ESP32_4M316k_ETH] -; extends = env:neopixel_ESP32_4M316k -; build_flags = ${env:neopixel_ESP32_4M316k.build_flags} -; -DFEATURE_ETHERNET=1 - -; [env:collection_A_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_SET_COLLECTION_ESP32 -; -DFEATURE_ETHERNET=1 - -; [env:collection_B_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_SET_COLLECTION_B_ESP32 -; -DFEATURE_ETHERNET=1 - -; [env:collection_C_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_SET_COLLECTION_C_ESP32 -; -DFEATURE_ETHERNET=1 - -; [env:collection_D_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_SET_COLLECTION_D_ESP32 -; -DFEATURE_ETHERNET=1 - -; [env:collection_E_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_SET_COLLECTION_E_ESP32 -; -DFEATURE_ETHERNET=1 - -; [env:collection_F_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_SET_COLLECTION_F_ESP32 -; -DFEATURE_ETHERNET=1 - -; [env:collection_G_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_SET_COLLECTION_G_ESP32 -; -DFEATURE_ETHERNET=1 - -; [env:energy_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_ENERGY_COLLECTION -; -DFEATURE_ETHERNET=1 - -; [env:display_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_DISPLAY_COLLECTION -; -DFEATURE_ETHERNET=1 - -; [env:climate_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -DPLUGIN_CLIMATE_COLLECTION -; -DFEATURE_ETHERNET=1 - -; [env:neopixel_ESP32_IRExt_4M316k_ETH] -; extends = esp32_IRExt -; board = esp32_4M -; build_flags = ${esp32_IRExt.build_flags} -; -D PLUGIN_NEOPIXEL_COLLECTION -; -DFEATURE_ETHERNET=1 ; ESP32 MAX builds 16M flash ------------------------------ -; A Lolin D32 PRO with 16MB Flash, allowing 4MB sketch size, and file storage using the default (SPIFFS) filesystem -[env:max_ESP32_16M1M_ETH] -extends = esp32_common -board = esp32_16M1M -board_upload.flash_size = 16MB -lib_ignore = ${esp32_always.lib_ignore} - ESP32_ping -build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DPLUGIN_BUILD_MAX_ESP32 - -DPLUGIN_BUILD_IR_EXTENDED - -D ST7789_EXTRA_INIT=1 - -D P116_EXTRA_ST7789=1 - -DFEATURE_ETHERNET=1 - -; [env:max_ESP32_16M1M_ETH] -; extends = env:max_ESP32_16M1M -; build_flags = ${env:max_ESP32_16M1M.build_flags} -; -DFEATURE_ETHERNET=1 - - ; A Lolin D32 PRO with 16MB Flash, allowing 4MB sketch size, and file storage using LittleFS filesystem [env:max_ESP32_16M8M_LittleFS_ETH] extends = esp32_common_LittleFS @@ -624,10 +355,9 @@ build_flags = ${esp32_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_MAX_ESP32 -DPLUGIN_BUILD_IR_EXTENDED - -DFEATURE_ETHERNET=1 -D ST7789_EXTRA_INIT=1 -D P116_EXTRA_ST7789=1 -extra_scripts = ${esp32_common.extra_scripts} +extra_scripts = ${esp32_common_LittleFS.extra_scripts} board_build.filesystem = littlefs ; If you have a board with Ethernet integrated and 16MB Flash, then this configuration could be enabled, it's based on the max_ESP32_16M8M_LittleFS definition @@ -635,7 +365,6 @@ board_build.filesystem = littlefs ; extends = env:max_ESP32_16M8M_LittleFS ; board = ${env:max_ESP32_16M8M_LittleFS.board} ; build_flags = ${env:max_ESP32_16M8M_LittleFS.build_flags} -; -DFEATURE_ETHERNET=1 diff --git a/platformio_esp32c3_envs.ini b/platformio_esp32c3_envs.ini index 3ccbec85c..a0764a93d 100644 --- a/platformio_esp32c3_envs.ini +++ b/platformio_esp32c3_envs.ini @@ -1,23 +1,8 @@ - - - -[esp32c3_common] -extends = esp32_base -lib_ignore = ${esp32_always.lib_ignore} - ESP32_ping - ${no_ir.lib_ignore} - ESP32 BLE Arduino -build_flags = ${esp32_base.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DESP32C3 -extra_scripts = ${esp32_base.extra_scripts} -build_unflags = ${esp32_base.build_unflags} - -fexceptions - [esp32c3_common_LittleFS] extends = esp32_base_idf5 build_flags = ${esp32_base_idf5.build_flags} -DFEATURE_ARDUINO_OTA=1 + -DFEATURE_ETHERNET=1 -DUSE_LITTLEFS -DESP32C3 extra_scripts = ${esp32_base_idf5.extra_scripts} @@ -27,153 +12,100 @@ board_build.filesystem = littlefs lib_ignore = ${esp32_base_idf5.lib_ignore} -[env:custom_ESP32c3_4M316k_CDC] -extends = esp32c3_common -board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} - -DPLUGIN_BUILD_CUSTOM -extra_scripts = ${esp32c3_common.extra_scripts} - pre:tools/pio/pre_custom_esp32.py - - -[env:custom_IR_ESP32c3_4M316k_CDC] -extends = esp32c3_common -board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} - -DPLUGIN_BUILD_CUSTOM - -DPLUGIN_BUILD_IR -lib_ignore = ${esp32_always.lib_ignore} - ESP32_ping -extra_scripts = ${esp32c3_common.extra_scripts} - pre:tools/pio/pre_custom_esp32_IR.py - pre:tools/pio/ir_build_check.py - -; [env:custom_ESP32c3_4M316k_LittleFS_CDC] -; extends = esp32c3_common_LittleFS -; board = esp32c3cdc -; build_flags = ${esp32c3_common_LittleFS.build_flags} -; -DPLUGIN_BUILD_CUSTOM -; extra_scripts = ${esp32c3_common_LittleFS.extra_scripts} -; pre:tools/pio/pre_custom_esp32.py - [env:custom_ESP32c3_4M316k_LittleFS_CDC_ETH] extends = esp32c3_common_LittleFS board = esp32c3cdc build_flags = ${esp32c3_common_LittleFS.build_flags} -DPLUGIN_BUILD_CUSTOM - -DFEATURE_ETHERNET=1 extra_scripts = ${esp32c3_common_LittleFS.extra_scripts} pre:tools/pio/pre_custom_esp32.py -[env:normal_ESP32c3_4M316k_CDC] -extends = esp32c3_common -board = esp32c3cdc -lib_ignore = ${esp32_common.lib_ignore} - ${no_ir.lib_ignore} - - [env:normal_ESP32c3_4M316k_LittleFS_CDC_ETH] extends = esp32c3_common_LittleFS board = esp32c3cdc build_flags = ${esp32c3_common_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 lib_ignore = ${esp32c3_common_LittleFS.lib_ignore} ${no_ir.lib_ignore} -[env:collection_A_ESP32c3_4M316k_CDC] -extends = esp32c3_common +[env:collection_A_ESP32c3_4M316k_LittleFS_CDC_ETH] +extends = esp32c3_common_LittleFS board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} +build_flags = ${esp32c3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_B_ESP32c3_4M316k_CDC] -extends = esp32c3_common +[env:collection_B_ESP32c3_4M316k_LittleFS_CDC_ETH] +extends = esp32c3_common_LittleFS board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} +build_flags = ${esp32c3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_B_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_C_ESP32c3_4M316k_CDC] -extends = esp32c3_common +[env:collection_C_ESP32c3_4M316k_LittleFS_CDC_ETH] +extends = esp32c3_common_LittleFS board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} +build_flags = ${esp32c3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_C_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_D_ESP32c3_4M316k_CDC] -extends = esp32c3_common +[env:collection_D_ESP32c3_4M316k_LittleFS_CDC_ETH] +extends = esp32c3_common_LittleFS board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} +build_flags = ${esp32c3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_D_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_E_ESP32c3_4M316k_CDC] -extends = esp32c3_common +[env:collection_E_ESP32c3_4M316k_LittleFS_CDC_ETH] +extends = esp32c3_common_LittleFS board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} +build_flags = ${esp32c3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_E_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_F_ESP32c3_4M316k_CDC] -extends = esp32c3_common +[env:collection_F_ESP32c3_4M316k_LittleFS_CDC_ETH] +extends = esp32c3_common_LittleFS board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} +build_flags = ${esp32c3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_F_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_G_ESP32c3_4M316k_CDC] -extends = esp32c3_common +[env:collection_G_ESP32c3_4M316k_LittleFS_CDC_ETH] +extends = esp32c3_common_LittleFS board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} +build_flags = ${esp32c3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_G_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:energy_ESP32c3_4M316k_CDC] -extends = esp32c3_common -board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} - -D PLUGIN_ENERGY_COLLECTION - [env:energy_ESP32c3_4M316k_LittleFS_CDC_ETH] extends = esp32c3_common_LittleFS board = esp32c3cdc build_flags = ${esp32c3_common_LittleFS.build_flags} -D PLUGIN_ENERGY_COLLECTION - -DFEATURE_ETHERNET=1 + -[env:display_ESP32c3_4M316k_CDC] -extends = esp32c3_common +[env:display_ESP32c3_4M316k_LittleFS_CDC_ETH] +extends = esp32c3_common_LittleFS board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} +build_flags = ${esp32c3_common_LittleFS.build_flags} -D PLUGIN_DISPLAY_COLLECTION -D ST7789_EXTRA_INIT=1 -D P116_EXTRA_ST7789=1 -[env:climate_ESP32c3_4M316k_CDC] -extends = esp32c3_common +[env:climate_ESP32c3_4M316k_LittleFS_CDC_ETH] +extends = esp32c3_common_LittleFS board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} +build_flags = ${esp32c3_common_LittleFS.build_flags} -D PLUGIN_CLIMATE_COLLECTION -[env:neopixel_ESP32c3_4M316k_CDC] -extends = esp32c3_common -board = esp32c3cdc -build_flags = ${esp32c3_common.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DFEATURE_SD=1 - -DPLUGIN_NEOPIXEL_COLLECTION - [env:neopixel_ESP32c3_4M316k_LittleFS_CDC_ETH] extends = esp32c3_common_LittleFS board = esp32c3cdc build_flags = ${esp32c3_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DFEATURE_SD=1 - -DFEATURE_ETHERNET=1 -DPLUGIN_NEOPIXEL_COLLECTION [env:max_ESP32c3_16M8M_LittleFS_CDC_ETH] @@ -182,7 +114,6 @@ board = esp32c3cdc-16M build_flags = ${esp32c3_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DFEATURE_SD=1 - -DFEATURE_ETHERNET=1 -DPLUGIN_BUILD_MAX_ESP32 -DPLUGIN_BUILD_IR_EXTENDED extra_scripts = ${esp32c3_common_LittleFS.extra_scripts} diff --git a/platformio_esp32c5_envs.ini b/platformio_esp32c5_envs.ini index ae0a669c8..3f3092566 100644 --- a/platformio_esp32c5_envs.ini +++ b/platformio_esp32c5_envs.ini @@ -1,16 +1,16 @@ [esp32c5_common_LittleFS] -extends = esp32_base_idf5 -build_flags = ${esp32_base_idf5.build_flags} +extends = esp32_base_idf5_5 +build_flags = ${esp32_base_idf5_5.build_flags} -DFEATURE_ARDUINO_OTA=1 -DUSE_LITTLEFS -DESP32C5 -extra_scripts = ${esp32_base_idf5.extra_scripts} -build_unflags = ${esp32_base_idf5.build_unflags} +extra_scripts = ${esp32_base_idf5_5.extra_scripts} +build_unflags = ${esp32_base_idf5_5.build_unflags} -fexceptions board_build.filesystem = littlefs -lib_ignore = ${esp32_base_idf5.lib_ignore} +lib_ignore = ${esp32_base_idf5_5.lib_ignore} board = esp32c5cdc diff --git a/platformio_esp32s2_envs.ini b/platformio_esp32s2_envs.ini index f51587d68..473b131ef 100644 --- a/platformio_esp32s2_envs.ini +++ b/platformio_esp32s2_envs.ini @@ -1,24 +1,8 @@ - - - - -[esp32s2_common] -extends = esp32_base -lib_ignore = ${esp32_always.lib_ignore} - ESP32_ping - ${no_ir.lib_ignore} - ESP32 BLE Arduino -build_flags = ${esp32_base.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DESP32S2 -extra_scripts = ${esp32_base.extra_scripts} -build_unflags = ${esp32_base.build_unflags} - -fexceptions - [esp32s2_common_LittleFS] extends = esp32_base_idf5 build_flags = ${esp32_base_idf5.build_flags} -DFEATURE_ARDUINO_OTA=1 + -DFEATURE_ETHERNET=1 -DUSE_LITTLEFS -DESP32S2 extra_scripts = ${esp32_base_idf5.extra_scripts} @@ -28,23 +12,6 @@ board_build.filesystem = littlefs lib_ignore = ${esp32_base_idf5.lib_ignore} -[env:custom_ESP32s2_4M316k_CDC] -extends = esp32s2_common -board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} - -DPLUGIN_BUILD_CUSTOM - -DESP_CONSOLE_USB_CDC=y -extra_scripts = ${esp32s2_common.extra_scripts} - pre:tools/pio/pre_custom_esp32.py - -[env:neopixel_ESP32s2_4M316k_CDC] -extends = esp32s2_common -board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DFEATURE_SD=1 - -DPLUGIN_NEOPIXEL_COLLECTION - [env:neopixel_ESP32s2_4M316k_LittleFS_CDC_ETH] extends = esp32s2_common_LittleFS board = esp32s2cdc @@ -52,29 +19,22 @@ build_flags = ${esp32s2_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DFEATURE_SD=1 -DPLUGIN_NEOPIXEL_COLLECTION - -DFEATURE_ETHERNET=1 + -[env:custom_IR_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:custom_IR_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -DPLUGIN_BUILD_CUSTOM -DPLUGIN_BUILD_IR lib_ignore = ${esp32_always.lib_ignore} ESP32_ping -extra_scripts = ${esp32s2_common.extra_scripts} +extra_scripts = ${esp32s2_common_LittleFS.extra_scripts} pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py - -[env:normal_ESP32s2_4M316k_CDC] -extends = esp32s2_common -board = esp32s2cdc -lib_ignore = ${esp32s2_common.lib_ignore} - ${no_ir.lib_ignore} - [env:custom_ESP32s2_4M316k_LittleFS_CDC_ETH] extends = esp32s2_common_LittleFS board = esp32s2cdc @@ -83,7 +43,6 @@ lib_ignore = ${esp32s2_common_LittleFS.lib_ignore} build_flags = ${esp32s2_common_LittleFS.build_flags} -DPLUGIN_BUILD_CUSTOM -DESP_CONSOLE_USB_CDC=y - -DFEATURE_ETHERNET=1 extra_scripts = ${esp32s2_common_LittleFS.extra_scripts} pre:tools/pio/pre_custom_esp32.py @@ -94,77 +53,76 @@ extends = esp32s2_common_LittleFS board = esp32s2cdc build_flags = ${esp32s2_common_LittleFS.build_flags} -DESP_CONSOLE_USB_CDC=y - -DFEATURE_ETHERNET=1 lib_ignore = ${esp32s2_common_LittleFS.lib_ignore} ${no_ir.lib_ignore} -[env:collection_A_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:collection_A_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_B_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:collection_B_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_B_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_C_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:collection_C_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_C_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_D_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:collection_D_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_D_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_E_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:collection_E_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_E_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_F_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:collection_F_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_F_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_G_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:collection_G_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_G_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:energy_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:energy_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -D PLUGIN_ENERGY_COLLECTION -[env:display_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:display_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -D PLUGIN_DISPLAY_COLLECTION -D ST7789_EXTRA_INIT=1 -D P116_EXTRA_ST7789=1 -[env:climate_ESP32s2_4M316k_CDC] -extends = esp32s2_common +[env:climate_ESP32s2_4M316k_LittleFS_CDC_ETH] +extends = esp32s2_common_LittleFS board = esp32s2cdc -build_flags = ${esp32s2_common.build_flags} +build_flags = ${esp32s2_common_LittleFS.build_flags} -D PLUGIN_CLIMATE_COLLECTION diff --git a/platformio_esp32s3_envs.ini b/platformio_esp32s3_envs.ini index a70755617..aa3bde873 100644 --- a/platformio_esp32s3_envs.ini +++ b/platformio_esp32s3_envs.ini @@ -1,20 +1,3 @@ - - - - -[esp32s3_common] -extends = esp32_base -lib_ignore = ${esp32_always.lib_ignore} - ESP32_ping - ${no_ir.lib_ignore} - ESP32 BLE Arduino -build_flags = ${esp32_base.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DESP32S3 -extra_scripts = ${esp32_base.extra_scripts} -build_unflags = ${esp32_base.build_unflags} - -fexceptions - [esp32s3_common_LittleFS] extends = esp32_base_idf5 lib_ignore = ${esp32_common_LittleFS.lib_ignore} @@ -23,6 +6,7 @@ lib_ignore = ${esp32_common_LittleFS.lib_ignore} build_flags = ${esp32_base_idf5.build_flags} ; -mtext-section-literals -DFEATURE_ARDUINO_OTA=1 + -DFEATURE_ETHERNET=1 -DUSE_LITTLEFS -DESP32S3 extra_scripts = ${esp32_base_idf5.extra_scripts} @@ -31,35 +15,28 @@ build_unflags = ${esp32_base_idf5.build_unflags} board_build.filesystem = littlefs -[env:custom_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:custom_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_BUILD_CUSTOM -extra_scripts = ${esp32s3_common.extra_scripts} +extra_scripts = ${esp32s3_common_LittleFS.extra_scripts} pre:tools/pio/pre_custom_esp32.py -[env:custom_IR_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:custom_IR_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_BUILD_CUSTOM -DPLUGIN_BUILD_IR lib_ignore = ${esp32_always.lib_ignore} ESP32_ping -extra_scripts = ${esp32s3_common.extra_scripts} +extra_scripts = ${esp32s3_common_LittleFS.extra_scripts} pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py - -[env:normal_ESP32s3_4M316k_CDC] -extends = esp32s3_common -board = esp32s3cdc-qio_qspi -lib_ignore = ${esp32s3_common.lib_ignore} - ${no_ir.lib_ignore} - [env:normal_ESP32s3_4M316k_LittleFS_CDC_ETH] extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi @@ -68,85 +45,78 @@ lib_ignore = ${esp32s3_common_LittleFS.lib_ignore} build_flags = ${esp32s3_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DFEATURE_SD=1 - -DFEATURE_ETHERNET=1 + -[env:collection_A_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:collection_A_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_B_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:collection_B_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_B_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_C_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:collection_C_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_C_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_D_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:collection_D_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_D_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_E_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:collection_E_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_E_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_F_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:collection_F_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_F_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:collection_G_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:collection_G_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -DPLUGIN_SET_COLLECTION_G_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 -[env:energy_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:energy_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -D PLUGIN_ENERGY_COLLECTION -[env:display_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:display_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -D PLUGIN_DISPLAY_COLLECTION -D ST7789_EXTRA_INIT=1 -D P116_EXTRA_ST7789=1 -[env:climate_ESP32s3_4M316k_CDC] -extends = esp32s3_common +[env:climate_ESP32s3_4M316k_LittleFS_CDC_ETH] +extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} +build_flags = ${esp32s3_common_LittleFS.build_flags} -D PLUGIN_CLIMATE_COLLECTION -[env:neopixel_ESP32s3_4M316k_CDC] -extends = esp32s3_common -board = esp32s3cdc-qio_qspi -build_flags = ${esp32s3_common.build_flags} - -DFEATURE_ARDUINO_OTA=1 - -DFEATURE_SD=1 - -DPLUGIN_NEOPIXEL_COLLECTION [env:neopixel_ESP32s3_4M316k_LittleFS_CDC_ETH] extends = esp32s3_common_LittleFS @@ -155,14 +125,13 @@ build_flags = ${esp32s3_common_LittleFS.build_flags} -DFEATURE_ARDUINO_OTA=1 -DFEATURE_SD=1 -DPLUGIN_NEOPIXEL_COLLECTION - -DFEATURE_ETHERNET=1 + [env:custom_ESP32s3_8M1M_LittleFS_CDC_ETH] extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi-8M build_flags = ${esp32s3_common_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_CUSTOM -DFEATURE_SD=1 @@ -178,7 +147,6 @@ board = esp32s3cdc-qio_opi-8M extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi-8M build_flags = ${esp32s3_common_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_MAX_ESP32 -DPLUGIN_BUILD_IR_EXTENDED @@ -196,7 +164,6 @@ board = esp32s3cdc-qio_opi-8M extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi-16M build_flags = ${esp32s3_common_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_CUSTOM -DPLUGIN_BUILD_IR_EXTENDED @@ -213,7 +180,6 @@ board = esp32s3cdc-qio_opi-16M extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_qspi-16M build_flags = ${esp32s3_common_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_MAX_ESP32 -DPLUGIN_BUILD_IR_EXTENDED @@ -226,7 +192,6 @@ extra_scripts = ${esp32s3_common_LittleFS.extra_scripts} extends = esp32s3_common_LittleFS board = esp32s3cdc-qio_opi-16M build_flags = ${esp32s3_common_LittleFS.build_flags} - -DFEATURE_ETHERNET=1 -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_MAX_ESP32 -DPLUGIN_BUILD_IR_EXTENDED diff --git a/src/src/Helpers/Hardware_GPIO_ESP32C3.cpp b/src/src/Helpers/Hardware_GPIO_ESP32C3.cpp index daf353e55..b7e90b3f4 100644 --- a/src/src/Helpers/Hardware_GPIO_ESP32C3.cpp +++ b/src/src/Helpers/Hardware_GPIO_ESP32C3.cpp @@ -45,7 +45,9 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) output = false; } else { // See: https://www.letscontrolit.com/forum/viewtopic.php?p=71880#p71874 - if ((gpio == MSPI_IOMUX_PIN_NUM_HD) || (gpio == MSPI_IOMUX_PIN_NUM_WP)) { + if ((gpio == 12) || (gpio == 13)) { + // SPIHD/GPIO12 + // SPIWP/GPIO13 if ((ESP.getFlashChipMode() != FM_DOUT) && (ESP.getFlashChipMode() != FM_DIO)) { input = false; diff --git a/tools/pio/post_esp32.py b/tools/pio/post_esp32.py index 5de862526..b96787f26 100644 --- a/tools/pio/post_esp32.py +++ b/tools/pio/post_esp32.py @@ -55,14 +55,14 @@ def esp32_create_combined_bin(source, target, env): cmd = [ "--chip", chip, - "merge_bin", + "merge-bin", "-o", new_file_name, - "--flash_mode", + "--flash-mode", flash_mode, - "--flash_freq", + "--flash-freq", flash_freq, - "--flash_size", + "--flash-size", flash_size, ] From 4703d4f9484ba7b55a467cc8cc9e21018ad01413 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 21 Jun 2025 01:24:53 +0200 Subject: [PATCH 063/564] [Build] Fix display ESP32 build --- platformio_esp32_envs.ini | 89 +++++++++++++++++++------------------ platformio_esp32s3_envs.ini | 2 +- platformio_special_envs.ini | 16 +++---- 3 files changed, 54 insertions(+), 53 deletions(-) diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 6670dced5..0c92f8b2c 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -88,10 +88,11 @@ lib_ignore = ESP8266Ping -[esp32_common_LittleFS] +[esp32_common_LittleFS_ETH] extends = esp32_base_idf5 build_flags = ${esp32_base_idf5.build_flags} ; -mtext-section-literals + -DFEATURE_ETHERNET=1 -DESP32_CLASSIC -DUSE_LITTLEFS build_unflags = ${esp32_base_idf5.build_unflags} @@ -104,23 +105,23 @@ lib_ignore = ${esp32_always.lib_ignore} [esp32_IRExt_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH lib_ignore = ${esp32_always.lib_ignore} ESP32_ping -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ETHERNET=1 -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_NORMAL_IRext -DCOLLECTION_FEATURE_RTTTL=1 -extra_scripts = ${esp32_common_LittleFS.extra_scripts} +extra_scripts = ${esp32_common_LittleFS_ETH.extra_scripts} pre:tools/pio/ir_build_check.py [esp32_custom_base_LittleFS] -extends = esp32_common_LittleFS -build_flags = ${esp32_common_LittleFS.build_flags} +extends = esp32_common_LittleFS_ETH +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DPLUGIN_BUILD_CUSTOM -extra_scripts = ${esp32_common_LittleFS.extra_scripts} +extra_scripts = ${esp32_common_LittleFS_ETH.extra_scripts} pre:tools/pio/pre_custom_esp32.py @@ -139,15 +140,15 @@ build_flags = ${env:custom_ESP32_4M316k_LittleFS_ETH.build_flags} [env:custom_IR_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DPLUGIN_BUILD_CUSTOM -DPLUGIN_BUILD_IR lib_ignore = ${esp32_always.lib_ignore} ESP32_ping -extra_scripts = ${esp32_common_LittleFS.extra_scripts} +extra_scripts = ${esp32_common_LittleFS_ETH.extra_scripts} pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py @@ -160,63 +161,63 @@ build_flags = ${env:custom_ESP32_4M316k_LittleFS_ETH.build_flags} [env:collection_A_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 [env:collection_B_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_B_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 [env:collection_C_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_C_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 [env:collection_D_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_D_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 [env:collection_E_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_E_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 [env:collection_F_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_F_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 [env:collection_G_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_G_ESP32 -DCOLLECTION_FEATURE_RTTTL=1 @@ -266,17 +267,17 @@ build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} -DPLUGIN_SET_COLLECTION_G_ESP32 [env:energy_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_ENERGY_COLLECTION [env:display_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_DISPLAY_COLLECTION -D ST7789_EXTRA_INIT=1 @@ -285,20 +286,20 @@ build_flags = ${esp32_common_LittleFS.build_flags} [env:climate_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M lib_ignore = ${esp32_always.lib_ignore} ESP32_ping - ${esp32_common_LittleFS.lib_ignore} + ${esp32_common_LittleFS_ETH.lib_ignore} ${no_ir.lib_ignore} -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DPLUGIN_CLIMATE_COLLECTION [env:neopixel_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DFEATURE_SD=1 -D PLUGIN_NEOPIXEL_COLLECTION @@ -307,29 +308,29 @@ build_flags = ${esp32_common_LittleFS.build_flags} [env:custom_IR_ESP32_16M8M_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_16M8M board_upload.flash_size = 16MB -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DPLUGIN_BUILD_CUSTOM -DPLUGIN_BUILD_IR lib_ignore = ${esp32_always.lib_ignore} ESP32_ping - ${esp32_common_LittleFS.lib_ignore} -extra_scripts = ${esp32_common_LittleFS.extra_scripts} + ${esp32_common_LittleFS_ETH.lib_ignore} +extra_scripts = ${esp32_common_LittleFS_ETH.extra_scripts} pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py [env:normal_ESP32_4M316k_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_4M lib_ignore = ${esp32_always.lib_ignore} ESP32_ping - ${esp32_common_LittleFS.lib_ignore} + ${esp32_common_LittleFS_ETH.lib_ignore} ${no_ir.lib_ignore} -build_flags = ${esp32_common_LittleFS.build_flags} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} @@ -345,19 +346,19 @@ build_flags = ${esp32_IRExt_LittleFS_ETH.build_flags} ; A Lolin D32 PRO with 16MB Flash, allowing 4MB sketch size, and file storage using LittleFS filesystem [env:max_ESP32_16M8M_LittleFS_ETH] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH board = esp32_16M8M board_upload.flash_size = 16MB lib_ignore = ${esp32_always.lib_ignore} ESP32_ping - ${esp32_common_LittleFS.lib_ignore} -build_flags = ${esp32_common_LittleFS.build_flags} + ${esp32_common_LittleFS_ETH.lib_ignore} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_MAX_ESP32 -DPLUGIN_BUILD_IR_EXTENDED -D ST7789_EXTRA_INIT=1 -D P116_EXTRA_ST7789=1 -extra_scripts = ${esp32_common_LittleFS.extra_scripts} +extra_scripts = ${esp32_common_LittleFS_ETH.extra_scripts} board_build.filesystem = littlefs ; If you have a board with Ethernet integrated and 16MB Flash, then this configuration could be enabled, it's based on the max_ESP32_16M8M_LittleFS definition diff --git a/platformio_esp32s3_envs.ini b/platformio_esp32s3_envs.ini index aa3bde873..a664f96fb 100644 --- a/platformio_esp32s3_envs.ini +++ b/platformio_esp32s3_envs.ini @@ -1,6 +1,6 @@ [esp32s3_common_LittleFS] extends = esp32_base_idf5 -lib_ignore = ${esp32_common_LittleFS.lib_ignore} +lib_ignore = ${esp32_common_LittleFS_ETH.lib_ignore} ESP32_ping ${esp32_base_idf5.lib_ignore} build_flags = ${esp32_base_idf5.build_flags} diff --git a/platformio_special_envs.ini b/platformio_special_envs.ini index 6b2c28ebd..179b27b68 100644 --- a/platformio_special_envs.ini +++ b/platformio_special_envs.ini @@ -50,14 +50,14 @@ extra_scripts = ${extra_scripts_esp8266.extra_scripts} [env:spec_debug_custom_ESP32_16M8M] -extends = esp32_common_LittleFS +extends = esp32_common_LittleFS_ETH build_type = ${debug_pio.build_type} check_tool = ${debug_pio.check_tool} check_flags = ${debug_pio.check_flags} -platform = ${esp32_common_LittleFS.platform} -build_flags = ${esp32_common_LittleFS.build_flags} ${debug_pio.build_flags} -DPLUGIN_BUILD_CUSTOM +platform = ${esp32_common_LittleFS_ETH.platform} +build_flags = ${esp32_common_LittleFS_ETH.build_flags} ${debug_pio.build_flags} -DPLUGIN_BUILD_CUSTOM board = esp32_16M8M -extra_scripts = ${esp32_common_LittleFS.extra_scripts} +extra_scripts = ${esp32_common_LittleFS_ETH.extra_scripts} pre:tools/pio/pre_custom_esp32.py [env:spec_debug_max_ESP32_16M8M] @@ -65,7 +65,7 @@ extends = esp32_base_idf5 build_type = ${debug_pio.build_type} check_tool = ${debug_pio.check_tool} check_flags = ${debug_pio.check_flags} -lib_ignore = ${esp32_common_LittleFS.lib_ignore} +lib_ignore = ${esp32_common_LittleFS_ETH.lib_ignore} build_flags = ${esp32_base_idf5.build_flags} ${debug_pio.build_flags} -DESP32_CLASSIC @@ -87,7 +87,7 @@ extends = esp32_base_idf5 build_type = ${debug_pio.build_type} check_tool = ${debug_pio.check_tool} check_flags = ${debug_pio.check_flags} -lib_ignore = ${esp32_common_LittleFS.lib_ignore} +lib_ignore = ${esp32_common_LittleFS_ETH.lib_ignore} build_flags = ${esp32_base_idf5.build_flags} ${debug_pio.build_flags} -DESP32_CLASSIC @@ -107,7 +107,7 @@ extends = esp32_base_idf5 build_type = ${debug_pio.build_type} check_tool = ${debug_pio.check_tool} check_flags = ${debug_pio.check_flags} -lib_ignore = ${esp32_common_LittleFS.lib_ignore} +lib_ignore = ${esp32_common_LittleFS_ETH.lib_ignore} build_flags = ${esp32_base_idf5.build_flags} ${debug_pio.build_flags} -DESP32_CLASSIC @@ -128,7 +128,7 @@ extends = esp32_base_idf5 build_type = ${debug_pio.build_type} check_tool = ${debug_pio.check_tool} check_flags = ${debug_pio.check_flags} -lib_ignore = ${esp32_common_LittleFS.lib_ignore} +lib_ignore = ${esp32_common_LittleFS_ETH.lib_ignore} build_flags = ${esp32_base_idf5.build_flags} ${debug_pio.build_flags} -DESP32_CLASSIC From 100d64e5ccd6665b3dd300592859041cd28d0224 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 21 Jun 2025 01:50:23 +0200 Subject: [PATCH 064/564] [build] Change ESP32 IRExt builds to LIMIT_BUILD_SIZE --- platformio_esp32_envs.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 0c92f8b2c..5b0f60e04 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -113,6 +113,7 @@ build_flags = ${esp32_common_LittleFS_ETH.build_flags} -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_NORMAL_IRext -DCOLLECTION_FEATURE_RTTTL=1 + -DLIMIT_BUILD_SIZE extra_scripts = ${esp32_common_LittleFS_ETH.extra_scripts} pre:tools/pio/ir_build_check.py From 5ed46c1c40573f418d574f8520665794f610bf76 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 23 Jun 2025 15:50:46 +0200 Subject: [PATCH 065/564] [ESP32-C61] Start adding support for new SoC & generalize WiFi features --- boards/esp32c61cdc-8M.json | 40 ++++ lib/ESPEasySerial/ESPEasySerialType.h | 120 ++++++----- .../ESPEasySerial_common_defines.h | 4 +- platformio.ini | 1 + platformio_core_defs.ini | 7 +- platformio_esp32c61_envs.ini | 27 +++ src/include/esp32x_fixes.h | 28 ++- src/src/CustomBuild/ESPEasy_buildinfo.h | 26 ++- src/src/DataStructs/WiFi_AP_Candidate.cpp | 4 +- src/src/DataTypes/NodeTypeID.cpp | 1 + src/src/DataTypes/NodeTypeID.h | 3 + src/src/DataTypes/SPI_options.cpp | 2 + src/src/DataTypes/SPI_options.h | 67 ++---- src/src/ESPEasyCore/ESPEasyWifi.cpp | 10 +- .../ESPEasyWifi_abstracted_ESP32.cpp | 43 +++- src/src/Helpers/Hardware_GPIO.h | 3 + src/src/WebServer/Markup.h | 192 +++++++++--------- 17 files changed, 349 insertions(+), 229 deletions(-) create mode 100644 boards/esp32c61cdc-8M.json create mode 100644 platformio_esp32c61_envs.ini diff --git a/boards/esp32c61cdc-8M.json b/boards/esp32c61cdc-8M.json new file mode 100644 index 000000000..3bc30400c --- /dev/null +++ b/boards/esp32c61cdc-8M.json @@ -0,0 +1,40 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32c61_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_TASMOTA -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_8M -DESP32C61 -DARDUINO_USB_CDC_ON_BOOT=1", + "f_cpu": "120000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32c61", + "variant": "esp32c61", + "partitions": "boards/partitions/esp32_partition_app3520k_spiffs1088k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth" + ], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], + "openocd_target": "esp32c61.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "Espressif Generic ESP32-C61 >= 8M Flash, ESPEasy 3520k Code/OTA 1088k FS", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html", + "vendor": "Espressif" + } diff --git a/lib/ESPEasySerial/ESPEasySerialType.h b/lib/ESPEasySerial/ESPEasySerialType.h index 65d15d5b9..90b71bb16 100644 --- a/lib/ESPEasySerial/ESPEasySerialType.h +++ b/lib/ESPEasySerial/ESPEasySerialType.h @@ -29,7 +29,7 @@ # elif CONFIG_IDF_TARGET_ESP32C2 # define SOC_RX0 19 # endif // if CONFIG_IDF_TARGET_ESP32 -# endif // ifndef SOC_RX0 +# endif // ifndef SOC_RX0 # ifndef SOC_TX0 # if CONFIG_IDF_TARGET_ESP32 @@ -45,67 +45,86 @@ # elif CONFIG_IDF_TARGET_ESP32C2 # define SOC_TX0 20 # endif // if CONFIG_IDF_TARGET_ESP32 -# endif // ifndef SOC_TX0 +# endif // ifndef SOC_TX0 -# if SOC_UART_NUM > 1 + +# if SOC_UART_HP_NUM > 1 # ifndef SOC_RX1 -# if CONFIG_IDF_TARGET_ESP32 -# define SOC_RX1 13 -# elif CONFIG_IDF_TARGET_ESP32S2 -# define SOC_RX1 18 -# elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 -# define SOC_RX1 4 -# elif CONFIG_IDF_TARGET_ESP32S3 -# define SOC_RX1 15 -# endif // if CONFIG_IDF_TARGET_ESP32 -# endif // ifndef SOC_RX1 +# ifdef RX1 +# define SOC_RX1 RX1 +# else +# if CONFIG_IDF_TARGET_ESP32 +# define SOC_RX1 13 +# elif CONFIG_IDF_TARGET_ESP32S2 +# define SOC_RX1 18 +# elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 +# define SOC_RX1 4 +# elif CONFIG_IDF_TARGET_ESP32S3 +# define SOC_RX1 15 +# endif // if CONFIG_IDF_TARGET_ESP32 +# endif // ifdef RX1 +# endif // ifndef SOC_RX1 # ifndef SOC_TX1 -# if CONFIG_IDF_TARGET_ESP32 -# define SOC_TX1 15 -# elif CONFIG_IDF_TARGET_ESP32S2 -# define SOC_TX1 17 -# elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 -# define SOC_TX1 5 -# elif CONFIG_IDF_TARGET_ESP32S3 -# define SOC_TX1 16 -# endif // if CONFIG_IDF_TARGET_ESP32 -# endif // ifndef SOC_TX1 +# ifdef TX1 +# define SOC_TX1 TX1 +# else +# if CONFIG_IDF_TARGET_ESP32 +# define SOC_TX1 15 +# elif CONFIG_IDF_TARGET_ESP32S2 +# define SOC_TX1 17 +# elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 +# define SOC_TX1 5 +# elif CONFIG_IDF_TARGET_ESP32S3 +# define SOC_TX1 16 +# endif // if CONFIG_IDF_TARGET_ESP32 +# endif // ifdef TX1 +# endif // ifndef SOC_TX1 -# endif // if SOC_UART_NUM > 1 +# endif // if SOC_UART_HP_NUM > 1 -# if SOC_UART_NUM > 2 +# if SOC_UART_HP_NUM > 2 # ifndef SOC_RX2 -# if CONFIG_IDF_TARGET_ESP32 -# define SOC_RX2 16 -# elif CONFIG_IDF_TARGET_ESP32S3 -# define SOC_RX2 19 -# elif CONFIG_IDF_TARGET_ESP32C6 -# define SOC_RX2 6 -# elif CONFIG_IDF_TARGET_ESP32C5 -# define SOC_RX2 6 -# else // if CONFIG_IDF_TARGET_ESP32 -# define SOC_RX2 -1 -# endif // if CONFIG_IDF_TARGET_ESP32 -# endif // ifndef SOC_RX2 +# ifdef RX2 +# define SOC_RX2 RX2 +# else + +# if CONFIG_IDF_TARGET_ESP32 +# define SOC_RX2 16 +# elif CONFIG_IDF_TARGET_ESP32S3 +# define SOC_RX2 19 +# elif CONFIG_IDF_TARGET_ESP32C6 +# define SOC_RX2 6 +# elif CONFIG_IDF_TARGET_ESP32C5 +# define SOC_RX2 6 +# else // if CONFIG_IDF_TARGET_ESP32 +# define SOC_RX2 -1 +# endif // if CONFIG_IDF_TARGET_ESP32 +# endif // ifdef RX2 +# endif // ifndef SOC_RX2 # ifndef SOC_TX2 -# if CONFIG_IDF_TARGET_ESP32 -# define SOC_TX2 17 -# elif CONFIG_IDF_TARGET_ESP32S3 -# define SOC_TX2 20 -# elif CONFIG_IDF_TARGET_ESP32C6 -# define SOC_TX2 7 -# elif CONFIG_IDF_TARGET_ESP32C5 -# define SOC_TX2 7 -# else // if CONFIG_IDF_TARGET_ESP32 -# define SOC_TX2 -1 -# endif // if CONFIG_IDF_TARGET_ESP32 -# endif // ifndef SOC_TX2 +# ifdef TX2 +# define SOC_TX2 TX2 +# else -# endif // if SOC_UART_NUM > 2 +# if CONFIG_IDF_TARGET_ESP32 +# define SOC_TX2 17 +# elif CONFIG_IDF_TARGET_ESP32S3 +# define SOC_TX2 20 +# elif CONFIG_IDF_TARGET_ESP32C6 +# define SOC_TX2 7 +# elif CONFIG_IDF_TARGET_ESP32C5 +# define SOC_TX2 7 +# else // if CONFIG_IDF_TARGET_ESP32 +# define SOC_TX2 -1 +# endif // if CONFIG_IDF_TARGET_ESP32 +# endif // ifdef TX2 +# endif // ifndef SOC_TX2 + +# endif // if SOC_UART_HP_NUM > 2 #endif // ifdef ESP32 @@ -117,6 +136,7 @@ struct ESPeasySerialType { static ESPEasySerialPort getSerialType(ESPEasySerialPort typeHint, int receivePin, int transmitPin); + }; diff --git a/lib/ESPEasySerial/ESPEasySerial_common_defines.h b/lib/ESPEasySerial/ESPEasySerial_common_defines.h index 6d8ce15dc..81ef0ba02 100644 --- a/lib/ESPEasySerial/ESPEasySerial_common_defines.h +++ b/lib/ESPEasySerial/ESPEasySerial_common_defines.h @@ -8,7 +8,7 @@ #ifndef SOC_UART_NUM # ifdef ESP8266 # define SOC_UART_NUM 2 -# elif defined(ESP32_CLASSIC) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) +# elif defined(ESP32_CLASSIC) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) || defined(ESP32C61) # include # else // ifdef ESP8266 static_assert(false, "Implement processor architecture"); @@ -40,7 +40,7 @@ static_assert(false, "Implement processor architecture"); CONFIG_IDF_TARGET_ESP32S2 || // support USB via USBCDC CONFIG_IDF_TARGET_ESP32S3 // support USB via HWCDC using JTAG interface or USBCDC */ -# if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +# if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C61 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // #if CONFIG_TINYUSB_CDC_ENABLED // This define is not recognized here so use USE_USB_CDC_CONSOLE # ifdef USE_USB_CDC_CONSOLE diff --git a/platformio.ini b/platformio.ini index 6e461dd30..a638e17b2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,6 +29,7 @@ extra_configs = platformio_esp32c3_envs.ini platformio_esp32c5_envs.ini platformio_esp32c6_envs.ini +; platformio_esp32c61_envs.ini ;default_envs = normal_ESP32_4M diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 569072a76..eb4b43371 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -165,10 +165,8 @@ extra_scripts = ${esp82xx_common.extra_scripts} ; ESP_IDF 5.4.1 [core_esp32_IDF5_4_1__3_2_0_LittleFS] -;platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF54 -;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3538/framework-arduinoespressif32-all-release_v5.4-8f5ad6d7.zip platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF54 -platform_packages = +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3717/framework-arduinoespressif32-all-release_v5.4-fea159f6.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 @@ -197,7 +195,8 @@ lib_extra_dirs = ; ESP_IDF 5.5.0 [core_esp32_IDF5_5_0__3_2_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3627/framework-arduinoespressif32-all-release_v5.5-5d572003.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3718/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip +;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3627/framework-arduinoespressif32-all-release_v5.5-5d572003.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 diff --git a/platformio_esp32c61_envs.ini b/platformio_esp32c61_envs.ini new file mode 100644 index 000000000..1743b7abb --- /dev/null +++ b/platformio_esp32c61_envs.ini @@ -0,0 +1,27 @@ +[esp32c61_common_LittleFS] +extends = esp32_base_idf5_5 +build_flags = ${esp32_base_idf5_5.build_flags} + -DFEATURE_ARDUINO_OTA=1 + -DUSE_LITTLEFS + -DESP32C61 +extra_scripts = ${esp32_base_idf5_5.extra_scripts} +build_unflags = ${esp32_base_idf5_5.build_unflags} + -fexceptions +board_build.filesystem = littlefs +lib_ignore = ${esp32_base_idf5_5.lib_ignore} +board = esp32c61cdc + + +[env:max_ESP32c61_8M1M_LittleFS_CDC_ETH] +extends = esp32c61_common_LittleFS +board = esp32c61cdc-8M +build_flags = ${esp32c61_common_LittleFS.build_flags} + -DFEATURE_ETHERNET=1 + -DFEATURE_ARDUINO_OTA=1 + -DPLUGIN_BUILD_MAX_ESP32 + -DPLUGIN_BUILD_IR_EXTENDED + -D ST7789_EXTRA_INIT=1 + -D P116_EXTRA_ST7789=1 +extra_scripts = ${esp32c61_common_LittleFS.extra_scripts} + + diff --git a/src/include/esp32x_fixes.h b/src/include/esp32x_fixes.h index 44c3ab47c..d8ecec688 100644 --- a/src/include/esp32x_fixes.h +++ b/src/include/esp32x_fixes.h @@ -32,6 +32,9 @@ * -I$PROJECT_DIR/include * -include "esp32x_fixes.h" */ + +//#include + #ifdef __riscv # undef __INT32_TYPE__ @@ -87,10 +90,14 @@ # endif // REG_SPI_BASE # endif // ESP_IDF_VERSION_MAJOR < 5 -#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 +#else # define SPI_HOST SPI1_HOST # define HSPI_HOST SPI2_HOST -# define VSPI_HOST SPI2_HOST /* No SPI3_host on C2/C6 */ +#if SOC_SPI_PERIPH_NUM > 2 +# define VSPI_HOST SPI3_HOST +#else +# define VSPI_HOST SPI2_HOST /* No SPI3_host */ +#endif # define VSPI SPI // #if ESP_IDF_VERSION_MAJOR < 5 @@ -105,3 +112,20 @@ #endif // TARGET + + +#ifndef CONFIG_SOC_WIFI_HE_SUPPORT +#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C61 +#define CONFIG_SOC_WIFI_HE_SUPPORT 1 +#else +#define CONFIG_SOC_WIFI_HE_SUPPORT 0 +#endif +#endif + +#ifndef CONFIG_SOC_WIFI_SUPPORT_5G +#if CONFIG_IDF_TARGET_ESP32C5 +#define CONFIG_SOC_WIFI_SUPPORT_5G 1 +#else +#define CONFIG_SOC_WIFI_SUPPORT_5G 0 +#endif +#endif \ No newline at end of file diff --git a/src/src/CustomBuild/ESPEasy_buildinfo.h b/src/src/CustomBuild/ESPEasy_buildinfo.h index b6f669d73..0fb8e9ba6 100644 --- a/src/src/CustomBuild/ESPEasy_buildinfo.h +++ b/src/src/CustomBuild/ESPEasy_buildinfo.h @@ -34,18 +34,22 @@ # define BUILD_NOTES " - Mega32-s2" #elif defined(ESP32S3) # define BUILD_NOTES " - Mega32-s3" - #elif defined(ESP32H2) - # define BUILD_NOTES " - Mega32-h2" - #elif defined(ESP32P4) - # define BUILD_NOTES " - Mega32-p4" - #elif defined(ESP32C6) - # define BUILD_NOTES " - Mega32-c6" - #elif defined(ESP32C5) - # define BUILD_NOTES " - Mega32-c5" - #elif defined(ESP32C3) - # define BUILD_NOTES " - Mega32-c3" #elif defined(ESP32C2) # define BUILD_NOTES " - Mega32-c2" + #elif defined(ESP32C3) + # define BUILD_NOTES " - Mega32-c3" + #elif defined(ESP32C5) + # define BUILD_NOTES " - Mega32-c5" + #elif defined(ESP32C6) + # define BUILD_NOTES " - Mega32-c6" + #elif defined(ESP32C61) + # define BUILD_NOTES " - Mega32-c61" + #elif defined(ESP32H2) + # define BUILD_NOTES " - Mega32-h2" + #elif defined(ESP32H21) + # define BUILD_NOTES " - Mega32-h21" + #elif defined(ESP32P4) + # define BUILD_NOTES " - Mega32-p4" # elif defined(ESP32_CLASSIC) # define BUILD_NOTES " - Mega32" # else @@ -72,7 +76,7 @@ CONFIG_IDF_TARGET_ESP32S2 || // support USB via USBCDC CONFIG_IDF_TARGET_ESP32S3 // support USB via HWCDC using JTAG interface or USBCDC */ -# if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +# if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C2) // #if CONFIG_TINYUSB_CDC_ENABLED // This define is not recognized here so use USE_USB_CDC_CONSOLE # ifdef USE_USB_CDC_CONSOLE diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index 907c3d5d2..e5a08dcae 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -115,7 +115,7 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { bits.phy_11ax = it->phy_11ax; bits.ftm_initiator = it->ftm_initiator; bits.ftm_responder = it->ftm_responder; -#ifdef ESP32C5 +#if CONFIG_SOC_WIFI_SUPPORT_5G bits.phy_11a = it->phy_11a; bits.phy_11ac = it->phy_11ac; #endif @@ -256,7 +256,7 @@ String WiFi_AP_Candidate::toString(const String& separator) const { separator.c_str(), channel); -#ifdef ESP32C5 +#if CONFIG_SOC_WIFI_SUPPORT_5G if (channel < 36) { result += F(" 2.4 GHz"); } else { diff --git a/src/src/DataTypes/NodeTypeID.cpp b/src/src/DataTypes/NodeTypeID.cpp index ea80827b9..0001a954d 100644 --- a/src/src/DataTypes/NodeTypeID.cpp +++ b/src/src/DataTypes/NodeTypeID.cpp @@ -15,6 +15,7 @@ const __FlashStringHelper* toNodeTypeDisplayString(uint8_t nodeType) { case NODE_TYPE_ID_ESP_EASY32C6_STD: return F("ESP Easy 32-C6"); case NODE_TYPE_ID_ESP_EASY32C61_STD: return F("ESP Easy 32-C61"); case NODE_TYPE_ID_ESP_EASY32H2_STD: return F("ESP Easy 32-H2"); + case NODE_TYPE_ID_ESP_EASY32H21_STD: return F("ESP Easy 32-H21"); case NODE_TYPE_ID_ESP_EASY32P4_STD: return F("ESP Easy 32-P4"); case NODE_TYPE_ID_RPI_EASY_STD: return F("RPI Easy"); case NODE_TYPE_ID_ARDUINO_EASY_STD: return F("Arduino Easy"); diff --git a/src/src/DataTypes/NodeTypeID.h b/src/src/DataTypes/NodeTypeID.h index d448efa7f..46c672f55 100644 --- a/src/src/DataTypes/NodeTypeID.h +++ b/src/src/DataTypes/NodeTypeID.h @@ -18,6 +18,7 @@ #define NODE_TYPE_ID_ESP_EASY32C61_STD 40 #define NODE_TYPE_ID_ESP_EASY32C5_STD 41 #define NODE_TYPE_ID_ESP_EASY32P4_STD 42 +#define NODE_TYPE_ID_ESP_EASY32H21_STD 43 #define NODE_TYPE_ID_ARDUINO_EASY_STD 65 #define NODE_TYPE_ID_NANO_EASY_STD 81 @@ -44,6 +45,8 @@ # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32C61_STD # elif defined(ESP32H2) # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32H2_STD + # elif defined(ESP32H21) + # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32H21_STD # elif defined(ESP32P4) # define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32P4_STD # elif defined(ESP32_CLASSIC) diff --git a/src/src/DataTypes/SPI_options.cpp b/src/src/DataTypes/SPI_options.cpp index 0736a212e..5f1c3ee79 100644 --- a/src/src/DataTypes/SPI_options.cpp +++ b/src/src/DataTypes/SPI_options.cpp @@ -46,6 +46,8 @@ #define VSPI_FSPI_SHORT_STRING "FSPI" # elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6 #define VSPI_FSPI_SHORT_STRING "FSPI" +# elif CONFIG_IDF_TARGET_ESP32C61 // ESP32-C61 +#define VSPI_FSPI_SHORT_STRING "FSPI" # elif CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #define VSPI_FSPI_SHORT_STRING "VSPI" diff --git a/src/src/DataTypes/SPI_options.h b/src/src/DataTypes/SPI_options.h index 341695d87..3bb385a8f 100644 --- a/src/src/DataTypes/SPI_options.h +++ b/src/src/DataTypes/SPI_options.h @@ -39,65 +39,26 @@ // HSPI option is disabled for now on other than ESP32_CLASSIC. // Should be added later as "Custom HSPI" when we support multiple SPI busses. #ifdef ESP32 -# if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) -# if CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3 -# define VSPI_FSPI_SCK 36 -# define VSPI_FSPI_MISO 37 -# define VSPI_FSPI_MOSI 35 -# elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2 -# define VSPI_FSPI_SCK 36 -# define VSPI_FSPI_MISO 37 -# define VSPI_FSPI_MOSI 35 -# elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6 -# define VSPI_FSPI_SCK 21 -# define VSPI_FSPI_MISO 20 -# define VSPI_FSPI_MOSI 19 -# elif CONFIG_IDF_TARGET_ESP32C5 // ESP32-C5 -# define VSPI_FSPI_SCK SPI2_IOMUX_PIN_NUM_CLK -# define VSPI_FSPI_MISO SPI2_IOMUX_PIN_NUM_MISO -# define VSPI_FSPI_MOSI SPI2_IOMUX_PIN_NUM_MOSI -# elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 -# define VSPI_FSPI_SCK 4 -# define VSPI_FSPI_MISO 5 -# define VSPI_FSPI_MOSI 6 -# elif CONFIG_IDF_TARGET_ESP32C2 // ESP32-C2 -# define VSPI_FSPI_SCK 4 -# define VSPI_FSPI_MISO 5 -# define VSPI_FSPI_MOSI 6 -# elif CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 -# define VSPI_FSPI_SCK 18 -# define VSPI_FSPI_MISO 19 -# define VSPI_FSPI_MOSI 23 -# define HSPI_SCLK 14 -# define HSPI_MISO 12 -# define HSPI_MOSI 13 -# define HSPI_SS 15 +# if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 -# else // if CONFIG_IDF_TARGET_ESP32S2 -# error Target CONFIG_IDF_TARGET is not supported -# endif // if CONFIG_IDF_TARGET_ESP32S2 -# else // if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) -# if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +# define VSPI_FSPI_SCK 18 +# define VSPI_FSPI_MISO 19 +# define VSPI_FSPI_MOSI 23 -# define VSPI_FSPI_SCK 18 -# define VSPI_FSPI_MISO 19 -# define VSPI_FSPI_MOSI 23 +# define HSPI_SCLK 14 +# define HSPI_MISO 12 +# define HSPI_MOSI 13 +# define HSPI_SS 15 -# define HSPI_SCLK 14 -# define HSPI_MISO 12 -# define HSPI_MOSI 13 -# define HSPI_SS 15 +# else // if CONFIG_IDF_TARGET_ESP32 +# include -# else // if CONFIG_IDF_TARGET_ESP32 -# include +# define VSPI_FSPI_SCK SPI2_IOMUX_PIN_NUM_CLK +# define VSPI_FSPI_MISO SPI2_IOMUX_PIN_NUM_MISO +# define VSPI_FSPI_MOSI SPI2_IOMUX_PIN_NUM_MOSI -# define VSPI_FSPI_SCK SPI2_IOMUX_PIN_NUM_CLK -# define VSPI_FSPI_MISO SPI2_IOMUX_PIN_NUM_MISO -# define VSPI_FSPI_MOSI SPI2_IOMUX_PIN_NUM_MOSI - -# endif // if CONFIG_IDF_TARGET_ESP32 -# endif // if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0) +# endif // if CONFIG_IDF_TARGET_ESP32 #endif // ifdef ESP32 enum class SPI_Options_e { // Do not change values as this is stored in the settings! diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 828736fe5..17af3cb25 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -379,9 +379,13 @@ void WifiScan(bool async, uint8_t channel) { # ifdef ESP32 const bool passive = Settings.PassiveWiFiScan(); const uint32_t max_ms_per_chan = 120; -#ifndef ESP32C5 - // C5 scans both 2.4 and 5 GHz band, which takes much longer - WiFi.setScanTimeout(14 * max_ms_per_chan * 2); +#if CONFIG_SOC_WIFI_SUPPORT_5G + // ESP32-C5 scans both 2.4 and 5 GHz band, which takes much longer + // 14 channels on 2.4 GHz + // 36 channels on 5 GHz: 36~177 (36, 40, 44 ... 177) + WiFi.setScanTimeout(50 * (max_ms_per_chan + 10)); +#else +// WiFi.setScanTimeout(14 * (max_ms_per_chan + 10)); #endif WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan /*, channel */); # endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index cb83130f1..dd1c656cd 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -23,7 +23,6 @@ # include - namespace ESPEasy { namespace net { namespace wifi { @@ -295,24 +294,46 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { // The response speed and stability is better at HT20 for ESP units. esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT20); - // uint8_t protocol = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G; // Default to BG uint8_t protocol = 0; + if (ForceWiFi_bg_mode) { + protocol = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G; // Default to BG + } + if (!ForceWiFi_bg_mode || (WiFiEventData.connectionFailures > 10)) { // Set to use BGN protocol |= WIFI_PROTOCOL_11N; - # if defined(ESP32C5) || defined(ESP32C6) +# if CONFIG_SOC_WIFI_HE_SUPPORT protocol |= WIFI_PROTOCOL_11AX; - # endif - #ifdef ESP32C5 +# endif +# if CONFIG_SOC_WIFI_SUPPORT_5G protocol |= WIFI_PROTOCOL_11A; protocol |= WIFI_PROTOCOL_11AC; - #endif +# endif // if CONFIG_SOC_WIFI_SUPPORT_5G } const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); if (candidate.phy_known()) { + if (protocol == 0) { + // No protocol preference set, so we try to match at least the modes supported by the AP + if (candidate.bits.phy_11b) { protocol |= WIFI_PROTOCOL_11B; } + + if (candidate.bits.phy_11g) { protocol |= WIFI_PROTOCOL_11G; } + + if (candidate.bits.phy_11n) { protocol |= WIFI_PROTOCOL_11N; } +# if CONFIG_SOC_WIFI_HE_SUPPORT + + if (candidate.bits.phy_11ax) { protocol |= WIFI_PROTOCOL_11AX; } +# endif // if CONFIG_SOC_WIFI_HE_SUPPORT +# if CONFIG_SOC_WIFI_SUPPORT_5G + + if (candidate.bits.phy_11a) { protocol |= WIFI_PROTOCOL_11A; } + + if (candidate.bits.phy_11ac) { protocol |= WIFI_PROTOCOL_11AC; } +# endif // if CONFIG_SOC_WIFI_SUPPORT_5G + } else + // Check to see if the access point is set to "N-only" if ((protocol & WIFI_PROTOCOL_11N) == 0) { if (!candidate.bits.phy_11b && !candidate.bits.phy_11g && candidate.bits.phy_11n) { @@ -321,26 +342,28 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { protocol |= WIFI_PROTOCOL_11N; addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11n only")); } -# if defined(ESP32C5) || defined(ESP32C6) +# if CONFIG_SOC_WIFI_HE_SUPPORT if (candidate.bits.phy_11ax) { // Set to use WiFi6 protocol |= WIFI_PROTOCOL_11AX; addLog(LOG_LEVEL_INFO, F("WIFI : AP allows 802.11ax, Wi-Fi 6")); } -#ifdef ESP32C5 +# if CONFIG_SOC_WIFI_SUPPORT_5G + if (candidate.bits.phy_11a) { // Set to use 5 GHz WiFi protocol |= WIFI_PROTOCOL_11A; addLog(LOG_LEVEL_INFO, F("WIFI : AP allows 802.11a, 5 GHz")); } + if (candidate.bits.phy_11ac) { // Set to use 5 GHz WiFi-5 protocol |= WIFI_PROTOCOL_11AC; addLog(LOG_LEVEL_INFO, F("WIFI : AP allows 802.11ac, 5 GHz Wi-Fi 5")); } -#endif -# endif // ifdef ESP32C6 +# endif // if CONFIG_SOC_WIFI_SUPPORT_5G +# endif // if CONFIG_SOC_WIFI_HE_SUPPORT } } } diff --git a/src/src/Helpers/Hardware_GPIO.h b/src/src/Helpers/Hardware_GPIO.h index e03522aa6..73c94d9d5 100644 --- a/src/src/Helpers/Hardware_GPIO.h +++ b/src/src/Helpers/Hardware_GPIO.h @@ -17,6 +17,9 @@ bool getGpioInfo(int gpio, bool& input, bool& output, bool& warning); + + +// For ESP32, see: https://github.com/espressif/arduino-esp32/blob/9d84c78cf2d44911639530e54a9dbb9ee9164f6c/cores/esp32/esp32-hal.h#L64-L75 bool isBootModePin(int gpio); bool isBootStrapPin(int gpio); diff --git a/src/src/WebServer/Markup.h b/src/src/WebServer/Markup.h index 94011dbf6..d638308e7 100644 --- a/src/src/WebServer/Markup.h +++ b/src/src/WebServer/Markup.h @@ -9,32 +9,36 @@ #include "../Helpers/StringGenerator_GPIO.h" -#ifdef ESP32_CLASSIC -#define ESP32XX "esp32" -#elif defined(ESP32C2) -#define ESP32XX "esp32c2" -#elif defined(ESP32C3) -#define ESP32XX "esp32c3" -#elif defined(ESP32C5) -#define ESP32XX "esp32c5" -#elif defined(ESP32C6) -#define ESP32XX "esp32c6" -#elif defined(ESP32C61) -#define ESP32XX "esp32c61" -#elif defined(ESP32H2) -#define ESP32XX "esp32h2" -#elif defined(ESP32H21) -#define ESP32XX "esp32h21" -#elif defined(ESP32H4) -#define ESP32XX "esp32h4" -#elif defined(ESP32S2) -#define ESP32XX "esp32s2" -#elif defined(ESP32S3) -#define ESP32XX "esp32s3" -#elif defined(ESP32P4) -#define ESP32XX "esp32p4" -#endif - +#ifdef CONFIG_ARDUINO_VARIANT +// TD-er: Might also use CONFIG_IDF_TARGET +# define ESP32XX CONFIG_ARDUINO_VARIANT +#else +# ifdef ESP32_CLASSIC +# define ESP32XX "esp32" +# elif defined(ESP32C2) +# define ESP32XX "esp32c2" +# elif defined(ESP32C3) +# define ESP32XX "esp32c3" +# elif defined(ESP32C5) +# define ESP32XX "esp32c5" +# elif defined(ESP32C6) +# define ESP32XX "esp32c6" +# elif defined(ESP32C61) +# define ESP32XX "esp32c61" +# elif defined(ESP32H2) +# define ESP32XX "esp32h2" +# elif defined(ESP32H21) +# define ESP32XX "esp32h21" +# elif defined(ESP32H4) +# define ESP32XX "esp32h4" +# elif defined(ESP32S2) +# define ESP32XX "esp32s2" +# elif defined(ESP32S3) +# define ESP32XX "esp32s3" +# elif defined(ESP32P4) +# define ESP32XX "esp32p4" +# endif // ifdef ESP32_CLASSIC +#endif // ifdef CONFIG_ARDUINO_VARIANT #if FEATURE_TOOLTIPS void addTooltip(const String& tooltip); @@ -46,62 +50,63 @@ void addTooltip(const String& tooltip); void addSelector_Head(const String& id); -void addSelector_Head_reloadOnChange(const __FlashStringHelper * id); -//void addSelector_Head_reloadOnChange(const String& id); +void addSelector_Head_reloadOnChange(const __FlashStringHelper *id); + +// void addSelector_Head_reloadOnChange(const String& id); -void addSelector_Head_reloadOnChange(const String& id, - const __FlashStringHelper * classname, +void addSelector_Head_reloadOnChange(const String & id, + const __FlashStringHelper *classname, bool disabled - #if FEATURE_TOOLTIPS + #if FEATURE_TOOLTIPS , - const String& tooltip = EMPTY_STRING + const String & tooltip = EMPTY_STRING #endif // if FEATURE_TOOLTIPS ); -void addSelector_Head_reloadOnChange(const String& id, - const __FlashStringHelper * classname, - const String& onChangeCall, +void addSelector_Head_reloadOnChange(const String & id, + const __FlashStringHelper *classname, + const String & onChangeCall, bool disabled - #if FEATURE_TOOLTIPS + #if FEATURE_TOOLTIPS , - const String& tooltip = EMPTY_STRING + const String & tooltip = EMPTY_STRING #endif // if FEATURE_TOOLTIPS ); -void do_addSelector_Head(const String& id, - const __FlashStringHelper * classname, - const String& onChangeCall, +void do_addSelector_Head(const String & id, + const __FlashStringHelper *classname, + const String & onChangeCall, const bool& disabled - #if FEATURE_TOOLTIPS + #if FEATURE_TOOLTIPS , - const String& tooltip = EMPTY_STRING + const String & tooltip = EMPTY_STRING #endif // if FEATURE_TOOLTIPS ); void addPinSelector_Item(PinSelectPurpose purpose, const String & gpio_label, int gpio, - bool selected, - bool disabled = false, + bool selected, + bool disabled = false, const String & attr = EMPTY_STRING); void addSelector_Item(const __FlashStringHelper *option, int index, - bool selected, - bool disabled = false, + bool selected, + bool disabled = false, const String & attr = EMPTY_STRING); void addSelector_Item(const String& option, int index, - bool selected, - bool disabled = false, + bool selected, + bool disabled = false, const String& attr = EMPTY_STRING); -void addSelector_Foot(bool reloadonchange = false); +void addSelector_Foot(bool reloadonchange = false); -void addUnit(const __FlashStringHelper *unit); -void addUnit(const String& unit); -void addUnit(char unit); +void addUnit(const __FlashStringHelper *unit); +void addUnit(const String& unit); +void addUnit(char unit); #if FEATURE_TASKVALUE_UNIT_OF_MEASURE String toUnitOfMeasureName(const uint32_t unitOfMeasureIndex, @@ -154,13 +159,15 @@ void addFormHeader(const __FlashStringHelper *header, void addFormHeader(const __FlashStringHelper *header, const __FlashStringHelper *helpButton, const __FlashStringHelper *rtdHelpButton); -/* -void addFormHeader(const String& header, + +/* + void addFormHeader(const String& header, const String& helpButton = EMPTY_STRING); -void addFormHeader(const String& header, + void addFormHeader(const String& header, const String& helpButton, const String& rtdHelpButton); -*/ + */ + // ******************************************************************************** // Add a sub header // ******************************************************************************** @@ -171,28 +178,28 @@ void addFormSubHeader(const String& header); // Add a checkbox // ******************************************************************************** void addCheckBox(const String& id, - bool checked, + bool checked, bool disabled = false - #if FEATURE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING #endif // if FEATURE_TOOLTIPS ); void addCheckBox(const __FlashStringHelper *id, - bool checked, + bool checked, bool disabled = false); // ******************************************************************************** // Add a numeric box // ******************************************************************************** #if FEATURE_TOOLTIPS -void addNumericBox(const String& id, - int value, - int min, - int max, - const __FlashStringHelper * classname, - const String& tooltip = EMPTY_STRING, - bool disabled = false); +void addNumericBox(const String & id, + int value, + int min, + int max, + const __FlashStringHelper *classname, + const String & tooltip = EMPTY_STRING, + bool disabled = false); #endif // if FEATURE_TOOLTIPS void addFloatNumberBox(const String& id, @@ -220,23 +227,23 @@ void addNumericBox(const String& id, // ******************************************************************************** // Add Textbox // ******************************************************************************** -void addTextBox(const __FlashStringHelper * id, - const String& value, - int maxlength, - const __FlashStringHelper * classname); +void addTextBox(const __FlashStringHelper *id, + const String & value, + int maxlength, + const __FlashStringHelper *classname); -void addTextBox(const String& id, - const String& value, - int maxlength, - const __FlashStringHelper * classname); +void addTextBox(const String & id, + const String & value, + int maxlength, + const __FlashStringHelper *classname); -void addTextBox(const __FlashStringHelper * id, - const String& value, - int maxlength, - bool readonly = false, - bool required = false, - const String& pattern = EMPTY_STRING); +void addTextBox(const __FlashStringHelper *id, + const String & value, + int maxlength, + bool readonly = false, + bool required = false, + const String & pattern = EMPTY_STRING); void addTextBox(const String& id, const String& value, @@ -250,8 +257,8 @@ void addTextBox(const String& id, bool readonly, bool required, const String& pattern, - const __FlashStringHelper * classname - #if FEATURE_TOOLTIPS + const __FlashStringHelper *classname + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING #endif // if FEATURE_TOOLTIPS @@ -269,7 +276,7 @@ void addTextArea(const String& id, int columns, bool readonly, bool required - #if FEATURE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING #endif // if FEATURE_TOOLTIPS @@ -290,9 +297,9 @@ void addHelpButton(const String& url, bool isRTD); void addRTDPluginButton(pluginID_t pluginID); -# ifndef LIMIT_BUILD_SIZE +#ifndef LIMIT_BUILD_SIZE void addRTDControllerButton(cpluginID_t cpluginID); -# endif // ifndef LIMIT_BUILD_SIZE +#endif // ifndef LIMIT_BUILD_SIZE String makeDocLink(const String& url, bool isRTD); @@ -307,24 +314,25 @@ void addPinSelect(PinSelectPurpose purpose, #ifdef ESP32 -#if SOC_ADC_SUPPORTED +# if SOC_ADC_SUPPORTED enum class AdcPinSelectPurpose { TouchOnly, ADC_Touch, -#if HAS_HALL_EFFECT_SENSOR +# if HAS_HALL_EFFECT_SENSOR ADC_Touch_HallEffect, -#endif +# endif ADC_Touch_Optional + }; void addADC_PinSelect(AdcPinSelectPurpose purpose, const String & id, int choice); -#endif -#if SOC_DAC_SUPPORTED -void addDAC_PinSelect(const String& id, +# endif // if SOC_ADC_SUPPORTED +# if SOC_DAC_SUPPORTED +void addDAC_PinSelect(const String& id, int choice); -#endif +# endif // if SOC_DAC_SUPPORTED #endif // ifdef ESP32 From ac392105a41d9360ebadeca525c782c8daea398e Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 23 Jun 2025 19:50:21 +0200 Subject: [PATCH 066/564] [ADC] Fix not setting attenuation on internal ADC --- src/src/PluginStructs/P002_data_struct.cpp | 32 ++++++++++++++++------ src/src/PluginStructs/P002_data_struct.h | 2 ++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/src/PluginStructs/P002_data_struct.cpp b/src/src/PluginStructs/P002_data_struct.cpp index bf97f9a03..6492fd526 100644 --- a/src/src/PluginStructs/P002_data_struct.cpp +++ b/src/src/PluginStructs/P002_data_struct.cpp @@ -31,13 +31,10 @@ void P002_data_struct::init(struct EventStruct *event) _pin_analogRead = CONFIG_PIN1; _useFactoryCalibration = useFactoryCalibration(event); _attenuation = getAttenuation(event); - int channel{}; - const int adc = getADC_num_for_gpio(_pin_analogRead, channel); - - if ((adc == 1) || (adc == 2)) { - analogSetPinAttenuation(_pin_analogRead, static_cast(_attenuation)); - } + // Initialize attenuation and perform read + // This way there is less chance of a big difference between 1st read and any next reads + analog_read(); # endif // ifdef ESP32 if (P002_CALIBRATION_ENABLED) { @@ -839,7 +836,7 @@ String P002_data_struct::webformSave(struct EventStruct *event) void P002_data_struct::takeSample() { if (_sampleMode == P002_USE_CURENT_SAMPLE) { return; } - int raw = espeasy_analogRead(_pin_analogRead); + const int raw = analog_read(); # if FEATURE_PLUGIN_STATS PluginStats *stats = getPluginStats(0); @@ -892,7 +889,7 @@ bool P002_data_struct::getValue(float& float_value, return false; } - raw_value = espeasy_analogRead(_pin_analogRead); + raw_value = analog_read(); # if FEATURE_PLUGIN_STATS PluginStats *stats = getPluginStats(0); @@ -1114,6 +1111,10 @@ float P002_data_struct::getCurrentValue(struct EventStruct *event, int& raw_valu # endif // ifdef ESP8266 # ifdef ESP32 const int pin = CONFIG_PIN1; + + auto att = getAttenuation(event); + + analogSetPinAttenuation(pin, static_cast(att)); # endif // ifdef ESP32 raw_value = espeasy_analogRead(pin); @@ -1121,7 +1122,7 @@ float P002_data_struct::getCurrentValue(struct EventStruct *event, int& raw_valu # ifdef ESP32 if (useFactoryCalibration(event)) { - return applyADCFactoryCalibration(raw_value, getAttenuation(event)); + return applyADCFactoryCalibration(raw_value, att); } # endif // ifdef ESP32 @@ -1289,5 +1290,18 @@ bool P002_data_struct::plugin_set_config(struct EventStruct *event, return success; } +int P002_data_struct::analog_read() const { +#ifdef ESP32 + int channel{}; + const int adc = getADC_num_for_gpio(_pin_analogRead, channel); + + if ((adc == 1) || (adc == 2)) { + analogSetPinAttenuation(_pin_analogRead, static_cast(_attenuation)); + } +#endif + + return espeasy_analogRead(_pin_analogRead); +} + #endif #endif // ifdef USES_P002 diff --git a/src/src/PluginStructs/P002_data_struct.h b/src/src/PluginStructs/P002_data_struct.h index 07a070245..4d924ecfd 100644 --- a/src/src/PluginStructs/P002_data_struct.h +++ b/src/src/PluginStructs/P002_data_struct.h @@ -245,6 +245,8 @@ public: private: + int analog_read() const; + OversamplingHelperOverSampling; int _calib_adc1 = 0; From d6d7f139bc1b1a1b0607d54e1f992dbd0d32d692 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 23 Jun 2025 22:10:58 +0200 Subject: [PATCH 067/564] [ESP-IDF] Update to latest IDF/Arduino code for IDF 5.5 --- platformio_core_defs.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index eb4b43371..0df4f2eba 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -195,7 +195,7 @@ lib_extra_dirs = ; ESP_IDF 5.5.0 [core_esp32_IDF5_5_0__3_2_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3718/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3722/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip ;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3627/framework-arduinoespressif32-all-release_v5.5-5d572003.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 From a6aca34f4e08f5bea453c237127cc96cfd409dae Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 24 Jun 2025 22:03:15 +0200 Subject: [PATCH 068/564] [MFRC522] Speed-up detecting cards + make error recovery more stable --- lib/MFRC522/MFRC522.cpp | 45 +++++++++------- lib/MFRC522/MFRC522.h | 28 ++++++++-- platformio_core_defs.ini | 2 +- platformio_esp32_envs.ini | 2 +- platformio_esp32s3_envs.ini | 10 ++-- src/_P111_RC522_RFID.ino | 27 +++++++++- src/src/PluginStructs/P111_data_struct.cpp | 60 ++++++++++++++++++++-- src/src/PluginStructs/P111_data_struct.h | 2 + 8 files changed, 141 insertions(+), 35 deletions(-) diff --git a/lib/MFRC522/MFRC522.cpp b/lib/MFRC522/MFRC522.cpp index e06ae4b97..f9bde8207 100644 --- a/lib/MFRC522/MFRC522.cpp +++ b/lib/MFRC522/MFRC522.cpp @@ -291,7 +291,7 @@ void MFRC522::PCD_AntennaOff() { /** * Get the current MFRC522 Receiver Gain (RxGain[2:0]) value. - * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf + * See 9.3.3.6 / table 98 in https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf * NOTE: Return value scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. * * @return Value of the RxGain, scrubbed to the 3 bits used. @@ -302,7 +302,7 @@ uint8_t MFRC522::PCD_GetAntennaGain() { /** * Set the MFRC522 Receiver Gain (RxGain) to value specified by given mask. - * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf + * See 9.3.3.6 / table 98 in https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf * NOTE: Given mask is scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. */ void MFRC522::PCD_SetAntennaGain(uint8_t mask) { @@ -314,7 +314,7 @@ void MFRC522::PCD_SetAntennaGain(uint8_t mask) { /** * Performs a self-test of the MFRC522 - * See 16.1.1 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf + * See 16.1.1 in https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf * * @return Whether or not the test passed. Or false if no firmware reference is available. */ @@ -368,21 +368,28 @@ bool MFRC522::PCD_PerformSelfTest() { // Pick the appropriate reference values const uint8_t *reference; - switch (version) { - case 0x88: // Fudan Semiconductor FM17522 clone - reference = FM17522_firmware_reference; - break; - case 0x90: // Version 0.0 - reference = MFRC522_firmware_referenceV0_0; - break; - case 0x91: // Version 1.0 - reference = MFRC522_firmware_referenceV1_0; - break; - case 0x92: // Version 2.0 - reference = MFRC522_firmware_referenceV2_0; - break; - default: // Unknown version - return false; // abort test + switch(version) { + // Fudan Semiconductor clone: + case 0xb2: // FM17522 + reference = FM17522_firmware_referenceB2; + break; + case 0x88: // FM17522 + reference = FM17522_firmware_reference88; + break; + case 0x89: // FM17522E + reference = FM17522E_firmware_reference; + break; + case 0x90: // Version 0.0 + reference = MFRC522_firmware_referenceV0_0; + break; + case 0x91: // Version 1.0 + reference = MFRC522_firmware_referenceV1_0; + break; + case 0x92: // Version 2.0 + reference = MFRC522_firmware_referenceV2_0; + break; + default: // Unknown version + return false; // abort test } // Verify that the results match up to our expectations @@ -868,7 +875,7 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() { /** * Executes the MFRC522 MFAuthent command. * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card. - * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1. + * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and https://www.nxp.com/docs/en/data-sheet/MF1S503x.pdf section 10.1. * For use with MIFARE Classic PICCs. * The PICC must be selected - ie in state ACTIVE(*) - before calling this function. * Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start. diff --git a/lib/MFRC522/MFRC522.h b/lib/MFRC522/MFRC522.h index 9044c0e90..0e94b071a 100644 --- a/lib/MFRC522/MFRC522.h +++ b/lib/MFRC522/MFRC522.h @@ -64,7 +64,7 @@ const uint8_t MFRC522_firmware_referenceV2_0[] PROGMEM = { }; // Clone // Fudan Semiconductor FM17522 (0x88) -const uint8_t FM17522_firmware_reference[] PROGMEM = { +const uint8_t FM17522_firmware_reference88[] PROGMEM = { 0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18, 0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B, 0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7, @@ -74,6 +74,28 @@ const uint8_t FM17522_firmware_reference[] PROGMEM = { 0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB, 0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62 }; +// Another "FM17522" ic form Aliexpress +const uint8_t FM17522_firmware_referenceB2[] PROGMEM = { + 0x00, 0xeb, 0x44, 0x85, 0xfa, 0x9a, 0x78, 0x01, + 0x74, 0xe5, 0x1c, 0x7a, 0x0a, 0xa0, 0x71, 0xe1, + 0xf3, 0xfa, 0x96, 0x6d, 0x28, 0xa1, 0x34, 0x46, + 0x3a, 0x1c, 0x32, 0x96, 0xb9, 0xe6, 0x44, 0x87, + 0x0a, 0x45, 0x98, 0xa9, 0x36, 0x60, 0x89, 0x0f, + 0x06, 0x9b, 0x7b, 0x17, 0xb3, 0x0c, 0x1a, 0x6c, + 0x1a, 0xae, 0x2c, 0xac, 0x0e, 0x6f, 0x2e, 0x02, + 0x2b, 0xcb, 0x8a, 0xb2, 0x45, 0xdd, 0x7e, 0x3c +}; +// Fudan Semiconductor FM17522E (0x89) +const uint8_t FM17522E_firmware_reference[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x04, 0xcc, 0xc8, 0x00, + 0x10, 0x04, 0x00, 0xc0, 0x00, 0x90, 0x00, 0x20, + 0x00, 0x00, 0x23, 0x00, 0x38, 0x06, 0x01, 0x33, + 0x98, 0xf3, 0x80, 0x06, 0xc0, 0xf9, 0x80, 0x08, + 0x27, 0x04, 0x23, 0x82, 0x21, 0x12, 0xf9, 0xc7 +}; class MFRC522 { public: @@ -173,7 +195,7 @@ public: }; // MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD). - // Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf + // Described in 9.3.3.6 / table 98 of the datasheet at https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf enum PCD_RxGain : uint8_t { RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum RxGain_23dB = 0x01 << 4, // 001b - 23 dB @@ -210,7 +232,7 @@ public: PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register. PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register. PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block. - // The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) + // The commands used for MIFARE Ultralight (from https://www.nxp.com/docs/en/data-sheet/MF0ICU1.pdf, Section 8.6) // The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight. PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 uint8_t page to the PICC. }; diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 0df4f2eba..f18f5d9a9 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -195,7 +195,7 @@ lib_extra_dirs = ; ESP_IDF 5.5.0 [core_esp32_IDF5_5_0__3_2_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3722/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3725/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip ;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3627/framework-arduinoespressif32-all-release_v5.5-5d572003.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 5b0f60e04..d1d7b3979 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -101,7 +101,7 @@ board_build.filesystem = littlefs lib_ignore = ${esp32_always.lib_ignore} ESP32_ping ESP32 BLE Arduino - ${core_esp32_IDF5_4_1__3_2_0_LittleFS.lib_ignore} + ${esp32_base_idf5.lib_ignore} [esp32_IRExt_LittleFS_ETH] diff --git a/platformio_esp32s3_envs.ini b/platformio_esp32s3_envs.ini index a664f96fb..b8e9be2ec 100644 --- a/platformio_esp32s3_envs.ini +++ b/platformio_esp32s3_envs.ini @@ -1,16 +1,16 @@ [esp32s3_common_LittleFS] -extends = esp32_base_idf5 +extends = esp32_base_idf5_5 lib_ignore = ${esp32_common_LittleFS_ETH.lib_ignore} ESP32_ping - ${esp32_base_idf5.lib_ignore} -build_flags = ${esp32_base_idf5.build_flags} + ${esp32_base_idf5_5.lib_ignore} +build_flags = ${esp32_base_idf5_5.build_flags} ; -mtext-section-literals -DFEATURE_ARDUINO_OTA=1 -DFEATURE_ETHERNET=1 -DUSE_LITTLEFS -DESP32S3 -extra_scripts = ${esp32_base_idf5.extra_scripts} -build_unflags = ${esp32_base_idf5.build_unflags} +extra_scripts = ${esp32_base_idf5_5.extra_scripts} +build_unflags = ${esp32_base_idf5_5.build_unflags} -fexceptions board_build.filesystem = littlefs diff --git a/src/_P111_RC522_RFID.ino b/src/_P111_RC522_RFID.ino index 403482c91..42aa1e5f2 100644 --- a/src/_P111_RC522_RFID.ino +++ b/src/_P111_RC522_RFID.ino @@ -36,7 +36,7 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string) { auto& dev = Device[++deviceCount]; dev.Number = PLUGIN_ID_111; - dev.Type = DEVICE_TYPE_SPI2; + dev.Type = DEVICE_TYPE_SPI3; dev.VType = Sensor_VType::SENSOR_TYPE_ULONG; dev.ValueCount = 1; dev.SendDataOption = true; @@ -59,9 +59,23 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string) { event->String1 = formatGpioName_output(F("CS PIN")); // P111_CS_PIN event->String2 = formatGpioName_output_optional(F("RST PIN ")); // P111_RST_PIN + event->String3 = formatGpioName_input_optional(F("IRQ PIN ")); // P111_IRQ_PIN break; } + case PLUGIN_WEBFORM_SHOW_GPIO_DESCR: + { + string = event->String1; + string += concat(F("CS: "), formatGpioLabel(CONFIG_PIN1, false)); + string += event->String1; + string += concat(F("RST: "), formatGpioLabel(CONFIG_PIN2, false)); + string += event->String1; + string += concat(F("IRQ: "), formatGpioLabel(CONFIG_PIN3, false)); + success = true; + break; + } + + case PLUGIN_SET_DEFAULTS: { P111_REMOVALTIMEOUT = 500; // Default 500 msec reset delay @@ -70,8 +84,17 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_LOAD: { - addFormSubHeader(F("Options")); + P111_data_struct *P111_data = static_cast(getPluginTaskData(event->TaskIndex)); + if (nullptr != P111_data) { + uint8_t v{}; + const String version = P111_data->PCD_getVersion(v); + if (v != 0 && v != 0xFF) { + addRowLabel(F("Reader Version")); + addHtml(version); + } + } + addFormSubHeader(F("Options")); { const __FlashStringHelper *removaltype[] = { F("None"), diff --git a/src/src/PluginStructs/P111_data_struct.cpp b/src/src/PluginStructs/P111_data_struct.cpp index aee4a1edb..3d1953962 100644 --- a/src/src/PluginStructs/P111_data_struct.cpp +++ b/src/src/PluginStructs/P111_data_struct.cpp @@ -26,6 +26,8 @@ void P111_data_struct::init() { if (mfrc522 != nullptr) { mfrc522->PCD_Init(); // Initialize MFRC522 reader + mfrc522->PCD_WriteRegister(MFRC522::ComIEnReg, 0b10100000); // enable receiver interrupt + mfrc522->PCD_WriteRegister(MFRC522::DivIEnReg, 0x80); // Set as CMOS output pin initPhase = P111_initPhases::Ready; } } @@ -116,10 +118,15 @@ bool P111_data_struct::reset(int8_t csPin, if ((resetPin != -1) && (initPhase == P111_initPhases::Ready)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("MFRC522: Reset on pin: "); - log += resetPin; - addLogMove(LOG_LEVEL_INFO, log); + addLogMove( + LOG_LEVEL_INFO, + concat(F("MFRC522: Reset on pin: "), resetPin)); } + + init(); + return true; + + // FIXME TD-er: Remove the rest of this function. pinMode(resetPin, OUTPUT); digitalWrite(resetPin, LOW); timeToWait = 100; @@ -140,6 +147,8 @@ bool P111_data_struct::reset(int8_t csPin, digitalWrite(csPin, LOW); mfrc522->PCD_Init(csPin, resetPin); // Init MFRC522 module + mfrc522->PCD_WriteRegister(MFRC522::ComIEnReg, 0b10100000); // enable receiver interrupt + mfrc522->PCD_WriteRegister(MFRC522::DivIEnReg, 0x80); // Set as CMOS output pin // If you set Antenna Gain to Max it will increase reading distance mfrc522->PCD_SetAntennaGain(mfrc522->RxGain_max); @@ -226,8 +235,10 @@ bool P111_data_struct::plugin_ten_per_second(struct EventStruct *event) { } counter++; // This variable replaces a static variable in the original implementation + const bool ComIrqReg_bits = (mfrc522->PCD_ReadRegister(MFRC522::ComIrqReg) & (1<<5)) != 0; + mfrc522->PCD_WriteRegister(MFRC522::ComIrqReg, 0x34); - if (counter == 3) { // Only every 3rd 0.1 second we do a read + if (counter >= 10 || ComIrqReg_bits) { // Only every 3rd 0.1 second we do a read counter = 0; uint32_t key = P111_NO_KEY; @@ -300,4 +311,45 @@ bool P111_data_struct::plugin_fifty_per_second() { return true; } + +String P111_data_struct::PCD_getVersion(uint8_t& v) { + v = 0xFF; + if (mfrc522) { + v = mfrc522->PCD_ReadRegister(MFRC522::VersionReg); + if (v != 0xFF && v != 0) { + // Human readable version. + String res = concat(formatToHex(v, 2), F(" = ")); + switch(v) { + case 0xb2: + res += F("FM17522_1"); + break; + case 0x88: + res += F("FM17522"); + break; + case 0x89: + res += F("FM17522E"); + break; + case 0x90: + res += F("v0.0"); + break; + case 0x91: + res += F("v1.0"); + break; + case 0x92: + res += F("v2.0"); + break; + case 0x12: + res += F("counterfeit chip"); + break; + default: + res += F("(unknown)"); + break; + } + return res; + } + } + return EMPTY_STRING; +} + + #endif // ifdef USES_P111 diff --git a/src/src/PluginStructs/P111_data_struct.h b/src/src/PluginStructs/P111_data_struct.h index 219af16fb..4a5d68c40 100644 --- a/src/src/PluginStructs/P111_data_struct.h +++ b/src/src/PluginStructs/P111_data_struct.h @@ -39,6 +39,8 @@ struct P111_data_struct : public PluginTaskData_base { bool plugin_ten_per_second(struct EventStruct *event); bool plugin_fifty_per_second(); + String PCD_getVersion(uint8_t& v); + private: MFRC522 *mfrc522 = nullptr; From 445f66cc9a111a01e19a1fbcba9cd61147e73396 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 25 Jun 2025 00:55:03 +0200 Subject: [PATCH 069/564] [MFRC522] Improve range of reader --- lib/MFRC522/MFRC522.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/MFRC522/MFRC522.cpp b/lib/MFRC522/MFRC522.cpp index f9bde8207..05fbad01f 100644 --- a/lib/MFRC522/MFRC522.cpp +++ b/lib/MFRC522/MFRC522.cpp @@ -233,6 +233,11 @@ void MFRC522::PCD_Init() { PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting PCD_WriteRegister(ModeReg, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4) + + PCD_WriteRegister(CWGsPReg, 0b111111); // conductance of the p-driver output + PCD_WriteRegister(ModGsPReg, 0b111111); // conductance of the p-driver output + PCD_WriteRegister(GsNReg, 0b11111111); // impedance of the n-driver + PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) } // End PCD_Init() From 0323cabbed5ae7434f4b151d5eb524339c475734 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 25 Jun 2025 13:02:22 +0200 Subject: [PATCH 070/564] Add HTML_Print and PrintToString helpers --- src/src/Helpers/PrintToString.cpp | 21 +++++++++++++++++++++ src/src/Helpers/PrintToString.h | 29 +++++++++++++++++++++++++++++ src/src/WebServer/HTML_Print.cpp | 9 +++++++++ src/src/WebServer/HTML_Print.h | 20 ++++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 src/src/Helpers/PrintToString.cpp create mode 100644 src/src/Helpers/PrintToString.h create mode 100644 src/src/WebServer/HTML_Print.cpp create mode 100644 src/src/WebServer/HTML_Print.h diff --git a/src/src/Helpers/PrintToString.cpp b/src/src/Helpers/PrintToString.cpp new file mode 100644 index 000000000..9cc44a316 --- /dev/null +++ b/src/src/Helpers/PrintToString.cpp @@ -0,0 +1,21 @@ +#include "../Helpers/PrintToString.h" + +void PrintToString::clear() { _str.clear(); } + +size_t PrintToString::length() const +{ + return _str.length(); +} + +bool PrintToString::reserve(unsigned int size) { return _str.reserve(size); } + +size_t PrintToString::write(uint8_t c) +{ + _str += (char)c; + return 1; +} + +const String& PrintToString::get() const +{ + return _str; +} diff --git a/src/src/Helpers/PrintToString.h b/src/src/Helpers/PrintToString.h new file mode 100644 index 000000000..79113710b --- /dev/null +++ b/src/src/Helpers/PrintToString.h @@ -0,0 +1,29 @@ +#ifndef HELPERS_PRINTTOSTRING_H +#define HELPERS_PRINTTOSTRING_H + +#include "../../ESPEasy_common.h" + +class PrintToString : public Print +{ +public: + + virtual ~PrintToString() {} + + void clear(); + + size_t length() const; + + bool reserve(unsigned int size); + + + size_t write(uint8_t c) override; + + const String& get() const; + +private: + + String _str; +}; // class PrintToString + + +#endif // HELPERS_PRINTTOSTRING_H diff --git a/src/src/WebServer/HTML_Print.cpp b/src/src/WebServer/HTML_Print.cpp new file mode 100644 index 000000000..cb19b92ef --- /dev/null +++ b/src/src/WebServer/HTML_Print.cpp @@ -0,0 +1,9 @@ +#include "../WebServer/HTML_Print.h" + +#include "../Globals/TXBuffer.h" + +size_t HTML_Print::write(uint8_t c) +{ + TXBuffer += (char)c; + return 1; +} diff --git a/src/src/WebServer/HTML_Print.h b/src/src/WebServer/HTML_Print.h new file mode 100644 index 000000000..403261b87 --- /dev/null +++ b/src/src/WebServer/HTML_Print.h @@ -0,0 +1,20 @@ +#ifndef WEBSERVER_HTML_PRINT_H +#define WEBSERVER_HTML_PRINT_H + + +#include "../../ESPEasy_common.h" + + +// Class to redirect any function expecting a Print stream to output to the TXBuffer of our webserver. +class HTML_Print : public Print +{ +public: + + virtual ~HTML_Print() {} + + size_t write(uint8_t c) override; + +}; + + +#endif // WEBSERVER_HTML_PRINT_H From 88986c77441c6d160f7e880bd9a89482147db463 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 25 Jun 2025 13:04:47 +0200 Subject: [PATCH 071/564] [MFRC522] Simplify board reset during init --- lib/MFRC522/MFRC522.cpp | 33 ++++++++++++++++++--------------- lib/MFRC522/MFRC522.h | 1 + 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/MFRC522/MFRC522.cpp b/lib/MFRC522/MFRC522.cpp index 05fbad01f..6284d3f39 100644 --- a/lib/MFRC522/MFRC522.cpp +++ b/lib/MFRC522/MFRC522.cpp @@ -198,22 +198,13 @@ void MFRC522::PCD_Init() { digitalWrite(_chipSelectPin, HIGH); // If a valid pin number has been set, pull device out of power down / reset state. - if (_resetPowerDownPin != UNUSED_PIN) { - // First set the resetPowerDownPin as digital input, to check the MFRC522 power down mode. - pinMode(_resetPowerDownPin, INPUT); - - if (digitalRead(_resetPowerDownPin) == LOW) { // The MFRC522 chip is in power down mode. - pinMode(_resetPowerDownPin, OUTPUT); // Now set the resetPowerDownPin as digital output. - digitalWrite(_resetPowerDownPin, LOW); // Make sure we have a clean LOW state. - delayMicroseconds(2); // 8.8.1 Reset timing requirements says about 100ns. Let us be generous: 2μsl - digitalWrite(_resetPowerDownPin, HIGH); // Exit power down mode. This triggers a hard reset. - // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms. - delay(50); - hardReset = true; - } + if (_resetPowerDownPin != UNUSED_PIN) + { + pinMode(_resetPowerDownPin, OUTPUT); + PCD_HardReset(); } - - if (!hardReset) { // Perform a soft reset if we haven't triggered a hard reset above. + else + { // Perform a soft reset if we haven't triggered a hard reset above. PCD_Reset(); } @@ -276,6 +267,18 @@ void MFRC522::PCD_Reset() { } while ((PCD_ReadRegister(CommandReg) & (1 << 4)) && (++count) < 3); } // End PCD_Reset() +void MFRC522::PCD_HardReset() +{ + if (_resetPowerDownPin != UNUSED_PIN) + { + digitalWrite(_resetPowerDownPin, LOW); // Make sure we have a clean LOW state. + delayMicroseconds(2); // 8.8.1 Reset timing requirements says about 100ns. Let us be generous: 2μsl + digitalWrite(_resetPowerDownPin, HIGH); // Exit power down mode. This triggers a hard reset. + // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms. + delay(50); + } +} + /** * Turns the antenna on by enabling pins TX1 and TX2. * After a reset these pins are disabled. diff --git a/lib/MFRC522/MFRC522.h b/lib/MFRC522/MFRC522.h index 0e94b071a..b00a57f42 100644 --- a/lib/MFRC522/MFRC522.h +++ b/lib/MFRC522/MFRC522.h @@ -314,6 +314,7 @@ public: void PCD_Init(uint8_t resetPowerDownPin); void PCD_Init(uint8_t chipSelectPin, uint8_t resetPowerDownPin); void PCD_Reset(); + void PCD_HardReset(); void PCD_AntennaOn(); void PCD_AntennaOff(); uint8_t PCD_GetAntennaGain(); From b48d96e135f0b8a0cdccf600557a59a4916065a9 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 25 Jun 2025 13:07:06 +0200 Subject: [PATCH 072/564] [MFRC522] Allow to dump card info to debug logs --- lib/MFRC522/MFRC522.cpp | 144 ++++++++++----------- lib/MFRC522/MFRC522.h | 12 +- src/src/PluginStructs/P111_data_struct.cpp | 17 ++- 3 files changed, 94 insertions(+), 79 deletions(-) diff --git a/lib/MFRC522/MFRC522.cpp b/lib/MFRC522/MFRC522.cpp index 6284d3f39..4956cfed3 100644 --- a/lib/MFRC522/MFRC522.cpp +++ b/lib/MFRC522/MFRC522.cpp @@ -1361,36 +1361,36 @@ const __FlashStringHelper *MFRC522::PICC_GetTypeName(PICC_Type piccType ///< One * Dumps debug info about the connected PCD to Serial. * Shows all known firmware versions */ -void MFRC522::PCD_DumpVersionToSerial() { +void MFRC522::PCD_DumpVersionToSerial(Print &logPrint) { // Get the MFRC522 firmware version uint8_t v = PCD_ReadRegister(VersionReg); - Serial.print(F("Firmware Version: 0x")); - Serial.print(v, HEX); + logPrint.print(F("Firmware Version: 0x")); + logPrint.print(v, HEX); // Lookup which version switch(v) { - case 0x88: Serial.println(F(" = (clone)")); break; - case 0x90: Serial.println(F(" = v0.0")); break; - case 0x91: Serial.println(F(" = v1.0")); break; - case 0x92: Serial.println(F(" = v2.0")); break; - case 0x12: Serial.println(F(" = counterfeit chip")); break; - default: Serial.println(F(" = (unknown)")); + case 0x88: logPrint.println(F(" = (clone)")); break; + case 0x90: logPrint.println(F(" = v0.0")); break; + case 0x91: logPrint.println(F(" = v1.0")); break; + case 0x92: logPrint.println(F(" = v2.0")); break; + case 0x12: logPrint.println(F(" = counterfeit chip")); break; + default: logPrint.println(F(" = (unknown)")); } // When 0x00 or 0xFF is returned, communication probably failed if ((v == 0x00) || (v == 0xFF)) - Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?")); + logPrint.println(F("WARNING: Communication failure, is the MFRC522 properly connected?")); } // End PCD_DumpVersionToSerial() /** - * Dumps debug info about the selected PICC to Serial. + * Dumps debug info about the selected PICC to logPrint. * On success the PICC is halted after dumping the data. * For MIFARE Classic the factory default key of 0xFFFFFFFFFFFF is tried. */ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). - ) { + , Print &logPrint) { MIFARE_Key key; // Dump UID, SAK and Type - PICC_DumpDetailsToSerial(uid); + PICC_DumpDetailsToSerial(uid, logPrint); // Dump contents PICC_Type piccType = PICC_GetType(uid->sak); @@ -1402,11 +1402,11 @@ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned fro for (uint8_t i = 0; i < 6; i++) { key.keyByte[i] = 0xFF; } - PICC_DumpMifareClassicToSerial(uid, piccType, &key); + PICC_DumpMifareClassicToSerial(uid, piccType, &key, logPrint); break; case PICC_TYPE_MIFARE_UL: - PICC_DumpMifareUltralightToSerial(); + PICC_DumpMifareUltralightToSerial(logPrint); break; case PICC_TYPE_ISO_14443_4: @@ -1414,7 +1414,7 @@ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned fro case PICC_TYPE_ISO_18092: case PICC_TYPE_MIFARE_PLUS: case PICC_TYPE_TNP3XXX: - Serial.println(F("Dumping memory contents not implemented for that PICC type.")); + logPrint.println(F("Dumping memory contents not implemented for that PICC type.")); break; case PICC_TYPE_UNKNOWN: @@ -1423,36 +1423,36 @@ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned fro break; // No memory dump here } - Serial.println(); + logPrint.println(); PICC_HaltA(); // Already done if it was a MIFARE Classic PICC. } // End PICC_DumpToSerial() /** - * Dumps card info (UID,SAK,Type) about the selected PICC to Serial. + * Dumps card info (UID,SAK,Type) about the selected PICC to logPrint. */ void MFRC522::PICC_DumpDetailsToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). - ) { + , Print &logPrint) { // UID - Serial.print(F("Card UID:")); + logPrint.print(F("Card UID:")); for (uint8_t i = 0; i < uid->size; i++) { if(uid->uidByte[i] < 0x10) - Serial.print(F(" 0")); + logPrint.print(F(" 0")); else - Serial.print(F(" ")); - Serial.print(uid->uidByte[i], HEX); + logPrint.print(F(" ")); + logPrint.print(uid->uidByte[i], HEX); } - Serial.println(); + logPrint.println(); // SAK - Serial.print(F("Card SAK: ")); + logPrint.print(F("Card SAK: ")); if(uid->sak < 0x10) - Serial.print(F("0")); - Serial.println(uid->sak, HEX); + logPrint.print(F("0")); + logPrint.println(uid->sak, HEX); // (suggested) PICC type PICC_Type piccType = PICC_GetType(uid->sak); - Serial.print(F("PICC type: ")); - Serial.println(PICC_GetTypeName(piccType)); + logPrint.print(F("PICC type: ")); + logPrint.println(PICC_GetTypeName(piccType)); } // End PICC_DumpDetailsToSerial() /** @@ -1462,7 +1462,7 @@ void MFRC522::PICC_DumpDetailsToSerial(Uid *uid ///< Pointer to Uid struct retur void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). PICC_Type piccType, ///< One of the PICC_Type enums. MIFARE_Key *key ///< Key A used for all sectors. - ) { + , Print &logPrint) { uint8_t no_of_sectors = 0; switch (piccType) { case PICC_TYPE_MIFARE_MINI: @@ -1486,9 +1486,9 @@ void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid st // Dump sectors, highest address first. if (no_of_sectors) { - Serial.println(F("Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits")); + logPrint.println(F("Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits")); for (int8_t i = no_of_sectors - 1; i >= 0; i--) { - PICC_DumpMifareClassicSectorToSerial(uid, key, i); + PICC_DumpMifareClassicSectorToSerial(uid, key, i, logPrint); } } PICC_HaltA(); // Halt the PICC before stopping the encrypted session. @@ -1503,7 +1503,7 @@ void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid st void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). MIFARE_Key *key, ///< Key A for the sector. uint8_t sector ///< The sector to dump, 0..39. - ) { + , Print &logPrint) { MFRC522::StatusCode status; uint8_t firstBlock; // Address of lowest address to dump actually last block dumped) uint8_t no_of_blocks; // Number of blocks in sector @@ -1548,32 +1548,32 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U // Sector number - only on first line if (isSectorTrailer) { if(sector < 10) - Serial.print(F(" ")); // Pad with spaces + logPrint.print(F(" ")); // Pad with spaces else - Serial.print(F(" ")); // Pad with spaces - Serial.print(sector); - Serial.print(F(" ")); + logPrint.print(F(" ")); // Pad with spaces + logPrint.print(sector); + logPrint.print(F(" ")); } else { - Serial.print(F(" ")); + logPrint.print(F(" ")); } // Block number if(blockAddr < 10) - Serial.print(F(" ")); // Pad with spaces + logPrint.print(F(" ")); // Pad with spaces else { if(blockAddr < 100) - Serial.print(F(" ")); // Pad with spaces + logPrint.print(F(" ")); // Pad with spaces else - Serial.print(F(" ")); // Pad with spaces + logPrint.print(F(" ")); // Pad with spaces } - Serial.print(blockAddr); - Serial.print(F(" ")); + logPrint.print(blockAddr); + logPrint.print(F(" ")); // Establish encrypted communications before reading the first block if (isSectorTrailer) { status = PCD_Authenticate(PICC_CMD_MF_AUTH_KEY_A, firstBlock, key, uid); if (status != STATUS_OK) { - Serial.print(F("PCD_Authenticate() failed: ")); - Serial.println(GetStatusCodeName(status)); + logPrint.print(F("PCD_Authenticate() failed: ")); + logPrint.println(GetStatusCodeName(status)); return; } } @@ -1581,19 +1581,19 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U byteCount = sizeof(buffer); status = MIFARE_Read(blockAddr, buffer, &byteCount); if (status != STATUS_OK) { - Serial.print(F("MIFARE_Read() failed: ")); - Serial.println(GetStatusCodeName(status)); + logPrint.print(F("MIFARE_Read() failed: ")); + logPrint.println(GetStatusCodeName(status)); continue; } // Dump data for (uint8_t index = 0; index < 16; index++) { if(buffer[index] < 0x10) - Serial.print(F(" 0")); + logPrint.print(F(" 0")); else - Serial.print(F(" ")); - Serial.print(buffer[index], HEX); + logPrint.print(F(" ")); + logPrint.print(buffer[index], HEX); if ((index % 4) == 3) { - Serial.print(F(" ")); + logPrint.print(F(" ")); } } // Parse sector trailer data @@ -1624,22 +1624,22 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U if (firstInGroup) { // Print access bits - Serial.print(F(" [ ")); - Serial.print((g[group] >> 2) & 1, DEC); Serial.print(F(" ")); - Serial.print((g[group] >> 1) & 1, DEC); Serial.print(F(" ")); - Serial.print((g[group] >> 0) & 1, DEC); - Serial.print(F(" ] ")); + logPrint.print(F(" [ ")); + logPrint.print((g[group] >> 2) & 1, DEC); logPrint.print(F(" ")); + logPrint.print((g[group] >> 1) & 1, DEC); logPrint.print(F(" ")); + logPrint.print((g[group] >> 0) & 1, DEC); + logPrint.print(F(" ] ")); if (invertedError) { - Serial.print(F(" Inverted access bits did not match! ")); + logPrint.print(F(" Inverted access bits did not match! ")); } } if (group != 3 && (g[group] == 1 || g[group] == 6)) { // Not a sector trailer, a value block int32_t value = (int32_t(buffer[3])<<24) | (int32_t(buffer[2])<<16) | (int32_t(buffer[1])<<8) | int32_t(buffer[0]); - Serial.print(F(" Value=0x")); Serial.print(value, HEX); - Serial.print(F(" Adr=0x")); Serial.print(buffer[12], HEX); + logPrint.print(F(" Value=0x")); logPrint.print(value, HEX); + logPrint.print(F(" Adr=0x")); logPrint.print(buffer[12], HEX); } - Serial.println(); + logPrint.println(); } return; @@ -1648,41 +1648,41 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U /** * Dumps memory contents of a MIFARE Ultralight PICC. */ -void MFRC522::PICC_DumpMifareUltralightToSerial() { +void MFRC522::PICC_DumpMifareUltralightToSerial(Print &logPrint) { MFRC522::StatusCode status; uint8_t byteCount; uint8_t buffer[18]; uint8_t i; - Serial.println(F("Page 0 1 2 3")); + logPrint.println(F("Page 0 1 2 3")); // Try the mpages of the original Ultralight. Ultralight C has more pages. for (uint8_t page = 0; page < 16; page +=4) { // Read returns data for 4 pages at a time. // Read pages byteCount = sizeof(buffer); status = MIFARE_Read(page, buffer, &byteCount); if (status != STATUS_OK) { - Serial.print(F("MIFARE_Read() failed: ")); - Serial.println(GetStatusCodeName(status)); + logPrint.print(F("MIFARE_Read() failed: ")); + logPrint.println(GetStatusCodeName(status)); break; } // Dump data for (uint8_t offset = 0; offset < 4; offset++) { i = page + offset; if(i < 10) - Serial.print(F(" ")); // Pad with spaces + logPrint.print(F(" ")); // Pad with spaces else - Serial.print(F(" ")); // Pad with spaces - Serial.print(i); - Serial.print(F(" ")); + logPrint.print(F(" ")); // Pad with spaces + logPrint.print(i); + logPrint.print(F(" ")); for (uint8_t index = 0; index < 4; index++) { i = 4 * offset + index; if(buffer[i] < 0x10) - Serial.print(F(" 0")); + logPrint.print(F(" 0")); else - Serial.print(F(" ")); - Serial.print(buffer[i], HEX); + logPrint.print(F(" ")); + logPrint.print(buffer[i], HEX); } - Serial.println(); + logPrint.println(); } } } // End PICC_DumpMifareUltralightToSerial() diff --git a/lib/MFRC522/MFRC522.h b/lib/MFRC522/MFRC522.h index b00a57f42..0a7f0e426 100644 --- a/lib/MFRC522/MFRC522.h +++ b/lib/MFRC522/MFRC522.h @@ -367,12 +367,12 @@ public: static const __FlashStringHelper *PICC_GetTypeName(PICC_Type type); // Support functions for debuging - void PCD_DumpVersionToSerial(); - void PICC_DumpToSerial(Uid *uid); - void PICC_DumpDetailsToSerial(Uid *uid); - void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key); - void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, uint8_t sector); - void PICC_DumpMifareUltralightToSerial(); + void PCD_DumpVersionToSerial(Print &logPrint); + void PICC_DumpToSerial(Uid *uid, Print &logPrint); + void PICC_DumpDetailsToSerial(Uid *uid, Print &logPrint); + void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key, Print &logPrint); + void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, uint8_t sector, Print &logPrint); + void PICC_DumpMifareUltralightToSerial(Print &logPrint); // Advanced functions for MIFARE void MIFARE_SetAccessBits(uint8_t *accessBitBuffer, uint8_t g0, uint8_t g1, uint8_t g2, uint8_t g3); diff --git a/src/src/PluginStructs/P111_data_struct.cpp b/src/src/PluginStructs/P111_data_struct.cpp index 3d1953962..3dc5e9600 100644 --- a/src/src/PluginStructs/P111_data_struct.cpp +++ b/src/src/PluginStructs/P111_data_struct.cpp @@ -3,6 +3,7 @@ #ifdef USES_P111 # include "../PluginStructs/P111_data_struct.h" +# include "../Helpers/PrintToString.h" // Needed also here for PlatformIO's library finder as the .h file // is in a directory which is excluded in the src_filter @@ -215,6 +216,20 @@ uint8_t P111_data_struct::readPassiveTargetID(uint8_t *uid, uid[i] = mfrc522->uid.uidByte[i]; } *uidLength = 4; + + + #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) + { + PrintToString p2str; + mfrc522->PICC_DumpToSerial(&(mfrc522->uid), p2str); + if (p2str.length()) { + addLog(LOG_LEVEL_DEBUG, concat(F("MFRC522: "), p2str.get())); + } + } + #endif + + mfrc522->PICC_HaltA(); // Stop reading return P111_NO_ERROR; } @@ -269,7 +284,7 @@ bool P111_data_struct::plugin_ten_per_second(struct EventStruct *event) { } else { log += F("Old Tag: "); } - log += key; + log += formatToHex_decimal(key); if (!removedTag) { log += F(" card: "); From 1c995d5fe341f779fe50a18130fe51e207b00038 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 25 Jun 2025 13:07:58 +0200 Subject: [PATCH 073/564] [MFRC522] Do proper timing for communicating with card --- lib/MFRC522/MFRC522.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/MFRC522/MFRC522.cpp b/lib/MFRC522/MFRC522.cpp index 4956cfed3..bb96dc27e 100644 --- a/lib/MFRC522/MFRC522.cpp +++ b/lib/MFRC522/MFRC522.cpp @@ -478,6 +478,8 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( uint8_t command, ///< The uint8_t rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. ) { + const long software_timeout_ms = 36; // 36ms + // Prepare values for BitFramingReg uint8_t txLastBits = validBits ? *validBits : 0; uint8_t bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] @@ -496,8 +498,9 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( uint8_t command, ///< The // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops transmitting. // Each iteration of the do-while-loop takes 17.86μs. // TODO check/modify for other architectures than Arduino Uno 16bit - uint16_t i; - for (i = 2000; i > 0; i--) { + long t_delta=0; + long t_start=millis(); + while(t_delta < software_timeout_ms) { uint8_t n = PCD_ReadRegister(ComIrqReg); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq if (n & waitIRq) { // One of the interrupts that signal success has been set. break; @@ -505,9 +508,11 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( uint8_t command, ///< The if (n & 0x01) { // Timer interrupt - nothing received in 25ms return STATUS_TIMEOUT; } + delay(1); // prevents bus flood + t_delta = millis() - t_start; } // 35.7ms and nothing happend. Communication with the MFRC522 might be down. - if (i == 0) { + if(t_delta >= software_timeout_ms) { return STATUS_TIMEOUT; } From 69f04883d6231478e07a39d8538d60a31c30c10e Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Jun 2025 12:04:37 +0200 Subject: [PATCH 074/564] [Rules] Fix processing variables with index > 2^31 --- src/src/Globals/RulesCalculate.cpp | 15 +++++++++------ src/src/Globals/RulesCalculate.h | 4 ++-- src/src/Helpers/SystemVariables.cpp | 7 ++++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/src/Globals/RulesCalculate.cpp b/src/src/Globals/RulesCalculate.cpp index 9c95d3de5..979fd4a0e 100644 --- a/src/src/Globals/RulesCalculate.cpp +++ b/src/src/Globals/RulesCalculate.cpp @@ -10,8 +10,8 @@ RulesCalculate_t RulesCalculate{}; /******************************************************************************************* * Helper functions to actually interact with the rules calculation functions. * *****************************************************************************************/ -int CalculateParam(const String& TmpStr, int errorValue) { - int32_t returnValue = errorValue; +int64_t CalculateParam(const String& TmpStr, int64_t errorValue) { + int64_t returnValue = errorValue; if (TmpStr.length() == 0) { return returnValue; @@ -20,7 +20,7 @@ int CalculateParam(const String& TmpStr, int errorValue) { // Minimize calls to the Calulate function. // Only if TmpStr starts with '=' then call Calculate(). Otherwise do not call it if (TmpStr[0] != '=') { - if (!validIntFromString(TmpStr, returnValue)) { + if (!validInt64FromString(TmpStr, returnValue)) { return errorValue; } } else { @@ -37,10 +37,13 @@ int CalculateParam(const String& TmpStr, int errorValue) { strformat(F("CALCULATE PARAM: %s = %.6g"), TmpStr.c_str(), roundf(param))); } #endif // ifndef BUILD_NO_DEBUG - } else { - return errorValue; + // return integer only as it's valid only for variable indices and device/task id + #if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE + return round(param); + #else + return roundf(param); + #endif } - returnValue = roundf(param); // return integer only as it's valid only for device and task id } return returnValue; } diff --git a/src/src/Globals/RulesCalculate.h b/src/src/Globals/RulesCalculate.h index 1de0df501..72cf41a57 100644 --- a/src/src/Globals/RulesCalculate.h +++ b/src/src/Globals/RulesCalculate.h @@ -17,8 +17,8 @@ extern RulesCalculate_t RulesCalculate; * Helper functions to actually interact with the rules calculation functions. * *****************************************************************************************/ -int CalculateParam(const String& TmpStr, - int errorValue = 0); +int64_t CalculateParam(const String& TmpStr, + int64_t errorValue = 0ll); CalculateReturnCode Calculate_preProcessed(const String & preprocessd_input, ESPEASY_RULES_FLOAT_TYPE& result); diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index 8147d24ce..4c3387910 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -303,10 +303,11 @@ bool parse_pct_v_num_pct(String& s, boolean useURLencode, int start_pos) const int pos_closing_pct = s.indexOf('%', v_index + 1); const String arg = s.substring(v_index + 2 + (isv_ ? 1 : 0), pos_closing_pct); String valArg(arg); - const int32_t i = CalculateParam(arg, -1); + constexpr int64_t errorvalue = -1; + const int64_t i = CalculateParam(arg, errorvalue); // addLog(LOG_LEVEL_INFO, strformat(F("s: '%s', calc parse: %s => %d"), s.c_str(), arg.c_str(), i)); - if (i != -1) { // We're calculating a numeric index like %v=1+%v2%%, so have to use the result for the value - valArg = String(i); + if (i != errorvalue) { // We're calculating a numeric index like %v=1+%v2%%, so have to use the result for the value + valArg = ll2String(i); } // Need to replace the entire arg From 44b0694f1ce3711909c3f9e5e94df94774023e0c Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Jun 2025 15:49:51 +0200 Subject: [PATCH 075/564] [Log] Add PrintToLog helper --- src/src/Helpers/PrintToLog.cpp | 80 ++++++++++++++++++++++++++++++++++ src/src/Helpers/PrintToLog.h | 49 +++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/src/Helpers/PrintToLog.cpp create mode 100644 src/src/Helpers/PrintToLog.h diff --git a/src/src/Helpers/PrintToLog.cpp b/src/src/Helpers/PrintToLog.cpp new file mode 100644 index 000000000..d0a9726e2 --- /dev/null +++ b/src/src/Helpers/PrintToLog.cpp @@ -0,0 +1,80 @@ +#include "../Helpers/PrintToLog.h" + +#include "../Helpers/StringConverter.h" + +PrintToLog::PrintToLog(uint8_t logLevel) : _logLevel(logLevel) +{ + _logLevelActive = loglevelActiveFor(_logLevel); +} + +PrintToLog::PrintToLog(uint8_t logLevel, const String& logPrefix) + : _prefix(logPrefix), _logLevel(logLevel) +{ + _logLevelActive = loglevelActiveFor(_logLevel); +} + +PrintToLog::PrintToLog(uint8_t logLevel, const __FlashStringHelper *logPrefix) + : _prefix(logPrefix), _logLevel(logLevel) +{ + _logLevelActive = loglevelActiveFor(_logLevel); +} + +PrintToLog::~PrintToLog() +{ + sendToLog(); +} + +PrintToLog::operator bool() const +{ + return loglevelActiveFor(_logLevel); +} + +void PrintToLog::flush() +{ + // For compatibility + sendToLog(); +} + +void PrintToLog::sendToLog() +{ + // Update cached loglevel + _logLevelActive = loglevelActiveFor(_logLevel); + + if (_logLevelActive) { + if (!_str.isEmpty()) { + if (_prefix.isEmpty()) { + addLogMove(_logLevel, _str); + } else { + addLog(_logLevel, concat(_prefix, _str)); + } + } + } + _str.clear(); +} + +void PrintToLog::clear() { + _str.clear(); + _logLevelActive = loglevelActiveFor(_logLevel); +} + +size_t PrintToLog::length() const +{ + return _str.length(); +} + +bool PrintToLog::reserve(unsigned int size) { return _str.reserve(size); } + +size_t PrintToLog::write(uint8_t c) +{ + if (!_logLevelActive) { return 0; } + _str += (char)c; + return 1; +} + +String PrintToLog::get() const +{ + if (!_str.isEmpty() && !_prefix.isEmpty()) { + return concat(_prefix, _str); + } + return _str; +} diff --git a/src/src/Helpers/PrintToLog.h b/src/src/Helpers/PrintToLog.h new file mode 100644 index 000000000..7ca82d7bd --- /dev/null +++ b/src/src/Helpers/PrintToLog.h @@ -0,0 +1,49 @@ +#ifndef HELPERS_PRINTTOLOG_H +#define HELPERS_PRINTTOLOG_H + +#include "../../ESPEasy_common.h" + +class PrintToLog : public Print +{ +public: + + PrintToLog(uint8_t logLevel); + + PrintToLog(uint8_t logLevel, + const String& logPrefix); + + PrintToLog(uint8_t logLevel, + const __FlashStringHelper *logPrefix); + + virtual ~PrintToLog(); + + // Check if loglevel is active + operator bool() const; + + void flush() override; + + void sendToLog(); + + void clear(); + + size_t length() const; + + bool reserve(unsigned int size); + + size_t write(uint8_t c) override; + + String get() const; + +private: + + String _prefix; + + String _str; + uint8_t _logLevel{}; + + // Cached loglevel to speed up write. + bool _logLevelActive{}; +}; // class PrintToLog + + +#endif // ifndef HELPERS_PRINTTOLOG_H From 7b6fd5f3446ced5399a2dc317170d0141d14b2e0 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Jun 2025 15:50:21 +0200 Subject: [PATCH 076/564] [Build] Add ESP32C5 to release.yml build script --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d41dc5e09..b20edfc45 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -169,6 +169,7 @@ jobs: find . -name '*ESP32c3*' -print | zip -@ ../ESPEasy_ESP32c3.zip find . -name '*ESP32s3*' -print | zip -@ ../ESPEasy_ESP32s3.zip find . -name '*ESP32c2*' -print | zip -@ ../ESPEasy_ESP32c2.zip + find . -name '*ESP32c5*' -print | zip -@ ../ESPEasy_ESP32c5.zip find . -name '*ESP32c6*' -print | zip -@ ../ESPEasy_ESP32c6.zip find . -name '*ESP32solo1*' -print | zip -@ ../ESPEasy_ESP32solo1.zip find . -name '*ESP32_*' -print | zip -@ ../ESPEasy_ESP32.zip @@ -186,6 +187,7 @@ jobs: zipmerge ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c3_binaries.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip ESPEasy_ESP32c3.zip zipmerge ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32s3_binaries.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip ESPEasy_ESP32s3.zip zipmerge ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c2_binaries.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip ESPEasy_ESP32c2.zip + zipmerge ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c5_binaries.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip ESPEasy_ESP32c5.zip zipmerge ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c6_binaries.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip ESPEasy_ESP32c6.zip zipmerge ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32solo1_binaries.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip ESPEasy_ESP32solo1.zip zipmerge ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip ESPEasy_ESP32.zip @@ -193,6 +195,6 @@ jobs: with: # Upload all separately supported CPU models and the docs zip # TODO if/when available: ESP32h2 - artifacts: "ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP82xx_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32solo1_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32s2_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c3_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32s3_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c2_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c6_binaries.zip,distribution/*.zip" + artifacts: "ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP82xx_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32solo1_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32s2_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c3_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32s3_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c2_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c5_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c6_binaries.zip,distribution/*.zip" body: ${{ needs.prepare-notes.outputs.notes }} token: ${{ secrets.GITHUB_TOKEN }} From 873c6c731d1cc6cf5a955d0f28377c7ebd833d57 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Jun 2025 18:14:52 +0200 Subject: [PATCH 077/564] [ESP-IDF] Update to latest SDK version --- platformio_core_defs.ini | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index f18f5d9a9..94be31e37 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -166,7 +166,7 @@ extra_scripts = ${esp82xx_common.extra_scripts} ; ESP_IDF 5.4.1 [core_esp32_IDF5_4_1__3_2_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF54 -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3717/framework-arduinoespressif32-all-release_v5.4-fea159f6.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3743/framework-arduinoespressif32-all-release_v5.4-a4437683.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 @@ -195,8 +195,7 @@ lib_extra_dirs = ; ESP_IDF 5.5.0 [core_esp32_IDF5_5_0__3_2_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3725/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip -;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3627/framework-arduinoespressif32-all-release_v5.5-5d572003.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3744/framework-arduinoespressif32-all-release_v5.5-c241ccd4.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 From c7e6397a7ba0b04714f247b1290899f3c8c78102 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Jun 2025 18:15:26 +0200 Subject: [PATCH 078/564] [MFRC522] Speedup reading by acting on interrupt pin --- src/_P111_RC522_RFID.ino | 4 +-- src/src/PluginStructs/P111_data_struct.cpp | 35 ++++++++++++++++++++-- src/src/PluginStructs/P111_data_struct.h | 15 ++++++++-- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/_P111_RC522_RFID.ino b/src/_P111_RC522_RFID.ino index 42aa1e5f2..17a4eb28e 100644 --- a/src/_P111_RC522_RFID.ino +++ b/src/_P111_RC522_RFID.ino @@ -139,7 +139,7 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { - initPluginTaskData(event->TaskIndex, new (std::nothrow) P111_data_struct(P111_CS_PIN, P111_RST_PIN)); + initPluginTaskData(event->TaskIndex, new (std::nothrow) P111_data_struct(P111_CS_PIN, P111_RST_PIN, P111_IRQ_PIN)); P111_data_struct *P111_data = static_cast(getPluginTaskData(event->TaskIndex)); if (nullptr != P111_data) { @@ -186,7 +186,7 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string) P111_data_struct *P111_data = static_cast(getPluginTaskData(event->TaskIndex)); if (nullptr != P111_data) { - success = P111_data->plugin_fifty_per_second(); + success = P111_data->plugin_fifty_per_second(event); } break; } diff --git a/src/src/PluginStructs/P111_data_struct.cpp b/src/src/PluginStructs/P111_data_struct.cpp index 3dc5e9600..2f5fcebc6 100644 --- a/src/src/PluginStructs/P111_data_struct.cpp +++ b/src/src/PluginStructs/P111_data_struct.cpp @@ -11,11 +11,16 @@ # include P111_data_struct::P111_data_struct(int8_t csPin, - int8_t rstPin) - : mfrc522(nullptr), _csPin(csPin), _rstPin(rstPin) + int8_t rstPin, + int8_t irqPin) + : mfrc522(nullptr), _csPin(csPin), _rstPin(rstPin), _irqPin(irqPin) {} P111_data_struct::~P111_data_struct() { + if (validGpio(_irqPin)) { + detachInterrupt(digitalPinToInterrupt(_irqPin)); + } + delete mfrc522; mfrc522 = nullptr; } @@ -30,6 +35,15 @@ void P111_data_struct::init() { mfrc522->PCD_WriteRegister(MFRC522::ComIEnReg, 0b10100000); // enable receiver interrupt mfrc522->PCD_WriteRegister(MFRC522::DivIEnReg, 0x80); // Set as CMOS output pin initPhase = P111_initPhases::Ready; + + if (validGpio(_irqPin)) { + pinMode(_irqPin, INPUT); + + attachInterruptArg( + digitalPinToInterrupt(_irqPin), + reinterpret_cast(mfrc522_interrupt), + this, FALLING); + } } } @@ -234,10 +248,19 @@ uint8_t P111_data_struct::readPassiveTargetID(uint8_t *uid, return P111_NO_ERROR; } +void P111_data_struct::mfrc522_interrupt(P111_data_struct * self) +{ + self->_irq_pin_time_micros = getMicros64(); +} + /********************************************************************************************* * Handle regular read and reset processing ********************************************************************************************/ bool P111_data_struct::plugin_ten_per_second(struct EventStruct *event) { + return loop(event); +} + +bool P111_data_struct::loop(struct EventStruct *event) { bool success = false; if (((initPhase == P111_initPhases::ResetDelay1) || // Whichever handler comes first @@ -306,7 +329,7 @@ bool P111_data_struct::plugin_ten_per_second(struct EventStruct *event) { /********************************************************************************************* * Handle timers instead of using delay() ********************************************************************************************/ -bool P111_data_struct::plugin_fifty_per_second() { +bool P111_data_struct::plugin_fifty_per_second(struct EventStruct *event) { if ((initPhase == P111_initPhases::ResetDelay1) || (initPhase == P111_initPhases::ResetDelay2)) { timeToWait -= 20; // milliseconds @@ -323,6 +346,12 @@ bool P111_data_struct::plugin_fifty_per_second() { } } } + if (_irq_pin_time_micros > _last_served_irq_pin_time_micros) { + _last_served_irq_pin_time_micros = _irq_pin_time_micros; + //addLog(LOG_LEVEL_INFO, F("P111: acting on interrupt")); + loop(event); + } + return true; } diff --git a/src/src/PluginStructs/P111_data_struct.h b/src/src/PluginStructs/P111_data_struct.h index 4a5d68c40..8acabdc6f 100644 --- a/src/src/PluginStructs/P111_data_struct.h +++ b/src/src/PluginStructs/P111_data_struct.h @@ -8,6 +8,7 @@ # define P111_CS_PIN PIN(0) # define P111_RST_PIN PIN(1) +# define P111_IRQ_PIN PIN(2) # define P111_TAG_AUTOREMOVAL PCONFIG(0) # define P111_SENDRESET PCONFIG(1) # define P111_REMOVALVALUE PCONFIG_LONG(0) @@ -31,18 +32,21 @@ enum class P111_initPhases : uint8_t { struct P111_data_struct : public PluginTaskData_base { P111_data_struct(int8_t csPin, - int8_t rstPin); + int8_t rstPin, + int8_t irqPin); P111_data_struct() = delete; virtual ~P111_data_struct(); void init(); bool plugin_ten_per_second(struct EventStruct *event); - bool plugin_fifty_per_second(); + bool plugin_fifty_per_second(struct EventStruct *event); String PCD_getVersion(uint8_t& v); private: + bool loop(struct EventStruct *event); + MFRC522 *mfrc522 = nullptr; uint8_t counter = 0; @@ -55,14 +59,21 @@ private: uint8_t readPassiveTargetID(uint8_t *uid, uint8_t *uidLength); + static void mfrc522_interrupt(P111_data_struct * self); + int32_t timeToWait = 0; int8_t _csPin; int8_t _rstPin; + int8_t _irqPin; uint8_t errorCount = 0; bool removedState = true; // On startup, there will usually not be a tag nearby P111_initPhases initPhase = P111_initPhases::Undefined; + + int64_t _last_served_irq_pin_time_micros{}; + + ESPEASY_VOLATILE(int64_t) _irq_pin_time_micros = -1; }; #endif // ifdef USES_P111 From 59e3a1b119a2c688894051dfa7e36d1918a507ae Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Jun 2025 18:16:14 +0200 Subject: [PATCH 079/564] [PWM motor] Speedup acting on limit switch interrupt --- src/src/PluginStructs/P098_data_struct.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/src/PluginStructs/P098_data_struct.cpp b/src/src/PluginStructs/P098_data_struct.cpp index 154a60ba9..922405039 100644 --- a/src/src/PluginStructs/P098_data_struct.cpp +++ b/src/src/PluginStructs/P098_data_struct.cpp @@ -4,6 +4,8 @@ # include "../ESPEasyCore/ESPEasyGPIO.h" +# include + # include "../Commands/GPIO.h" // FIXME TD-er: Only needed till we can call GPIO commands from the ESPEasy core. @@ -440,7 +442,8 @@ void ICACHE_RAM_ATTR P098_data_struct::process_limit_switch( ISR_noInterrupts(); { // Don't call gpio_config.readState() here - const bool pinState = gpio_config.inverted ? digitalRead(gpio_config.gpio) == 0 : digitalRead(gpio_config.gpio) != 0; + const bool pinState = + (DIRECT_pinRead_ISR(gpio_config.gpio) == 0) ^ gpio_config.inverted; const uint64_t currentTime = getMicros64(); From 0ed022e6b4bc59aa503d22f4abc377165c3c0571 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 27 Jun 2025 10:19:57 +0200 Subject: [PATCH 080/564] [Web flasher] Update esp web tools to 8.1.10 to support ESP32-C5 --- tools/pio/generate_web_flasher_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pio/generate_web_flasher_manifest.py b/tools/pio/generate_web_flasher_manifest.py index 8e9021063..a92646c59 100644 --- a/tools/pio/generate_web_flasher_manifest.py +++ b/tools/pio/generate_web_flasher_manifest.py @@ -371,7 +371,7 @@ def generate_manifest_files(bin_folder, output_prefix): ' \n', ' \n', ' \n', ' \n', From 7fb4d4e821dc24961354072d2d55535abcad03cf Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 28 Jun 2025 23:20:27 +0200 Subject: [PATCH 081/564] [PubSubClient] Update to new fork PubSubClient3 --- lib/pubsubclient/.gitignore | 1 - lib/pubsubclient/CHANGES.txt | 76 -- .../examples/mqtt_auth/mqtt_auth.ino | 43 - .../examples/mqtt_basic/mqtt_basic.ino | 77 -- .../examples/mqtt_esp8266/mqtt_esp8266.ino | 132 --- .../mqtt_large_message/mqtt_large_message.ino | 179 ---- .../mqtt_publish_in_callback.ino | 60 -- .../mqtt_reconnect_nonblocking.ino | 67 -- lib/pubsubclient/src/PubSubClient.cpp | 842 ------------------ lib/pubsubclient/src/PubSubClient.h | 205 ----- lib/pubsubclient/tests/src/connect_spec.cpp | 302 ------- lib/pubsubclient/tests/src/lib/Arduino.h | 26 - lib/pubsubclient/tests/src/lib/Client.h | 21 - lib/pubsubclient/tests/src/lib/ShimClient.h | 51 -- lib/pubsubclient/tests/src/publish_spec.cpp | 190 ---- lib/pubsubclient/tests/src/receive_spec.cpp | 279 ------ lib/pubsubclient3/.clang-format | 8 + lib/pubsubclient3/.editorconfig | 17 + lib/pubsubclient3/.github/build-arduino.sh | 53 ++ lib/pubsubclient3/.github/clang-lint.sh | 21 + lib/pubsubclient3/.github/workflows/build.yml | 31 + lib/pubsubclient3/.gitignore | 5 + .../.travis.yml | 0 lib/pubsubclient3/CHANGES.txt | 136 +++ .../LICENSE.txt | 3 +- lib/{pubsubclient => pubsubclient3}/README.md | 25 +- .../examples/mqtt_auth/mqtt_auth.ino | 41 + .../examples/mqtt_basic/mqtt_basic.ino | 74 ++ .../examples/mqtt_esp8266/mqtt_esp8266.ino | 135 +++ .../mqtt_large_message/mqtt_large_message.ino | 185 ++++ .../mqtt_publish_in_callback.ino | 56 ++ .../mqtt_reconnect_nonblocking.ino | 62 ++ .../examples/mqtt_stream/mqtt_stream.ino | 46 +- .../keywords.txt | 3 + .../library.json | 7 +- .../library.properties | 11 +- lib/pubsubclient3/src/PubSubClient.cpp | 772 ++++++++++++++++ lib/pubsubclient3/src/PubSubClient.h | 612 +++++++++++++ .../tests/.gitignore | 0 .../tests/Makefile | 8 +- .../tests/README.md | 21 +- lib/pubsubclient3/tests/src/connect_spec.cpp | 361 ++++++++ .../tests/src/keepalive_spec.cpp | 119 +-- lib/pubsubclient3/tests/src/lib/Arduino.h | 38 + .../tests/src/lib/BDDTest.cpp | 16 +- .../tests/src/lib/BDDTest.h | 4 +- .../tests/src/lib/Buffer.cpp | 5 +- .../tests/src/lib/Buffer.h | 12 +- lib/pubsubclient3/tests/src/lib/Client.h | 21 + .../tests/src/lib/IPAddress.cpp | 24 +- .../tests/src/lib/IPAddress.h | 37 +- .../tests/src/lib/Print.h | 4 +- .../tests/src/lib/ShimClient.cpp | 81 +- lib/pubsubclient3/tests/src/lib/ShimClient.h | 50 ++ .../tests/src/lib/Stream.cpp | 14 +- .../tests/src/lib/Stream.h | 8 +- .../tests/src/lib/trace.h | 4 +- lib/pubsubclient3/tests/src/publish_spec.cpp | 228 +++++ lib/pubsubclient3/tests/src/receive_spec.cpp | 345 +++++++ .../tests/src/subscribe_spec.cpp | 96 +- .../tests/testcases/__init__.py | 0 .../tests/testcases/mqtt_basic.py | 13 +- .../testcases/mqtt_publish_in_callback.py | 12 +- .../tests/testcases/settings.py | 0 .../tests/testsuite.py | 2 +- .../ESPEasyControllerCache_CSV_dumper.cpp | 2 +- src/src/PluginStructs/P146_data_struct.cpp | 2 +- 67 files changed, 3563 insertions(+), 2818 deletions(-) delete mode 100644 lib/pubsubclient/.gitignore delete mode 100644 lib/pubsubclient/CHANGES.txt delete mode 100644 lib/pubsubclient/examples/mqtt_auth/mqtt_auth.ino delete mode 100644 lib/pubsubclient/examples/mqtt_basic/mqtt_basic.ino delete mode 100644 lib/pubsubclient/examples/mqtt_esp8266/mqtt_esp8266.ino delete mode 100644 lib/pubsubclient/examples/mqtt_large_message/mqtt_large_message.ino delete mode 100644 lib/pubsubclient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino delete mode 100644 lib/pubsubclient/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino delete mode 100644 lib/pubsubclient/src/PubSubClient.cpp delete mode 100644 lib/pubsubclient/src/PubSubClient.h delete mode 100644 lib/pubsubclient/tests/src/connect_spec.cpp delete mode 100644 lib/pubsubclient/tests/src/lib/Arduino.h delete mode 100644 lib/pubsubclient/tests/src/lib/Client.h delete mode 100644 lib/pubsubclient/tests/src/lib/ShimClient.h delete mode 100644 lib/pubsubclient/tests/src/publish_spec.cpp delete mode 100644 lib/pubsubclient/tests/src/receive_spec.cpp create mode 100644 lib/pubsubclient3/.clang-format create mode 100644 lib/pubsubclient3/.editorconfig create mode 100644 lib/pubsubclient3/.github/build-arduino.sh create mode 100644 lib/pubsubclient3/.github/clang-lint.sh create mode 100644 lib/pubsubclient3/.github/workflows/build.yml create mode 100644 lib/pubsubclient3/.gitignore rename lib/{pubsubclient => pubsubclient3}/.travis.yml (100%) create mode 100644 lib/pubsubclient3/CHANGES.txt rename lib/{pubsubclient => pubsubclient3}/LICENSE.txt (93%) rename lib/{pubsubclient => pubsubclient3}/README.md (56%) create mode 100644 lib/pubsubclient3/examples/mqtt_auth/mqtt_auth.ino create mode 100644 lib/pubsubclient3/examples/mqtt_basic/mqtt_basic.ino create mode 100644 lib/pubsubclient3/examples/mqtt_esp8266/mqtt_esp8266.ino create mode 100644 lib/pubsubclient3/examples/mqtt_large_message/mqtt_large_message.ino create mode 100644 lib/pubsubclient3/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino create mode 100644 lib/pubsubclient3/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino rename lib/{pubsubclient => pubsubclient3}/examples/mqtt_stream/mqtt_stream.ino (50%) rename lib/{pubsubclient => pubsubclient3}/keywords.txt (91%) rename lib/{pubsubclient => pubsubclient3}/library.json (83%) rename lib/{pubsubclient => pubsubclient3}/library.properties (75%) create mode 100644 lib/pubsubclient3/src/PubSubClient.cpp create mode 100644 lib/pubsubclient3/src/PubSubClient.h rename lib/{pubsubclient => pubsubclient3}/tests/.gitignore (100%) rename lib/{pubsubclient => pubsubclient3}/tests/Makefile (52%) rename lib/{pubsubclient => pubsubclient3}/tests/README.md (93%) create mode 100644 lib/pubsubclient3/tests/src/connect_spec.cpp rename lib/{pubsubclient => pubsubclient3}/tests/src/keepalive_spec.cpp (51%) create mode 100644 lib/pubsubclient3/tests/src/lib/Arduino.h rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/BDDTest.cpp (82%) rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/BDDTest.h (87%) rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/Buffer.cpp (90%) rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/Buffer.h (84%) create mode 100644 lib/pubsubclient3/tests/src/lib/Client.h rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/IPAddress.cpp (58%) rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/IPAddress.h (79%) rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/Print.h (94%) rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/ShimClient.cpp (67%) create mode 100644 lib/pubsubclient3/tests/src/lib/ShimClient.h rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/Stream.cpp (86%) rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/Stream.h (78%) rename lib/{pubsubclient => pubsubclient3}/tests/src/lib/trace.h (100%) create mode 100644 lib/pubsubclient3/tests/src/publish_spec.cpp create mode 100644 lib/pubsubclient3/tests/src/receive_spec.cpp rename lib/{pubsubclient => pubsubclient3}/tests/src/subscribe_spec.cpp (52%) rename lib/{pubsubclient => pubsubclient3}/tests/testcases/__init__.py (100%) rename lib/{pubsubclient => pubsubclient3}/tests/testcases/mqtt_basic.py (77%) rename lib/{pubsubclient => pubsubclient3}/tests/testcases/mqtt_publish_in_callback.py (86%) rename lib/{pubsubclient => pubsubclient3}/tests/testcases/settings.py (100%) rename lib/{pubsubclient => pubsubclient3}/tests/testsuite.py (99%) diff --git a/lib/pubsubclient/.gitignore b/lib/pubsubclient/.gitignore deleted file mode 100644 index 1c3ba189b..000000000 --- a/lib/pubsubclient/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tests/bin diff --git a/lib/pubsubclient/CHANGES.txt b/lib/pubsubclient/CHANGES.txt deleted file mode 100644 index ff4da62ab..000000000 --- a/lib/pubsubclient/CHANGES.txt +++ /dev/null @@ -1,76 +0,0 @@ -2.7 - * Fix remaining-length handling to prevent buffer overrun - * Add large-payload API - beginPublish/write/publish/endPublish - * Add yield call to improve reliability on ESP - * Add Clean Session flag to connect options - * Add ESP32 support for functional callback signature - * Various other fixes - -2.4 - * Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely - whilst waiting for inbound data - * Fixed return code when publishing >256 bytes - -2.3 - * Add publish(topic,payload,retained) function - -2.2 - * Change code layout to match Arduino Library reqs - -2.1 - * Add MAX_TRANSFER_SIZE def to chunk messages if needed - * Reject topic/payloads that exceed MQTT_MAX_PACKET_SIZE - -2.0 - * Add (and default to) MQTT 3.1.1 support - * Fix PROGMEM handling for Intel Galileo/ESP8266 - * Add overloaded constructors for convenience - * Add chainable setters for server/callback/client/stream - * Add state function to return connack return code - -1.9 - * Do not split MQTT packets over multiple calls to _client->write() - * API change: All constructors now require an instance of Client - to be passed in. - * Fixed example to match 1.8 api changes - dpslwk - * Added username/password support - WilHall - * Added publish_P - publishes messages from PROGMEM - jobytaffey - -1.8 - * KeepAlive interval is configurable in PubSubClient.h - * Maximum packet size is configurable in PubSubClient.h - * API change: Return boolean rather than int from various functions - * API change: Length parameter in message callback changed - from int to unsigned int - * Various internal tidy-ups around types -1.7 - * Improved keepalive handling - * Updated to the Arduino-1.0 API -1.6 - * Added the ability to publish a retained message - -1.5 - * Added default constructor - * Fixed compile error when used with arduino-0021 or later - -1.4 - * Fixed connection lost handling - -1.3 - * Fixed packet reading bug in PubSubClient.readPacket - -1.2 - * Fixed compile error when used with arduino-0016 or later - - -1.1 - * Reduced size of library - * Added support for Will messages - * Clarified licensing - see LICENSE.txt - - -1.0 - * Only Quality of Service (QOS) 0 messaging is supported - * The maximum message size, including header, is 128 bytes - * The keepalive interval is set to 30 seconds - * No support for Will messages diff --git a/lib/pubsubclient/examples/mqtt_auth/mqtt_auth.ino b/lib/pubsubclient/examples/mqtt_auth/mqtt_auth.ino deleted file mode 100644 index e9f7b180f..000000000 --- a/lib/pubsubclient/examples/mqtt_auth/mqtt_auth.ino +++ /dev/null @@ -1,43 +0,0 @@ -/* - Basic MQTT example with Authentication - - - connects to an MQTT server, providing username - and password - - publishes "hello world" to the topic "outTopic" - - subscribes to the topic "inTopic" -*/ - -#include -#include -#include - -// Update these with values suitable for your network. -byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; -IPAddress ip(172, 16, 0, 100); -IPAddress server(172, 16, 0, 2); - -void callback(char* topic, byte* payload, unsigned int length) { - // handle message arrived -} - -EthernetClient ethClient; -PubSubClient client(server, 1883, callback, ethClient); - -void setup() -{ - Ethernet.begin(mac, ip); - // Note - the default maximum packet size is 128 bytes. If the - // combined length of clientId, username and password exceed this, - // you will need to increase the value of MQTT_MAX_PACKET_SIZE in - // PubSubClient.h - - if (client.connect("arduinoClient", "testuser", "testpass")) { - client.publish("outTopic","hello world"); - client.subscribe("inTopic"); - } -} - -void loop() -{ - client.loop(); -} diff --git a/lib/pubsubclient/examples/mqtt_basic/mqtt_basic.ino b/lib/pubsubclient/examples/mqtt_basic/mqtt_basic.ino deleted file mode 100644 index f545adef8..000000000 --- a/lib/pubsubclient/examples/mqtt_basic/mqtt_basic.ino +++ /dev/null @@ -1,77 +0,0 @@ -/* - Basic MQTT example - - This sketch demonstrates the basic capabilities of the library. - It connects to an MQTT server then: - - publishes "hello world" to the topic "outTopic" - - subscribes to the topic "inTopic", printing out any messages - it receives. NB - it assumes the received payloads are strings not binary - - It will reconnect to the server if the connection is lost using a blocking - reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to - achieve the same result without blocking the main loop. - -*/ - -#include -#include -#include - -// Update these with values suitable for your network. -byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; -IPAddress ip(172, 16, 0, 100); -IPAddress server(172, 16, 0, 2); - -void callback(char* topic, byte* payload, unsigned int length) { - Serial.print("Message arrived ["); - Serial.print(topic); - Serial.print("] "); - for (int i=0;i Preferences -> Additional Boards Manager URLs": - http://arduino.esp8266.com/stable/package_esp8266com_index.json - - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266" - - Select your ESP8266 in "Tools -> Board" - -*/ - -#include -#include - -// Update these with values suitable for your network. - -const char* ssid = "........"; -const char* password = "........"; -const char* mqtt_server = "broker.mqtt-dashboard.com"; - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -void setup_wifi() { - - delay(10); - // We start by connecting to a WiFi network - Serial.println(); - Serial.print("Connecting to "); - Serial.println(ssid); - - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - - randomSeed(micros()); - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void callback(char* topic, byte* payload, unsigned int length) { - Serial.print("Message arrived ["); - Serial.print(topic); - Serial.print("] "); - for (int i = 0; i < length; i++) { - Serial.print((char)payload[i]); - } - Serial.println(); - - // Switch on the LED if an 1 was received as first character - if ((char)payload[0] == '1') { - digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level - // but actually the LED is on; this is because - // it is active low on the ESP-01) - } else { - digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH - } - -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Create a random client ID - String clientId = "ESP8266Client-"; - clientId += String(random(0xffff), HEX); - // Attempt to connect - if (client.connect(clientId.c_str())) { - Serial.println("connected"); - // Once connected, publish an announcement... - client.publish("outTopic", "hello world"); - // ... and resubscribe - client.subscribe("inTopic"); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void setup() { - pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_server, 1883); - client.setCallback(callback); -} - -void loop() { - - if (!client.connected()) { - reconnect(); - } - client.loop(); - - long now = millis(); - if (now - lastMsg > 2000) { - lastMsg = now; - ++value; - snprintf (msg, 50, "hello world #%ld", value); - Serial.print("Publish message: "); - Serial.println(msg); - client.publish("outTopic", msg); - } -} diff --git a/lib/pubsubclient/examples/mqtt_large_message/mqtt_large_message.ino b/lib/pubsubclient/examples/mqtt_large_message/mqtt_large_message.ino deleted file mode 100644 index e048c3ed3..000000000 --- a/lib/pubsubclient/examples/mqtt_large_message/mqtt_large_message.ino +++ /dev/null @@ -1,179 +0,0 @@ -/* - Long message ESP8266 MQTT example - - This sketch demonstrates sending arbitrarily large messages in combination - with the ESP8266 board/library. - - It connects to an MQTT server then: - - publishes "hello world" to the topic "outTopic" - - subscribes to the topic "greenBottles/#", printing out any messages - it receives. NB - it assumes the received payloads are strings not binary - - If the sub-topic is a number, it publishes a "greenBottles/lyrics" message - with a payload consisting of the lyrics to "10 green bottles", replacing - 10 with the number given in the sub-topic. - - It will reconnect to the server if the connection is lost using a blocking - reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to - achieve the same result without blocking the main loop. - - To install the ESP8266 board, (using Arduino 1.6.4+): - - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs": - http://arduino.esp8266.com/stable/package_esp8266com_index.json - - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266" - - Select your ESP8266 in "Tools -> Board" - -*/ - -#include -#include - -// Update these with values suitable for your network. - -const char* ssid = "........"; -const char* password = "........"; -const char* mqtt_server = "broker.mqtt-dashboard.com"; - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -void setup_wifi() { - - delay(10); - // We start by connecting to a WiFi network - Serial.println(); - Serial.print("Connecting to "); - Serial.println(ssid); - - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - - randomSeed(micros()); - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void callback(char* topic, byte* payload, unsigned int length) { - Serial.print("Message arrived ["); - Serial.print(topic); - Serial.print("] "); - for (int i = 0; i < length; i++) { - Serial.print((char)payload[i]); - } - Serial.println(); - - // Find out how many bottles we should generate lyrics for - String topicStr(topic); - int bottleCount = 0; // assume no bottles unless we correctly parse a value from the topic - if (topicStr.indexOf('/') >= 0) { - // The topic includes a '/', we'll try to read the number of bottles from just after that - topicStr.remove(0, topicStr.indexOf('/')+1); - // Now see if there's a number of bottles after the '/' - bottleCount = topicStr.toInt(); - } - - if (bottleCount > 0) { - // Work out how big our resulting message will be - int msgLen = 0; - for (int i = bottleCount; i > 0; i--) { - String numBottles(i); - msgLen += 2*numBottles.length(); - if (i == 1) { - msgLen += 2*String(" green bottle, standing on the wall\n").length(); - } else { - msgLen += 2*String(" green bottles, standing on the wall\n").length(); - } - msgLen += String("And if one green bottle should accidentally fall\nThere'll be ").length(); - switch (i) { - case 1: - msgLen += String("no green bottles, standing on the wall\n\n").length(); - break; - case 2: - msgLen += String("1 green bottle, standing on the wall\n\n").length(); - break; - default: - numBottles = i-1; - msgLen += numBottles.length(); - msgLen += String(" green bottles, standing on the wall\n\n").length(); - break; - }; - } - - // Now we can start to publish the message - client.beginPublish("greenBottles/lyrics", msgLen, false); - for (int i = bottleCount; i > 0; i--) { - for (int j = 0; j < 2; j++) { - client.print(i); - if (i == 1) { - client.print(" green bottle, standing on the wall\n"); - } else { - client.print(" green bottles, standing on the wall\n"); - } - } - client.print("And if one green bottle should accidentally fall\nThere'll be "); - switch (i) { - case 1: - client.print("no green bottles, standing on the wall\n\n"); - break; - case 2: - client.print("1 green bottle, standing on the wall\n\n"); - break; - default: - client.print(i-1); - client.print(" green bottles, standing on the wall\n\n"); - break; - }; - } - // Now we're done! - client.endPublish(); - } -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Create a random client ID - String clientId = "ESP8266Client-"; - clientId += String(random(0xffff), HEX); - // Attempt to connect - if (client.connect(clientId.c_str())) { - Serial.println("connected"); - // Once connected, publish an announcement... - client.publish("outTopic", "hello world"); - // ... and resubscribe - client.subscribe("greenBottles/#"); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void setup() { - pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_server, 1883); - client.setCallback(callback); -} - -void loop() { - - if (!client.connected()) { - reconnect(); - } - client.loop(); -} diff --git a/lib/pubsubclient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino b/lib/pubsubclient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino deleted file mode 100644 index 42afb2a3a..000000000 --- a/lib/pubsubclient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino +++ /dev/null @@ -1,60 +0,0 @@ -/* - Publishing in the callback - - - connects to an MQTT server - - subscribes to the topic "inTopic" - - when a message is received, republishes it to "outTopic" - - This example shows how to publish messages within the - callback function. The callback function header needs to - be declared before the PubSubClient constructor and the - actual callback defined afterwards. - This ensures the client reference in the callback function - is valid. - -*/ - -#include -#include -#include - -// Update these with values suitable for your network. -byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; -IPAddress ip(172, 16, 0, 100); -IPAddress server(172, 16, 0, 2); - -// Callback function header -void callback(char* topic, byte* payload, unsigned int length); - -EthernetClient ethClient; -PubSubClient client(server, 1883, callback, ethClient); - -// Callback function -void callback(char* topic, byte* payload, unsigned int length) { - // In order to republish this payload, a copy must be made - // as the orignal payload buffer will be overwritten whilst - // constructing the PUBLISH packet. - - // Allocate the correct amount of memory for the payload copy - byte* p = (byte*)malloc(length); - // Copy the payload to the new buffer - memcpy(p,payload,length); - client.publish("outTopic", p, length); - // Free the memory - free(p); -} - -void setup() -{ - - Ethernet.begin(mac, ip); - if (client.connect("arduinoClient")) { - client.publish("outTopic","hello world"); - client.subscribe("inTopic"); - } -} - -void loop() -{ - client.loop(); -} diff --git a/lib/pubsubclient/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino b/lib/pubsubclient/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino deleted file mode 100644 index 080b7391c..000000000 --- a/lib/pubsubclient/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino +++ /dev/null @@ -1,67 +0,0 @@ -/* - Reconnecting MQTT example - non-blocking - - This sketch demonstrates how to keep the client connected - using a non-blocking reconnect function. If the client loses - its connection, it attempts to reconnect every 5 seconds - without blocking the main loop. - -*/ - -#include -#include -#include - -// Update these with values suitable for your hardware/network. -byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; -IPAddress ip(172, 16, 0, 100); -IPAddress server(172, 16, 0, 2); - -void callback(char* topic, byte* payload, unsigned int length) { - // handle message arrived -} - -EthernetClient ethClient; -PubSubClient client(ethClient); - -long lastReconnectAttempt = 0; - -boolean reconnect() { - if (client.connect("arduinoClient")) { - // Once connected, publish an announcement... - client.publish("outTopic","hello world"); - // ... and resubscribe - client.subscribe("inTopic"); - } - return client.connected(); -} - -void setup() -{ - client.setServer(server, 1883); - client.setCallback(callback); - - Ethernet.begin(mac, ip); - delay(1500); - lastReconnectAttempt = 0; -} - - -void loop() -{ - if (!client.connected()) { - long now = millis(); - if (now - lastReconnectAttempt > 5000) { - lastReconnectAttempt = now; - // Attempt to reconnect - if (reconnect()) { - lastReconnectAttempt = 0; - } - } - } else { - // Client connected - - client.loop(); - } - -} diff --git a/lib/pubsubclient/src/PubSubClient.cpp b/lib/pubsubclient/src/PubSubClient.cpp deleted file mode 100644 index 34a8cab7b..000000000 --- a/lib/pubsubclient/src/PubSubClient.cpp +++ /dev/null @@ -1,842 +0,0 @@ -/* - PubSubClient.cpp - A simple client for MQTT. - Nick O'Leary - http://knolleary.net -*/ - -#include "PubSubClient.h" -#include - -#ifdef ESP32 -#include -#endif - -#ifdef USE_SECOND_HEAP - #include -#endif - - -PubSubClient::PubSubClient() { - this->_state = MQTT_DISCONNECTED; - this->_client = NULL; - this->stream = NULL; - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; - - setCallback(NULL); -} - -PubSubClient::PubSubClient(Client& client) { - this->_state = MQTT_DISCONNECTED; - setClient(client); - this->stream = NULL; - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} - -PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(addr, port); - setClient(client); - this->stream = NULL; - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} -PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(addr,port); - setClient(client); - setStream(stream); - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} -PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(addr, port); - setCallback(callback); - setClient(client); - this->stream = NULL; - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} -PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(addr,port); - setCallback(callback); - setClient(client); - setStream(stream); - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} - -PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(ip, port); - setClient(client); - this->stream = NULL; - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} -PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(ip,port); - setClient(client); - setStream(stream); - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} -PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(ip, port); - setCallback(callback); - setClient(client); - this->stream = NULL; - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} -PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(ip,port); - setCallback(callback); - setClient(client); - setStream(stream); - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} - -PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(domain,port); - setClient(client); - this->stream = NULL; - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} -PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(domain,port); - setClient(client); - setStream(stream); - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} -PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(domain,port); - setCallback(callback); - setClient(client); - this->stream = NULL; - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} -PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(domain,port); - setCallback(callback); - setClient(client); - setStream(stream); - this->keepAlive_sec = MQTT_KEEPALIVE; - this->socketTimeout_msec = MQTT_SOCKET_TIMEOUT * 1000; -} - -PubSubClient::~PubSubClient() -{ - if (buffer != nullptr) { - free(buffer); - buffer = nullptr; - } -} - -boolean PubSubClient::connect(const char *id) { - return connect(id,NULL,NULL,0,0,0,0,1); -} - -boolean PubSubClient::connect(const char *id, const char *user, const char *pass) { - return connect(id,user,pass,0,0,0,0,1); -} - -boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { - return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1); -} - -boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { - return connect(id,user,pass,willTopic,willQos,willRetain,willMessage,1); -} - -boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) { - if (!initBuffer()) { - return false; - } - - if (!connected()) { - int result = 0; - - if (_client == nullptr) { - return false; - } - if (_client->connected()) { - result = 1; - } else { - if (domain.length() != 0) { -#if defined(ESP32) && ESP_IDF_VERSION_MAJOR < 5 - WiFiClient* wfc = (WiFiClient*)_client; - result = wfc->connect(this->domain.c_str(), this->port, _client->getTimeout()); -#else - result = _client->connect(this->domain.c_str(), this->port); -#endif - } else { -#if defined(ESP32) && ESP_IDF_VERSION_MAJOR < 5 - WiFiClient* wfc = (WiFiClient*)_client; - result = wfc->connect(this->ip, this->port, _client->getTimeout()); -#else - result = _client->connect(this->ip, this->port); -#endif - } - } - if (result == 1) { - nextMsgId = 1; - // Leave room in the buffer for header and variable length field - uint16_t length = MQTT_MAX_HEADER_SIZE; - unsigned int j; - -#if MQTT_VERSION == MQTT_VERSION_3_1 - uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION}; -#define MQTT_HEADER_VERSION_LENGTH 9 -#elif MQTT_VERSION == MQTT_VERSION_3_1_1 - uint8_t d[7] = {0x00,0x04,'M','Q','T','T',MQTT_VERSION}; -#define MQTT_HEADER_VERSION_LENGTH 7 -#endif - for (j = 0;j>1); - } - } - - buffer[length++] = v; - - buffer[length++] = ((keepAlive_sec) >> 8); - buffer[length++] = ((keepAlive_sec) & 0xFF); - - CHECK_STRING_LENGTH(length,id) - length = writeString(id,buffer,length); - if (willTopic) { - CHECK_STRING_LENGTH(length,willTopic) - length = writeString(willTopic,buffer,length); - CHECK_STRING_LENGTH(length,willMessage) - length = writeString(willMessage,buffer,length); - } - - if(user != NULL) { - CHECK_STRING_LENGTH(length,user) - length = writeString(user,buffer,length); - if(pass != NULL) { - CHECK_STRING_LENGTH(length,pass) - length = writeString(pass,buffer,length); - } - } - - write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE); - - lastInActivity = lastOutActivity = millis(); - pingOutstanding = false; // See: https://github.com/knolleary/pubsubclient/pull/802 - - while (!_client->available()) { - delay(0); // Prevent watchdog crashes - unsigned long t = millis(); - if ((int32_t)(t - lastInActivity) >= socketTimeout_msec) { - _state = MQTT_CONNECTION_TIMEOUT; - _client->stop(); - return false; - } - } - uint8_t llen; - uint16_t len = readPacket(&llen); - - if (len == 4) { - if (buffer[3] == 0) { - lastInActivity = millis(); - pingOutstanding = false; - _state = MQTT_CONNECTED; - return true; - } else { - _state = buffer[3]; - } - } - _client->stop(); - } else { - _state = MQTT_CONNECT_FAILED; - } - return false; - } - return true; -} - -// reads a byte into result -boolean PubSubClient::readByte(uint8_t * result) { - if (_client == nullptr) { - return false; - } - uint32_t previousMillis = millis(); - - while(!_client->available() && _client->connected()) { - delay(1); // Prevent watchdog crashes - - if((int32_t)(millis() - previousMillis) >= socketTimeout_msec){ - return false; - } - } - *result = _client->read(); - return true; -} - -// reads a byte into result[*index] and increments index -boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){ - uint16_t current_index = *index; - uint8_t * write_address = &(result[current_index]); - if(readByte(write_address)){ - *index = current_index + 1; - return true; - } - return false; -} - -uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { - if (!initBuffer()) { - return 0; - } - - uint16_t len = 0; - if(!readByte(buffer, &len)) return 0; - bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; - uint32_t multiplier = 1; - uint16_t length = 0; - uint8_t digit = 0; - uint16_t skip = 0; - uint8_t start = 0; - - do { - if (len == 5) { - // Invalid remaining length encoding - kill the connection - _state = MQTT_DISCONNECTED; - _client->stop(); - return 0; - } - if(!readByte(&digit)) return 0; - buffer[len++] = digit; - length += (digit & 127) * multiplier; - multiplier *= 128; - } while ((digit & 128) != 0 && len < (MQTT_MAX_PACKET_SIZE -2)); - *lengthLength = len-1; - - if (isPublish) { - // Read in topic length to calculate bytes to skip over for Stream writing - if(!readByte(buffer, &len)) return 0; - if(!readByte(buffer, &len)) return 0; - skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; - start = 2; - if (buffer[0]&MQTTQOS1) { - // skip message id - skip += 2; - } - } - - for (uint16_t i = start;istream) { - if (isPublish && len-*lengthLength-2>skip) { - this->stream->write(digit); - } - } - if (len < MQTT_MAX_PACKET_SIZE) { - buffer[len] = digit; - } - len++; - } - - if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { - len = 0; // This will cause the packet to be ignored. - } - - return len; -} - -bool PubSubClient::loop_read() { - if (!initBuffer()) { - return false; - } - - if (_client == nullptr) { - return false; - } - if (!_client->available()) { - return false; - } - uint8_t llen; - uint16_t len = readPacket(&llen); - if (len == 0) { - return false; - } - unsigned long t = millis(); - lastInActivity = t; - uint8_t type = buffer[0]&0xF0; - - switch(type) { - case MQTTPUBLISH: - { - if (callback) { - const bool msgId_present = (buffer[0]&0x06) == MQTTQOS1; - const uint16_t tl_offset = llen+1; - const uint16_t tl = (buffer[tl_offset]<<8)+buffer[tl_offset+1]; /* topic length in bytes */ - const uint16_t topic_offset = tl_offset+2; - const uint16_t msgId_offset = topic_offset+tl; - const uint16_t payload_offset = msgId_present ? msgId_offset+2 : msgId_offset; - if (payload_offset >= MQTT_MAX_PACKET_SIZE) return false; - if (len < payload_offset) return false; - // Need to move the topic 1 byte to insert a '\0' at the end of the topic. - memmove(buffer+topic_offset-1,buffer+topic_offset,tl); /* move topic inside buffer 1 byte to front */ - buffer[topic_offset-1+tl] = 0; /* end the topic as a 'C' string with \x00 */ - char *topic = (char*) buffer+topic_offset-1; - uint8_t *payload; - // msgId only present for QOS>0 - if (msgId_present) { - const uint16_t msgId = (buffer[msgId_offset]<<8)+buffer[msgId_offset+1]; - payload = buffer+payload_offset; - callback(topic,payload,len-payload_offset); - if (_client->connected()) { - buffer[0] = MQTTPUBACK; - buffer[1] = 2; - buffer[2] = (msgId >> 8); - buffer[3] = (msgId & 0xFF); - if (_client->write(buffer,4) != 0) { - lastOutActivity = t; - } - } - } else { - // No msgId - payload = buffer+payload_offset; - callback(topic,payload,len-payload_offset); - } - } - break; - } - case MQTTPINGREQ: - { - if (_client->connected()) { - buffer[0] = MQTTPINGRESP; - buffer[1] = 0; - if (_client->write(buffer,2) != 0) { - lastOutActivity = t; - } - } - break; - } - case MQTTPINGRESP: - { - pingOutstanding = false; - break; - } - default: - return false; - } - return true; -} - -boolean PubSubClient::loop() { - delay(0); - loop_read(); - if (connected()) { - unsigned long t = millis(); - // Send message at 2/3 of keepalive interval - // Wait for server-sent keep-alive till 3/2 of keepalive interval - // Just to make sure the broker will not disconnect us - const int32_t keepalive_66pct = pingOutstanding - ? keepAlive_sec * 1500 - : keepAlive_sec * 666; - if (((int32_t)(t - lastInActivity) > keepalive_66pct) || - ((int32_t)(t - lastOutActivity) > keepalive_66pct)) { - if (pingOutstanding) { - this->_state = MQTT_CONNECTION_TIMEOUT; - _client->stop(); - return false; - } else { - buffer[0] = MQTTPINGREQ; - buffer[1] = 0; - if (_client->write(buffer,2) != 0) { - lastOutActivity = t; - lastInActivity = t; - } - pingOutstanding = true; - } - } - return true; - } - return false; -} - -boolean PubSubClient::publish(const char* topic, const char* payload) { - size_t plength = (payload != nullptr) ? strlen(payload) : 0; - return publish(topic,(const uint8_t*)payload,plength,false); -} - -boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { - size_t plength = (payload != nullptr) ? strlen(payload) : 0; - return publish(topic,(const uint8_t*)payload,plength,retained); -} - -boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { - return publish(topic, payload, plength, false); -} - -boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { - if (!beginPublish(topic, plength, retained)) { - return false; - } - for (unsigned int i=0;iwrite(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen)); - if (rc > 0) { - lastOutActivity = millis(); - } - return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen))); - } - return false; -} - -int PubSubClient::endPublish() { - flushBuffer(); - return 1; -} - -size_t PubSubClient::write(uint8_t data) { - if (_client == nullptr) { - lastOutActivity = millis(); - return 0; - } - size_t rc = appendBuffer(data); - if (rc != 0) { - lastOutActivity = millis(); - } - return rc; -} - -size_t PubSubClient::write(const uint8_t *data, size_t size) { - if (_client == nullptr) { - lastOutActivity = millis(); - return 0; - } - size_t rc = appendBuffer(data,size); - if (rc != 0) { - lastOutActivity = millis(); - } - return rc; -} - -size_t PubSubClient::write(const String& message) { - return write(reinterpret_cast(message.c_str()), message.length()); -} - - -size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint32_t length) { - uint8_t lenBuf[4]; - uint8_t llen = 0; - uint8_t digit; - uint8_t pos = 0; - uint32_t len = length; - do { - digit = len % 128; - len = len / 128; - if (len > 0) { - digit |= 0x80; - } - lenBuf[pos++] = digit; - llen++; - } while(len>0 && pos < 4); - - buf[4-llen] = header; - for (int i=0;i 0) && result) { - delay(0); // Prevent watchdog crashes - bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining; - rc = _client->write(writeBuf,bytesToWrite); - result = (rc == bytesToWrite); - bytesRemaining -= rc; - writeBuf += rc; - if (rc != 0) { - lastOutActivity = millis(); - } - } - return result; -#else - rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen); - if (rc != 0) { - lastOutActivity = millis(); - } - return (rc == hlen+length); -#endif -} - -boolean PubSubClient::subscribe(const char* topic) { - return subscribe(topic, 0); -} - -boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { - if (qos > 1) { - return false; - } - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { - // Too long - return false; - } - if (connected()) { - // Leave room in the buffer for header and variable length field - uint16_t length = MQTT_MAX_HEADER_SIZE; - nextMsgId++; - if (nextMsgId == 0) { - nextMsgId = 1; - } - buffer[length++] = (nextMsgId >> 8); - buffer[length++] = (nextMsgId & 0xFF); - length = writeString((char*)topic, buffer,length); - buffer[length++] = qos; - return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE); - } - return false; -} - -boolean PubSubClient::unsubscribe(const char* topic) { - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { - // Too long - return false; - } - if (connected()) { - uint16_t length = MQTT_MAX_HEADER_SIZE; - nextMsgId++; - if (nextMsgId == 0) { - nextMsgId = 1; - } - buffer[length++] = (nextMsgId >> 8); - buffer[length++] = (nextMsgId & 0xFF); - length = writeString(topic, buffer,length); - return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE); - } - return false; -} - -void PubSubClient::disconnect() { - if (_state == MQTT_DISCONNECTED || !initBuffer()) { - _state = MQTT_DISCONNECTED; - lastInActivity = lastOutActivity = millis(); - - return; - } - - buffer[0] = MQTTDISCONNECT; - buffer[1] = 0; - if (_client != nullptr) { - _client->write(buffer,2); - _client->flush(); - _client->stop(); - } - _state = MQTT_DISCONNECTED; - lastInActivity = lastOutActivity = millis(); -} - -uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) { - const char* idp = string; - uint16_t i = 0; - pos += 2; - while (*idp && pos < (MQTT_MAX_PACKET_SIZE - 2)) { - buf[pos++] = *idp++; - i++; - } - buf[pos-i-2] = (i >> 8); - buf[pos-i-1] = (i & 0xFF); - return pos; -} - -size_t PubSubClient::appendBuffer(uint8_t data) { - if (!initBuffer()) { - return 0; - } - - buffer[_bufferWritePos] = data; - ++_bufferWritePos; - if (_bufferWritePos >= MQTT_MAX_PACKET_SIZE) { - if (flushBuffer() == 0) return 0; - } - return 1; -} - -size_t PubSubClient::appendBuffer(const uint8_t *data, size_t size) { - for (size_t i = 0; i < size; ++i) { - if (appendBuffer(data[i]) == 0) return i; - } - return size; -} - -size_t PubSubClient::flushBuffer() { - size_t rc = 0; - if (_bufferWritePos > 0) { - if (connected()) { - rc = _client->write(buffer, _bufferWritePos); - if (rc != 0) { - lastOutActivity = millis(); - } - } - _bufferWritePos = 0; - } - return rc; -} - -bool PubSubClient::initBuffer() -{ - constexpr size_t size = sizeof(uint8_t) * MQTT_MAX_PACKET_SIZE; - if (buffer == nullptr) { -#ifdef ESP32 - buffer = (uint8_t*) heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - if (buffer == nullptr) { - buffer = (uint8_t*) malloc(size); - } -#else - { -#ifdef USE_SECOND_HEAP - // Try allocating on ESP8266 2nd heap - HeapSelectIram ephemeral; -#endif - buffer = (uint8_t*) malloc(size); - if (buffer != nullptr) return true; - } -#ifdef USE_SECOND_HEAP - // Not successful, try allocating on (ESP8266) main heap - HeapSelectDram ephemeral; -#endif - buffer = (uint8_t*) malloc(size); -#endif - } - return buffer != nullptr; -} - -boolean PubSubClient::connected() { - if (_client == NULL ) { - this->_state = MQTT_DISCONNECTED; - return false; - } - if (_client->connected() == 0) { - bool lastStateConnected = this->_state == MQTT_CONNECTED; - this->disconnect(); - if (lastStateConnected) { - this->_state = MQTT_CONNECTION_LOST; - } - return false; - } - return this->_state == MQTT_CONNECTED; -} - -PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) { - IPAddress addr(ip[0],ip[1],ip[2],ip[3]); - return setServer(addr,port); -} - -PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) { - this->ip = ip; - this->port = port; - this->domain = ""; - return *this; -} - -PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) { - this->domain = domain; - this->port = port; - return *this; -} - -PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) { - this->callback = callback; - return *this; -} - -PubSubClient& PubSubClient::setClient(Client& client){ - this->_client = &client; - return *this; -} - -PubSubClient& PubSubClient::setStream(Stream& stream){ - this->stream = &stream; - return *this; -} - -int PubSubClient::state() { - return this->_state; -} - -PubSubClient& PubSubClient::setKeepAlive(uint16_t keepAlive_sec) { - this->keepAlive_sec = keepAlive_sec; - return *this; -} - -PubSubClient& PubSubClient::setSocketTimeout(uint16_t timeout_ms) { - this->socketTimeout_msec = timeout_ms; - return *this; -} \ No newline at end of file diff --git a/lib/pubsubclient/src/PubSubClient.h b/lib/pubsubclient/src/PubSubClient.h deleted file mode 100644 index 4a59af578..000000000 --- a/lib/pubsubclient/src/PubSubClient.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - PubSubClient.h - A simple client for MQTT. - Nick O'Leary - http://knolleary.net -*/ - -#ifndef PubSubClient_h -#define PubSubClient_h - -#include -#include "IPAddress.h" -#include "Client.h" -#include "Stream.h" - -#define MQTT_VERSION_3_1 3 -#define MQTT_VERSION_3_1_1 4 - -// MQTT_VERSION : Pick the version -//#define MQTT_VERSION MQTT_VERSION_3_1 -#ifndef MQTT_VERSION -#define MQTT_VERSION MQTT_VERSION_3_1_1 -#endif - -// MQTT_MAX_PACKET_SIZE : Maximum packet size -#ifndef MQTT_MAX_PACKET_SIZE - // need to fix this here, because this define cannot be overruled within the Arduino sketch... - #define MQTT_MAX_PACKET_SIZE 1024 -#endif - -// MQTT_KEEPALIVE : keepAlive interval in Seconds -// Keepalive timeout for default MQTT Broker is 10s -#ifndef MQTT_KEEPALIVE -#define MQTT_KEEPALIVE 10 -#endif - -// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds -#ifndef MQTT_SOCKET_TIMEOUT -#define MQTT_SOCKET_TIMEOUT 15 -#endif - -// ESP32_CONNECTION_TIMEOUT : Specific case for ESP32, we need to manually provide timeout as default (-1) leads to WDT reset (after 5 seconds). -// By default (4500 milliseconds) 4,5 seconds to avoid reaching 5s default watchdog reset time. -// This is multiplied in WiFiClient.cpp (part of arduino-esp32) by 1000 inside [WiFiClient::connect] method. -// ESP8266 Arduino framework in contrast has fixed 5000ms timeout. No need to define it manually here. -// See: https://github.com/knolleary/pubsubclient/pull/842 -#ifndef ESP32_CONNECTION_TIMEOUT -#define ESP32_CONNECTION_TIMEOUT 4500 -#endif - -// MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client -// in each write call. Needed for the Arduino Wifi Shield. Leave undefined to -// pass the entire MQTT packet in each write call. -//#define MQTT_MAX_TRANSFER_SIZE 80 - -// Possible values for client.state() -#define MQTT_CONNECTION_TIMEOUT -4 -#define MQTT_CONNECTION_LOST -3 -#define MQTT_CONNECT_FAILED -2 -#define MQTT_DISCONNECTED -1 -#define MQTT_CONNECTED 0 -#define MQTT_CONNECT_BAD_PROTOCOL 1 -#define MQTT_CONNECT_BAD_CLIENT_ID 2 -#define MQTT_CONNECT_UNAVAILABLE 3 -#define MQTT_CONNECT_BAD_CREDENTIALS 4 -#define MQTT_CONNECT_UNAUTHORIZED 5 - -#define MQTTCONNECT 1 << 4 // Client request to connect to Server -#define MQTTCONNACK 2 << 4 // Connect Acknowledgment -#define MQTTPUBLISH 3 << 4 // Publish message -#define MQTTPUBACK 4 << 4 // Publish Acknowledgment -#define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1) -#define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2) -#define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3) -#define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request -#define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment -#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request -#define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment -#define MQTTPINGREQ 12 << 4 // PING Request -#define MQTTPINGRESP 13 << 4 // PING Response -#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting -#define MQTTReserved 15 << 4 // Reserved - -#define MQTTQOS0 (0 << 1) -#define MQTTQOS1 (1 << 1) -#define MQTTQOS2 (2 << 1) - -// Maximum size of fixed header and variable length size header -#define MQTT_MAX_HEADER_SIZE 5 - -#if defined(ESP8266) || defined(ESP32) -#include -#define MQTT_CALLBACK_SIGNATURE std::function callback -#else -#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) -#endif - -#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;} - -class PubSubClient : public Print { -private: - Client* _client; - uint8_t *buffer = nullptr; - uint16_t nextMsgId = 0; - unsigned long lastOutActivity = 0; - unsigned long lastInActivity = 0; - bool pingOutstanding = false; - MQTT_CALLBACK_SIGNATURE; - // Try to read from the client whatever is available. - bool loop_read(); - uint16_t readPacket(uint8_t*); - boolean readByte(uint8_t * result); - boolean readByte(uint8_t * result, uint16_t * index); - boolean write(uint8_t header, uint8_t* buf, uint32_t length); - uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos); - // Build up the header ready to send - // Returns the size of the header - // Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start - // (MQTT_MAX_HEADER_SIZE - ) bytes into the buffer - size_t buildHeader(uint8_t header, uint8_t* buf, uint32_t length); - - // Add to buffer and flush if full (only to be used with beginPublish/endPublish) - size_t appendBuffer(uint8_t data); - size_t appendBuffer(const uint8_t *data, size_t size); - size_t flushBuffer(); - - bool initBuffer(); - - IPAddress ip; - String domain; - uint16_t port = 0; - Stream* stream; - int _state = MQTT_DISCONNECTED; - int _bufferWritePos = 0; - int16_t keepAlive_sec = MQTT_KEEPALIVE; - int16_t socketTimeout_msec = MQTT_SOCKET_TIMEOUT*1000; -public: - PubSubClient(); - PubSubClient(Client& client); - PubSubClient(IPAddress, uint16_t, Client& client); - PubSubClient(IPAddress, uint16_t, Client& client, Stream&); - PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); - PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); - PubSubClient(uint8_t *, uint16_t, Client& client); - PubSubClient(uint8_t *, uint16_t, Client& client, Stream&); - PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); - PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); - PubSubClient(const char*, uint16_t, Client& client); - PubSubClient(const char*, uint16_t, Client& client, Stream&); - PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); - PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); - virtual ~PubSubClient(); - - PubSubClient& setServer(IPAddress ip, uint16_t port); - PubSubClient& setServer(uint8_t * ip, uint16_t port); - PubSubClient& setServer(const char * domain, uint16_t port); - PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); - PubSubClient& setClient(Client& client); - PubSubClient& setStream(Stream& stream); - - boolean connect(const char* id); - boolean connect(const char* id, const char* user, const char* pass); - boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); - boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); - boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession); - void disconnect(); - boolean publish(const char* topic, const char* payload); - boolean publish(const char* topic, const char* payload, boolean retained); - boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); - boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); - boolean publish_P(const char* topic, const char* payload, boolean retained); - boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); - // Start to publish a message. - // This API: - // beginPublish(...) - // one or more calls to write(...) - // endPublish() - // Allows for arbitrarily large payloads to be sent without them having to be copied into - // a new buffer and held in memory at one time - // Returns 1 if the message was started successfully, 0 if there was an error - boolean beginPublish(const char* topic, unsigned int plength, boolean retained); - // Finish off this publish message (started with beginPublish) - // Returns 1 if the packet was sent successfully, 0 if there was an error - int endPublish(); - // Write a single byte of payload (only to be used with beginPublish/endPublish) - virtual size_t write(uint8_t); - // Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish) - // Returns the number of bytes written - virtual size_t write(const uint8_t *buffer, size_t size); - // Write string into the payload (only to be used with beginPublish/endPublish) - size_t write(const String& message); - - - boolean subscribe(const char* topic); - boolean subscribe(const char* topic, uint8_t qos); - boolean unsubscribe(const char* topic); - boolean loop(); - boolean connected(); - int state(); - - PubSubClient& setKeepAlive(uint16_t keepAlive_sec); - PubSubClient& setSocketTimeout(uint16_t timeout_ms); -}; - - -#endif diff --git a/lib/pubsubclient/tests/src/connect_spec.cpp b/lib/pubsubclient/tests/src/connect_spec.cpp deleted file mode 100644 index e27a1f59f..000000000 --- a/lib/pubsubclient/tests/src/connect_spec.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include "PubSubClient.h" -#include "ShimClient.h" -#include "Buffer.h" -#include "BDDTest.h" -#include "trace.h" - - -byte server[] = { 172, 16, 0, 2 }; - -void callback(char* topic, byte* payload, unsigned int length) { - // handle message arrived -} - - -int test_connect_fails_no_network() { - IT("fails to connect if underlying client doesn't connect"); - ShimClient shimClient; - shimClient.setAllowConnect(false); - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_FALSE(rc); - int state = client.state(); - IS_TRUE(state == MQTT_CONNECT_FAILED); - END_IT -} - -int test_connect_fails_on_no_response() { - IT("fails to connect if no response received after 15 seconds"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_FALSE(rc); - int state = client.state(); - IS_TRUE(state == MQTT_CONNECTION_TIMEOUT); - END_IT -} - -int test_connect_properly_formatted() { - IT("sends a properly formatted connect packet and succeeds"); - ShimClient shimClient; - - shimClient.setAllowConnect(true); - byte expectServer[] = { 172, 16, 0, 2 }; - shimClient.expectConnect(expectServer,1883); - byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - - shimClient.expect(connect,26); - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int state = client.state(); - IS_TRUE(state == MQTT_DISCONNECTED); - - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - state = client.state(); - IS_TRUE(state == MQTT_CONNECTED); - - END_IT -} - -int test_connect_properly_formatted_hostname() { - IT("accepts a hostname"); - ShimClient shimClient; - - shimClient.setAllowConnect(true); - shimClient.expectConnect((char* const)"localhost",1883); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client((char* const)"localhost", 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - END_IT -} - - -int test_connect_fails_on_bad_rc() { - IT("fails to connect if a bad return code is received"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x01 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_FALSE(rc); - - int state = client.state(); - IS_TRUE(state == 0x01); - - END_IT -} - -int test_connect_non_clean_session() { - IT("sends a properly formatted non-clean session connect packet and succeeds"); - ShimClient shimClient; - - shimClient.setAllowConnect(true); - byte expectServer[] = { 172, 16, 0, 2 }; - shimClient.expectConnect(expectServer,1883); - byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x0,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - - shimClient.expect(connect,26); - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int state = client.state(); - IS_TRUE(state == MQTT_DISCONNECTED); - - int rc = client.connect((char*)"client_test1",0,0,0,0,0,0,0); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - state = client.state(); - IS_TRUE(state == MQTT_CONNECTED); - - END_IT -} - -int test_connect_accepts_username_password() { - IT("accepts a username and password"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connect[] = { 0x10,0x24,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x4,0x70,0x61,0x73,0x73}; - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,0x26); - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass"); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_connect_accepts_username_no_password() { - IT("accepts a username but no password"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connect[] = { 0x10,0x1e,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x82,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72}; - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,0x20); - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1",(char*)"user",0); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - END_IT -} -int test_connect_accepts_username_blank_password() { - IT("accepts a username and blank password"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connect[] = { 0x10,0x20,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x0}; - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,0x26); - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass"); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_connect_ignores_password_no_username() { - IT("ignores a password but no username"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,26); - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1",0,(char*)"pass"); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_connect_with_will() { - IT("accepts a will"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connect[] = {0x10,0x30,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xe,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65}; - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,0x32); - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1",(char*)"willTopic",1,0,(char*)"willMessage"); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_connect_with_will_username_password() { - IT("accepts a will, username and password"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connect[] = {0x10,0x40,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xce,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x8,0x70,0x61,0x73,0x73,0x77,0x6f,0x72,0x64}; - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,0x42); - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"password",(char*)"willTopic",1,0,(char*)"willMessage"); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_connect_disconnect_connect() { - IT("connects, disconnects and connects again"); - ShimClient shimClient; - - shimClient.setAllowConnect(true); - byte expectServer[] = { 172, 16, 0, 2 }; - shimClient.expectConnect(expectServer,1883); - byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - - shimClient.expect(connect,26); - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - - int state = client.state(); - IS_TRUE(state == MQTT_DISCONNECTED); - - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - - state = client.state(); - IS_TRUE(state == MQTT_CONNECTED); - - byte disconnect[] = {0xE0,0x00}; - shimClient.expect(disconnect,2); - - client.disconnect(); - - IS_FALSE(client.connected()); - IS_FALSE(shimClient.connected()); - IS_FALSE(shimClient.error()); - - state = client.state(); - IS_TRUE(state == MQTT_DISCONNECTED); - - shimClient.expect(connect,28); - shimClient.respond(connack,4); - rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - IS_FALSE(shimClient.error()); - state = client.state(); - IS_TRUE(state == MQTT_CONNECTED); - - END_IT -} - -int main() -{ - SUITE("Connect"); - - test_connect_fails_no_network(); - test_connect_fails_on_no_response(); - - test_connect_properly_formatted(); - test_connect_non_clean_session(); - test_connect_accepts_username_password(); - test_connect_fails_on_bad_rc(); - test_connect_properly_formatted_hostname(); - - test_connect_accepts_username_no_password(); - test_connect_ignores_password_no_username(); - test_connect_with_will(); - test_connect_with_will_username_password(); - test_connect_disconnect_connect(); - FINISH -} diff --git a/lib/pubsubclient/tests/src/lib/Arduino.h b/lib/pubsubclient/tests/src/lib/Arduino.h deleted file mode 100644 index 2a00f24bc..000000000 --- a/lib/pubsubclient/tests/src/lib/Arduino.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef Arduino_h -#define Arduino_h - -#include -#include -#include -#include -#include "Print.h" - - -extern "C"{ - typedef uint8_t byte ; - typedef uint8_t boolean ; - - /* sketch */ - extern void setup( void ) ; - extern void loop( void ) ; - uint32_t millis( void ); -} - -#define PROGMEM -#define pgm_read_byte_near(x) *(x) - -#define yield(x) {} - -#endif // Arduino_h diff --git a/lib/pubsubclient/tests/src/lib/Client.h b/lib/pubsubclient/tests/src/lib/Client.h deleted file mode 100644 index 9e18c0764..000000000 --- a/lib/pubsubclient/tests/src/lib/Client.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef client_h -#define client_h -#include "IPAddress.h" - -class Client { -public: - virtual int connect(IPAddress ip, uint16_t port) =0; - virtual int connect(const char *host, uint16_t port) =0; - virtual size_t write(uint8_t) =0; - virtual size_t write(const uint8_t *buf, size_t size) =0; - virtual int available() = 0; - virtual int read() = 0; - virtual int read(uint8_t *buf, size_t size) = 0; - virtual int peek() = 0; - virtual void flush() = 0; - virtual void stop() = 0; - virtual uint8_t connected() = 0; - virtual operator bool() = 0; -}; - -#endif diff --git a/lib/pubsubclient/tests/src/lib/ShimClient.h b/lib/pubsubclient/tests/src/lib/ShimClient.h deleted file mode 100644 index 2e3f874fc..000000000 --- a/lib/pubsubclient/tests/src/lib/ShimClient.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef shimclient_h -#define shimclient_h - -#include "Arduino.h" -#include "Client.h" -#include "IPAddress.h" -#include "Buffer.h" - - -class ShimClient : public Client { -private: - Buffer* responseBuffer; - Buffer* expectBuffer; - bool _allowConnect; - bool _connected; - bool expectAnything; - bool _error; - uint16_t _received; - IPAddress _expectedIP; - uint16_t _expectedPort; - const char* _expectedHost; - -public: - ShimClient(); - virtual int connect(IPAddress ip, uint16_t port); - virtual int connect(const char *host, uint16_t port); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *buf, size_t size); - virtual int available(); - virtual int read(); - virtual int read(uint8_t *buf, size_t size); - virtual int peek(); - virtual void flush(); - virtual void stop(); - virtual uint8_t connected(); - virtual operator bool(); - - virtual ShimClient* respond(uint8_t *buf, size_t size); - virtual ShimClient* expect(uint8_t *buf, size_t size); - - virtual void expectConnect(IPAddress ip, uint16_t port); - virtual void expectConnect(const char *host, uint16_t port); - - virtual uint16_t received(); - virtual bool error(); - - virtual void setAllowConnect(bool b); - virtual void setConnected(bool b); -}; - -#endif diff --git a/lib/pubsubclient/tests/src/publish_spec.cpp b/lib/pubsubclient/tests/src/publish_spec.cpp deleted file mode 100644 index 232df0d37..000000000 --- a/lib/pubsubclient/tests/src/publish_spec.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include "PubSubClient.h" -#include "ShimClient.h" -#include "Buffer.h" -#include "BDDTest.h" -#include "trace.h" - - -byte server[] = { 172, 16, 0, 2 }; - -void callback(char* topic, byte* payload, unsigned int length) { - // handle message arrived -} - -int test_publish() { - IT("publishes a null-terminated string"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - shimClient.expect(publish,16); - - rc = client.publish((char*)"topic",(char*)"payload"); - IS_TRUE(rc); - - IS_FALSE(shimClient.error()); - - END_IT -} - - -int test_publish_bytes() { - IT("publishes a byte array"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte payload[] = { 0x01,0x02,0x03,0x0,0x05 }; - int length = 5; - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - byte publish[] = {0x30,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5}; - shimClient.expect(publish,14); - - rc = client.publish((char*)"topic",payload,length); - IS_TRUE(rc); - - IS_FALSE(shimClient.error()); - - END_IT -} - - -int test_publish_retained() { - IT("publishes retained - 1"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte payload[] = { 0x01,0x02,0x03,0x0,0x05 }; - int length = 5; - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5}; - shimClient.expect(publish,14); - - rc = client.publish((char*)"topic",payload,length,true); - IS_TRUE(rc); - - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_publish_retained_2() { - IT("publishes retained - 2"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,'A','B','C','D','E'}; - shimClient.expect(publish,14); - - rc = client.publish((char*)"topic",(char*)"ABCDE",true); - IS_TRUE(rc); - - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_publish_not_connected() { - IT("publish fails when not connected"); - ShimClient shimClient; - - PubSubClient client(server, 1883, callback, shimClient); - - int rc = client.publish((char*)"topic",(char*)"payload"); - IS_FALSE(rc); - - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_publish_too_long() { - IT("publish fails when topic/payload are too long"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - // 0 1 2 3 4 5 6 7 8 9 0 1 2 - rc = client.publish((char*)"topic",(char*)"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); - IS_FALSE(rc); - - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_publish_P() { - IT("publishes using PROGMEM"); - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte payload[] = { 0x01,0x02,0x03,0x0,0x05 }; - int length = 5; - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5}; - shimClient.expect(publish,14); - - rc = client.publish_P((char*)"topic",payload,length,true); - IS_TRUE(rc); - - IS_FALSE(shimClient.error()); - - END_IT -} - - - - -int main() -{ - SUITE("Publish"); - test_publish(); - test_publish_bytes(); - test_publish_retained(); - test_publish_retained_2(); - test_publish_not_connected(); - test_publish_too_long(); - test_publish_P(); - - FINISH -} diff --git a/lib/pubsubclient/tests/src/receive_spec.cpp b/lib/pubsubclient/tests/src/receive_spec.cpp deleted file mode 100644 index 9a18af042..000000000 --- a/lib/pubsubclient/tests/src/receive_spec.cpp +++ /dev/null @@ -1,279 +0,0 @@ -#include "PubSubClient.h" -#include "ShimClient.h" -#include "Buffer.h" -#include "BDDTest.h" -#include "trace.h" - - -byte server[] = { 172, 16, 0, 2 }; - -bool callback_called = false; -char lastTopic[1024]; -char lastPayload[1024]; -unsigned int lastLength; - -void reset_callback() { - callback_called = false; - lastTopic[0] = '\0'; - lastPayload[0] = '\0'; - lastLength = 0; -} - -void callback(char* topic, byte* payload, unsigned int length) { - callback_called = true; - strcpy(lastTopic,topic); - memcpy(lastPayload,payload,length); - lastLength = length; -} - -int test_receive_callback() { - IT("receives a callback message"); - reset_callback(); - - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - shimClient.respond(publish,16); - - rc = client.loop(); - - IS_TRUE(rc); - - IS_TRUE(callback_called); - IS_TRUE(strcmp(lastTopic,"topic")==0); - IS_TRUE(memcmp(lastPayload,"payload",7)==0); - IS_TRUE(lastLength == 7); - - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_receive_stream() { - IT("receives a streamed callback message"); - reset_callback(); - - Stream stream; - stream.expect((uint8_t*)"payload",7); - - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient, stream); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - shimClient.respond(publish,16); - - rc = client.loop(); - - IS_TRUE(rc); - - IS_TRUE(callback_called); - IS_TRUE(strcmp(lastTopic,"topic")==0); - IS_TRUE(lastLength == 7); - - IS_FALSE(stream.error()); - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_receive_max_sized_message() { - IT("receives an max-sized message"); - reset_callback(); - - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - int length = MQTT_MAX_PACKET_SIZE; - byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - byte bigPublish[length]; - memset(bigPublish,'A',length); - bigPublish[length] = 'B'; - memcpy(bigPublish,publish,16); - shimClient.respond(bigPublish,length); - - rc = client.loop(); - - IS_TRUE(rc); - - IS_TRUE(callback_called); - IS_TRUE(strcmp(lastTopic,"topic")==0); - IS_TRUE(lastLength == length-9); - IS_TRUE(memcmp(lastPayload,bigPublish+9,lastLength)==0); - - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_receive_oversized_message() { - IT("drops an oversized message"); - reset_callback(); - - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - int length = MQTT_MAX_PACKET_SIZE+1; - byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - byte bigPublish[length]; - memset(bigPublish,'A',length); - bigPublish[length] = 'B'; - memcpy(bigPublish,publish,16); - shimClient.respond(bigPublish,length); - - rc = client.loop(); - - IS_TRUE(rc); - - IS_FALSE(callback_called); - - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_drop_invalid_remaining_length_message() { - IT("drops invalid remaining length message"); - reset_callback(); - - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - byte publish[] = {0x30,0x92,0x92,0x92,0x92,0x01,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - shimClient.respond(publish,20); - - rc = client.loop(); - - IS_FALSE(rc); - - IS_FALSE(callback_called); - - IS_FALSE(shimClient.error()); - - END_IT -} - - -int test_receive_oversized_stream_message() { - IT("drops an oversized message"); - reset_callback(); - - Stream stream; - - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient, stream); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - int length = MQTT_MAX_PACKET_SIZE+1; - byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - - byte bigPublish[length]; - memset(bigPublish,'A',length); - bigPublish[length] = 'B'; - memcpy(bigPublish,publish,16); - - shimClient.respond(bigPublish,length); - stream.expect(bigPublish+9,length-9); - - rc = client.loop(); - - IS_TRUE(rc); - - IS_TRUE(callback_called); - IS_TRUE(strcmp(lastTopic,"topic")==0); - IS_TRUE(lastLength == length-9); - - IS_FALSE(stream.error()); - IS_FALSE(shimClient.error()); - - END_IT -} - -int test_receive_qos1() { - IT("receives a qos1 message"); - reset_callback(); - - ShimClient shimClient; - shimClient.setAllowConnect(true); - - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); - - PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); - IS_TRUE(rc); - - byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - shimClient.respond(publish,18); - - byte puback[] = {0x40,0x2,0x12,0x34}; - shimClient.expect(puback,4); - - rc = client.loop(); - - IS_TRUE(rc); - - IS_TRUE(callback_called); - IS_TRUE(strcmp(lastTopic,"topic")==0); - IS_TRUE(memcmp(lastPayload,"payload",7)==0); - IS_TRUE(lastLength == 7); - - IS_FALSE(shimClient.error()); - - END_IT -} - -int main() -{ - SUITE("Receive"); - test_receive_callback(); - test_receive_stream(); - test_receive_max_sized_message(); - test_drop_invalid_remaining_length_message(); - test_receive_oversized_message(); - test_receive_oversized_stream_message(); - test_receive_qos1(); - - FINISH -} diff --git a/lib/pubsubclient3/.clang-format b/lib/pubsubclient3/.clang-format new file mode 100644 index 000000000..a96fa8ab5 --- /dev/null +++ b/lib/pubsubclient3/.clang-format @@ -0,0 +1,8 @@ +BasedOnStyle: Google +Language: Cpp +IndentWidth: 4 +ColumnLimit: 155 +AllowShortFunctionsOnASingleLine: Empty +AlignConsecutiveMacros: Consecutive +SkipMacroDefinitionBody: true +LineEnding: LF diff --git a/lib/pubsubclient3/.editorconfig b/lib/pubsubclient3/.editorconfig new file mode 100644 index 000000000..392dfa64d --- /dev/null +++ b/lib/pubsubclient3/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{c,cpp}] +indent_style = space +indent_size = 4 +max_line_length = 155 + +[*.py] +indent_style = space +indent_size = 4 +max_line_length = 155 diff --git a/lib/pubsubclient3/.github/build-arduino.sh b/lib/pubsubclient3/.github/build-arduino.sh new file mode 100644 index 000000000..551fe8bd7 --- /dev/null +++ b/lib/pubsubclient3/.github/build-arduino.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# Exit immediately if a command exits with a non-zero status. +set -e +# Enable the globstar shell option +shopt -s globstar +# Make sure we are inside the github workspace +cd $GITHUB_WORKSPACE +# Create directories +mkdir $HOME/Arduino +mkdir $HOME/Arduino/libraries +# Install Arduino IDE +export PATH=$PATH:$GITHUB_WORKSPACE/bin +curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh +arduino-cli config init +arduino-cli config add board_manager.additional_urls http://arduino.esp8266.com/stable/package_esp8266com_index.json +arduino-cli config set library.enable_unsafe_install true +arduino-cli core update-index +#arduino-cli core search +# Install Arduino cores +arduino-cli core install arduino:avr +arduino-cli core install esp8266:esp8266 +arduino-cli core install esp32:esp32 +#arduino-cli board listall +# Install Arduino libs +arduino-cli lib install Ethernet +arduino-cli lib install --git-url https://github.com/ennui2342/arduino-sram +# Link the project to the Arduino library +ln -s $GITHUB_WORKSPACE $HOME/Arduino/libraries/CI_Test_Library + +# Compile all *.ino files for the Arduino +for f in **/*.ino ; do + if [[ "$f" != *mqtt_esp8266.ino && "$f" != *mqtt_large_message.ino ]]; then + echo "################################################################" + echo "Arduino Uno compiling file ${f}" + arduino-cli compile -b arduino:avr:uno $f + fi +done + +# Compile all *.ino files for the ESP32 +for f in **/*.ino ; do + if [[ "$f" != *"mqtt_stream.ino" ]]; then + echo "################################################################" + echo "ESP32 compiling file ${f}" + arduino-cli compile -b esp32:esp32:esp32 $f + fi +done + +# Compile all *.ino files for the ESP8266 +for f in **/*.ino ; do + echo "################################################################" + echo "ESP8266 compiling file ${f}" + arduino-cli compile -b esp8266:esp8266:generic $f +done diff --git a/lib/pubsubclient3/.github/clang-lint.sh b/lib/pubsubclient3/.github/clang-lint.sh new file mode 100644 index 000000000..2018fd2be --- /dev/null +++ b/lib/pubsubclient3/.github/clang-lint.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Exit immediately if a command exits with a non-zero status. +set -e +# Enable the globstar shell option +shopt -s globstar +# Make sure we are inside the github workspace +cd $GITHUB_WORKSPACE +# Install clang-format (if not already installed) +#command -v clang-format >/dev/null 2>&1 || sudo apt-get -y install clang-format +# need Ubuntu clang-format version 19.1.1 (1ubuntu1~24.04.2) +# default Ubuntu clang-format version 18.1.3 (1ubuntu1) is not working +sudo apt-get -y install clang-format-19 +# Check clang-format output +for f in **/*.{h,c,hpp,cpp,ino} ; do + #if [ -f "$f" ] && [[ "$f" != "tests/"* ]]; then + if [ -f "$f" ]; then + echo "################################################################" + echo "Checking file ${f}" + diff $f <(clang-format-19 -assume-filename=main.cpp $f) 1>&2 + fi +done diff --git a/lib/pubsubclient3/.github/workflows/build.yml b/lib/pubsubclient3/.github/workflows/build.yml new file mode 100644 index 000000000..f8c919060 --- /dev/null +++ b/lib/pubsubclient3/.github/workflows/build.yml @@ -0,0 +1,31 @@ +name: build + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Check clang-format conformity + run: bash .github/clang-lint.sh + + - name: Build tests + # Build / Execute tests defined in tests folder + working-directory: ${{ github.workspace }}/tests + run: make + + - name: Execute tests + # Build / Execute tests defined in tests folder + working-directory: ${{ github.workspace }}/tests + #run: make test + run: bin/connect_spec && bin/publish_spec && bin/receive_spec && bin/subscribe_spec + + - name: Build on Arduino CLI + run: bash .github/build-arduino.sh diff --git a/lib/pubsubclient3/.gitignore b/lib/pubsubclient3/.gitignore new file mode 100644 index 000000000..a42cc406e --- /dev/null +++ b/lib/pubsubclient3/.gitignore @@ -0,0 +1,5 @@ +tests/bin +.pioenvs +.piolibdeps +.clang_complete +.gcc-flags.json diff --git a/lib/pubsubclient/.travis.yml b/lib/pubsubclient3/.travis.yml similarity index 100% rename from lib/pubsubclient/.travis.yml rename to lib/pubsubclient3/.travis.yml diff --git a/lib/pubsubclient3/CHANGES.txt b/lib/pubsubclient3/CHANGES.txt new file mode 100644 index 000000000..c06984322 --- /dev/null +++ b/lib/pubsubclient3/CHANGES.txt @@ -0,0 +1,136 @@ +3.1.0 + * Fix setServer(domain, ...) by copy domain string to own buffer (prevent potential dangling string pointer) #10 + * Connect to broker only if port != 0 (e.g. in case of incorrect PubSubClient initialization) #10 + * Refactored different buffer length types to size_t #11 + * Added a bunch of warnings and -Werror to tests Makefile #11 + * Reformatted tests code using Google sytle (see .clang-format) #11 + * Fix keepalive handling, thanks to @uschnindler providing this to thingsboard #14 + * Use initializer lists instead of assigning global members in constructor #15 + * Fix DEBUG_PSC_PRINTF outputs #18 + * Added ERROR_PSC_PRINTF and ERROR_PSC_PRINTF_P outputs #25 + * Introduce MQTTRETAINED flag instead of hard coding #21 + * Added documentation on readByte() and readPacket() functions #23 + * Refactored buildHeader() (change return type, use MQTT_MAX_HEADER_SIZE, locals) #22, #34, #37 + * Refactored readPacket() (changed return type to size_t, used MQTT_MAX_HEADER_SIZE, locals) #23 + * Refactored readByte() #23 + * Refactored beginPublish() and endPublish() #28 + * Refactored publish() #31 + * Refactored publish_P() #30 + * Refactored connect() #40 + * Refactored connected() (mostly rewritten and simplified, added setting pingOutstanding, don't need flush()) #44 + * Refactored subscribe() and unsubscribe() #44 + * Refactored internal socketTimeout and keepAlive to millis to improve performance #33, #38, #39 + * Fix potential memory corruption in MQTTPUBLISH callback preparation #25 + * Fix potential error in readByte() (missing failure test on _client->read()) #32 + * Switch from constructor init-lists to class member initialization, see C++ core guideline C.45 #42 + +3.0.2 + * Added github workflow to execute tests + * Added github workflow to compile examples using arduino-cli + * Examples: Use a better source of random #9 + * Deactivate use of std::function on demand #7 + +3.0.1 + * Reformatted code using Google sytle (see .clang-format) + * Added .editorconfig + * Added github workflow to check code sytle on push and pull request + * Fix-tests: missing def for strlen_P & Python libs + +3.0 + * Maintenance taken over by Holger Mueller + * Adds in-source documentation to PubSubClient header. + * Add flag for enabling debugging of library + * Always use PubSubClient() constructor + * Use bool instead of boolean + * Add yield() calls in connect() and write() to avoid wdt resets if either blocks for too long + * Fix bug in publish_P which will always treat the payload length as 0 when used with PROGMEM + * Fix increase `bytesToWrite` to uint16_t to prevent overflow + * Remove compiler warning `expectedLength` should be unsigned + * Extend usage of std::function on all the platforms where it's available + * Fix for keep alive zero + +2.8 + * Add setBufferSize() to override MQTT_MAX_PACKET_SIZE + * Add setKeepAlive() to override MQTT_KEEPALIVE + * Add setSocketTimeout() to overide MQTT_SOCKET_TIMEOUT + * Added check to prevent subscribe/unsubscribe to empty topics + * Declare wifi mode prior to connect in ESP example + * Use `strnlen` to avoid overruns + * Support pre-connected Client objects + +2.7 + * Fix remaining-length handling to prevent buffer overrun + * Add large-payload API - beginPublish/write/publish/endPublish + * Add yield call to improve reliability on ESP + * Add Clean Session flag to connect options + * Add ESP32 support for functional callback signature + * Various other fixes + +2.4 + * Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely + whilst waiting for inbound data + * Fixed return code when publishing >256 bytes + +2.3 + * Add publish(topic,payload,retained) function + +2.2 + * Change code layout to match Arduino Library reqs + +2.1 + * Add MAX_TRANSFER_SIZE def to chunk messages if needed + * Reject topic/payloads that exceed MQTT_MAX_PACKET_SIZE + +2.0 + * Add (and default to) MQTT 3.1.1 support + * Fix PROGMEM handling for Intel Galileo/ESP8266 + * Add overloaded constructors for convenience + * Add chainable setters for server/callback/client/stream + * Add state function to return connack return code + +1.9 + * Do not split MQTT packets over multiple calls to _client->write() + * API change: All constructors now require an instance of Client + to be passed in. + * Fixed example to match 1.8 api changes - dpslwk + * Added username/password support - WilHall + * Added publish_P - publishes messages from PROGMEM - jobytaffey + +1.8 + * KeepAlive interval is configurable in PubSubClient.h + * Maximum packet size is configurable in PubSubClient.h + * API change: Return boolean rather than int from various functions + * API change: Length parameter in message callback changed + from int to unsigned int + * Various internal tidy-ups around types + +1.7 + * Improved keepalive handling + * Updated to the Arduino-1.0 API + +1.6 + * Added the ability to publish a retained message + +1.5 + * Added default constructor + * Fixed compile error when used with arduino-0021 or later + +1.4 + * Fixed connection lost handling + +1.3 + * Fixed packet reading bug in PubSubClient.readPacket + +1.2 + * Fixed compile error when used with arduino-0016 or later + +1.1 + * Reduced size of library + * Added support for Will messages + * Clarified licensing - see LICENSE.txt + +1.0 + * Only Quality of Service (QOS) 0 messaging is supported + * The maximum message size, including header, is 128 bytes + * The keepalive interval is set to 30 seconds + * No support for Will messages diff --git a/lib/pubsubclient/LICENSE.txt b/lib/pubsubclient3/LICENSE.txt similarity index 93% rename from lib/pubsubclient/LICENSE.txt rename to lib/pubsubclient3/LICENSE.txt index 217df35cc..3fa566ac0 100644 --- a/lib/pubsubclient/LICENSE.txt +++ b/lib/pubsubclient3/LICENSE.txt @@ -1,4 +1,5 @@ -Copyright (c) 2008-2015 Nicholas O'Leary +Copyright (c) 2008-2020 Nicholas O'Leary +Copyright (c) 2025 Holger Mueller Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/lib/pubsubclient/README.md b/lib/pubsubclient3/README.md similarity index 56% rename from lib/pubsubclient/README.md rename to lib/pubsubclient3/README.md index 69cbb8f0c..8233d8e11 100644 --- a/lib/pubsubclient/README.md +++ b/lib/pubsubclient3/README.md @@ -3,6 +3,22 @@ This library provides a client for doing simple publish/subscribe messaging with a server that supports MQTT. +## Notes of this fork + +This is a fork of the repository [knolleary/pubsubclient v2.8](https://github.com/knolleary/pubsubclient/releases/tag/v2.8), which was last updated in May 20, 2020. There was an update approach in [#1045](https://github.com/knolleary/pubsubclient/issues/1045), but it's also stale. + +I tried lot's of different other MQTT libs, but they need more resources than PubSubClient or lacking maintenance as well: + + - https://github.com/256dpi/arduino-mqtt + - https://github.com/hideakitai/MQTTPubSubClient + - https://github.com/bertmelis/espMqttClient + - https://github.com/arduino-libraries/ArduinoMqttClient + - https://github.com/thingsboard/pubsubclient + +Since there was no progress I decided to merge the most important PRs manually and publish a new major version. I also renamed to PubSubClient3 to have a similar but different name of the library. + +I appreciate every contribution to this library. + ## Examples The library comes with a number of example sketches. See File > Examples > PubSubClient @@ -12,11 +28,14 @@ Full API documentation is available here: https://pubsubclient.knolleary.net ## Limitations + - The client is based on the [MQTT Version 3.1.1 specification](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html) with some limitations. - It can only publish QoS 0 messages. It can subscribe at QoS 0 or QoS 1. - - The maximum message size, including header, is **128 bytes** by default. This - is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h`. + - The maximum message size, including header, is **256 bytes** by default. This + is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h` or can be changed + by calling `PubSubClient::setBufferSize(size)`. - The keepalive interval is set to 15 seconds by default. This is configurable - via `MQTT_KEEPALIVE` in `PubSubClient.h`. + via `MQTT_KEEPALIVE` in `PubSubClient.h` or can be changed by calling + `PubSubClient::setKeepAlive(keepAlive)`. - The client uses MQTT 3.1.1 by default. It can be changed to use MQTT 3.1 by changing value of `MQTT_VERSION` in `PubSubClient.h`. diff --git a/lib/pubsubclient3/examples/mqtt_auth/mqtt_auth.ino b/lib/pubsubclient3/examples/mqtt_auth/mqtt_auth.ino new file mode 100644 index 000000000..cdeb7959d --- /dev/null +++ b/lib/pubsubclient3/examples/mqtt_auth/mqtt_auth.ino @@ -0,0 +1,41 @@ +/* + Basic MQTT example with Authentication + + - connects to an MQTT server, providing username + and password + - publishes "hello world" to the topic "outTopic" + - subscribes to the topic "inTopic" +*/ + +#include +#include +#include + +// Update these with values suitable for your network. +byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED}; +IPAddress ip(172, 16, 0, 100); +IPAddress server(172, 16, 0, 2); + +void callback(char* topic, uint8_t* payload, size_t length) { + // handle message arrived +} + +EthernetClient ethClient; +PubSubClient client(server, 1883, callback, ethClient); + +void setup() { + Ethernet.begin(mac, ip); + // Note - the default maximum packet size is 128 bytes. If the + // combined length of clientId, username and password exceed this use the + // following to increase the buffer size: + // client.setBufferSize(255); + + if (client.connect("arduinoClient", "testuser", "testpass")) { + client.publish("outTopic", "hello world"); + client.subscribe("inTopic"); + } +} + +void loop() { + client.loop(); +} diff --git a/lib/pubsubclient3/examples/mqtt_basic/mqtt_basic.ino b/lib/pubsubclient3/examples/mqtt_basic/mqtt_basic.ino new file mode 100644 index 000000000..f790aab6a --- /dev/null +++ b/lib/pubsubclient3/examples/mqtt_basic/mqtt_basic.ino @@ -0,0 +1,74 @@ +/* + Basic MQTT example + + This sketch demonstrates the basic capabilities of the library. + It connects to an MQTT server then: + - publishes "hello world" to the topic "outTopic" + - subscribes to the topic "inTopic", printing out any messages + it receives. NB - it assumes the received payloads are strings not binary + + It will reconnect to the server if the connection is lost using a blocking + reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to + achieve the same result without blocking the main loop. +*/ + +#include +#include +#include + +// Update these with values suitable for your network. +byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED}; +IPAddress ip(172, 16, 0, 100); +IPAddress server(172, 16, 0, 2); + +void callback(char* topic, uint8_t* payload, size_t length) { + Serial.print("Message arrived ["); + Serial.print(topic); + Serial.print("] "); + for (size_t i = 0; i < length; i++) { + Serial.print((char)payload[i]); + } + Serial.println(); +} + +EthernetClient ethClient; +PubSubClient client(ethClient); + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect("arduinoClient")) { + Serial.println("connected"); + // Once connected, publish an announcement... + client.publish("outTopic", "hello world"); + // ... and resubscribe + client.subscribe("inTopic"); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void setup() { + Serial.begin(57600); + + client.setServer(server, 1883); + client.setCallback(callback); + + Ethernet.begin(mac, ip); + // Allow the hardware to sort itself out + delay(1500); +} + +void loop() { + if (!client.connected()) { + reconnect(); + } + client.loop(); +} diff --git a/lib/pubsubclient3/examples/mqtt_esp8266/mqtt_esp8266.ino b/lib/pubsubclient3/examples/mqtt_esp8266/mqtt_esp8266.ino new file mode 100644 index 000000000..b41192ab4 --- /dev/null +++ b/lib/pubsubclient3/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -0,0 +1,135 @@ +/* + Basic ESP8266 / ESP32 MQTT example + This sketch demonstrates the capabilities of the pubsub library in combination + with the ESP8266 board/library. + It connects to an MQTT server then: + - publishes "hello world" to the topic "outTopic" every two seconds + - subscribes to the topic "inTopic", printing out any messages + it receives. NB - it assumes the received payloads are strings not binary + - If the first character of the topic "inTopic" is an 1, switch ON the ESP Led, + else switch it off + It will reconnect to the server if the connection is lost using a blocking + reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to + achieve the same result without blocking the main loop. + To install the ESP8266 board, (using Arduino 1.6.4+): + - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs": + http://arduino.esp8266.com/stable/package_esp8266com_index.json + - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266" + - Select your ESP8266 in "Tools -> Board" +*/ + +#ifdef ESP8266 +#include +#elif defined(ESP32) +#include +#include +#define BUILTIN_LED A0 +#define RANDOM_REG32 esp_random() +#else +#error Platform not supported. +#endif +#include + +// Update these with values suitable for your network. + +const char* ssid = "........"; +const char* password = "........"; +const char* mqtt_server = "broker.mqtt-dashboard.com"; + +WiFiClient espClient; +PubSubClient client(espClient); +unsigned long lastMsg = 0; +#define MSG_BUFFER_SIZE (50) +char msg[MSG_BUFFER_SIZE]; +int value = 0; + +void setup_wifi() { + delay(10); + // We start by connecting to a WiFi network + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + randomSeed(RANDOM_REG32); + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void callback(char* topic, uint8_t* payload, size_t length) { + Serial.print("Message arrived ["); + Serial.print(topic); + Serial.print("] "); + for (size_t i = 0; i < length; i++) { + Serial.print((char)payload[i]); + } + Serial.println(); + + // Switch on the LED if an 1 was received as first character + if ((char)payload[0] == '1') { + digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level + // but actually the LED is on; this is because + // it is active low on the ESP-01) + } else { + digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Create a random client ID + String clientId = "ESP8266Client-"; + clientId += String(random(0xffff), HEX); + // Attempt to connect + if (client.connect(clientId.c_str())) { + Serial.println("connected"); + // Once connected, publish an announcement... + client.publish("outTopic", "hello world"); + // ... and resubscribe + client.subscribe("inTopic"); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void setup() { + pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_server, 1883); + client.setCallback(callback); +} + +void loop() { + if (!client.connected()) { + reconnect(); + } + client.loop(); + + unsigned long now = millis(); + if (now - lastMsg > 2000) { + lastMsg = now; + ++value; + snprintf(msg, MSG_BUFFER_SIZE, "hello world #%ld", value); + Serial.print("Publish message: "); + Serial.println(msg); + client.publish("outTopic", msg); + } +} diff --git a/lib/pubsubclient3/examples/mqtt_large_message/mqtt_large_message.ino b/lib/pubsubclient3/examples/mqtt_large_message/mqtt_large_message.ino new file mode 100644 index 000000000..48049c3e9 --- /dev/null +++ b/lib/pubsubclient3/examples/mqtt_large_message/mqtt_large_message.ino @@ -0,0 +1,185 @@ +/* + Long message ESP8266 / ESP32 MQTT example + + This sketch demonstrates sending arbitrarily large messages in combination + with the ESP8266 board/library. + + It connects to an MQTT server then: + - publishes "hello world" to the topic "outTopic" + - subscribes to the topic "greenBottles/#", printing out any messages + it receives. NB - it assumes the received payloads are strings not binary + - If the sub-topic is a number, it publishes a "greenBottles/lyrics" message + with a payload consisting of the lyrics to "10 green bottles", replacing + 10 with the number given in the sub-topic. + + It will reconnect to the server if the connection is lost using a blocking + reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to + achieve the same result without blocking the main loop. + + To install the ESP8266 board, (using Arduino 1.6.4+): + - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs": + http://arduino.esp8266.com/stable/package_esp8266com_index.json + - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266" + - Select your ESP8266 in "Tools -> Board" +*/ + +#ifdef ESP8266 +#include +#elif defined(ESP32) +#include +#include +#define BUILTIN_LED A0 +#define RANDOM_REG32 esp_random() +#else +#error Platform not supported. +#endif +#include + +// Update these with values suitable for your network. + +const char* ssid = "........"; +const char* password = "........"; +const char* mqtt_server = "broker.mqtt-dashboard.com"; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +void setup_wifi() { + delay(10); + // We start by connecting to a WiFi network + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + randomSeed(RANDOM_REG32); + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void callback(char* topic, uint8_t* payload, size_t length) { + Serial.print("Message arrived ["); + Serial.print(topic); + Serial.print("] "); + for (size_t i = 0; i < length; i++) { + Serial.print((char)payload[i]); + } + Serial.println(); + + // Find out how many bottles we should generate lyrics for + String topicStr(topic); + int bottleCount = 0; // assume no bottles unless we correctly parse a value from the topic + if (topicStr.indexOf('/') >= 0) { + // The topic includes a '/', we'll try to read the number of bottles from just after that + topicStr.remove(0, topicStr.indexOf('/') + 1); + // Now see if there's a number of bottles after the '/' + bottleCount = topicStr.toInt(); + } + + if (bottleCount > 0) { + // Work out how big our resulting message will be + size_t msgLen = 0; + for (size_t i = bottleCount; i > 0; i--) { + String numBottles(i); + msgLen += 2 * numBottles.length(); + if (i == 1) { + msgLen += 2 * String(" green bottle, standing on the wall\n").length(); + } else { + msgLen += 2 * String(" green bottles, standing on the wall\n").length(); + } + msgLen += String("And if one green bottle should accidentally fall\nThere'll be ").length(); + switch (i) { + case 1: + msgLen += String("no green bottles, standing on the wall\n\n").length(); + break; + case 2: + msgLen += String("1 green bottle, standing on the wall\n\n").length(); + break; + default: + numBottles = i - 1; + msgLen += numBottles.length(); + msgLen += String(" green bottles, standing on the wall\n\n").length(); + break; + }; + } + + // Now we can start to publish the message + client.beginPublish("greenBottles/lyrics", msgLen, false); + for (int i = bottleCount; i > 0; i--) { + for (int j = 0; j < 2; j++) { + client.print(i); + if (i == 1) { + client.print(" green bottle, standing on the wall\n"); + } else { + client.print(" green bottles, standing on the wall\n"); + } + } + client.print("And if one green bottle should accidentally fall\nThere'll be "); + switch (i) { + case 1: + client.print("no green bottles, standing on the wall\n\n"); + break; + case 2: + client.print("1 green bottle, standing on the wall\n\n"); + break; + default: + client.print(i - 1); + client.print(" green bottles, standing on the wall\n\n"); + break; + }; + } + // Now we're done! + client.endPublish(); + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Create a random client ID + String clientId = "ESP8266Client-"; + clientId += String(random(0xffff), HEX); + // Attempt to connect + if (client.connect(clientId.c_str())) { + Serial.println("connected"); + // Once connected, publish an announcement... + client.publish("outTopic", "hello world"); + // ... and resubscribe + client.subscribe("greenBottles/#"); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void setup() { + pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_server, 1883); + client.setCallback(callback); +} + +void loop() { + if (!client.connected()) { + reconnect(); + } + client.loop(); +} diff --git a/lib/pubsubclient3/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino b/lib/pubsubclient3/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino new file mode 100644 index 000000000..733bea3f5 --- /dev/null +++ b/lib/pubsubclient3/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino @@ -0,0 +1,56 @@ +/* + Publishing in the callback + + - connects to an MQTT server + - subscribes to the topic "inTopic" + - when a message is received, republishes it to "outTopic" + + This example shows how to publish messages within the + callback function. The callback function header needs to + be declared before the PubSubClient constructor and the + actual callback defined afterwards. + This ensures the client reference in the callback function + is valid. +*/ + +#include +#include +#include + +// Update these with values suitable for your network. +byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED}; +IPAddress ip(172, 16, 0, 100); +IPAddress server(172, 16, 0, 2); + +// Callback function header +void callback(char* topic, uint8_t* payload, size_t length); + +EthernetClient ethClient; +PubSubClient client(server, 1883, callback, ethClient); + +// Callback function +void callback(char* topic, uint8_t* payload, size_t length) { + // In order to republish this payload, a copy must be made + // as the orignal payload buffer will be overwritten whilst + // constructing the PUBLISH packet. + + // Allocate the correct amount of memory for the payload copy + byte* p = (byte*)malloc(length); + // Copy the payload to the new buffer + memcpy(p, payload, length); + client.publish("outTopic", p, length); + // Free the memory + free(p); +} + +void setup() { + Ethernet.begin(mac, ip); + if (client.connect("arduinoClient")) { + client.publish("outTopic", "hello world"); + client.subscribe("inTopic"); + } +} + +void loop() { + client.loop(); +} diff --git a/lib/pubsubclient3/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino b/lib/pubsubclient3/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino new file mode 100644 index 000000000..9d5c60098 --- /dev/null +++ b/lib/pubsubclient3/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino @@ -0,0 +1,62 @@ +/* + Reconnecting MQTT example - non-blocking + + This sketch demonstrates how to keep the client connected + using a non-blocking reconnect function. If the client loses + its connection, it attempts to reconnect every 5 seconds + without blocking the main loop. +*/ + +#include +#include +#include + +// Update these with values suitable for your hardware/network. +byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED}; +IPAddress ip(172, 16, 0, 100); +IPAddress server(172, 16, 0, 2); + +void callback(char* topic, uint8_t* payload, size_t length) { + // handle message arrived +} + +EthernetClient ethClient; +PubSubClient client(ethClient); + +long lastReconnectAttempt = 0; + +boolean reconnect() { + if (client.connect("arduinoClient")) { + // Once connected, publish an announcement... + client.publish("outTopic", "hello world"); + // ... and resubscribe + client.subscribe("inTopic"); + } + return client.connected(); +} + +void setup() { + client.setServer(server, 1883); + client.setCallback(callback); + + Ethernet.begin(mac, ip); + delay(1500); + lastReconnectAttempt = 0; +} + +void loop() { + if (!client.connected()) { + unsigned long now = millis(); + if (now - lastReconnectAttempt > 5000) { + lastReconnectAttempt = now; + // Attempt to reconnect + if (reconnect()) { + lastReconnectAttempt = 0; + } + } + } else { + // Client connected + + client.loop(); + } +} diff --git a/lib/pubsubclient/examples/mqtt_stream/mqtt_stream.ino b/lib/pubsubclient3/examples/mqtt_stream/mqtt_stream.ino similarity index 50% rename from lib/pubsubclient/examples/mqtt_stream/mqtt_stream.ino rename to lib/pubsubclient3/examples/mqtt_stream/mqtt_stream.ino index 67c22872c..5e620a0e3 100644 --- a/lib/pubsubclient/examples/mqtt_stream/mqtt_stream.ino +++ b/lib/pubsubclient3/examples/mqtt_stream/mqtt_stream.ino @@ -9,49 +9,47 @@ - subscribes to the topic "inTopic" */ -#include #include #include +#include #include // Update these with values suitable for your network. -byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; +byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED}; IPAddress ip(172, 16, 0, 100); IPAddress server(172, 16, 0, 2); SRAM sram(4, SRAM_1024); -void callback(char* topic, byte* payload, unsigned int length) { - sram.seek(1); +void callback(char* topic, uint8_t* payload, size_t length) { + sram.seek(1); - // do something with the message - for(uint8_t i=0; i -maintainer=Nick O'Leary +maintainer=Holger Mueller +license=MIT sentence=A client library for MQTT messaging. paragraph=MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison, ESP8266 and TI CC3000. category=Communication -url=http://pubsubclient.knolleary.net -architectures=esp8266,esp32 +url=https://github.com/hmueller01/pubsubclient3.git +architectures=* diff --git a/lib/pubsubclient3/src/PubSubClient.cpp b/lib/pubsubclient3/src/PubSubClient.cpp new file mode 100644 index 000000000..e50c0973a --- /dev/null +++ b/lib/pubsubclient3/src/PubSubClient.cpp @@ -0,0 +1,772 @@ +/* + PubSubClient.cpp - A simple client for MQTT. + Nick O'Leary, Holger Mueller + http://knolleary.net + https://github.com/hmueller01/pubsubclient3 +*/ + +#include "PubSubClient.h" + +PubSubClient::PubSubClient() { + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); +} + +PubSubClient::PubSubClient(Client& client) : PubSubClient() { + setClient(client); +} + +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) : PubSubClient() { + setServer(addr, port); + setClient(client); +} + +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) : PubSubClient() { + setServer(addr, port); + setClient(client); + setStream(stream); +} + +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) : PubSubClient() { + setServer(addr, port); + setCallback(callback); + setClient(client); +} + +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) : PubSubClient() { + setServer(addr, port); + setCallback(callback); + setClient(client); + setStream(stream); +} + +PubSubClient::PubSubClient(uint8_t* ip, uint16_t port, Client& client) : PubSubClient() { + setServer(ip, port); + setClient(client); +} + +PubSubClient::PubSubClient(uint8_t* ip, uint16_t port, Client& client, Stream& stream) : PubSubClient() { + setServer(ip, port); + setClient(client); + setStream(stream); +} + +PubSubClient::PubSubClient(uint8_t* ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) : PubSubClient() { + setServer(ip, port); + setCallback(callback); + setClient(client); +} + +PubSubClient::PubSubClient(uint8_t* ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) : PubSubClient() { + setServer(ip, port); + setCallback(callback); + setClient(client); + setStream(stream); +} + +PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) : PubSubClient() { + setServer(domain, port); + setClient(client); +} + +PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) : PubSubClient() { + setServer(domain, port); + setClient(client); + setStream(stream); +} + +PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) : PubSubClient() { + setServer(domain, port); + setCallback(callback); + setClient(client); +} + +PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) : PubSubClient() { + setServer(domain, port); + setCallback(callback); + setClient(client); + setStream(stream); +} + +PubSubClient::~PubSubClient() { + free(this->domain); + free(this->buffer); +} + +bool PubSubClient::connect(const char* id) { + return connect(id, nullptr, nullptr, 0, 0, 0, 0, 1); +} + +bool PubSubClient::connect(const char* id, const char* user, const char* pass) { + return connect(id, user, pass, 0, 0, 0, 0, 1); +} + +bool PubSubClient::connect(const char* id, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage) { + return connect(id, nullptr, nullptr, willTopic, willQos, willRetain, willMessage, 1); +} + +bool PubSubClient::connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain, + const char* willMessage) { + return connect(id, user, pass, willTopic, willQos, willRetain, willMessage, 1); +} + +bool PubSubClient::connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain, + const char* willMessage, bool cleanSession) { + if (!connected()) { + int result = 0; + + if (_client->connected()) { + result = 1; + } else if (this->port != 0) { + if (this->domain) { + result = _client->connect(this->domain, this->port); + } else { + result = _client->connect(this->ip, this->port); + } + } + + if (result == 1) { + nextMsgId = 1; // init msgId (packet identifier) + +#if MQTT_VERSION == MQTT_VERSION_3_1 + const uint8_t protocol[9] = {0x00, 0x06, 'M', 'Q', 'I', 's', 'd', 'p', MQTT_VERSION}; +#elif MQTT_VERSION == MQTT_VERSION_3_1_1 + const uint8_t protocol[7] = {0x00, 0x04, 'M', 'Q', 'T', 'T', MQTT_VERSION}; +#endif + // Leave room in the buffer for header and variable length field + memcpy(this->buffer + MQTT_MAX_HEADER_SIZE, protocol, sizeof(protocol)); + + size_t length = MQTT_MAX_HEADER_SIZE + sizeof(protocol); + uint8_t flags = 0x00; + if (willTopic) { + flags = (0x01 << 2) | (willQos << 3) | (willRetain << 5); // set will flag bit 2, will QoS and will retain bit 5 + } + if (cleanSession) { + flags = flags | (0x01 << 1); // set clean session bit 1 + } + if (user) { + flags = flags | (0x01 << 7); // set user name flag bit 7 + if (pass) { + flags = flags | (0x01 << 6); // set password flag bit 6 + } + } + const uint16_t keepAlive = this->keepAliveMillis / 1000; + this->buffer[length++] = flags; + this->buffer[length++] = keepAlive >> 8; + this->buffer[length++] = keepAlive & 0xFF; + + CHECK_STRING_LENGTH(length, id) + length = writeString(id, this->buffer, length); + if (willTopic) { + CHECK_STRING_LENGTH(length, willTopic) + length = writeString(willTopic, this->buffer, length); + CHECK_STRING_LENGTH(length, willMessage) + length = writeString(willMessage, this->buffer, length); + } + + if (user) { + CHECK_STRING_LENGTH(length, user) + length = writeString(user, this->buffer, length); + if (pass) { + CHECK_STRING_LENGTH(length, pass) + length = writeString(pass, this->buffer, length); + } + } + + write(MQTTCONNECT, this->buffer, length - MQTT_MAX_HEADER_SIZE); + + lastInActivity = lastOutActivity = millis(); + pingOutstanding = false; + + while (!_client->available()) { + yield(); + unsigned long t = millis(); + if (t - lastInActivity >= this->socketTimeoutMillis) { + DEBUG_PSC_PRINTF("connect aborting due to timeout\n"); + _state = MQTT_CONNECTION_TIMEOUT; + _client->stop(); + return false; + } + } + uint8_t hdrLen; + size_t len = readPacket(&hdrLen); + + if (len == 4) { + if (buffer[3] == 0) { + lastInActivity = millis(); + _state = MQTT_CONNECTED; + return true; + } else { + _state = buffer[3]; + } + } + DEBUG_PSC_PRINTF("connect aborting due to protocol error\n"); + _client->stop(); + } else { + _state = MQTT_CONNECT_FAILED; + } + return false; + } + return true; +} + +bool PubSubClient::connected() { + if (!_client) return false; + + if (_client->connected()) { + return (_state == MQTT_CONNECTED); + } else if (_state == MQTT_CONNECTED) { + DEBUG_PSC_PRINTF("lost connection (client may have more details)\n"); + _state = MQTT_CONNECTION_LOST; + _client->stop(); + pingOutstanding = false; + } + return false; +} + +void PubSubClient::disconnect() { + DEBUG_PSC_PRINTF("disconnect called\n"); + this->buffer[0] = MQTTDISCONNECT; + this->buffer[1] = 0; + _client->write(this->buffer, 2); + _state = MQTT_DISCONNECTED; + _client->flush(); + _client->stop(); + lastInActivity = lastOutActivity = millis(); + pingOutstanding = false; +} + +/** + * @brief Reads a byte into result. + * + * @param result Pointer to result buffer. + * @return true if byte was read, false if socketTimeout occurred. + */ +bool PubSubClient::readByte(uint8_t* result) { + unsigned long previousMillis = millis(); + while (!_client->available()) { + yield(); + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= this->socketTimeoutMillis) { + return false; + } + } + int rc = _client->read(); + if (rc < 0) { + return false; + } + *result = (uint8_t)rc; + return true; +} + +/** + * @brief Reads a byte into result[*pos] and increments *pos. + * Note: *pos may go out of bounds of result. This must be checked outside of this function! + * + * @return true if a byte was read, otherwise false (socketTimeout). + */ +bool PubSubClient::readByte(uint8_t* result, size_t* pos) { + uint8_t* write_address = &(result[*pos]); + if (readByte(write_address)) { + (*pos)++; + return true; + } + return false; +} + +/** + * @brief Reads a complete packet (header, topic, payload) into this->buffer. + * + * @param *hdrLen Returns the variable header length send by MQTT broker (1 .. MQTT_MAX_HEADER_SIZE - 1) + * @return Number of read bytes, 0 in case of an error (socketTimeout, buffer overflow) + */ +size_t PubSubClient::readPacket(uint8_t* hdrLen) { + size_t len = 0; + if (!readByte(this->buffer, &len)) return 0; + bool isPublish = (this->buffer[0] & 0xF0) == MQTTPUBLISH; + uint32_t multiplier = 1; + size_t length = 0; + uint8_t digit = 0; + uint16_t skip = 0; + uint8_t start = 0; + + do { + if (len == MQTT_MAX_HEADER_SIZE) { + // Invalid remaining length encoding - kill the connection + DEBUG_PSC_PRINTF("readPacket detected packet of invalid length\n"); + _state = MQTT_DISCONNECTED; + _client->stop(); + return 0; + } + if (!readByte(&digit)) return 0; + this->buffer[len++] = digit; + length += (digit & 0x7F) * multiplier; // length is coded in the lower 7 bits + multiplier <<= 7; // multiplier *= 128 + } while ((digit & 0x80) != 0); // do while 8th continuation bit is set + *hdrLen = (uint8_t)(len - 1); + + DEBUG_PSC_PRINTF("readPacket received packet of length %zu (isPublish = %u)\n", length, isPublish); + + if (isPublish) { + // Read in topic length to calculate bytes to skip over for Stream writing + if (!readByte(this->buffer, &len)) return 0; + if (!readByte(this->buffer, &len)) return 0; + skip = (this->buffer[*hdrLen + 1] << 8) + this->buffer[*hdrLen + 2]; + start = 2; + if (this->buffer[0] & MQTTQOS1) { + // skip message id + skip += 2; + } + } + size_t idx = len; + + for (size_t i = start; i < length; i++) { + if (!readByte(&digit)) return 0; + if (this->stream) { + if (isPublish && idx - *hdrLen - 2 > skip) { + this->stream->write(digit); + } + } + + if (len < this->bufferSize) { + this->buffer[len++] = digit; + } + idx++; + } + + if (!this->stream && idx > this->bufferSize) { + DEBUG_PSC_PRINTF("readPacket ignoring packet of size %zu exceeding buffer of size %zu\n", length, this->bufferSize); + len = 0; // This will cause the packet to be ignored. + } + return len; +} + +/** + * @brief After a packet is read handle the content here (call the callback, handle pings). + * + * @param hdrLen Variable header length send by MQTT broker (1 .. MQTT_MAX_HEADER_SIZE - 1). + * @param length Number of read bytes in this->buffer. + * @return true if packet was successfully processed, false if a buffer over or underflow occurred. + */ +bool PubSubClient::handlePacket(uint8_t hdrLen, size_t length) { + uint8_t type = this->buffer[0] & 0xF0; + DEBUG_PSC_PRINTF("received message of type %u\n", type); + switch (type) { + case MQTTPUBLISH: + if (callback) { + // MQTT Publish packet: See section 3.3 MQTT v3.1 protocol specification: + // - Header: 1 byte + // - Remaining header length: hdrLen bytes, multibyte field (1 .. MQTT_MAX_HEADER_SIZE - 1) + // - Topic length: 2 bytes (starts at buffer[hdrLen + 1]) + // - Topic: topicLen bytes (starts at buffer[hdrLen + 3]) + // - Packet Identifier (msgId): 0 bytes for QoS 0, 2 bytes for QoS 1 and 2 (starts at buffer[hdrLen + 3 + topicLen]) + // - Payload (for QoS = 0): length - (hdrLen + 3 + topicLen) bytes (starts at buffer[hdrLen + 3 + topicLen]) + // - Payload (for QoS > 0): length - (hdrLen + 5 + topicLen) bytes (starts at buffer[hdrLen + 5 + topicLen]) + // To get a null reminated 'C' topic string we move the topic 1 byte to the front (overwriting the LSB of the topic lenght) + uint16_t topicLen = (this->buffer[hdrLen + 1] << 8) + this->buffer[hdrLen + 2]; // topic length in bytes + char* topic = (char*)(this->buffer + hdrLen + 3 - 1); // set the topic in the LSB of the topic lenght, as we move it there + uint16_t payloadOffset = hdrLen + 3 + topicLen; // payload starts after header and topic (if there is no packet identifier) + size_t payloadLen = length - payloadOffset; // this might change by 2 if we have a QoS 1 or 2 message + uint8_t* payload = this->buffer + payloadOffset; + + if (length < payloadOffset) { // do not move outside the max bufferSize + ERROR_PSC_PRINTF_P("handlePacket(): Suspicious topicLen (%u) points outside of received buffer length (%zu)\n", topicLen, length); + return false; + } + memmove(topic, topic + 1, topicLen); // move topic inside buffer 1 byte to front + topic[topicLen] = '\0'; // end the topic as a 'C' string with \x00 + + if ((this->buffer[0] & 0x06) == MQTTQOS0) { + // No msgId for QOS == 0 + callback(topic, payload, payloadLen); + } else { + // For QOS 1 and 2 we have a msgId (packet identifier) after the topic at the current payloadOffset + if (payloadLen < 2) { // payload must be >= 2, as we have the msgId before + ERROR_PSC_PRINTF_P("handlePacket(): Missing msgId in QoS 1/2 message\n"); + return false; + } + uint16_t msgId = (this->buffer[payloadOffset] << 8) + this->buffer[payloadOffset + 1]; + callback(topic, payload + 2, payloadLen - 2); // remove the msgId from the callback payload + + this->buffer[0] = MQTTPUBACK; + this->buffer[1] = 2; + this->buffer[2] = (msgId >> 8); + this->buffer[3] = (msgId & 0xFF); + if (_client->write(this->buffer, 4) == 4) { + lastOutActivity = millis(); + } + } + } + break; + case MQTTPINGREQ: + this->buffer[0] = MQTTPINGRESP; + this->buffer[1] = 0; + if (_client->write(this->buffer, 2) == 2) { + lastOutActivity = millis(); + } + break; + case MQTTPINGRESP: + pingOutstanding = false; + break; + default: + break; + } + return true; +} + +bool PubSubClient::loop() { + if (!connected()) { + return false; + } + bool ret = true; + const unsigned long t = millis(); + if (keepAliveMillis && ((t - lastInActivity > this->keepAliveMillis) || (t - lastOutActivity > this->keepAliveMillis))) { + if (pingOutstanding) { + DEBUG_PSC_PRINTF("loop aborting due to timeout\n"); + _state = MQTT_CONNECTION_TIMEOUT; + _client->stop(); + pingOutstanding = false; + return false; + } else { + this->buffer[0] = MQTTPINGREQ; + this->buffer[1] = 0; + if (_client->write(this->buffer, 2) == 2) { + lastInActivity = lastOutActivity = t; + pingOutstanding = true; + } + } + } + if (_client->available()) { + uint8_t hdrLen; + size_t len = readPacket(&hdrLen); + if (len > 0) { + lastInActivity = t; + ret = handlePacket(hdrLen, len); + if (!ret) { + _state = MQTT_DISCONNECTED; + _client->stop(); + } + } else if (!connected()) { + // readPacket has closed the connection + return false; + } + } + return ret; +} + +bool PubSubClient::publish(const char* topic, const char* payload) { + return publish(topic, (const uint8_t*)payload, payload ? strnlen(payload, MQTT_MAX_POSSIBLE_PACKET_SIZE) : 0, false); +} + +bool PubSubClient::publish(const char* topic, const char* payload, bool retained) { + return publish(topic, (const uint8_t*)payload, payload ? strnlen(payload, MQTT_MAX_POSSIBLE_PACKET_SIZE) : 0, retained); +} + +bool PubSubClient::publish(const char* topic, const uint8_t* payload, size_t plength) { + return publish(topic, payload, plength, false); +} + +bool PubSubClient::publish(const char* topic, const uint8_t* payload, size_t plength, bool retained) { + if (beginPublish(topic, plength, retained)) { + size_t rc = write(payload, plength); + lastOutActivity = millis(); + return endPublish() && (rc == plength); + } + return false; +} + +bool PubSubClient::publish_P(const char* topic, const char* payload, bool retained) { + return publish_P(topic, (const uint8_t*)payload, payload ? strnlen_P(payload, MQTT_MAX_POSSIBLE_PACKET_SIZE) : 0, retained); +} + +bool PubSubClient::publish_P(const char* topic, const uint8_t* payload, size_t plength, bool retained) { + if (beginPublish(topic, plength, retained)) { + size_t rc = 0; + for (size_t i = 0; i < plength; i++) { + rc += _client->write((uint8_t)pgm_read_byte_near(payload + i)); + } + lastOutActivity = millis(); + return endPublish() && (rc == plength); + } + return false; +} + +bool PubSubClient::beginPublish(const char* topic, size_t plength, bool retained) { + if (!topic) return false; + // check if the header and the topic (including 2 length bytes) fit into the buffer + if (connected() && MQTT_MAX_HEADER_SIZE + strlen(topic) + 2 <= this->bufferSize) { + // first write the topic at the end of the maximal variable header (MQTT_MAX_HEADER_SIZE) to the buffer + size_t topicLen = writeString(topic, this->buffer, MQTT_MAX_HEADER_SIZE) - MQTT_MAX_HEADER_SIZE; + // we now know the length of the topic string (lenght + 2 bytes signalling the length) and can build the variable header information + const uint8_t header = MQTTPUBLISH | (retained ? MQTTRETAINED : 0); + uint8_t hdrLen = buildHeader(header, this->buffer, topicLen + plength); + if (hdrLen == 0) return false; // exit here in case of header generation failure + // as the header length is variable, it starts at MQTT_MAX_HEADER_SIZE - hdrLen (see buildHeader() documentation) + size_t rc = _client->write(this->buffer + (MQTT_MAX_HEADER_SIZE - hdrLen), hdrLen + topicLen); + lastOutActivity = millis(); + return (rc == (hdrLen + topicLen)); + } + return false; +} + +bool PubSubClient::endPublish() { + return connected(); +} + +/** + * @brief Build up the header ready to send. + * Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start + * (MQTT_MAX_HEADER_SIZE - ) bytes into the buffer. + * + * @param header Header byte, e.g. MQTTCONNECT, MQTTPUBLISH, MQTTSUBSCRIBE, MQTTUNSUBSCRIBE. + * @param buf Buffer to write header to. + * @param length Length to encode in the header. + * @return Returns the size of the header (1 .. MQTT_MAX_HEADER_SIZE), or 0 in case of a failure (e.g. length to big). + */ +uint8_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, size_t length) { + uint8_t hdrBuf[MQTT_MAX_HEADER_SIZE - 1]; + uint8_t hdrLen = 0; + uint8_t digit; + size_t len = length; + do { + digit = len & 0x7F; // digit = len % 128 + len >>= 7; // len = len / 128 + if (len > 0) { + digit |= 0x80; + } + hdrBuf[hdrLen++] = digit; + } while (len > 0 && hdrLen < MQTT_MAX_HEADER_SIZE - 1); + + if (len > 0) { + ERROR_PSC_PRINTF_P("buildHeader() length too big %zu, left %zu\n", length, len); + return 0; + } + + buf[MQTT_MAX_HEADER_SIZE - 1 - hdrLen] = header; + memcpy(buf + MQTT_MAX_HEADER_SIZE - hdrLen, hdrBuf, hdrLen); + return hdrLen + 1; // Full header size is variable length bit plus the 1-byte fixed header +} + +size_t PubSubClient::write(uint8_t data) { + lastOutActivity = millis(); + return _client->write(data); +} + +size_t PubSubClient::write(const uint8_t* buffer, size_t size) { + lastOutActivity = millis(); + return _client->write(buffer, size); +} + +/** + * @brief Send the header and the prepared data to the client / MQTT broker. + * + * @param header Header byte, e.g. MQTTCONNECT, MQTTPUBLISH, MQTTSUBSCRIBE, MQTTUNSUBSCRIBE. + * @param buf Buffer of data to write. + * @param length Length of buf to write. + * @return True if successfully sent, otherwise false if buildHeader() failed or buf could not be written. + */ +bool PubSubClient::write(uint8_t header, uint8_t* buf, size_t length) { + bool result = true; + size_t rc; + uint8_t hdrLen = buildHeader(header, buf, length); + if (hdrLen == 0) return false; // exit here in case of header generation failure + +#ifdef MQTT_MAX_TRANSFER_SIZE + uint8_t* writeBuf = buf + (MQTT_MAX_HEADER_SIZE - hdrLen); + size_t bytesRemaining = length + hdrLen; // Match the length type + size_t bytesToWrite; + while ((bytesRemaining > 0) && result) { + yield(); + bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE) ? MQTT_MAX_TRANSFER_SIZE : bytesRemaining; + rc = _client->write(writeBuf, bytesToWrite); + result = (rc == bytesToWrite); + bytesRemaining -= rc; + writeBuf += rc; + if (result) { + lastOutActivity = millis(); + } + } +#else + rc = _client->write(buf + (MQTT_MAX_HEADER_SIZE - hdrLen), length + hdrLen); + result = (rc == length + hdrLen); + if (result) { + lastOutActivity = millis(); + } +#endif + return result; +} + +/** + * @brief Write an UTF-8 encoded string to the give buffer and position. The string can have a length of 0 to 65535 bytes. The buffer is prefixed with two + * bytes representing the length of the string. See section 1.5.3 of MQTT v3.1.1 protocol specification. + * @note If the string does not fit in the buffer (bufferSize) or is longer than 65535 bytes nothing is written to the buffer and the returned position + * is unchanged. + * + * @param string 'C' string of the data that shall be written in the buffer. + * @param buf Buffer to write the string into. + * @param pos Position in the buffer to write the string. + * @return New position in the buffer (pos + 2 + string length), or pos if a buffer overrun would occur. + */ +size_t PubSubClient::writeString(const char* string, uint8_t* buf, size_t pos) { + return writeString(string, buf, pos, this->bufferSize); +} + +/** + * @brief Write an UTF-8 encoded string to the give buffer and position. The string can have a length of 0 to 65535 bytes. The buffer is prefixed with two + * bytes representing the length of the string. See section 1.5.3 of MQTT v3.1.1 protocol specification. + * @note If the string does not fit in the buffer or is longer than 65535 bytes nothing is written to the buffer and the returned position is unchanged. + * + * @param string 'C' string of the data that shall be written in the buffer. + * @param buf Buffer to write the string into. + * @param pos Position in the buffer to write the string. + * @param size Maximal size of the buffer. + * @return New position in the buffer (pos + 2 + string length), or pos if a buffer overrun would occur or the string is a nullptr. + */ +size_t PubSubClient::writeString(const char* string, uint8_t* buf, size_t pos, size_t size) { + if (!string) return pos; + + size_t sLen = strlen(string); + if (pos + 2 + sLen <= size && sLen <= 0xFFFF) { + buf[pos++] = (uint8_t)(sLen >> 8); + buf[pos++] = (uint8_t)(sLen & 0xFF); + memcpy(buf + pos, string, sLen); + pos += sLen; + } else { + ERROR_PSC_PRINTF_P("writeString(): string (%zu) does not fit into buf (%zu)\n", pos + 2 + sLen, size); + } + return pos; +} + +bool PubSubClient::subscribe(const char* topic) { + return subscribe(topic, 0); +} + +bool PubSubClient::subscribe(const char* topic, uint8_t qos) { + if (!topic) return false; + if (qos > 1) return false; // only QoS 0 and 1 supported + + size_t topicLen = strnlen(topic, this->bufferSize); + if (this->bufferSize < MQTT_MAX_HEADER_SIZE + 2 + 2 + topicLen) { + // Too long: header + nextMsgId (2) + topic length bytes (2) + topicLen + return false; + } + if (connected()) { + // Leave room in the buffer for header and variable length field + uint16_t length = MQTT_MAX_HEADER_SIZE; + nextMsgId++; + if (nextMsgId == 0) { + nextMsgId = 1; + } + this->buffer[length++] = (nextMsgId >> 8); + this->buffer[length++] = (nextMsgId & 0xFF); + length = writeString(topic, this->buffer, length); + this->buffer[length++] = qos; + return write(MQTTSUBSCRIBE | MQTTQOS1, this->buffer, length - MQTT_MAX_HEADER_SIZE); + } + return false; +} + +bool PubSubClient::unsubscribe(const char* topic) { + if (!topic) return false; + + size_t topicLen = strnlen(topic, this->bufferSize); + if (this->bufferSize < MQTT_MAX_HEADER_SIZE + 2 + 2 + topicLen) { + // Too long: header + nextMsgId (2) + topic length bytes (2) + topicLen + return false; + } + if (connected()) { + uint16_t length = MQTT_MAX_HEADER_SIZE; + nextMsgId++; + if (nextMsgId == 0) { + nextMsgId = 1; + } + this->buffer[length++] = (nextMsgId >> 8); + this->buffer[length++] = (nextMsgId & 0xFF); + length = writeString(topic, this->buffer, length); + return write(MQTTUNSUBSCRIBE | MQTTQOS1, this->buffer, length - MQTT_MAX_HEADER_SIZE); + } + return false; +} + +PubSubClient& PubSubClient::setServer(uint8_t* ip, uint16_t port) { + IPAddress addr(ip[0], ip[1], ip[2], ip[3]); + return setServer(addr, port); +} + +PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) { + this->ip = ip; + this->port = port; + free(this->domain); + this->domain = nullptr; + return *this; +} + +PubSubClient& PubSubClient::setServer(const char* domain, uint16_t port) { + char* newDomain = nullptr; + if (domain) { + newDomain = (char*)realloc(this->domain, strlen(domain) + 1); + } + if (newDomain) { + strcpy(newDomain, domain); + this->domain = newDomain; + this->port = port; + } else { + free(this->domain); + this->domain = nullptr; + this->port = 0; + } + return *this; +} + +PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) { + this->callback = callback; + return *this; +} + +PubSubClient& PubSubClient::setClient(Client& client) { + this->_client = &client; + return *this; +} + +PubSubClient& PubSubClient::setStream(Stream& stream) { + this->stream = &stream; + return *this; +} + +bool PubSubClient::setBufferSize(size_t size) { + if (size == 0) { + // Cannot set it back to 0 + return false; + } + if (this->bufferSize == 0) { + this->buffer = (uint8_t*)malloc(size); + } else { + uint8_t* newBuffer = (uint8_t*)realloc(this->buffer, size); + if (newBuffer) { + this->buffer = newBuffer; + } else { + return false; + } + } + this->bufferSize = size; + return (this->buffer != nullptr); +} + +size_t PubSubClient::getBufferSize() { + return this->bufferSize; +} + +PubSubClient& PubSubClient::setKeepAlive(uint16_t keepAlive) { + this->keepAliveMillis = keepAlive * 1000UL; + return *this; +} + +PubSubClient& PubSubClient::setSocketTimeout(uint16_t timeout) { + this->socketTimeoutMillis = timeout * 1000UL; + return *this; +} + +int PubSubClient::state() { + return this->_state; +} diff --git a/lib/pubsubclient3/src/PubSubClient.h b/lib/pubsubclient3/src/PubSubClient.h new file mode 100644 index 000000000..d899786bc --- /dev/null +++ b/lib/pubsubclient3/src/PubSubClient.h @@ -0,0 +1,612 @@ +/* + PubSubClient.h - A simple client for MQTT. + Nick O'Leary, Holger Mueller + http://knolleary.net + https://github.com/hmueller01/pubsubclient3 +*/ + +#ifndef PubSubClient_h +#define PubSubClient_h + +#include + +#include "Client.h" +#include "IPAddress.h" +#include "Stream.h" + +#define MQTT_VERSION_3_1 3 +#define MQTT_VERSION_3_1_1 4 + +//< @note The following #define directives can be used to configure the library. + +/** + * @brief Sets the version of the MQTT protocol to use. + * @note Default value is MQTT_VERSION_3_1_1 for MQTT 3.1.1. + */ +#ifndef MQTT_VERSION +#define MQTT_VERSION MQTT_VERSION_3_1_1 +#endif + +// MQTT_MAX_POSSIBLE_PACKET_SIZE : Maximum packet size defined by MQTT protocol. +#ifndef MQTT_MAX_POSSIBLE_PACKET_SIZE +#define MQTT_MAX_POSSIBLE_PACKET_SIZE 268435455 +#endif + +/** + * @brief Sets the largest packet size, in bytes, the client will handle. + * Any packet received that exceeds this size will be ignored. + * This value can be overridden by calling setBufferSize. + * @note Default value is 256 bytes. + */ +#ifndef MQTT_MAX_PACKET_SIZE +#define MQTT_MAX_PACKET_SIZE 256 +#endif + +/** + * @brief Sets the keepalive interval, in seconds, the client will use. + * This is used to maintain the connection when no other packets are being sent or received. + * This value can be overridden by calling setKeepAlive. + * @note Default value is 15 seconds. + */ +#ifndef MQTT_KEEPALIVE +#define MQTT_KEEPALIVE 15 +#endif + +/** + * @brief Sets the timeout, in seconds, when reading from the network. + * This also applies as the timeout for calls to connect. + * This value can be overridden by calling setSocketTimeout. + * @note Default value is 15 seconds. + */ +#ifndef MQTT_SOCKET_TIMEOUT +#define MQTT_SOCKET_TIMEOUT 15 +#endif + +/** + * @brief Sets the maximum number of bytes passed to the network client in each write call. + * Some hardware has a limit to how much data can be passed to them in one go, + * such as the Arduino Wifi Shield. + * @note Defaults to undefined, which passes the entire packet in each write call. + */ +// #define MQTT_MAX_TRANSFER_SIZE 80 + +// Possible values for client.state() +#define MQTT_CONNECTION_TIMEOUT -4 +#define MQTT_CONNECTION_LOST -3 +#define MQTT_CONNECT_FAILED -2 +#define MQTT_DISCONNECTED -1 +#define MQTT_CONNECTED 0 +#define MQTT_CONNECT_BAD_PROTOCOL 1 +#define MQTT_CONNECT_BAD_CLIENT_ID 2 +#define MQTT_CONNECT_UNAVAILABLE 3 +#define MQTT_CONNECT_BAD_CREDENTIALS 4 +#define MQTT_CONNECT_UNAUTHORIZED 5 + +#define MQTTRETAINED 1 // Retained flag in the header +#define MQTTCONNECT 1 << 4 // Client request to connect to Server +#define MQTTCONNACK 2 << 4 // Connect Acknowledgment +#define MQTTPUBLISH 3 << 4 // Publish message +#define MQTTPUBACK 4 << 4 // Publish Acknowledgment +#define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1) +#define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2) +#define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3) +#define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request +#define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment +#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request +#define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment +#define MQTTPINGREQ 12 << 4 // PING Request +#define MQTTPINGRESP 13 << 4 // PING Response +#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting +#define MQTTRESERVED 15 << 4 // Reserved + +#define MQTTQOS0 (0 << 1) +#define MQTTQOS1 (1 << 1) +#define MQTTQOS2 (2 << 1) + +// Maximum size of fixed header and variable length size header +#define MQTT_MAX_HEADER_SIZE 5 + +#if defined(__has_include) && __has_include() && !defined(NOFUNCTIONAL) +#include +/** + * @brief Define the signature required by any callback function. + * @note The parameters are TOPIC, PAYLOAD, and LENGTH, respectively. + */ +#define MQTT_CALLBACK_SIGNATURE std::function callback +#else +#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, size_t) +#endif + +#define CHECK_STRING_LENGTH(l, s) \ + if (l + 2 + strnlen(s, this->bufferSize) > this->bufferSize) { \ + _client->stop(); \ + return false; \ + } + +#ifdef DEBUG_ESP_PORT +#ifdef DEBUG_PUBSUBCLIENT +#define DEBUG_PSC_PRINTF(fmt, ...) DEBUG_ESP_PORT.printf(("PubSubClient: " fmt), ##__VA_ARGS__) +#else +#define DEBUG_PSC_PRINTF(...) +#endif + +#define ERROR_PSC_PRINTF(fmt, ...) DEBUG_ESP_PORT.printf(("PubSubClient error: " fmt), ##__VA_ARGS__) +#define ERROR_PSC_PRINTF_P(fmt, ...) DEBUG_ESP_PORT.printf_P(PSTR("PubSubClient error: " fmt), ##__VA_ARGS__) +#else // DEBUG_ESP_PORT +#ifndef DEBUG_PSC_PRINTF +#define DEBUG_PSC_PRINTF(...) +#endif +#ifndef ERROR_PSC_PRINTF +#define ERROR_PSC_PRINTF(fmt, ...) +#endif +#ifndef ERROR_PSC_PRINTF_P +#define ERROR_PSC_PRINTF_P(fmt, ...) +#endif +#endif + +/** + * @class PubSubClient + * @brief This class provides a client for doing simple publish and subscribe messaging with a server that supports MQTT. + */ +class PubSubClient : public Print { + private: + Client* _client{}; + uint8_t* buffer{}; + size_t bufferSize{}; + unsigned long keepAliveMillis{}; + unsigned long socketTimeoutMillis{}; + uint16_t nextMsgId{}; + unsigned long lastOutActivity{}; + unsigned long lastInActivity{}; + bool pingOutstanding{}; + MQTT_CALLBACK_SIGNATURE{}; + IPAddress ip{}; + char* domain{}; + uint16_t port{}; + Stream* stream{}; + int _state{MQTT_DISCONNECTED}; + + size_t readPacket(uint8_t* hdrLen); + bool handlePacket(uint8_t hdrLen, size_t len); + bool readByte(uint8_t* result); + bool readByte(uint8_t* result, size_t* pos); + uint8_t buildHeader(uint8_t header, uint8_t* buf, size_t length); + bool write(uint8_t header, uint8_t* buf, size_t length); + size_t writeString(const char* string, uint8_t* buf, size_t pos); + size_t writeString(const char* string, uint8_t* buf, size_t pos, size_t size); + + public: + /** + * @brief Creates an uninitialised client instance. + * @note Before it can be used, + * it must be configured using the property setters setClient and setServer. + */ + PubSubClient(); + + /** + * @brief Creates a partially initialised client instance. + * @param client The network client to use, for example WiFiClient. + * @note Before it can be used, + * it must be configured with the property setter setServer. + */ + PubSubClient(Client& client); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param client The network client to use, for example WiFiClient. + */ + PubSubClient(IPAddress, uint16_t, Client& client); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param client The network client to use, for example WiFiClient. + * @param stream A stream to write received messages to. + */ + PubSubClient(IPAddress, uint16_t, Client& client, Stream&); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param callback Pointer to a message callback function. + * Called when a message arrives for a subscription created by this client. + * @param client The network client to use, for example WiFiClient. + */ + PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param callback Pointer to a message callback function. + * Called when a message arrives for a subscription created by this client. + * @param client The network client to use, for example WiFiClient. + * @param stream A stream to write received messages to. + */ + PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client, Stream&); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param client The network client to use, for example WiFiClient. + */ + PubSubClient(uint8_t*, uint16_t, Client& client); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param client The network client to use, for example WiFiClient. + * @param stream A stream to write received messages to. + */ + PubSubClient(uint8_t*, uint16_t, Client& client, Stream&); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param callback Pointer to a message callback function. + * Called when a message arrives for a subscription created by this client. + * @param client The network client to use, for example WiFiClient. + */ + PubSubClient(uint8_t*, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param callback Pointer to a message callback function. + * Called when a message arrives for a subscription created by this client. + * @param client The network client to use, for example WiFiClient. + * @param stream A stream to write received messages to. + */ + PubSubClient(uint8_t*, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client, Stream&); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param client The network client to use, for example WiFiClient. + */ + PubSubClient(const char*, uint16_t, Client& client); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param client The network client to use, for example WiFiClient. + * @param stream A stream to write received messages to. + */ + PubSubClient(const char*, uint16_t, Client& client, Stream&); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param callback Pointer to a message callback function. + * Called when a message arrives for a subscription created by this client. + * @param client The network client to use, for example WiFiClient. + */ + PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client); + + /** + * @brief Creates a fully configured client instance. + * @param domain The address of the server. + * @param port The port to connect to. + * @param callback Pointer to a message callback function. + * Called when a message arrives for a subscription created by this client. + * @param client The network client to use, for example WiFiClient. + * @param stream A stream to write received messages to. + */ + PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client, Stream&); + + /** + * @brief Destructor for the PubSubClient class. + */ + ~PubSubClient(); + + /** + * @brief Sets the server details. + * @param ip The address of the server. + * @param port The port to connect to. + * @return The client instance, allowing the function to be chained. + */ + PubSubClient& setServer(IPAddress ip, uint16_t port); + + /** + * @brief Sets the server details. + * @param ip The address of the server. + * @param port The port to connect to. + * @return The client instance, allowing the function to be chained. + */ + PubSubClient& setServer(uint8_t* ip, uint16_t port); + + /** + * @brief Sets the server details. + * @param ip The address of the server. + * @param port The port to connect to. + * @return The client instance, allowing the function to be chained. + */ + PubSubClient& setServer(const char* domain, uint16_t port); + + /** + * @brief Sets the message callback function. + * @param callback Pointer to a message callback function. + * Called when a message arrives for a subscription created by this client. + * @return The client instance, allowing the function to be chained. + */ + PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); + + /** + * @brief Sets the network client instance to use. + * @param client The network client to use, for example WiFiClient. + * @return The client instance, allowing the function to be chained. + */ + PubSubClient& setClient(Client& client); + + /** + * @brief Sets the stream to write received messages to. + * @param stream A stream to write received messages to. + * @return The client instance, allowing the function to be chained. + */ + PubSubClient& setStream(Stream& stream); + + /** + * @brief Sets the keep alive interval used by the client. + * This value should only be changed when the client is not connected. + * Set keepAlive to zero (0) to turn off the keep alive mechanism. + * @param keepAlive The keep alive interval, in seconds. + * @return The client instance, allowing the function to be chained. + */ + PubSubClient& setKeepAlive(uint16_t keepAlive); + + /** + * @brief Sets the socket timeout used by the client. + * This determines how long the client will wait for incoming data when it expects data to arrive - for example, + * whilst it is in the middle of reading a MQTT packet. + * @param timeout The socket timeout, in seconds. + * @return The client instance, allowing the function to be chained. + */ + PubSubClient& setSocketTimeout(uint16_t timeout); + + /** + * @brief Sets the size, in bytes, of the internal send and receive buffer. + * This must be large enough to contain the full MQTT packet. + * When sending or receiving messages, the packet will contain the full topic string, + * the payload data, and a small number of header bytes. + * @param size The size, in bytes, for the internal buffer. + * @return true If the buffer was resized. + * false If the buffer could not be resized. + */ + bool setBufferSize(size_t size); + + /** + * @brief Gets the current size of the internal buffer. + * @return The size of the internal buffer. + */ + size_t getBufferSize(); + + /** + * @brief Connects the client. + * @param id The client ID to use when connecting to the server. + * @return true If client succeeded in establishing a connection to the broker. + * false If client failed to establish a connection to the broker. + */ + bool connect(const char* id); + + /** + * @brief Connects the client. + * @param id The client ID to use when connecting to the server. + * @param user The username to use. If NULL, no username or password is used. + * @param pass The password to use. If NULL, no password is used. + * @return true If client succeeded in establishing a connection to the broker. + * false If client failed to establish a connection to the broker. + */ + bool connect(const char* id, const char* user, const char* pass); + + /** + * @brief Connects the client. + * @param id The client ID to use when connecting to the server. + * @param willTopic The topic to be used by the will message. + * @param willQos The quality of service to be used by the will message. [0, 1, 2]. + * @param willRetain Publish the will message with the retain flag. + * @return true If client succeeded in establishing a connection to the broker. + * false If client failed to establish a connection to the broker. + */ + bool connect(const char* id, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage); + + /** + * @brief Connects the client. + * @param id The client ID to use when connecting to the server. + * @param user The username to use. If NULL, no username or password is used. + * @param pass The password to use. If NULL, no password is used. + * @param willTopic The topic to be used by the will message. + * @param willQos The quality of service to be used by the will message. [0, 1, 2]. + * @param willRetain Publish the will message with the retain flag. + * @return true If client succeeded in establishing a connection to the broker. + * false If client failed to establish a connection to the broker. + */ + bool connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage); + + /** + * @brief Connects the client. + * @param id The client ID to use when connecting to the server. + * @param user The username to use. If NULL, no username or password is used. + * @param pass The password to use. If NULL, no password is used. + * @param willTopic The topic to be used by the will message. + * @param willQos The quality of service to be used by the will message. [0, 1, 2]. + * @param willRetain Publish the will message with the retain flag. + * @param cleanSession Connect with a clean session. + * @return true If client succeeded in establishing a connection to the broker. + * false If client failed to establish a connection to the broker. + */ + bool connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage, + bool cleanSession); + + /** + * @brief Disconnects the client. + */ + void disconnect(); + + /** + * @brief Publishes a non retained message to the specified topic. + * @param topic The topic to publish to. + * @param payload The message to publish. + * @return true If the publish succeeded. + * false If the publish failed, either connection lost or message too large. + */ + bool publish(const char* topic, const char* payload); + + /** + * @brief Publishes a message to the specified topic. + * @param topic The topic to publish to. + * @param payload The message to publish. + * @param retained Publish the message with the retain flag. + * @return true If the publish succeeded. + * false If the publish failed, either connection lost or message too large. + */ + bool publish(const char* topic, const char* payload, bool retained); + + /** + * @brief Publishes a non retained message to the specified topic. + * @param topic The topic to publish to. + * @param payload The message to publish. + * @param plength The length of the payload. + * @return true If the publish succeeded. + * false If the publish failed, either connection lost or message too large. + */ + bool publish(const char* topic, const uint8_t* payload, size_t plength); + + /** + * @brief Publishes a message to the specified topic. + * @param topic The topic to publish to. + * @param payload The message to publish. + * @param plength The length of the payload. + * @param retained Publish the message with the retain flag. + * @return true If the publish succeeded. + * false If the publish failed, either connection lost or message too large. + */ + bool publish(const char* topic, const uint8_t* payload, size_t plength, bool retained); + + /** + * @brief Publishes a message stored in PROGMEM to the specified topic. + * @param topic The topic to publish to. + * @param payload The message to publish. + * @param retained Publish the message with the retain flag. + * @return true If the publish succeeded. + * false If the publish failed, either connection lost or message too large. + */ + bool publish_P(const char* topic, const char* payload, bool retained); + + /** + * @brief Publishes a message stored in PROGMEM to the specified topic. + * @param topic The topic to publish to. + * @param payload The message to publish. + * @param plength The length of the payload. + * @param retained Publish the message with the retain flag. + * @return true If the publish succeeded. + * false If the publish failed, either connection lost or message too large. + */ + bool publish_P(const char* topic, const uint8_t* payload, size_t plength, bool retained); + + /** + * @brief Start to publish a message. + * This API: + * beginPublish(...) + * one or more calls to write(...) + * endPublish() + * Allows for arbitrarily large payloads to be sent without them having to be copied into + * a new buffer and held in memory at one time. + * @param topic The topic to publish to. + * @param plength The length of the payload. + * @param retained Publish the message with the retain flag. + * @return true If the publish succeeded. + * false If the publish failed, either connection lost or message too large. + */ + bool beginPublish(const char* topic, size_t plength, bool retained); + + /** + * @brief Finish sending a message that was started with a call to beginPublish. + * @return true If the publish succeeded. + * false If the publish failed, either connection lost or message too large. + */ + bool endPublish(); + + /** + * @brief Writes a single byte as a component of a publish started with a call to beginPublish. + * @param byte A byte to write to the publish payload. + * @return The number of bytes written. + */ + virtual size_t write(uint8_t); + + /** + * @brief Writes an array of bytes as a component of a publish started with a call to beginPublish. + * @param buffer The bytes to write. + * @param size The length of the payload to be sent. + * @return The number of bytes written. + */ + virtual size_t write(const uint8_t* buffer, size_t size); + + /** + * @brief Subscribes to messages published to the specified topic. + * @param topic The topic to subscribe to. + * @return true If sending the subscribe succeeded. + * false If sending the subscribe failed, either connection lost or message too large. + */ + bool subscribe(const char* topic); + + /** + * @brief Subscribes to messages published to the specified topic. + * @param topic The topic to subscribe to. + * @param qos The qos to subscribe at. [0, 1]. + * @return true If sending the subscribe succeeded. + * false If sending the subscribe failed, either connection lost or message too large. + */ + bool subscribe(const char* topic, uint8_t qos); + + /** + * @brief Unsubscribes from the specified topic. + * @param topic The topic to unsubscribe from. + * @return true If sending the unsubscribe succeeded. + * false If sending the unsubscribe failed, either connection lost or message too large. + */ + bool unsubscribe(const char* topic); + + /** + * @brief This should be called regularly to allow the client to process incoming messages and maintain its connection to the server. + * @return true If the client is still connected. + * false If the client is no longer connected. + */ + bool loop(); + + /** + * @brief Checks whether the client is connected to the server. + * @return true If the client is connected. + * false If the client is not connected. + */ + bool connected(); + + /** + * @brief Returns the current state of the client. + * If a connection attempt fails, this can be used to get more information about the failure. + * @note All of the values have corresponding constants defined in PubSubClient.h. + * @return -4 : MQTT_CONNECTION_TIMEOUT - The server didn't respond within the keepalive time. + * -3 : MQTT_CONNECTION_LOST - The network connection was broken. + * -2 : MQTT_CONNECT_FAILED - The network connection failed. + * -1 : MQTT_DISCONNECTED - The client is disconnected cleanly. + * 0 : MQTT_CONNECTED - The client is connected. + * 1 : MQTT_CONNECT_BAD_PROTOCOL - The server doesn't support the requested version of MQTT. + * 2 : MQTT_CONNECT_BAD_CLIENT_ID - The server rejected the client identifier. + * 3 : MQTT_CONNECT_UNAVAILABLE - The server was unable to accept the connection. + * 4 : MQTT_CONNECT_BAD_CREDENTIALS - The username/password were rejected. + * 5 : MQTT_CONNECT_UNAUTHORIZED - The client was not authorized to connect. + */ + int state(); +}; + +#endif diff --git a/lib/pubsubclient/tests/.gitignore b/lib/pubsubclient3/tests/.gitignore similarity index 100% rename from lib/pubsubclient/tests/.gitignore rename to lib/pubsubclient3/tests/.gitignore diff --git a/lib/pubsubclient/tests/Makefile b/lib/pubsubclient3/tests/Makefile similarity index 52% rename from lib/pubsubclient/tests/Makefile rename to lib/pubsubclient3/tests/Makefile index 1f7163675..1e67aac80 100644 --- a/lib/pubsubclient/tests/Makefile +++ b/lib/pubsubclient3/tests/Makefile @@ -6,7 +6,11 @@ VPATH=${SRC_PATH} SHIM_FILES=${SRC_PATH}/lib/*.cpp PSC_FILE=../src/PubSubClient.cpp CC=g++ -CFLAGS=-I${SRC_PATH}/lib -I../src +CFLAGS=-std=c++11 -I${SRC_PATH}/lib -I../src +CFLAGS+=-pedantic -Werror -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 +CFLAGS+=-Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wno-unused -Wnull-dereference -Woverloaded-virtual +CFLAGS+=-Wredundant-decls -Wreorder -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch-default -Wundef +#CFLAGS+=-DDEBUG_PUBSUBCLIENT all: $(TEST_BIN) @@ -17,7 +21,7 @@ ${OUT_PATH}/%: ${SRC_PATH}/%.cpp ${PSC_FILE} ${SHIM_FILES} clean: @rm -rf ${OUT_PATH} -test: +test: all @bin/connect_spec @bin/publish_spec @bin/receive_spec diff --git a/lib/pubsubclient/tests/README.md b/lib/pubsubclient3/tests/README.md similarity index 93% rename from lib/pubsubclient/tests/README.md rename to lib/pubsubclient3/tests/README.md index e5700a6d6..e29496ad5 100644 --- a/lib/pubsubclient/tests/README.md +++ b/lib/pubsubclient3/tests/README.md @@ -7,9 +7,7 @@ There are two parts: - Tests that can be compiled and run on any machine - Tests that build the example sketches using the Arduino IDE - -It is a work-in-progress and is subject to complete refactoring as the whim takes -me. +It is a work-in-progress and is subject to complete refactoring as the whim takes me. ## Local tests @@ -17,8 +15,7 @@ me. These are a set of executables that can be run to test specific areas of functionality. They do not require a real Arduino to be attached, nor the use of the Arduino IDE. -The tests include a set of mock files to stub out the parts of the Arduino environment the library -depends on. +The tests include a set of mock files to stub out the parts of the Arduino environment the library depends on. ### Dependencies @@ -30,13 +27,15 @@ Build the tests using the provided `Makefile`: $ make -This will create a set of executables in `./bin/`. Run each of these executables to test the corresponding functionality. +This will create a set of executables in `./bin/`. Run each of these executables to test the corresponding functionality. + + $ make test *Note:* the `connect_spec` and `keepalive_spec` tests involve testing keepalive timers so naturally take a few minutes to run through. ## Arduino tests -*Note:* INO Tool doesn't currently play nicely with Arduino 1.5. This has broken this test suite. +*Note:* INO Tool doesn't currently play nicely with Arduino 1.5. This has broken this test suite. Without a suitable arduino plugged in, the test suite will only check the example sketches compile cleanly against the library. @@ -52,7 +51,7 @@ test case is built, uploaded and then the tests run. ### Running The test suite _does not_ run an MQTT server - it is assumed to be running already. - + $ python testsuite.py A summary of activity is printed to the console. More comprehensive logs are written @@ -67,7 +66,7 @@ The test case must follow these conventions: - sub-class `unittest.TestCase` - provide the class methods `setUpClass` and `tearDownClass` (TODO: make this optional) - all test method names begin with `test_` - + The suite will call the `setUpClass` method _before_ uploading the sketch. This allows any test setup to be performed before the sketch runs - such as connecting a client and subscribing to topics. @@ -87,7 +86,3 @@ do this, the suite looks for lines that _start_ with the following: byte ip[] = { and replaces them with the appropriate values. - - - - diff --git a/lib/pubsubclient3/tests/src/connect_spec.cpp b/lib/pubsubclient3/tests/src/connect_spec.cpp new file mode 100644 index 000000000..75dc819b5 --- /dev/null +++ b/lib/pubsubclient3/tests/src/connect_spec.cpp @@ -0,0 +1,361 @@ +#include "BDDTest.h" +#include "Buffer.h" +#include "PubSubClient.h" +#include "ShimClient.h" +#include "trace.h" + +byte server[] = {172, 16, 0, 2}; + +// function declarations +void callback(char* topic, uint8_t* payload, size_t length); +int test_connect_fails_no_network(); +int test_connect_fails_on_no_response(); +int test_connect_properly_formatted(); +int test_connect_properly_formatted_hostname(); +int test_connect_fails_on_bad_rc(); +int test_connect_non_clean_session(); +int test_connect_accepts_username_password(); +int test_connect_accepts_username_no_password(); +int test_connect_accepts_username_blank_password(); +int test_connect_ignores_password_no_username(); +int test_connect_with_will(); +int test_connect_with_will_username_password(); +int test_connect_disconnect_connect(); +int test_connect_custom_keepalive(); + +void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t length) { + // handle message arrived +} + +int test_connect_fails_no_network() { + IT("fails to connect if underlying client doesn't connect"); + ShimClient shimClient; + shimClient.setAllowConnect(false); + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_FALSE(rc); + int state = client.state(); + IS_TRUE(state == MQTT_CONNECT_FAILED); + END_IT +} + +int test_connect_fails_on_no_response() { + IT("fails to connect if no response received after 15 seconds"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_FALSE(rc); + int state = client.state(); + IS_TRUE(state == MQTT_CONNECTION_TIMEOUT); + END_IT +} + +int test_connect_properly_formatted() { + IT("sends a properly formatted connect packet and succeeds"); + ShimClient shimClient; + + shimClient.setAllowConnect(true); + byte expectServer[] = {172, 16, 0, 2}; + shimClient.expectConnect(expectServer, 1883); + byte connect[] = {0x10, 0x18, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0x2, 0x0, 0xf, 0x0, + 0xc, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x31}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + + shimClient.expect(connect, 26); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + int state = client.state(); + IS_TRUE(state == MQTT_DISCONNECTED); + + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + state = client.state(); + IS_TRUE(state == MQTT_CONNECTED); + + END_IT +} + +int test_connect_properly_formatted_hostname() { + IT("accepts a hostname"); + ShimClient shimClient; + + shimClient.setAllowConnect(true); + shimClient.expectConnect("localhost", 1883); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client("localhost", 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_connect_fails_on_bad_rc() { + IT("fails to connect if a bad return code is received"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + byte connack[] = {0x20, 0x02, 0x00, 0x01}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_FALSE(rc); + + int state = client.state(); + IS_TRUE(state == 0x01); + + END_IT +} + +int test_connect_non_clean_session() { + IT("sends a properly formatted non-clean session connect packet and succeeds"); + ShimClient shimClient; + + shimClient.setAllowConnect(true); + byte expectServer[] = {172, 16, 0, 2}; + shimClient.expectConnect(expectServer, 1883); + byte connect[] = {0x10, 0x18, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0x0, 0x0, 0xf, 0x0, + 0xc, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x31}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + + shimClient.expect(connect, 26); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + int state = client.state(); + IS_TRUE(state == MQTT_DISCONNECTED); + + bool rc = client.connect("client_test1", 0, 0, 0, 0, 0, 0, 0); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + state = client.state(); + IS_TRUE(state == MQTT_CONNECTED); + + END_IT +} + +int test_connect_accepts_username_password() { + IT("accepts a username and password"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connect[] = {0x10, 0x24, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0xc2, 0x0, 0xf, 0x0, 0xc, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x31, 0x0, 0x4, 0x75, 0x73, 0x65, 0x72, 0x0, 0x4, 0x70, 0x61, 0x73, 0x73}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.expect(connect, 0x26); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1", "user", "pass"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_connect_accepts_username_no_password() { + IT("accepts a username but no password"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connect[] = {0x10, 0x1e, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0x82, 0x0, 0xf, 0x0, 0xc, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x31, 0x0, 0x4, 0x75, 0x73, 0x65, 0x72}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.expect(connect, 0x20); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1", "user", 0); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_connect_accepts_username_blank_password() { + IT("accepts a username and blank password"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connect[] = {0x10, 0x20, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0xc2, 0x0, 0xf, 0x0, 0xc, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x31, 0x0, 0x4, 0x75, 0x73, 0x65, 0x72, 0x0, 0x0}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.expect(connect, 0x26); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1", "user", "pass"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_connect_ignores_password_no_username() { + IT("ignores a password but no username"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connect[] = {0x10, 0x18, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0x2, 0x0, 0xf, 0x0, + 0xc, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x31}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.expect(connect, 26); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1", 0, "pass"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_connect_with_will() { + IT("accepts a will"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connect[] = {0x10, 0x30, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0xe, 0x0, 0xf, 0x0, 0xc, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x31, 0x0, 0x9, 0x77, 0x69, 0x6c, 0x6c, 0x54, 0x6f, + 0x70, 0x69, 0x63, 0x0, 0xb, 0x77, 0x69, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.expect(connect, 0x32); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1", "willTopic", 1, 0, "willMessage"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_connect_with_will_username_password() { + IT("accepts a will, username and password"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connect[] = {0x10, 0x40, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0xce, 0x0, 0xf, 0x0, 0xc, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x31, 0x0, 0x9, 0x77, 0x69, 0x6c, 0x6c, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x0, 0xb, 0x77, 0x69, 0x6c, 0x6c, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0, 0x4, 0x75, 0x73, 0x65, 0x72, 0x0, 0x8, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.expect(connect, 0x42); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1", "user", "password", "willTopic", 1, 0, "willMessage"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_connect_disconnect_connect() { + IT("connects, disconnects and connects again"); + ShimClient shimClient; + + shimClient.setAllowConnect(true); + byte expectServer[] = {172, 16, 0, 2}; + shimClient.expectConnect(expectServer, 1883); + byte connect[] = {0x10, 0x18, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0x2, 0x0, 0xf, 0x0, + 0xc, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x31}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + + shimClient.expect(connect, 26); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + + int state = client.state(); + IS_TRUE(state == MQTT_DISCONNECTED); + + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + state = client.state(); + IS_TRUE(state == MQTT_CONNECTED); + + byte disconnect[] = {0xE0, 0x00}; + shimClient.expect(disconnect, 2); + + client.disconnect(); + + IS_FALSE(client.connected()); + IS_FALSE(shimClient.connected()); + IS_FALSE(shimClient.error()); + + state = client.state(); + IS_TRUE(state == MQTT_DISCONNECTED); + + shimClient.expect(connect, 28); + shimClient.respond(connack, 4); + rc = client.connect("client_test1"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + state = client.state(); + IS_TRUE(state == MQTT_CONNECTED); + + END_IT +} + +int test_connect_custom_keepalive() { + IT("sends a properly formatted connect packet with custom keepalive value"); + ShimClient shimClient; + + shimClient.setAllowConnect(true); + byte expectServer[] = {172, 16, 0, 2}; + shimClient.expectConnect(expectServer, 1883); + + // Set keepalive to 300secs == 0x01 0x2c + byte connect[] = {0x10, 0x18, 0x0, 0x4, 0x4d, 0x51, 0x54, 0x54, 0x4, 0x2, 0x01, 0x2c, 0x0, + 0xc, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x31}; + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + + shimClient.expect(connect, 26); + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + int state = client.state(); + IS_TRUE(state == MQTT_DISCONNECTED); + + client.setKeepAlive(300); + + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + state = client.state(); + IS_TRUE(state == MQTT_CONNECTED); + + END_IT +} + +int main() { + SUITE("Connect"); + + test_connect_fails_no_network(); + test_connect_fails_on_no_response(); + + test_connect_properly_formatted(); + test_connect_non_clean_session(); + test_connect_accepts_username_password(); + test_connect_fails_on_bad_rc(); + test_connect_properly_formatted_hostname(); + + test_connect_accepts_username_no_password(); + test_connect_ignores_password_no_username(); + test_connect_with_will(); + test_connect_with_will_username_password(); + test_connect_disconnect_connect(); + + test_connect_custom_keepalive(); + FINISH +} diff --git a/lib/pubsubclient/tests/src/keepalive_spec.cpp b/lib/pubsubclient3/tests/src/keepalive_spec.cpp similarity index 51% rename from lib/pubsubclient/tests/src/keepalive_spec.cpp rename to lib/pubsubclient3/tests/src/keepalive_spec.cpp index ea643cf17..58e3f206c 100644 --- a/lib/pubsubclient/tests/src/keepalive_spec.cpp +++ b/lib/pubsubclient3/tests/src/keepalive_spec.cpp @@ -1,40 +1,48 @@ -#include "PubSubClient.h" -#include "ShimClient.h" -#include "Buffer.h" -#include "BDDTest.h" -#include "trace.h" #include -byte server[] = { 172, 16, 0, 2 }; +#include "BDDTest.h" +#include "Buffer.h" +#include "PubSubClient.h" +#include "ShimClient.h" +#include "trace.h" -void callback(char* topic, byte* payload, unsigned int length) { - // handle message arrived +byte server[] = {172, 16, 0, 2}; + +// function declarations +void callback(char* topic, uint8_t* payload, size_t length); +int test_keepalive_pings_idle(); +int test_keepalive_pings_with_outbound_qos0(); +int test_keepalive_pings_with_inbound_qos0(); +int test_keepalive_no_pings_inbound_qos1(); +int test_keepalive_disconnects_hung(); + +void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t length) { + // handle message arrived } - int test_keepalive_pings_idle() { IT("keeps an idle connection alive (takes 1 minute)"); ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + bool rc = client.connect("client_test1"); IS_TRUE(rc); - byte pingreq[] = { 0xC0,0x0 }; - shimClient.expect(pingreq,2); - byte pingresp[] = { 0xD0,0x0 }; - shimClient.respond(pingresp,2); + byte pingreq[] = {0xC0, 0x0}; + shimClient.expect(pingreq, 2); + byte pingresp[] = {0xD0, 0x0}; + shimClient.respond(pingresp, 2); for (int i = 0; i < 50; i++) { sleep(1); - if ( i == 15 || i == 31 || i == 47) { - shimClient.expect(pingreq,2); - shimClient.respond(pingresp,2); + if (i == 15 || i == 31 || i == 47) { + shimClient.expect(pingreq, 2); + shimClient.respond(pingresp, 2); } rc = client.loop(); IS_TRUE(rc); @@ -51,27 +59,27 @@ int test_keepalive_pings_with_outbound_qos0() { ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + bool rc = client.connect("client_test1"); IS_TRUE(rc); - byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; + byte publish[] = {0x30, 0xe, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; for (int i = 0; i < 50; i++) { - TRACE(i<<":"); - shimClient.expect(publish,16); - rc = client.publish((char*)"topic",(char*)"payload"); + TRACE(i << ":"); + shimClient.expect(publish, 16); + rc = client.publish("topic", "payload"); IS_TRUE(rc); IS_FALSE(shimClient.error()); sleep(1); - if ( i == 15 || i == 31 || i == 47) { - byte pingreq[] = { 0xC0,0x0 }; - shimClient.expect(pingreq,2); - byte pingresp[] = { 0xD0,0x0 }; - shimClient.respond(pingresp,2); + if (i == 15 || i == 31 || i == 47) { + byte pingreq[] = {0xC0, 0x0}; + shimClient.expect(pingreq, 2); + byte pingresp[] = {0xD0, 0x0}; + shimClient.respond(pingresp, 2); } rc = client.loop(); IS_TRUE(rc); @@ -87,25 +95,25 @@ int test_keepalive_pings_with_inbound_qos0() { ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + bool rc = client.connect("client_test1"); IS_TRUE(rc); - byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; + byte publish[] = {0x30, 0xe, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; for (int i = 0; i < 50; i++) { - TRACE(i<<":"); + TRACE(i << ":"); sleep(1); - if ( i == 15 || i == 31 || i == 47) { - byte pingreq[] = { 0xC0,0x0 }; - shimClient.expect(pingreq,2); - byte pingresp[] = { 0xD0,0x0 }; - shimClient.respond(pingresp,2); + if (i == 15 || i == 31 || i == 47) { + byte pingreq[] = {0xC0, 0x0}; + shimClient.expect(pingreq, 2); + byte pingresp[] = {0xD0, 0x0}; + shimClient.respond(pingresp, 2); } - shimClient.respond(publish,16); + shimClient.respond(publish, 16); rc = client.loop(); IS_TRUE(rc); IS_FALSE(shimClient.error()); @@ -120,19 +128,19 @@ int test_keepalive_no_pings_inbound_qos1() { ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + bool rc = client.connect("client_test1"); IS_TRUE(rc); - byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - byte puback[] = {0x40,0x2,0x12,0x34}; + byte publish[] = {0x32, 0x10, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x34, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + byte puback[] = {0x40, 0x2, 0x12, 0x34}; for (int i = 0; i < 50; i++) { - shimClient.respond(publish,18); - shimClient.expect(puback,4); + shimClient.respond(publish, 18); + shimClient.expect(puback, 4); sleep(1); rc = client.loop(); IS_TRUE(rc); @@ -148,15 +156,15 @@ int test_keepalive_disconnects_hung() { ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + bool rc = client.connect("client_test1"); IS_TRUE(rc); - byte pingreq[] = { 0xC0,0x0 }; - shimClient.expect(pingreq,2); + byte pingreq[] = {0xC0, 0x0}; + shimClient.expect(pingreq, 2); for (int i = 0; i < 32; i++) { sleep(1); @@ -172,8 +180,7 @@ int test_keepalive_disconnects_hung() { END_IT } -int main() -{ +int main() { SUITE("Keep-alive"); test_keepalive_pings_idle(); test_keepalive_pings_with_outbound_qos0(); diff --git a/lib/pubsubclient3/tests/src/lib/Arduino.h b/lib/pubsubclient3/tests/src/lib/Arduino.h new file mode 100644 index 000000000..b5903ea5c --- /dev/null +++ b/lib/pubsubclient3/tests/src/lib/Arduino.h @@ -0,0 +1,38 @@ +#ifndef Arduino_h +#define Arduino_h + +#include +#include +#include +#include + +#include + +#include "Print.h" + +extern "C" { +typedef uint8_t byte; +typedef uint8_t boolean; + +/* sketch */ +extern void setup(void); +extern void loop(void); +unsigned long millis(void); +} + +#define PROGMEM +#define strnlen_P strnlen +#define pgm_read_byte_near(x) *(x) + +#define yield(x) {} + +#pragma GCC system_header +#define ERROR_PSC_PRINTF(fmt, ...) printf(("PubSubClient error: " fmt), ##__VA_ARGS__) +#define ERROR_PSC_PRINTF_P(fmt, ...) printf(("PubSubClient error: " fmt), ##__VA_ARGS__) +#ifdef DEBUG_PUBSUBCLIENT +#define DEBUG_PSC_PRINTF(fmt, ...) printf(("PubSubClient: " fmt), ##__VA_ARGS__) +#endif + +#define _UNUSED_ __attribute__((unused)) + +#endif // Arduino_h diff --git a/lib/pubsubclient/tests/src/lib/BDDTest.cpp b/lib/pubsubclient3/tests/src/lib/BDDTest.cpp similarity index 82% rename from lib/pubsubclient/tests/src/lib/BDDTest.cpp rename to lib/pubsubclient3/tests/src/lib/BDDTest.cpp index a72bf65e2..10d392d3e 100644 --- a/lib/pubsubclient/tests/src/lib/BDDTest.cpp +++ b/lib/pubsubclient3/tests/src/lib/BDDTest.cpp @@ -1,9 +1,11 @@ #include "BDDTest.h" -#include "trace.h" -#include + #include -#include #include +#include +#include + +#include "trace.h" int testCount = 0; int testPasses = 0; @@ -19,20 +21,20 @@ int bddtest_test(const char* file, int line, const char* assertion, int result) if (!result) { LOG("✗\n"); std::ostringstream os; - os << " ! "<pos = 0; this->length = 0; - this->add(buf,size); + this->add(buf, size); } bool Buffer::available() { return this->pos < this->length; @@ -28,7 +29,7 @@ void Buffer::reset() { void Buffer::add(uint8_t* buf, size_t size) { uint16_t i = 0; - for (;ibuffer[this->length++] = buf[i]; } } diff --git a/lib/pubsubclient/tests/src/lib/Buffer.h b/lib/pubsubclient3/tests/src/lib/Buffer.h similarity index 84% rename from lib/pubsubclient/tests/src/lib/Buffer.h rename to lib/pubsubclient3/tests/src/lib/Buffer.h index f448cade8..ae3002ba2 100644 --- a/lib/pubsubclient/tests/src/lib/Buffer.h +++ b/lib/pubsubclient3/tests/src/lib/Buffer.h @@ -4,19 +4,19 @@ #include "Arduino.h" class Buffer { -private: - uint8_t buffer[1024]; + private: + uint8_t buffer[2048]; uint16_t pos; uint16_t length; - -public: + + public: Buffer(); Buffer(uint8_t* buf, size_t size); - + virtual bool available(); virtual uint8_t next(); virtual void reset(); - + virtual void add(uint8_t* buf, size_t size); }; diff --git a/lib/pubsubclient3/tests/src/lib/Client.h b/lib/pubsubclient3/tests/src/lib/Client.h new file mode 100644 index 000000000..54c86d1bd --- /dev/null +++ b/lib/pubsubclient3/tests/src/lib/Client.h @@ -0,0 +1,21 @@ +#ifndef client_h +#define client_h +#include "IPAddress.h" + +class Client { + public: + virtual int connect(IPAddress ip, uint16_t port) = 0; + virtual int connect(const char *host, uint16_t port) = 0; + virtual size_t write(uint8_t) = 0; + virtual size_t write(const uint8_t *buf, size_t size) = 0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +}; + +#endif diff --git a/lib/pubsubclient/tests/src/lib/IPAddress.cpp b/lib/pubsubclient3/tests/src/lib/IPAddress.cpp similarity index 58% rename from lib/pubsubclient/tests/src/lib/IPAddress.cpp rename to lib/pubsubclient3/tests/src/lib/IPAddress.cpp index 610ff4c53..99d4ede07 100644 --- a/lib/pubsubclient/tests/src/lib/IPAddress.cpp +++ b/lib/pubsubclient3/tests/src/lib/IPAddress.cpp @@ -2,43 +2,35 @@ #include #include -IPAddress::IPAddress() -{ +IPAddress::IPAddress() { memset(_address, 0, sizeof(_address)); } -IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) -{ +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) { _address[0] = first_octet; _address[1] = second_octet; _address[2] = third_octet; _address[3] = fourth_octet; } -IPAddress::IPAddress(uint32_t address) -{ +IPAddress::IPAddress(uint32_t address) { memcpy(_address, &address, sizeof(_address)); } -IPAddress::IPAddress(const uint8_t *address) -{ +IPAddress::IPAddress(const uint8_t* address) { memcpy(_address, address, sizeof(_address)); } -IPAddress& IPAddress::operator=(const uint8_t *address) -{ +IPAddress& IPAddress::operator=(const uint8_t* address) { memcpy(_address, address, sizeof(_address)); return *this; } -IPAddress& IPAddress::operator=(uint32_t address) -{ - memcpy(_address, (const uint8_t *)&address, sizeof(_address)); +IPAddress& IPAddress::operator=(uint32_t address) { + memcpy(_address, (const uint8_t*)&address, sizeof(_address)); return *this; } -bool IPAddress::operator==(const uint8_t* addr) -{ +bool IPAddress::operator==(const uint8_t* addr) { return memcmp(addr, _address, sizeof(_address)) == 0; } - diff --git a/lib/pubsubclient/tests/src/lib/IPAddress.h b/lib/pubsubclient3/tests/src/lib/IPAddress.h similarity index 79% rename from lib/pubsubclient/tests/src/lib/IPAddress.h rename to lib/pubsubclient3/tests/src/lib/IPAddress.h index e75a8fe65..05efdcd6c 100644 --- a/lib/pubsubclient/tests/src/lib/IPAddress.h +++ b/lib/pubsubclient3/tests/src/lib/IPAddress.h @@ -8,10 +8,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -26,40 +26,48 @@ #ifndef IPAddress_h #define IPAddress_h - // A class to make it easier to handle and pass around IP addresses class IPAddress { -private: - uint8_t _address[4]; // IPv4 address + private: + alignas(4) uint8_t _address[4]; // IPv4 address // Access the raw byte array containing the address. Because this returns a pointer // to the internal structure rather than a copy of the address this function should only // be used when you know that the usage of the returned uint8_t* will be transient and not // stored. - uint8_t* raw_address() { return _address; }; + uint8_t* raw_address() { + return _address; + }; -public: + public: // Constructors IPAddress(); IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); IPAddress(uint32_t address); - IPAddress(const uint8_t *address); + IPAddress(const uint8_t* address); // Overloaded cast operator to allow IPAddress objects to be used where a pointer // to a four-byte uint8_t array is expected - operator uint32_t() { return *((uint32_t*)_address); }; - bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; + operator uint32_t() { + return *((uint32_t*)_address); + }; + bool operator==(IPAddress& addr) { + return (*((uint32_t*)_address)) == (*(reinterpret_cast(addr._address))); + }; bool operator==(const uint8_t* addr); // Overloaded index operator to allow getting and setting individual octets of the address - uint8_t operator[](int index) const { return _address[index]; }; - uint8_t& operator[](int index) { return _address[index]; }; + uint8_t operator[](int index) const { + return _address[index]; + }; + uint8_t& operator[](int index) { + return _address[index]; + }; // Overloaded copy operators to allow initialisation of IPAddress objects from other types - IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(const uint8_t* address); IPAddress& operator=(uint32_t address); - friend class EthernetClass; friend class UDP; friend class Client; @@ -68,5 +76,4 @@ public: friend class DNSClient; }; - #endif diff --git a/lib/pubsubclient/tests/src/lib/Print.h b/lib/pubsubclient3/tests/src/lib/Print.h similarity index 94% rename from lib/pubsubclient/tests/src/lib/Print.h rename to lib/pubsubclient3/tests/src/lib/Print.h index 02ef77c2c..60084095b 100644 --- a/lib/pubsubclient/tests/src/lib/Print.h +++ b/lib/pubsubclient3/tests/src/lib/Print.h @@ -21,8 +21,8 @@ #define Print_h class Print { - public: - virtual size_t write(uint8_t) = 0; + public: + virtual size_t write(uint8_t) = 0; }; #endif diff --git a/lib/pubsubclient/tests/src/lib/ShimClient.cpp b/lib/pubsubclient3/tests/src/lib/ShimClient.cpp similarity index 67% rename from lib/pubsubclient/tests/src/lib/ShimClient.cpp rename to lib/pubsubclient3/tests/src/lib/ShimClient.cpp index f70115fa8..ba283020d 100644 --- a/lib/pubsubclient/tests/src/lib/ShimClient.cpp +++ b/lib/pubsubclient3/tests/src/lib/ShimClient.cpp @@ -1,13 +1,16 @@ #include "ShimClient.h" -#include "trace.h" -#include + #include + #include +#include + +#include "trace.h" extern "C" { - uint32_t millis(void) { - return time(0)*1000; - } +unsigned long millis(void) { + return (unsigned long)time(0) * 1000UL; +} } ShimClient::ShimClient() { @@ -25,36 +28,35 @@ int ShimClient::connect(IPAddress ip, uint16_t port) { if (this->_allowConnect) { this->_connected = true; } - if (this->_expectedPort !=0) { - // if (memcmp(ip,this->_expectedIP,4) != 0) { - // TRACE( "ip mismatch\n"); - // this->_error = true; - // } + if (this->_expectedPort != 0) { + if (memcmp(&ip, &this->_expectedIP, 4) != 0) { + TRACE("ip mismatch\n"); + this->_error = true; + } if (port != this->_expectedPort) { - TRACE( "port mismatch\n"); + TRACE("port mismatch\n"); this->_error = true; } } return this->_connected; } -int ShimClient::connect(const char *host, uint16_t port) { +int ShimClient::connect(const char *host, uint16_t port) { if (this->_allowConnect) { this->_connected = true; } - if (this->_expectedPort !=0) { - if (strcmp(host,this->_expectedHost) != 0) { - TRACE( "host mismatch\n"); + if (this->_expectedPort != 0) { + if (strcmp(host, this->_expectedHost) != 0) { + TRACE("host mismatch\n"); this->_error = true; } if (port != this->_expectedPort) { - TRACE( "port mismatch\n"); + TRACE("port mismatch\n"); this->_error = true; } - } return this->_connected; } -size_t ShimClient::write(uint8_t b) { +size_t ShimClient::write(uint8_t b) { this->_received += 1; TRACE(std::hex << (unsigned int)b); if (!this->expectAnything) { @@ -68,15 +70,15 @@ size_t ShimClient::write(uint8_t b) { this->_error = true; } } - TRACE("\n"<< std::dec); + TRACE("\n" << std::dec); return 1; } -size_t ShimClient::write(const uint8_t *buf, size_t size) { +size_t ShimClient::write(const uint8_t *buf, size_t size) { this->_received += size; - TRACE( "[" << std::dec << (unsigned int)(size) << "] "); - uint16_t i=0; - for (;i0) { + TRACE("[" << std::dec << (unsigned int)(size) << "] "); + uint16_t i = 0; + for (; i < size; i++) { + if (i > 0) { TRACE(":"); } TRACE(std::hex << (unsigned int)(buf[i])); @@ -93,37 +95,44 @@ size_t ShimClient::write(const uint8_t *buf, size_t size) { } } } - TRACE("\n"<responseBuffer->available(); } -int ShimClient::read() { return this->responseBuffer->next(); } +int ShimClient::read() { + return this->responseBuffer->next(); +} int ShimClient::read(uint8_t *buf, size_t size) { uint16_t i = 0; - for (;iread(); } return size; } -int ShimClient::peek() { return 0; } +int ShimClient::peek() { + return 0; +} void ShimClient::flush() {} void ShimClient::stop() { this->setConnected(false); } -uint8_t ShimClient::connected() { return this->_connected; } -ShimClient::operator bool() { return true; } +uint8_t ShimClient::connected() { + return this->_connected; +} +ShimClient::operator bool() { + return true; +} - -ShimClient* ShimClient::respond(uint8_t *buf, size_t size) { - this->responseBuffer->add(buf,size); +ShimClient *ShimClient::respond(uint8_t *buf, size_t size) { + this->responseBuffer->add(buf, size); return this; } -ShimClient* ShimClient::expect(uint8_t *buf, size_t size) { +ShimClient *ShimClient::expect(uint8_t *buf, size_t size) { this->expectAnything = false; - this->expectBuffer->add(buf,size); + this->expectBuffer->add(buf, size); return this; } diff --git a/lib/pubsubclient3/tests/src/lib/ShimClient.h b/lib/pubsubclient3/tests/src/lib/ShimClient.h new file mode 100644 index 000000000..cb369668b --- /dev/null +++ b/lib/pubsubclient3/tests/src/lib/ShimClient.h @@ -0,0 +1,50 @@ +#ifndef shimclient_h +#define shimclient_h + +#include "Arduino.h" +#include "Buffer.h" +#include "Client.h" +#include "IPAddress.h" + +class ShimClient : public Client { + private: + Buffer *responseBuffer; + Buffer *expectBuffer; + bool _allowConnect; + bool _connected; + bool expectAnything; + bool _error; + uint16_t _received; + IPAddress _expectedIP; + uint16_t _expectedPort; + const char *_expectedHost; + + public: + ShimClient(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + + virtual ShimClient *respond(uint8_t *buf, size_t size); + virtual ShimClient *expect(uint8_t *buf, size_t size); + + virtual void expectConnect(IPAddress ip, uint16_t port); + virtual void expectConnect(const char *host, uint16_t port); + + virtual uint16_t received(); + virtual bool error(); + + virtual void setAllowConnect(bool b); + virtual void setConnected(bool b); +}; + +#endif diff --git a/lib/pubsubclient/tests/src/lib/Stream.cpp b/lib/pubsubclient3/tests/src/lib/Stream.cpp similarity index 86% rename from lib/pubsubclient/tests/src/lib/Stream.cpp rename to lib/pubsubclient3/tests/src/lib/Stream.cpp index b0ecbb44e..20f514661 100644 --- a/lib/pubsubclient/tests/src/lib/Stream.cpp +++ b/lib/pubsubclient3/tests/src/lib/Stream.cpp @@ -1,15 +1,18 @@ #include "Stream.h" -#include "trace.h" -#include + #include +#include + +#include "trace.h" + Stream::Stream() { this->expectBuffer = new Buffer(); this->_error = false; this->_written = 0; } -size_t Stream::write(uint8_t b) { +size_t Stream::write(uint8_t b) { this->_written++; TRACE(std::hex << (unsigned int)b); if (this->expectBuffer->available()) { @@ -21,17 +24,16 @@ size_t Stream::write(uint8_t b) { } else { this->_error = true; } - TRACE("\n"<< std::dec); + TRACE("\n" << std::dec); return 1; } - bool Stream::error() { return this->_error; } void Stream::expect(uint8_t *buf, size_t size) { - this->expectBuffer->add(buf,size); + this->expectBuffer->add(buf, size); } uint16_t Stream::length() { diff --git a/lib/pubsubclient/tests/src/lib/Stream.h b/lib/pubsubclient3/tests/src/lib/Stream.h similarity index 78% rename from lib/pubsubclient/tests/src/lib/Stream.h rename to lib/pubsubclient3/tests/src/lib/Stream.h index 4e41f86fa..41f7058b3 100644 --- a/lib/pubsubclient/tests/src/lib/Stream.h +++ b/lib/pubsubclient3/tests/src/lib/Stream.h @@ -5,17 +5,17 @@ #include "Buffer.h" class Stream { -private: + private: Buffer* expectBuffer; bool _error; uint16_t _written; -public: + public: Stream(); virtual size_t write(uint8_t); - + virtual bool error(); - virtual void expect(uint8_t *buf, size_t size); + virtual void expect(uint8_t* buf, size_t size); virtual uint16_t length(); }; diff --git a/lib/pubsubclient/tests/src/lib/trace.h b/lib/pubsubclient3/tests/src/lib/trace.h similarity index 100% rename from lib/pubsubclient/tests/src/lib/trace.h rename to lib/pubsubclient3/tests/src/lib/trace.h index 42eb99104..36a9cd40f 100644 --- a/lib/pubsubclient/tests/src/lib/trace.h +++ b/lib/pubsubclient3/tests/src/lib/trace.h @@ -1,9 +1,9 @@ #ifndef trace_h #define trace_h -#include - #include +#include + #define LOG(x) {std::cout << x << std::flush; } #define TRACE(x) {if (getenv("TRACE")) { std::cout << x << std::flush; }} diff --git a/lib/pubsubclient3/tests/src/publish_spec.cpp b/lib/pubsubclient3/tests/src/publish_spec.cpp new file mode 100644 index 000000000..4346a721a --- /dev/null +++ b/lib/pubsubclient3/tests/src/publish_spec.cpp @@ -0,0 +1,228 @@ +#include "BDDTest.h" +#include "Buffer.h" +#include "PubSubClient.h" +#include "ShimClient.h" +#include "trace.h" + +byte server[] = {172, 16, 0, 2}; + +// function declarations +void callback(char* topic, uint8_t* payload, size_t length); +int test_publish(); +int test_publish_bytes(); +int test_publish_retained(); +int test_publish_retained_2(); +int test_publish_not_connected(); +int test_publish_too_long(); +int test_publish_P(); +int test_publish_P_too_long(); + +void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t length) { + // handle message arrived +} + +int test_publish() { + IT("publishes a null-terminated string"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30, 0xe, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + shimClient.expect(publish, 16); + + rc = client.publish("topic", "payload"); + IS_TRUE(rc); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_publish_bytes() { + IT("publishes a byte array"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte payload[] = {0x01, 0x02, 0x03, 0x0, 0x05}; + size_t length = 5; + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30, 0xc, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x1, 0x2, 0x3, 0x0, 0x5}; + shimClient.expect(publish, 14); + + rc = client.publish("topic", payload, length); + IS_TRUE(rc); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_publish_retained() { + IT("publishes retained - 1"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte payload[] = {0x01, 0x02, 0x03, 0x0, 0x05}; + size_t length = 5; + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x31, 0xc, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x1, 0x2, 0x3, 0x0, 0x5}; + shimClient.expect(publish, 14); + + rc = client.publish("topic", payload, length, true); + IS_TRUE(rc); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_publish_retained_2() { + IT("publishes retained - 2"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x31, 0xc, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 'A', 'B', 'C', 'D', 'E'}; + shimClient.expect(publish, 14); + + rc = client.publish("topic", "ABCDE", true); + IS_TRUE(rc); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_publish_not_connected() { + IT("publish fails when not connected"); + ShimClient shimClient; + + PubSubClient client(server, 1883, callback, shimClient); + + bool rc = client.publish("topic", "payload"); + IS_FALSE(rc); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_publish_too_long() { + IT("publish fails when topic/payload are too long"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + // 0 1 2 3 4 5 6 7 8 9 0 1 2 + char topic[] = "1234567890123456789012345678901234567890123456789012345678901234"; + + // 0 1 2 3 4 5 6 7 8 9 0 1 2 + char payload[] = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + client.setBufferSize(64); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + rc = client.publish(topic, payload); + IS_FALSE(rc); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_publish_P() { + IT("publishes using PROGMEM"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte payload[] = {0x01, 0x02, 0x03, 0x0, 0x05}; + size_t length = 5; + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x31, 0xc, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x1, 0x2, 0x3, 0x0, 0x5}; + shimClient.expect(publish, 14); + + rc = client.publish_P("topic", payload, length, true); + IS_TRUE(rc); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_publish_P_too_long() { + IT("publish using PROGMEM fails when topic are too long"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + // 0 1 2 3 4 5 6 7 8 9 0 1 2 + char topic[] = "1234567890123456789012345678901234567890123456789012345678901234"; + + // 0 1 2 3 4 5 6 7 8 9 0 1 2 + char payload[] = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + client.setBufferSize(64); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + rc = client.publish_P(topic, payload, false); + IS_FALSE(rc); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int main() { + SUITE("Publish"); + test_publish(); + test_publish_bytes(); + test_publish_retained(); + test_publish_retained_2(); + test_publish_not_connected(); + test_publish_too_long(); + test_publish_P(); + test_publish_P_too_long(); + + FINISH +} diff --git a/lib/pubsubclient3/tests/src/receive_spec.cpp b/lib/pubsubclient3/tests/src/receive_spec.cpp new file mode 100644 index 000000000..3635e9778 --- /dev/null +++ b/lib/pubsubclient3/tests/src/receive_spec.cpp @@ -0,0 +1,345 @@ +#include "BDDTest.h" +#include "Buffer.h" +#include "PubSubClient.h" +#include "ShimClient.h" +#include "trace.h" + +// If this is changed to > 128 then the publish packet below +// is no longer valid as it assumes the remaining length +// is a single-byte. Don't make that mistake like I just +// did and lose a whole evening tracking down the issue. +#define PUBLISH_LEN 80 + +byte server[] = {172, 16, 0, 2}; + +bool callback_called = false; +char lastTopic[1024]; +char lastPayload[1024]; +size_t lastLength; + +// function declarations +void callback(char* topic, uint8_t* payload, size_t length); +void reset_callback(); +int test_receive_callback(); +int test_receive_stream(); +int test_receive_max_sized_message(); +int test_drop_invalid_remaining_length_message(); +int test_receive_oversized_message(); +int test_resize_buffer(); +int test_receive_oversized_stream_message(); +int test_receive_qos1(); + +void reset_callback() { + callback_called = false; + lastTopic[0] = '\0'; + lastPayload[0] = '\0'; + lastLength = 0; +} + +void callback(char* topic, uint8_t* payload, size_t length) { + TRACE("Callback received topic=[" << topic << "] length=" << length << "\n") + callback_called = true; + strcpy(lastTopic, topic); + memcpy(lastPayload, payload, length); + lastLength = length; +} + +int test_receive_callback() { + IT("receives a callback message"); + reset_callback(); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30, 0xe, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + shimClient.respond(publish, 16); + + rc = client.loop(); + + IS_TRUE(rc); + + IS_TRUE(callback_called); + IS_TRUE(strcmp(lastTopic, "topic") == 0); + IS_TRUE(memcmp(lastPayload, "payload", 7) == 0); + IS_TRUE(lastLength == 7); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_receive_stream() { + IT("receives a streamed callback message"); + reset_callback(); + + Stream stream; + uint8_t payload[] = "payload"; + stream.expect(payload, sizeof(payload) - 1); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient, stream); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30, 0xe, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + shimClient.respond(publish, 16); + + rc = client.loop(); + + IS_TRUE(rc); + + IS_TRUE(callback_called); + IS_TRUE(strcmp(lastTopic, "topic") == 0); + IS_TRUE(lastLength == 7); + + IS_FALSE(stream.error()); + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_receive_max_sized_message() { + IT("receives an max-sized message"); + reset_callback(); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + client.setBufferSize(PUBLISH_LEN); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30, PUBLISH_LEN - 2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + byte bigPublish[PUBLISH_LEN]; + memset(bigPublish, 'A', PUBLISH_LEN); + bigPublish[PUBLISH_LEN - 1] = 'B'; + memcpy(bigPublish, publish, 16); + shimClient.respond(bigPublish, PUBLISH_LEN); + + rc = client.loop(); + + IS_TRUE(rc); + + IS_TRUE(callback_called); + IS_TRUE(strcmp(lastTopic, "topic") == 0); + IS_TRUE(lastLength == PUBLISH_LEN - 9); + IS_TRUE(memcmp(lastPayload, bigPublish + 9, lastLength) == 0); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_receive_oversized_message() { + IT("drops an oversized message"); + reset_callback(); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + client.setBufferSize(PUBLISH_LEN - 1); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30, PUBLISH_LEN - 2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + byte bigPublish[PUBLISH_LEN]; + memset(bigPublish, 'A', PUBLISH_LEN); + bigPublish[PUBLISH_LEN - 1] = 'B'; + memcpy(bigPublish, publish, 16); + shimClient.respond(bigPublish, PUBLISH_LEN); + + rc = client.loop(); + + IS_TRUE(rc); + + IS_FALSE(callback_called); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_drop_invalid_remaining_length_message() { + IT("drops invalid remaining length message"); + reset_callback(); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30, 0x92, 0x92, 0x92, 0x92, 0x01, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + shimClient.respond(publish, 20); + + rc = client.loop(); + + IS_FALSE(rc); + + IS_FALSE(callback_called); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_resize_buffer() { + IT("receives a message larger than the default maximum"); + reset_callback(); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + client.setBufferSize(PUBLISH_LEN - 1); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30, PUBLISH_LEN - 2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + byte bigPublish[PUBLISH_LEN]; + memset(bigPublish, 'A', PUBLISH_LEN); + bigPublish[PUBLISH_LEN - 1] = 'B'; + memcpy(bigPublish, publish, 16); + // Send it twice + shimClient.respond(bigPublish, PUBLISH_LEN); + shimClient.respond(bigPublish, PUBLISH_LEN); + + rc = client.loop(); + IS_TRUE(rc); + + // First message fails as it is too big + IS_FALSE(callback_called); + + // Resize the buffer + client.setBufferSize(PUBLISH_LEN); + + rc = client.loop(); + IS_TRUE(rc); + + IS_TRUE(callback_called); + + IS_TRUE(strcmp(lastTopic, "topic") == 0); + IS_TRUE(lastLength == PUBLISH_LEN - 9); + IS_TRUE(memcmp(lastPayload, bigPublish + 9, lastLength) == 0); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_receive_oversized_stream_message() { + IT("receive an oversized streamed message"); + reset_callback(); + + Stream stream; + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient, stream); + client.setBufferSize(PUBLISH_LEN - 1); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30, PUBLISH_LEN - 2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + + byte bigPublish[PUBLISH_LEN]; + memset(bigPublish, 'A', PUBLISH_LEN); + bigPublish[PUBLISH_LEN - 1] = 'B'; + memcpy(bigPublish, publish, 16); + + shimClient.respond(bigPublish, PUBLISH_LEN); + stream.expect(bigPublish + 9, PUBLISH_LEN - 9); + + rc = client.loop(); + + IS_TRUE(rc); + + IS_TRUE(callback_called); + IS_TRUE(strcmp(lastTopic, "topic") == 0); + + IS_TRUE(lastLength == PUBLISH_LEN - 10); + + IS_FALSE(stream.error()); + IS_FALSE(shimClient.error()); + + END_IT +} + +int test_receive_qos1() { + IT("receives a qos1 message"); + reset_callback(); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); + + PubSubClient client(server, 1883, callback, shimClient); + bool rc = client.connect("client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x32, 0x10, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x34, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}; + shimClient.respond(publish, 18); + + byte puback[] = {0x40, 0x2, 0x12, 0x34}; + shimClient.expect(puback, 4); + + rc = client.loop(); + + IS_TRUE(rc); + + IS_TRUE(callback_called); + IS_TRUE(strcmp(lastTopic, "topic") == 0); + IS_TRUE(memcmp(lastPayload, "payload", 7) == 0); + IS_TRUE(lastLength == 7); + + IS_FALSE(shimClient.error()); + + END_IT +} + +int main() { + SUITE("Receive"); + test_receive_callback(); + test_receive_stream(); + test_receive_max_sized_message(); + test_drop_invalid_remaining_length_message(); + test_receive_oversized_message(); + test_resize_buffer(); + test_receive_oversized_stream_message(); + test_receive_qos1(); + + FINISH +} diff --git a/lib/pubsubclient/tests/src/subscribe_spec.cpp b/lib/pubsubclient3/tests/src/subscribe_spec.cpp similarity index 52% rename from lib/pubsubclient/tests/src/subscribe_spec.cpp rename to lib/pubsubclient3/tests/src/subscribe_spec.cpp index a41982355..8ae83e7ad 100644 --- a/lib/pubsubclient/tests/src/subscribe_spec.cpp +++ b/lib/pubsubclient3/tests/src/subscribe_spec.cpp @@ -1,14 +1,23 @@ +#include "BDDTest.h" +#include "Buffer.h" #include "PubSubClient.h" #include "ShimClient.h" -#include "Buffer.h" -#include "BDDTest.h" #include "trace.h" +byte server[] = {172, 16, 0, 2}; -byte server[] = { 172, 16, 0, 2 }; +// function declarations +void callback(char* topic, uint8_t* payload, size_t length); +int test_subscribe_no_qos(); +int test_subscribe_qos_1(); +int test_subscribe_not_connected(); +int test_subscribe_invalid_qos(); +int test_subscribe_too_long(); +int test_unsubscribe(); +int test_unsubscribe_not_connected(); -void callback(char* topic, byte* payload, unsigned int length) { - // handle message arrived +void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t length) { + // handle message arrived } int test_subscribe_no_qos() { @@ -16,19 +25,19 @@ int test_subscribe_no_qos() { ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + bool rc = client.connect("client_test1"); IS_TRUE(rc); - byte subscribe[] = { 0x82,0xa,0x0,0x2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x0 }; - shimClient.expect(subscribe,12); - byte suback[] = { 0x90,0x3,0x0,0x2,0x0 }; - shimClient.respond(suback,5); + byte subscribe[] = {0x82, 0xa, 0x0, 0x2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x0}; + shimClient.expect(subscribe, 12); + byte suback[] = {0x90, 0x3, 0x0, 0x2, 0x0}; + shimClient.respond(suback, 5); - rc = client.subscribe((char*)"topic"); + rc = client.subscribe("topic"); IS_TRUE(rc); IS_FALSE(shimClient.error()); @@ -41,19 +50,19 @@ int test_subscribe_qos_1() { ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + bool rc = client.connect("client_test1"); IS_TRUE(rc); - byte subscribe[] = { 0x82,0xa,0x0,0x2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1 }; - shimClient.expect(subscribe,12); - byte suback[] = { 0x90,0x3,0x0,0x2,0x1 }; - shimClient.respond(suback,5); + byte subscribe[] = {0x82, 0xa, 0x0, 0x2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x1}; + shimClient.expect(subscribe, 12); + byte suback[] = {0x90, 0x3, 0x0, 0x2, 0x1}; + shimClient.respond(suback, 5); - rc = client.subscribe((char*)"topic",1); + rc = client.subscribe("topic", 1); IS_TRUE(rc); IS_FALSE(shimClient.error()); @@ -67,7 +76,7 @@ int test_subscribe_not_connected() { PubSubClient client(server, 1883, callback, shimClient); - int rc = client.subscribe((char*)"topic"); + bool rc = client.subscribe("topic"); IS_FALSE(rc); IS_FALSE(shimClient.error()); @@ -80,16 +89,16 @@ int test_subscribe_invalid_qos() { ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + bool rc = client.connect("client_test1"); IS_TRUE(rc); - rc = client.subscribe((char*)"topic",2); + rc = client.subscribe("topic", 2); IS_FALSE(rc); - rc = client.subscribe((char*)"topic",254); + rc = client.subscribe("topic", 254); IS_FALSE(rc); IS_FALSE(shimClient.error()); @@ -102,20 +111,21 @@ int test_subscribe_too_long() { ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + client.setBufferSize(128); + bool rc = client.connect("client_test1"); IS_TRUE(rc); // max length should be allowed // 0 1 2 3 4 5 6 7 8 9 0 1 2 - rc = client.subscribe((char*)"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); + rc = client.subscribe("12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); IS_TRUE(rc); // 0 1 2 3 4 5 6 7 8 9 0 1 2 - rc = client.subscribe((char*)"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); + rc = client.subscribe("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); IS_FALSE(rc); IS_FALSE(shimClient.error()); @@ -123,25 +133,24 @@ int test_subscribe_too_long() { END_IT } - int test_unsubscribe() { IT("unsubscribes"); ShimClient shimClient; shimClient.setAllowConnect(true); - byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.respond(connack,4); + byte connack[] = {0x20, 0x02, 0x00, 0x00}; + shimClient.respond(connack, 4); PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1"); + bool rc = client.connect("client_test1"); IS_TRUE(rc); - byte unsubscribe[] = { 0xA2,0x9,0x0,0x2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63 }; - shimClient.expect(unsubscribe,12); - byte unsuback[] = { 0xB0,0x2,0x0,0x2 }; - shimClient.respond(unsuback,4); + byte unsubscribe[] = {0xA2, 0x9, 0x0, 0x2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63}; + shimClient.expect(unsubscribe, 12); + byte unsuback[] = {0xB0, 0x2, 0x0, 0x2}; + shimClient.respond(unsuback, 4); - rc = client.unsubscribe((char*)"topic"); + rc = client.unsubscribe("topic"); IS_TRUE(rc); IS_FALSE(shimClient.error()); @@ -155,7 +164,7 @@ int test_unsubscribe_not_connected() { PubSubClient client(server, 1883, callback, shimClient); - int rc = client.unsubscribe((char*)"topic"); + bool rc = client.unsubscribe("topic"); IS_FALSE(rc); IS_FALSE(shimClient.error()); @@ -163,8 +172,7 @@ int test_unsubscribe_not_connected() { END_IT } -int main() -{ +int main() { SUITE("Subscribe"); test_subscribe_no_qos(); test_subscribe_qos_1(); diff --git a/lib/pubsubclient/tests/testcases/__init__.py b/lib/pubsubclient3/tests/testcases/__init__.py similarity index 100% rename from lib/pubsubclient/tests/testcases/__init__.py rename to lib/pubsubclient3/tests/testcases/__init__.py diff --git a/lib/pubsubclient/tests/testcases/mqtt_basic.py b/lib/pubsubclient3/tests/testcases/mqtt_basic.py similarity index 77% rename from lib/pubsubclient/tests/testcases/mqtt_basic.py rename to lib/pubsubclient3/tests/testcases/mqtt_basic.py index f23ef71c1..1a2754042 100644 --- a/lib/pubsubclient/tests/testcases/mqtt_basic.py +++ b/lib/pubsubclient3/tests/testcases/mqtt_basic.py @@ -1,22 +1,19 @@ import unittest import settings import time -import mosquitto - - -def on_message(mosq, obj, msg): - obj.message_queue.append(msg) +import paho.mqtt.client as mqttclinet class mqtt_basic(unittest.TestCase): - + def on_message(self, client, userdata, message: mqttclinet.MQTTMessage): + self.message_queue.append(message) message_queue = [] @classmethod def setUpClass(self): - self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self) + self.client = mqttclinet.Client("pubsubclient_ut", clean_session=True) self.client.connect(settings.server_ip) - self.client.on_message = on_message + self.client.on_message = self.on_message self.client.subscribe("outTopic", 0) @classmethod diff --git a/lib/pubsubclient/tests/testcases/mqtt_publish_in_callback.py b/lib/pubsubclient3/tests/testcases/mqtt_publish_in_callback.py similarity index 86% rename from lib/pubsubclient/tests/testcases/mqtt_publish_in_callback.py rename to lib/pubsubclient3/tests/testcases/mqtt_publish_in_callback.py index 45b0a8515..5dd591d28 100644 --- a/lib/pubsubclient/tests/testcases/mqtt_publish_in_callback.py +++ b/lib/pubsubclient3/tests/testcases/mqtt_publish_in_callback.py @@ -1,22 +1,20 @@ import unittest import settings import time -import mosquitto - - -def on_message(mosq, obj, msg): - obj.message_queue.append(msg) +import paho.mqtt.client as mqttclinet class mqtt_publish_in_callback(unittest.TestCase): + def on_message(self, client, userdata, message: mqttclinet.MQTTMessage): + self.message_queue.append(message) message_queue = [] @classmethod def setUpClass(self): - self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self) + self.client = mqttclinet.Client("pubsubclient_ut", clean_session=True) self.client.connect(settings.server_ip) - self.client.on_message = on_message + self.client.on_message = self.on_message self.client.subscribe("outTopic", 0) @classmethod diff --git a/lib/pubsubclient/tests/testcases/settings.py b/lib/pubsubclient3/tests/testcases/settings.py similarity index 100% rename from lib/pubsubclient/tests/testcases/settings.py rename to lib/pubsubclient3/tests/testcases/settings.py diff --git a/lib/pubsubclient/tests/testsuite.py b/lib/pubsubclient3/tests/testsuite.py similarity index 99% rename from lib/pubsubclient/tests/testsuite.py rename to lib/pubsubclient3/tests/testsuite.py index 788fc5d97..b00dd159a 100644 --- a/lib/pubsubclient/tests/testsuite.py +++ b/lib/pubsubclient3/tests/testsuite.py @@ -21,7 +21,7 @@ class Workspace(object): self.examples_dir = os.path.join(self.root_dir, "../PubSubClient/examples") self.examples = [] self.tests = [] - if not os.path.isdir("../PubSubClient"): + if not os.path.isdir("../src"): raise Exception("Cannot find PubSubClient library") try: return __import__('ino') diff --git a/src/src/DataStructs/ESPEasyControllerCache_CSV_dumper.cpp b/src/src/DataStructs/ESPEasyControllerCache_CSV_dumper.cpp index ac671cde3..6b80e0c3e 100644 --- a/src/src/DataStructs/ESPEasyControllerCache_CSV_dumper.cpp +++ b/src/src/DataStructs/ESPEasyControllerCache_CSV_dumper.cpp @@ -64,7 +64,7 @@ uint32_t ESPEasyControllerCache_CSV_dumper::writeToTarget(const String& str, boo if (_target == Target::CSV_file) { addHtml(str); } else { - MQTTclient.write(str); + MQTTclient.write((const uint8_t*)str.c_str(), str.length()); } } return str.length(); diff --git a/src/src/PluginStructs/P146_data_struct.cpp b/src/src/PluginStructs/P146_data_struct.cpp index 97f377f05..680d1b2f1 100644 --- a/src/src/PluginStructs/P146_data_struct.cpp +++ b/src/src/PluginStructs/P146_data_struct.cpp @@ -27,7 +27,7 @@ P146_data_struct::~P146_data_struct() uint32_t writeToMqtt(const String& str, bool send) { if (send) { - MQTTclient.write(str); + MQTTclient.write((const uint8_t*)str.c_str(), str.length()); } return str.length(); } From f2f58ada3e9e273c4974858e23a258861802bac5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 29 Jun 2025 00:18:13 +0200 Subject: [PATCH 082/564] [PubSubClient3] Speedup publish large messages using buffer As discussed here: https://github.com/hmueller01/pubsubclient3/issues/29#issuecomment-2727644476 --- lib/pubsubclient3/src/PubSubClient.cpp | 45 +++++++++++++++++++++++--- lib/pubsubclient3/src/PubSubClient.h | 10 ++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/lib/pubsubclient3/src/PubSubClient.cpp b/lib/pubsubclient3/src/PubSubClient.cpp index e50c0973a..dd1e5bf94 100644 --- a/lib/pubsubclient3/src/PubSubClient.cpp +++ b/lib/pubsubclient3/src/PubSubClient.cpp @@ -511,6 +511,7 @@ bool PubSubClient::beginPublish(const char* topic, size_t plength, bool retained } bool PubSubClient::endPublish() { + flushBuffer(); return connected(); } @@ -549,13 +550,19 @@ uint8_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, size_t length) { } size_t PubSubClient::write(uint8_t data) { - lastOutActivity = millis(); - return _client->write(data); + const size_t rc = appendBuffer(data); + if (rc != 0) { + lastOutActivity = millis(); + } + return rc; } size_t PubSubClient::write(const uint8_t* buffer, size_t size) { - lastOutActivity = millis(); - return _client->write(buffer, size); + const size_t rc = appendBuffer(buffer, size); + if (rc != 0) { + lastOutActivity = millis(); + } + return rc; } /** @@ -638,6 +645,36 @@ size_t PubSubClient::writeString(const char* string, uint8_t* buf, size_t pos, s return pos; } +size_t PubSubClient::appendBuffer(uint8_t data) { + buffer[_bufferWritePos] = data; + ++_bufferWritePos; + if (_bufferWritePos >= bufferSize) { + if (flushBuffer() == 0) return 0; + } + return 1; +} + +size_t PubSubClient::appendBuffer(const uint8_t *data, size_t size) { + for (size_t i = 0; i < size; ++i) { + if (appendBuffer(data[i]) == 0) return i; + } + return size; +} + +size_t PubSubClient::flushBuffer() { + size_t rc = 0; + if (_bufferWritePos > 0) { + if (connected()) { + rc = _client->write(buffer, _bufferWritePos); + if (rc != 0) { + lastOutActivity = millis(); + } + } + _bufferWritePos = 0; + } + return rc; +} + bool PubSubClient::subscribe(const char* topic) { return subscribe(topic, 0); } diff --git a/lib/pubsubclient3/src/PubSubClient.h b/lib/pubsubclient3/src/PubSubClient.h index d899786bc..6840d77bd 100644 --- a/lib/pubsubclient3/src/PubSubClient.h +++ b/lib/pubsubclient3/src/PubSubClient.h @@ -165,6 +165,7 @@ class PubSubClient : public Print { uint16_t port{}; Stream* stream{}; int _state{MQTT_DISCONNECTED}; + int _bufferWritePos = 0; size_t readPacket(uint8_t* hdrLen); bool handlePacket(uint8_t hdrLen, size_t len); @@ -175,6 +176,11 @@ class PubSubClient : public Print { size_t writeString(const char* string, uint8_t* buf, size_t pos); size_t writeString(const char* string, uint8_t* buf, size_t pos, size_t size); + // Add to buffer and flush if full (only to be used with beginPublish/endPublish)Add commentMore actions + size_t appendBuffer(uint8_t data); + size_t appendBuffer(const uint8_t *data, size_t size); + size_t flushBuffer(); + public: /** * @brief Creates an uninitialised client instance. @@ -539,6 +545,8 @@ class PubSubClient : public Print { /** * @brief Writes a single byte as a component of a publish started with a call to beginPublish. + * For performance reasons, this will be appended to the internal buffer, + * which will be flushed when full or on a call to endPublish(). * @param byte A byte to write to the publish payload. * @return The number of bytes written. */ @@ -546,6 +554,8 @@ class PubSubClient : public Print { /** * @brief Writes an array of bytes as a component of a publish started with a call to beginPublish. + * For performance reasons, this will be appended to the internal buffer, + * which will be flushed when full or on a call to endPublish(). * @param buffer The bytes to write. * @param size The length of the payload to be sent. * @return The number of bytes written. From c0a316822146276cc28a99fdaa538a79865101ed Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 29 Jun 2025 00:44:43 +0200 Subject: [PATCH 083/564] [Build] Fix failed build due to missing include --- src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp index 38186bdb9..3829dd659 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork_ESP32.cpp @@ -24,6 +24,11 @@ # include #endif +#if FEATURE_USE_IPV6 +# include +#endif + + void setNetworkMedium(NetworkMedium_t new_medium) { #if !(FEATURE_ETHERNET) From 5e7f1db5f3a7a2319b99e6037d806e3218794da9 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 2 Jul 2025 13:41:30 +0200 Subject: [PATCH 084/564] [ESP32-C5] Add option to force WiFi band 2.4/5 GHz --- src/src/DataStructs/SettingsStruct.h | 14 +- src/src/DataStructs/WiFi_AP_Candidate.cpp | 15 ++ src/src/DataStructs/WiFi_AP_Candidate.h | 1 + src/src/ESPEasyCore/ESPEasyWifi.cpp | 130 +------------ src/src/ESPEasyCore/ESPEasyWifi.h | 2 - .../ESPEasyCore/ESPEasyWifi_abstracted.cpp | 23 ++- src/src/ESPEasyCore/ESPEasyWifi_abstracted.h | 12 ++ .../ESPEasyWifi_abstracted_ESP32.cpp | 176 ++++++++++++++++-- .../ESPEasyWifi_abstracted_ESP8266.cpp | 86 +++++++++ src/src/ESPEasyCore/ESPEasy_setup.cpp | 6 +- src/src/Helpers/Networking.cpp | 2 +- src/src/Helpers/StringProvider.cpp | 13 +- src/src/Helpers/StringProvider.h | 3 + src/src/WebServer/AdvancedConfigPage.cpp | 56 ++++-- src/src/WebServer/RootPage.cpp | 2 +- src/src/WebServer/SetupPage.cpp | 4 +- src/src/WebServer/SysInfoPage.cpp | 3 + src/src/WebServer/WiFiScanner.cpp | 4 +- 18 files changed, 379 insertions(+), 173 deletions(-) diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index 3853b720d..9c5da80ce 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -217,6 +217,15 @@ class SettingsStruct_tmpl void ShowUnitOfMeasureOnDevicesPage(bool value) { VariousBits_2.ShowUnitOfMeasureOnDevicesPage = !value; } #endif // if FEATURE_TASKVALUE_UNIT_OF_MEASURE +#if CONFIG_SOC_WIFI_SUPPORT_5G + wifi_band_mode_t WiFi_band_mode() const { + if (VariousBits_2.WiFi_band_mode == 0) return WIFI_BAND_MODE_AUTO; + return static_cast(VariousBits_2.WiFi_band_mode); + } + void WiFi_band_mode(wifi_band_mode_t value) { VariousBits_2.WiFi_band_mode = value; } +#endif + + // Flag indicating whether all task values should be sent in a single event or one event per task value (default behavior) bool CombineTaskValues_SingleEvent(taskIndex_t taskIndex) const; void CombineTaskValues_SingleEvent(taskIndex_t taskIndex, bool value); @@ -568,7 +577,7 @@ public: int8_t SPI_SCLK_pin = -1; int8_t SPI_MISO_pin = -1; int8_t SPI_MOSI_pin = -1; - int8_t ForceESPEasyNOWchannel = 0; + uint8_t ForceESPEasyNOWchannel = 0; // Do not rename or move this checksum. // Checksum calculation will work "around" this @@ -584,8 +593,7 @@ public: uint32_t DisableSaveConfigAsTar : 1; // Bit 05 uint32_t PassiveWiFiScan : 1; // Bit 06 // inverted uint32_t ShowUnitOfMeasureOnDevicesPage : 1; // Bit 07 // inverted - uint32_t unused_08 : 1; // Bit 08 - uint32_t unused_09 : 1; // Bit 09 + uint32_t WiFi_band_mode : 2; // Bit 08 & 09 uint32_t unused_10 : 1; // Bit 10 uint32_t unused_11 : 1; // Bit 11 uint32_t unused_12 : 1; // Bit 12 diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index e5a08dcae..0bdfa6501 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -125,6 +125,7 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { // FIXME TD-er: Maybe also add other info like 2nd channel, ftm and phy_lr support? # if ESP_IDF_VERSION_MAJOR >= 5 memcpy(&country, &(it->country), sizeof(wifi_country_t)); + bandwidth = it->bandwidth; # endif } #endif // ifdef ESP32 @@ -206,6 +207,7 @@ WiFi_AP_Candidate& WiFi_AP_Candidate::operator=(const WiFi_AP_Candidate& other) #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 memcpy(&this->country, &other.country, sizeof(wifi_country_t)); + bandwidth = other.bandwidth; # endif #endif // ifdef ESP32 @@ -334,6 +336,19 @@ String WiFi_AP_Candidate::toString(const String& separator) const { #endif // ifdef ESP32 if (phy_str.length()) { +#ifdef ESP32 + switch (bandwidth) + { + case WIFI_BW_HT20: break; + case WIFI_BW_HT40: phy_str += F(" 40 MHz"); break; + case WIFI_BW80: phy_str += F(" 80 MHz"); break; + case WIFI_BW160: phy_str += F(" 160 MHz"); break; + case WIFI_BW80_BW80: phy_str += F(" 80+80 MHz"); break; + + default: + break; + } +#endif result += strformat(F(" (%s)"), phy_str.c_str()); } } diff --git a/src/src/DataStructs/WiFi_AP_Candidate.h b/src/src/DataStructs/WiFi_AP_Candidate.h index cfcb2bf1c..a552912fd 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.h +++ b/src/src/DataStructs/WiFi_AP_Candidate.h @@ -75,6 +75,7 @@ struct WiFi_AP_Candidate { #ifdef ESP32 # if ESP_IDF_VERSION_MAJOR >= 5 wifi_country_t country; + wifi_bandwidth_t bandwidth{WIFI_BW_HT20}; # endif #endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 17af3cb25..668950e33 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -294,134 +294,6 @@ bool WiFiScanAllowed() { return WiFiEventData.processedConnect; } -void WifiScan(bool async, uint8_t channel) { - ESPEasy::net::wifi::setSTA(true); - - if (!WiFiScanAllowed()) { - return; - } -# ifdef ESP32 - - // TD-er: Don't run async scan on ESP32. - // Since IDF 4.4 it seems like the active channel may be messed up when running async scan - // Perform a disconnect after scanning. - // See: https://github.com/letscontrolit/ESPEasy/pull/3579#issuecomment-967021347 - async = false; - - if (Settings.IncludeHiddenSSID()) { - ESPEasy::net::wifi::setWiFiCountryPolicyManual(); - } - - -# endif // ifdef ESP32 - - START_TIMER; - WiFiEventData.lastScanMoment.setNow(); - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - if (channel == 0) { - addLog(LOG_LEVEL_INFO, F("WiFi : Start network scan all channels")); - } else { - addLogMove(LOG_LEVEL_INFO, strformat(F("WiFi : Start network scan ch: %d "), channel)); - } - } - # endif // ifndef BUILD_NO_DEBUG - bool show_hidden = true; - WiFiEventData.processedScanDone = false; - WiFiEventData.lastGetScanMoment.setNow(); - WiFiEventData.lastScanChannel = channel; - - unsigned int nrScans = 1 + (async ? 0 : Settings.NumberExtraWiFiScans); - - while (nrScans > 0) { - if (!async) { - WiFi_AP_Candidates.begin_sync_scan(); - FeedSW_watchdog(); - } - --nrScans; -# ifdef ESP8266 -# if FEATURE_ESP8266_DIRECT_WIFI_SCAN - { - static bool FIRST_SCAN = true; - - struct scan_config config; - memset(&config, 0, sizeof(config)); - config.ssid = nullptr; - config.bssid = nullptr; - config.channel = channel; - config.show_hidden = show_hidden ? 1 : 0; - config.scan_type = WIFI_SCAN_TYPE_ACTIVE; - - if (FIRST_SCAN) { - config.scan_time.active.min = 100; - config.scan_time.active.max = 200; - } else { - config.scan_time.active.min = 400; - config.scan_time.active.max = 500; - } - FIRST_SCAN = false; - wifi_station_scan(&config, &onWiFiScanDone); - - if (!async) { - // will resume when SYSTEM_EVENT_SCAN_DONE event is fired - do - { - delay(0); - } while (!WiFiEventData.processedScanDone); - } - - } -# else // if FEATURE_ESP8266_DIRECT_WIFI_SCAN - WiFi.scanNetworks(async, show_hidden, channel); -# endif // if FEATURE_ESP8266_DIRECT_WIFI_SCAN -# endif // ifdef ESP8266 -# ifdef ESP32 - const bool passive = Settings.PassiveWiFiScan(); - const uint32_t max_ms_per_chan = 120; -#if CONFIG_SOC_WIFI_SUPPORT_5G - // ESP32-C5 scans both 2.4 and 5 GHz band, which takes much longer - // 14 channels on 2.4 GHz - // 36 channels on 5 GHz: 36~177 (36, 40, 44 ... 177) - WiFi.setScanTimeout(50 * (max_ms_per_chan + 10)); -#else -// WiFi.setScanTimeout(14 * (max_ms_per_chan + 10)); -#endif - WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan /*, channel */); -# endif // ifdef ESP32 - - if (!async) { - FeedSW_watchdog(); - processScanDone(); - } - } -# if FEATURE_TIMING_STATS - - if (async) { - STOP_TIMER(WIFI_SCAN_ASYNC); - } else { - STOP_TIMER(WIFI_SCAN_SYNC); - } -# endif // if FEATURE_TIMING_STATS - -# ifdef ESP32 -# if ESP_IDF_VERSION_MAJOR < 5 - RTC.clearLastWiFi(); - - if (WiFiConnected()) { - # ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, F("WiFi : Disconnect after scan")); - # endif - - const bool needReconnect = WiFiEventData.wifiConnectAttemptNeeded; - WifiDisconnect(); - WiFiEventData.wifiConnectAttemptNeeded = needReconnect; - } -# endif // if ESP_IDF_VERSION_MAJOR < 5 -# endif // ifdef ESP32 - -} - // ******************************************************************************** // Scan all Wifi Access Points // ******************************************************************************** @@ -432,7 +304,7 @@ void WiFiScan_log_to_serial() if (WiFi_AP_Candidates.scanComplete() <= 0) { WiFiMode_t cur_wifimode = WiFi.getMode(); - WifiScan(false); + ESPEasy::net::wifi::WifiScan(false); ESPEasy::net::wifi::setWifiMode(cur_wifimode); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.h b/src/src/ESPEasyCore/ESPEasyWifi.h index c1d421389..9102dd75f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.h +++ b/src/src/ESPEasyCore/ESPEasyWifi.h @@ -65,8 +65,6 @@ int64_t WiFi_get_TSF_time(); # endif // ifdef ESP32 void WifiDisconnect(); bool WiFiScanAllowed(); -void WifiScan(bool async, - uint8_t channel = 0); void WiFiScan_log_to_serial(); void setAPinternal(bool enable); // FIXME TD-er: Move to ESPEasyWifi_abstracted... diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp index 3937d3eb2..8e8b0d3fd 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.cpp @@ -26,6 +26,20 @@ const __FlashStringHelper* getWifiModeString(WiFiMode_t wifimode) return F("Unknown"); } +#if CONFIG_SOC_WIFI_SUPPORT_5G +const __FlashStringHelper* getWifiBandModeString(wifi_band_mode_t wifiBandMode) +{ + switch (wifiBandMode) + { + case WIFI_BAND_MODE_2G_ONLY: return F("2.4 GHz only"); + case WIFI_BAND_MODE_5G_ONLY: return F("5 GHz only"); + default: break; + } + return F("2.4 GHz + 5 GHz"); +} +#endif + + bool WiFiConnected() { return ESPEasyWiFi.connected(); } bool setSTA(bool enable) { return setSTA_AP(enable, WifiIsAP(WiFi.getMode())); } @@ -143,7 +157,14 @@ int GetRSSI_quality() { return (rssi / 5) + 1; } -void setConnectionSpeed() { setConnectionSpeed(Settings.ForceWiFi_bg_mode()); } +void setConnectionSpeed() { + setConnectionSpeed( + Settings.ForceWiFi_bg_mode() +#if CONFIG_SOC_WIFI_SUPPORT_5G + ,Settings.WiFi_band_mode() +#endif + ); +} } // namespace wifi } // namespace net diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h index a8a45d4f6..2de675c7a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted.h @@ -43,6 +43,10 @@ bool WifiIsSTA(WiFiMode_t wifimode); const __FlashStringHelper* getWifiModeString(WiFiMode_t wifimode); +#if CONFIG_SOC_WIFI_SUPPORT_5G +const __FlashStringHelper* getWifiBandModeString(wifi_band_mode_t wifiBandMode); +#endif + bool setSTA(bool enable); bool setAP(bool enable); bool setSTA_AP(bool sta_enable, @@ -51,6 +55,10 @@ bool setSTA_AP(bool sta_enable, bool setWifiMode(WiFiMode_t new_mode); +void WifiScan(bool async, + uint8_t channel = 0); + + // ******************************************************************************** // Event handlers // ******************************************************************************** @@ -79,7 +87,11 @@ void doSetWiFiTXpower(float& dBm); int GetRSSI_quality(); void setConnectionSpeed(); +#if CONFIG_SOC_WIFI_SUPPORT_5G +void setConnectionSpeed(bool ForceWiFi_bg_mode, wifi_band_mode_t WiFi_band_mode); +#else void setConnectionSpeed(bool ForceWiFi_bg_mode); +#endif void setWiFiNoneSleep(); void setWiFiEcoPowerMode(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp index dd1c656cd..a436a7e9a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP32.cpp @@ -3,6 +3,8 @@ #if FEATURE_WIFI # ifdef ESP32 +# include "../DataStructs/TimingStats.h" + # include "../Globals/ESPEasyWiFiEvent.h" # include "../Globals/EventQueue.h" # include "../Globals/Settings.h" @@ -192,6 +194,103 @@ bool setWifiMode(WiFiMode_t new_mode) return true; } +void WifiScan(bool async, uint8_t channel) { + ESPEasy::net::wifi::setSTA(true); + + if (!WiFiScanAllowed()) { + return; + } + +# if CONFIG_SOC_WIFI_SUPPORT_5G + const wifi_band_mode_t current_wifi_band_mode = WiFi.getBandMode(); + WiFi.setBandMode(Settings.WiFi_band_mode()); +# endif + + // TD-er: Don't run async scan on ESP32. + // Since IDF 4.4 it seems like the active channel may be messed up when running async scan + // Perform a disconnect after scanning. + // See: https://github.com/letscontrolit/ESPEasy/pull/3579#issuecomment-967021347 + async = false; + + if (Settings.IncludeHiddenSSID()) { + ESPEasy::net::wifi::setWiFiCountryPolicyManual(); + } + + START_TIMER; + WiFiEventData.lastScanMoment.setNow(); + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + if (channel == 0) { + addLog(LOG_LEVEL_INFO, F("WiFi : Start network scan all channels")); + } else { + addLogMove(LOG_LEVEL_INFO, strformat(F("WiFi : Start network scan ch: %d "), channel)); + } + } + # endif // ifndef BUILD_NO_DEBUG + bool show_hidden = true; + WiFiEventData.processedScanDone = false; + WiFiEventData.lastGetScanMoment.setNow(); + WiFiEventData.lastScanChannel = channel; + + unsigned int nrScans = 1 + (async ? 0 : Settings.NumberExtraWiFiScans); + + while (nrScans > 0) { + if (!async) { + WiFi_AP_Candidates.begin_sync_scan(); + FeedSW_watchdog(); + } + --nrScans; + + const bool passive = Settings.PassiveWiFiScan(); + const uint32_t max_ms_per_chan = 120; +# if CONFIG_SOC_WIFI_SUPPORT_5G + + // ESP32-C5 scans both 2.4 and 5 GHz band, which takes much longer + // 14 channels on 2.4 GHz + // 28 channels on 5 GHz: 36~177 (36, 40, 44 ... 177) + // Typically a scan takes 40 ... 60 msec per channel longer. + // To be safe, set the timeout to 2x max_ms_per_chan + + WiFi.setScanTimeout((14 + 28) * max_ms_per_chan * 2); +# else // if CONFIG_SOC_WIFI_SUPPORT_5G + WiFi.setScanTimeout(14 * max_ms_per_chan * 2); +# endif // if CONFIG_SOC_WIFI_SUPPORT_5G + WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan /*, channel */); + + if (!async) { + FeedSW_watchdog(); + processScanDone(); + } + } +# if FEATURE_TIMING_STATS + + if (async) { + STOP_TIMER(WIFI_SCAN_ASYNC); + } else { + STOP_TIMER(WIFI_SCAN_SYNC); + } +# endif // if FEATURE_TIMING_STATS + +# if ESP_IDF_VERSION_MAJOR < 5 + RTC.clearLastWiFi(); + + if (WiFiConnected()) { + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_INFO, F("WiFi : Disconnect after scan")); + # endif + + const bool needReconnect = WiFiEventData.wifiConnectAttemptNeeded; + WifiDisconnect(); + WiFiEventData.wifiConnectAttemptNeeded = needReconnect; + } +# endif // if ESP_IDF_VERSION_MAJOR < 5 +# if CONFIG_SOC_WIFI_SUPPORT_5G + // Restore band mode + WiFi.setBandMode(current_wifi_band_mode); +#endif +} + void removeWiFiEventHandler() { WiFi.removeEvent(WiFiEventData.wm_event_id); @@ -283,7 +382,44 @@ void doSetWiFiTXpower(float& dBm) # endif // if FEATURE_SET_WIFI_TX_PWR -void setConnectionSpeed(bool ForceWiFi_bg_mode) { +# if CONFIG_SOC_WIFI_SUPPORT_5G + +bool setProtocol(wifi_interface_t ifx, uint16_t protocol_2GHz, uint16_t protocol_5GHz) +{ + esp_err_t err; + switch (WiFi.getBandMode()) + { + case WIFI_BAND_MODE_2G_ONLY: err = esp_wifi_set_protocol(ifx, protocol_2GHz); break; + case WIFI_BAND_MODE_5G_ONLY: err = esp_wifi_set_protocol(ifx, protocol_5GHz); break; + default: + { + wifi_protocols_t protocols { .ghz_2g = protocol_2GHz, .ghz_5g = protocol_5GHz }; + err = esp_wifi_set_protocols(WIFI_IF_STA, &protocols); + break; + } + } + if (err != ESP_OK) { + // TODO TD-er: Log + } + + return err == ESP_OK; +} + +# else // if CONFIG_SOC_WIFI_SUPPORT_5G + +bool setProtocol(wifi_interface_t ifx, uint8_t protocol_2GHz) { return esp_wifi_set_protocol(ifx, protocol_2GHz) == ESP_OK; } + +# endif // if CONFIG_SOC_WIFI_SUPPORT_5G + + +# if CONFIG_SOC_WIFI_SUPPORT_5G + +void setConnectionSpeed(bool ForceWiFi_bg_mode, wifi_band_mode_t WiFi_band_mode) +# else // if CONFIG_SOC_WIFI_SUPPORT_5G + +void setConnectionSpeed(bool ForceWiFi_bg_mode) +# endif // if CONFIG_SOC_WIFI_SUPPORT_5G +{ // Does not (yet) work, so commented out. // HT20 = 20 MHz channel width. @@ -294,22 +430,27 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { // The response speed and stability is better at HT20 for ESP units. esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT20); +# if CONFIG_SOC_WIFI_SUPPORT_5G + WiFi.setBandMode(WiFi_band_mode); +# if CONFIG_SOC_WIFI_HE_SUPPORT + uint8_t protocol_5GHz = WIFI_PROTOCOL_11N | WIFI_PROTOCOL_11A | WIFI_PROTOCOL_11AC | WIFI_PROTOCOL_11AX; +# else + uint8_t protocol_5GHz = WIFI_PROTOCOL_11N | WIFI_PROTOCOL_11A | WIFI_PROTOCOL_11AC; +# endif // if CONFIG_SOC_WIFI_HE_SUPPORT +# endif // if CONFIG_SOC_WIFI_SUPPORT_5G + uint8_t protocol = 0; if (ForceWiFi_bg_mode) { protocol = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G; // Default to BG } - if (!ForceWiFi_bg_mode || (WiFiEventData.connectionFailures > 10)) { - // Set to use BGN - protocol |= WIFI_PROTOCOL_11N; + if (WiFiEventData.connectionFailures > 10) { + // Set to allow all protocols + protocol = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N; # if CONFIG_SOC_WIFI_HE_SUPPORT protocol |= WIFI_PROTOCOL_11AX; # endif -# if CONFIG_SOC_WIFI_SUPPORT_5G - protocol |= WIFI_PROTOCOL_11A; - protocol |= WIFI_PROTOCOL_11AC; -# endif // if CONFIG_SOC_WIFI_SUPPORT_5G } const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); @@ -326,12 +467,14 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { if (candidate.bits.phy_11ax) { protocol |= WIFI_PROTOCOL_11AX; } # endif // if CONFIG_SOC_WIFI_HE_SUPPORT +/* # if CONFIG_SOC_WIFI_SUPPORT_5G if (candidate.bits.phy_11a) { protocol |= WIFI_PROTOCOL_11A; } if (candidate.bits.phy_11ac) { protocol |= WIFI_PROTOCOL_11AC; } # endif // if CONFIG_SOC_WIFI_SUPPORT_5G +*/ } else // Check to see if the access point is set to "N-only" @@ -347,19 +490,20 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { if (candidate.bits.phy_11ax) { // Set to use WiFi6 protocol |= WIFI_PROTOCOL_11AX; +// protocol_5GHz |= WIFI_PROTOCOL_11AX; addLog(LOG_LEVEL_INFO, F("WIFI : AP allows 802.11ax, Wi-Fi 6")); } # if CONFIG_SOC_WIFI_SUPPORT_5G if (candidate.bits.phy_11a) { // Set to use 5 GHz WiFi - protocol |= WIFI_PROTOCOL_11A; +// protocol_5GHz |= WIFI_PROTOCOL_11A; addLog(LOG_LEVEL_INFO, F("WIFI : AP allows 802.11a, 5 GHz")); } if (candidate.bits.phy_11ac) { // Set to use 5 GHz WiFi-5 - protocol |= WIFI_PROTOCOL_11AC; +// protocol_5GHz |= WIFI_PROTOCOL_11AC; addLog(LOG_LEVEL_INFO, F("WIFI : AP allows 802.11ac, 5 GHz Wi-Fi 5")); } # endif // if CONFIG_SOC_WIFI_SUPPORT_5G @@ -373,11 +517,19 @@ void setConnectionSpeed(bool ForceWiFi_bg_mode) { // Set to use "Long GI" making it more resilliant to reflections // See: https://www.tp-link.com/us/configuration-guides/q_a_basic_wireless_concepts/?configurationId=2958#_idTextAnchor038 esp_wifi_config_80211_tx_rate(WIFI_IF_STA, WIFI_PHY_RATE_MCS3_LGI); - esp_wifi_set_protocol(WIFI_IF_STA, protocol); + # if CONFIG_SOC_WIFI_SUPPORT_5G + setProtocol(WIFI_IF_STA, protocol, protocol_5GHz); + # else + setProtocol(WIFI_IF_STA, protocol); + # endif // if CONFIG_SOC_WIFI_SUPPORT_5G } if (WifiIsAP(WiFi.getMode())) { - esp_wifi_set_protocol(WIFI_IF_AP, protocol); + # if CONFIG_SOC_WIFI_SUPPORT_5G + setProtocol(WIFI_IF_AP, protocol, protocol_5GHz); + # else + setProtocol(WIFI_IF_STA, protocol); + # endif // if CONFIG_SOC_WIFI_SUPPORT_5G } } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp index 349c04831..4b25ff4ae 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_abstracted_ESP8266.cpp @@ -3,6 +3,8 @@ #if FEATURE_WIFI # ifdef ESP8266 +# include "../DataStructs/TimingStats.h" + # include "../Helpers/StringConverter.h" # include "../Globals/ESPEasyWiFiEvent.h" @@ -122,6 +124,90 @@ bool setWifiMode(WiFiMode_t new_mode) return true; } +void WifiScan(bool async, uint8_t channel) { + ESPEasy::net::wifi::setSTA(true); + + if (!WiFiScanAllowed()) { + return; + } + + START_TIMER; + WiFiEventData.lastScanMoment.setNow(); + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + if (channel == 0) { + addLog(LOG_LEVEL_INFO, F("WiFi : Start network scan all channels")); + } else { + addLogMove(LOG_LEVEL_INFO, strformat(F("WiFi : Start network scan ch: %d "), channel)); + } + } + # endif // ifndef BUILD_NO_DEBUG + bool show_hidden = true; + WiFiEventData.processedScanDone = false; + WiFiEventData.lastGetScanMoment.setNow(); + WiFiEventData.lastScanChannel = channel; + + unsigned int nrScans = 1 + (async ? 0 : Settings.NumberExtraWiFiScans); + + while (nrScans > 0) { + if (!async) { + WiFi_AP_Candidates.begin_sync_scan(); + FeedSW_watchdog(); + } + --nrScans; +# if FEATURE_ESP8266_DIRECT_WIFI_SCAN + { + static bool FIRST_SCAN = true; + + struct scan_config config; + memset(&config, 0, sizeof(config)); + config.ssid = nullptr; + config.bssid = nullptr; + config.channel = channel; + config.show_hidden = show_hidden ? 1 : 0; + config.scan_type = WIFI_SCAN_TYPE_ACTIVE; + + if (FIRST_SCAN) { + config.scan_time.active.min = 100; + config.scan_time.active.max = 200; + } else { + config.scan_time.active.min = 400; + config.scan_time.active.max = 500; + } + FIRST_SCAN = false; + wifi_station_scan(&config, &onWiFiScanDone); + + if (!async) { + // will resume when SYSTEM_EVENT_SCAN_DONE event is fired + do + { + delay(0); + } while (!WiFiEventData.processedScanDone); + } + + } +# else // if FEATURE_ESP8266_DIRECT_WIFI_SCAN + WiFi.scanNetworks(async, show_hidden, channel); +# endif // if FEATURE_ESP8266_DIRECT_WIFI_SCAN + + if (!async) { + FeedSW_watchdog(); + processScanDone(); + } + } +# if FEATURE_TIMING_STATS + + if (async) { + STOP_TIMER(WIFI_SCAN_ASYNC); + } else { + STOP_TIMER(WIFI_SCAN_SYNC); + } +# endif // if FEATURE_TIMING_STATS + + +} + void removeWiFiEventHandler() { // Not needed for ESP8266 } diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index ddf65fddf..6ddafc386 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -461,7 +461,7 @@ void ESPEasy_setup() RTC.clearLastWiFi(); // Must scan all channels // Wait until scan has finished to make sure as many as possible are found // We're still in the setup phase, so nothing else is taking resources of the ESP. - WifiScan(false); + ESPEasy::net::wifi::WifiScan(false); WiFiEventData.lastScanMoment.clear(); } @@ -469,7 +469,7 @@ void ESPEasy_setup() // It appears reconnecting from RTC may take just as long to be able to send first packet as performing a scan first and then connect. // Perhaps the WiFi radio needs some time to stabilize first? if (!WiFi_AP_Candidates.hasCandidates()) { - WifiScan(false, RTC.lastWiFiChannel); + ESPEasy::net::wifi::WifiScan(false, RTC.lastWiFiChannel); } WiFi_AP_Candidates.clearCache(); processScanDone(); @@ -479,7 +479,7 @@ void ESPEasy_setup() #ifndef BUILD_MINIMAL_OTA addLog(LOG_LEVEL_INFO, F("Setup: Scan all channels")); #endif - WifiScan(false); + ESPEasy::net::wifi::WifiScan(false); } // ESPEasy::net::wifi::setWifiMode(WIFI_OFF); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 4b0550c63..4335fa99b 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -520,7 +520,7 @@ void refreshNodeList() // FIXME TD-er: Do not perform regular scans on ESP32 as long as we cannot scan per channel if (!Nodes.isEndpoint()) { - WifiScan(true, Nodes.getESPEasyNOW_channel()); + ESPEasy::net::wifi::WifiScan(true, Nodes.getESPEasyNOW_channel()); } # endif // ifdef ESP8266 # endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 8cdd31321..487d272e8 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -10,6 +10,7 @@ #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #if FEATURE_ETHERNET #include "../ESPEasyCore/ESPEasyEth.h" #endif @@ -142,9 +143,13 @@ const __FlashStringHelper * getLabel(LabelType::Enum label) { #if FEATURE_TARSTREAM_SUPPORT case LabelType::DISABLE_SAVE_CONFIG_AS_TAR: return F("Disable Save Config as .tar"); #endif // if FEATURE_TARSTREAM_SUPPORT - #if FEATURE_TASKVALUE_UNIT_OF_MEASURE +#if FEATURE_TASKVALUE_UNIT_OF_MEASURE case LabelType::SHOW_UOM_ON_DEVICES_PAGE: return F("Show Unit of Measure"); - #endif // if FEATURE_TASKVALUE_UNIT_OF_MEASURE +#endif // if FEATURE_TASKVALUE_UNIT_OF_MEASURE + +#if CONFIG_SOC_WIFI_SUPPORT_5G + case LabelType::WIFI_BAND_MODE: return F("WiFi Band Mode"); +#endif case LabelType::BOOT_TYPE: return F("Last Boot Cause"); case LabelType::BOOT_COUNT: return F("Boot Count"); @@ -442,6 +447,10 @@ String getValue(LabelType::Enum label) { case LabelType::SHOW_UOM_ON_DEVICES_PAGE: return jsonBool(Settings.ShowUnitOfMeasureOnDevicesPage()); #endif // if FEATURE_TASKVALUE_UNIT_OF_MEASURE +#if CONFIG_SOC_WIFI_SUPPORT_5G + case LabelType::WIFI_BAND_MODE: return ESPEasy::net::wifi::getWifiBandModeString(Settings.WiFi_band_mode()); +#endif + case LabelType::BOOT_TYPE: return getLastBootCauseString(); case LabelType::BOOT_COUNT: break; case LabelType::DEEP_SLEEP_ALTERNATIVE_CALL: return jsonBool(Settings.UseAlternativeDeepSleep()); diff --git a/src/src/Helpers/StringProvider.h b/src/src/Helpers/StringProvider.h index f15d3bc81..2e71af5b5 100644 --- a/src/src/Helpers/StringProvider.h +++ b/src/src/Helpers/StringProvider.h @@ -93,6 +93,9 @@ struct LabelType { #if FEATURE_TASKVALUE_UNIT_OF_MEASURE SHOW_UOM_ON_DEVICES_PAGE, #endif // if FEATURE_TASKVALUE_UNIT_OF_MEASURE +#if CONFIG_SOC_WIFI_SUPPORT_5G + WIFI_BAND_MODE, +#endif BOOT_TYPE, // Cold boot BOOT_COUNT, // 0 diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index 4e22f5852..ee9aa48f9 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -9,6 +9,7 @@ #include "../WebServer/ESPEasy_WebServer.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/ESPEasyWifi_abstracted.h" #include "../Globals/ESPEasy_time.h" #include "../Globals/Settings.h" @@ -147,6 +148,9 @@ void handle_advanced() { #ifdef ESP32 Settings.PassiveWiFiScan(isFormItemChecked(LabelType::WIFI_PASSIVE_SCAN)); #endif +#if CONFIG_SOC_WIFI_SUPPORT_5G + Settings.WiFi_band_mode(static_cast(getFormItemInt(getInternalLabel(LabelType::WIFI_BAND_MODE)))); +#endif #if FEATURE_USE_IPV6 Settings.EnableIPv6(isFormItemChecked(LabelType::ENABLE_IPV6)); #endif @@ -359,21 +363,23 @@ void handle_advanced() { addFormCheckBox(LabelType::ALLOW_OTA_UNLIMITED, Settings.AllowOTAUnlimited()); # endif // ifndef NO_HTTP_UPDATER #if FEATURE_AUTO_DARK_MODE - const __FlashStringHelper * cssModeNames[] = { - F("Auto"), - F("Light"), - F("Dark"), - }; - //const int cssModeOptions[] = { 0, 1, 2}; - constexpr int nrCssModeOptions = NR_ELEMENTS(cssModeNames); - const FormSelectorOptions selector( - nrCssModeOptions, - cssModeNames/*, - cssModeOptions*/); - selector.addFormSelector( - getLabel(LabelType::ENABLE_AUTO_DARK_MODE), - getInternalLabel(LabelType::ENABLE_AUTO_DARK_MODE), - Settings.getCssMode()); + { + const __FlashStringHelper * cssModeNames[] = { + F("Auto"), + F("Light"), + F("Dark"), + }; + //const int cssModeOptions[] = { 0, 1, 2}; + constexpr int nrCssModeOptions = NR_ELEMENTS(cssModeNames); + const FormSelectorOptions selector( + nrCssModeOptions, + cssModeNames/*, + cssModeOptions*/); + selector.addFormSelector( + getLabel(LabelType::ENABLE_AUTO_DARK_MODE), + getInternalLabel(LabelType::ENABLE_AUTO_DARK_MODE), + Settings.getCssMode()); + } #endif // FEATURE_AUTO_DARK_MODE #if FEATURE_RULES_EASY_COLOR_CODE @@ -419,6 +425,26 @@ void handle_advanced() { #ifdef ESP32 addFormCheckBox(LabelType::WIFI_PASSIVE_SCAN, Settings.PassiveWiFiScan()); #endif +#if CONFIG_SOC_WIFI_SUPPORT_5G + { + const __FlashStringHelper * wifiModeNames[] = { + ESPEasy::net::wifi::getWifiBandModeString(WIFI_BAND_MODE_2G_ONLY), + ESPEasy::net::wifi::getWifiBandModeString(WIFI_BAND_MODE_5G_ONLY), + ESPEasy::net::wifi::getWifiBandModeString(WIFI_BAND_MODE_AUTO), + }; + const int wifiModeOptions[] = { WIFI_BAND_MODE_2G_ONLY, WIFI_BAND_MODE_5G_ONLY, WIFI_BAND_MODE_AUTO}; + constexpr int nrWifiModeOptions = NR_ELEMENTS(wifiModeNames); + const FormSelectorOptions selector( + nrWifiModeOptions, + wifiModeNames, + wifiModeOptions); + selector.addFormSelector( + getLabel(LabelType::WIFI_BAND_MODE), + getInternalLabel(LabelType::WIFI_BAND_MODE), + Settings.WiFi_band_mode()); + } +#endif + #if FEATURE_USE_IPV6 addFormCheckBox(LabelType::ENABLE_IPV6, Settings.EnableIPv6()); #endif diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index df0749f29..534eade50 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -304,7 +304,7 @@ void handle_root() { html_table_header(F("Type")); } html_table_header(F("IP"), 160); // Should fit "255.255.255.255" - html_table_header(F("Load")); + html_table_header(F("Load (%)")); html_table_header(F("Age (s)")); # ifdef USES_ESPEASY_NOW diff --git a/src/src/WebServer/SetupPage.cpp b/src/src/WebServer/SetupPage.cpp index 51ea58abb..4a143d68f 100644 --- a/src/src/WebServer/SetupPage.cpp +++ b/src/src/WebServer/SetupPage.cpp @@ -92,7 +92,7 @@ void handle_setup() { const bool performRescan = hasArg(F("performrescan")); if (performRescan) { WiFiEventData.lastScanMoment.clear(); - WifiScan(false); + ESPEasy::net::wifi::WifiScan(false); } if (!other.isEmpty()) @@ -249,7 +249,7 @@ void handle_setup_scan_and_show(const String& ssid, const String& other, const S && WiFiScanAllowed(); if (needsRescan) { WiFiMode_t cur_wifimode = WiFi.getMode(); - WifiScan(false); + ESPEasy::net::wifi::WifiScan(false); scanCompleteStatus = WiFi_AP_Candidates.scanComplete(); ESPEasy::net::wifi::setWifiMode(cur_wifimode); } diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index 0ffd9b76d..aba0535c1 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -519,6 +519,9 @@ void handle_sysinfo_Network() { addRowLabel(getLabel(LabelType::CHANNEL)); if (showWiFiConnectionInfo) { addHtml(getValue(LabelType::CHANNEL)); +#if CONFIG_SOC_WIFI_SUPPORT_5G + addHtml(WiFi.channel() < 36 ? F(" (2.4 GHz)") : F(" (5 GHz)")); +#endif } else addHtml('-'); addRowLabel(getLabel(LabelType::ENCRYPTION_TYPE_STA)); diff --git a/src/src/WebServer/WiFiScanner.cpp b/src/src/WebServer/WiFiScanner.cpp index 207e23413..5ee884590 100644 --- a/src/src/WebServer/WiFiScanner.cpp +++ b/src/src/WebServer/WiFiScanner.cpp @@ -31,7 +31,7 @@ void handle_wifiscanner_json() { if (WiFi_AP_Candidates.scanComplete() <= 0) { WiFiMode_t cur_wifimode = WiFi.getMode(); - WifiScan(false); + ESPEasy::net::wifi::WifiScan(false); ESPEasy::net::wifi::setWifiMode(cur_wifimode); } @@ -67,7 +67,7 @@ void handle_wifiscanner() { if (!isLoggedIn()) { return; } WiFiMode_t cur_wifimode = WiFi.getMode(); - WifiScan(false); + ESPEasy::net::wifi::WifiScan(false); int8_t scanCompleteStatus = WiFi_AP_Candidates.scanComplete(); ESPEasy::net::wifi::setWifiMode(cur_wifimode); From 083778f1a3318a6954e3ea49b0ad49c574b17d5c Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 3 Jul 2025 11:27:44 +0200 Subject: [PATCH 085/564] [PubSubClient3] Add check for nullptr in CHECK_STRING_LENGTH strnlen will cause a crash when called with a nullptr. Where this macro is called, there are already some checks for optional fields, however it is a bit 'not so nice' for the device to crash when accidentally a nullptr is given for for example the id or will message. (will topic is checked, will message is not) See: https://github.com/hmueller01/pubsubclient3/pull/48 --- lib/pubsubclient3/src/PubSubClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pubsubclient3/src/PubSubClient.h b/lib/pubsubclient3/src/PubSubClient.h index 6840d77bd..db77df9e9 100644 --- a/lib/pubsubclient3/src/PubSubClient.h +++ b/lib/pubsubclient3/src/PubSubClient.h @@ -118,7 +118,7 @@ #endif #define CHECK_STRING_LENGTH(l, s) \ - if (l + 2 + strnlen(s, this->bufferSize) > this->bufferSize) { \ + if ((!s) || (l + 2 + strnlen(s, this->bufferSize) > this->bufferSize)) { \ _client->stop(); \ return false; \ } From 284047d884f33279f31c16fb20cce87baa5d93cf Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 3 Jul 2025 13:44:44 +0200 Subject: [PATCH 086/564] [Controller] Fix crashes on MQTT callback calls --- src/_C005.cpp | 4 ++-- src/src/DataStructs/ControllerSettingsStruct.cpp | 3 +++ src/src/Helpers/ESPEasy_Storage.cpp | 1 + src/src/Helpers/Scheduler_SystemEventTimer.cpp | 3 ++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/_C005.cpp b/src/_C005.cpp index f8e534501..9fb1b349d 100644 --- a/src/_C005.cpp +++ b/src/_C005.cpp @@ -137,7 +137,7 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& { controllerIndex_t ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_005); - if (validControllerIndex(ControllerID)) { + if (validControllerIndex(ControllerID) && event) { # if FEATURE_MQTT_DISCOVER MakeControllerSettings(ControllerSettings); // -V522 @@ -152,7 +152,7 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& if (ControllerSettings->mqtt_autoDiscovery() && (ControllerSettings->MqttAutoDiscoveryTrigger[0] != '\0') && event->String1.equals(ControllerSettings->MqttAutoDiscoveryTrigger) - && event->String2.equals(online.isEmpty() ? F("online") : online) + && event->String2.equals(online.isEmpty() ? String(F("online")) : online) ) { // We have received the Discovery request topic // Generate random time-offset in 0.1 sec, range 1..30 seconds diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index 340d4fdd3..9afc59e96 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -84,9 +84,12 @@ void ControllerSettingsStruct::validate() { ZERO_TERMINATE(MQTTLwtTopic); ZERO_TERMINATE(LWTMessageConnect); ZERO_TERMINATE(LWTMessageDisconnect); + ZERO_TERMINATE(ClientID); ZERO_TERMINATE(MqttAutoDiscoveryTopic); + ZERO_TERMINATE(MqttAutoDiscoveryConfig); ZERO_TERMINATE(MqttAutoDiscoveryTrigger); + #if FEATURE_MQTT #if FEATURE_MQTT_TLS if (TLStype() == TLS_types::NoTLS) { diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 613923cd8..b28063a90 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -1591,6 +1591,7 @@ String SaveControllerSettings(controllerIndex_t ControllerIndex, ControllerSetti Load Controller settings to file system \*********************************************************************************************/ String LoadControllerSettings(controllerIndex_t ControllerIndex, ControllerSettingsStruct& controller_settings) { + if (!validControllerIndex(ControllerIndex)) return EMPTY_STRING; #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadControllerSettings")); #endif // ifndef BUILD_NO_RAM_TRACKER diff --git a/src/src/Helpers/Scheduler_SystemEventTimer.cpp b/src/src/Helpers/Scheduler_SystemEventTimer.cpp index 688b1b0f2..492e849b0 100644 --- a/src/src/Helpers/Scheduler_SystemEventTimer.cpp +++ b/src/src/Helpers/Scheduler_SystemEventTimer.cpp @@ -92,7 +92,7 @@ void ESPEasy_Scheduler::schedule_mqtt_controller_event_timer( const char *c_topic, const uint8_t *b_payload, unsigned int length) { - if (validProtocolIndex(ProtocolIndex)) { + if (validProtocolIndex(ProtocolIndex) && c_topic && b_payload) { EventStruct event; const size_t topic_length = strlen_P(c_topic); @@ -117,6 +117,7 @@ void ESPEasy_Scheduler::schedule_mqtt_controller_event_timer( // Make sure emplace_back is not called when on 2nd heap HeapSelectDram ephemeral; # endif // ifdef USE_SECOND_HEAP + ScheduledEventQueue.emplace_back(timerID.mixed_id, std::move(event)); } } From 56a6706fb99fa505d405c0a6791581bde47f85a6 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 6 Jul 2025 01:34:38 +0200 Subject: [PATCH 087/564] [Network] Start adding Network config page --- platformio_core_defs.ini | 4 +- src/Custom-sample.h | 2 + src/src/CustomBuild/ESPEasyLimits.h | 6 + src/src/CustomBuild/define_plugin_sets.h | 3 + src/src/DataStructs/NetworkAdapterStruct.cpp | 1 + src/src/DataStructs/NetworkAdapterStruct.h | 19 + src/src/DataStructs/TimingStats.cpp | 15 + src/src/DataStructs/TimingStats.h | 8 + src/src/DataTypes/ESPEasy_plugin_functions.h | 23 + src/src/DataTypes/NWPluginID.cpp | 3 + src/src/DataTypes/NWPluginID.h | 11 + src/src/DataTypes/NetworkAdapterIndex.cpp | 5 + src/src/DataTypes/NetworkAdapterIndex.h | 11 + src/src/DataTypes/NetworkIndex.cpp | 5 + src/src/DataTypes/NetworkIndex.h | 10 + src/src/Globals/NWPlugins.cpp | 61 + src/src/Globals/NWPlugins.h | 33 + src/src/Helpers/_NWPlugin_init.cpp | 2195 ++++++++++++++++++ src/src/Helpers/_NWPlugin_init.h | 1062 +++++++++ src/src/WebServer/ESPEasy_WebServer.cpp | 4 + src/src/WebServer/NetworkPage.cpp | 75 + src/src/WebServer/NetworkPage.h | 40 + src/src/WebServer/WebTemplateParser.cpp | 15 +- src/src/WebServer/WebTemplateParser.h | 17 +- 24 files changed, 3619 insertions(+), 9 deletions(-) create mode 100644 src/src/DataStructs/NetworkAdapterStruct.cpp create mode 100644 src/src/DataStructs/NetworkAdapterStruct.h create mode 100644 src/src/DataTypes/NWPluginID.cpp create mode 100644 src/src/DataTypes/NWPluginID.h create mode 100644 src/src/DataTypes/NetworkAdapterIndex.cpp create mode 100644 src/src/DataTypes/NetworkAdapterIndex.h create mode 100644 src/src/DataTypes/NetworkIndex.cpp create mode 100644 src/src/DataTypes/NetworkIndex.h create mode 100644 src/src/Globals/NWPlugins.cpp create mode 100644 src/src/Globals/NWPlugins.h create mode 100644 src/src/Helpers/_NWPlugin_init.cpp create mode 100644 src/src/Helpers/_NWPlugin_init.h create mode 100644 src/src/WebServer/NetworkPage.cpp create mode 100644 src/src/WebServer/NetworkPage.h diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 94be31e37..3e3d3af5c 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -166,7 +166,7 @@ extra_scripts = ${esp82xx_common.extra_scripts} ; ESP_IDF 5.4.1 [core_esp32_IDF5_4_1__3_2_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF54 -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3743/framework-arduinoespressif32-all-release_v5.4-a4437683.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3765/framework-arduinoespressif32-all-release_v5.4-3138bf0e.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 @@ -195,7 +195,7 @@ lib_extra_dirs = ; ESP_IDF 5.5.0 [core_esp32_IDF5_5_0__3_2_0_LittleFS] platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55 -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3744/framework-arduinoespressif32-all-release_v5.5-c241ccd4.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3766/framework-arduinoespressif32-all-release_v5.5-1bc6b44d.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 232ae1963..47d541356 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -290,7 +290,9 @@ /* #define MENU_INDEX_CONFIG_VISIBLE false #define MENU_INDEX_CONTROLLERS_VISIBLE false +#define MENU_INDEX_NETWORK_VISIBLE false #define MENU_INDEX_HARDWARE_VISIBLE false +#define MENU_INDEX_BUSES_VISIBLE false #define MENU_INDEX_DEVICES_VISIBLE false #define MENU_INDEX_RULES_VISIBLE false #define MENU_INDEX_NOTIFICATIONS_VISIBLE false diff --git a/src/src/CustomBuild/ESPEasyLimits.h b/src/src/CustomBuild/ESPEasyLimits.h index 5b98587ea..0912bc25c 100644 --- a/src/src/CustomBuild/ESPEasyLimits.h +++ b/src/src/CustomBuild/ESPEasyLimits.h @@ -40,6 +40,9 @@ #endif +#ifndef NETWORK_MAX + #define NETWORK_MAX 8 +#endif #ifndef CONTROLLER_MAX #define CONTROLLER_MAX 3 // max 4! #endif @@ -92,6 +95,9 @@ #ifndef CPLUGIN_MAX #define CPLUGIN_MAX 255 #endif +#ifndef NWPLUGIN_MAX + #define NWPLUGIN_MAX 255 +#endif #ifndef NPLUGIN_MAX #define NPLUGIN_MAX 4 #endif diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 25c01d3cb..f5536e1fb 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -71,6 +71,9 @@ To create/register a plugin, you have to : #ifndef WEBSERVER_CONFIG #define WEBSERVER_CONFIG #endif + #ifndef WEBSERVER_NETWORK + #define WEBSERVER_NETWORK + #endif #ifndef WEBSERVER_CONTROL #define WEBSERVER_CONTROL #endif diff --git a/src/src/DataStructs/NetworkAdapterStruct.cpp b/src/src/DataStructs/NetworkAdapterStruct.cpp new file mode 100644 index 000000000..6d24e3bd0 --- /dev/null +++ b/src/src/DataStructs/NetworkAdapterStruct.cpp @@ -0,0 +1 @@ +#include "../DataStructs/NetworkAdapterStruct.h" \ No newline at end of file diff --git a/src/src/DataStructs/NetworkAdapterStruct.h b/src/src/DataStructs/NetworkAdapterStruct.h new file mode 100644 index 000000000..254dad82f --- /dev/null +++ b/src/src/DataStructs/NetworkAdapterStruct.h @@ -0,0 +1,19 @@ +#ifndef DATASTRUCTS_NETWORKADAPTERSTRUCT_H +#define DATASTRUCTS_NETWORKADAPTERSTRUCT_H + +#include "../../ESPEasy_common.h" +#include + +/*********************************************************************************************\ +* NetworkAdapterStruct +\*********************************************************************************************/ +struct NetworkAdapterStruct +{ + NetworkAdapterStruct() = default; + + + + +}; + +#endif \ No newline at end of file diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index d74f1bd24..276e350bb 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -9,6 +9,7 @@ std::map pluginStats; std::map controllerStats; +std::map networkStats; std::map miscStats; unsigned long timingstats_last_reset(0); @@ -202,6 +203,14 @@ bool mustLogCFunction(CPlugin::Function function) { return false; } +bool mustLogNWFunction(NWPlugin::Function function) +{ + if (!Settings.EnableTimingStats()) { return false; } + + return true; +} + + // Return flash string type to reduce bin size const __FlashStringHelper* getMiscStatsName_F(TimingStatsElements stat) { switch (stat) { @@ -327,6 +336,12 @@ void stopTimerController(protocolIndex_t T, CPlugin::Function F, uint32_t statis if (mustLogCFunction(F)) { controllerStats[static_cast(T) * 256 + static_cast(F)].add(usecPassedSince_fast(statisticsTimerStart)); } } +void stopTimerNetwork(networkAdapterIndex_t T, NWPlugin::Function F, uint32_t statisticsTimerStart) +{ + if (mustLogNWFunction(F)) { networkStats[static_cast(T) * 256 + static_cast(F)].add(usecPassedSince_fast(statisticsTimerStart)); } +} + + void stopTimer(TimingStatsElements L, uint32_t statisticsTimerStart) { if (Settings.EnableTimingStats()) { miscStats[L].add(usecPassedSince_fast(statisticsTimerStart)); } diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index 5d70d5dd5..5397d54e6 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -7,6 +7,7 @@ # include "../DataTypes/DeviceIndex.h" # include "../DataTypes/ESPEasy_plugin_functions.h" +# include "../DataTypes/NetworkAdapterIndex.h" # include "../DataTypes/ProtocolIndex.h" # include "../Globals/Settings.h" # include "../Helpers/ESPEasy_time_calc.h" @@ -165,6 +166,7 @@ const __FlashStringHelper* getPluginFunctionName(int function); bool mustLogFunction(int function); const __FlashStringHelper* getCPluginCFunctionName(CPlugin::Function function); bool mustLogCFunction(CPlugin::Function function); +bool mustLogNWFunction(NWPlugin::Function function); String getMiscStatsName(TimingStatsElements stat); void stopTimerTask(deviceIndex_t T, @@ -173,6 +175,9 @@ void stopTimerTask(deviceIndex_t T, void stopTimerController(protocolIndex_t T, CPlugin::Function F, uint32_t statisticsTimerStart); +void stopTimerNetwork(networkAdapterIndex_t T, + NWPlugin::Function F, + uint32_t statisticsTimerStart); void stopTimer(TimingStatsElements L, uint32_t statisticsTimerStart); void addMiscTimerStat(TimingStatsElements L, @@ -180,12 +185,14 @@ void addMiscTimerStat(TimingStatsElements L, extern std::map pluginStats; extern std::map controllerStats; +extern std::map networkStats; extern std::map miscStats; extern unsigned long timingstats_last_reset; # define START_TIMER const uint32_t statisticsTimerStart(micros()); # define STOP_TIMER_TASK(T, F) stopTimerTask(T, F, statisticsTimerStart); # define STOP_TIMER_CONTROLLER(T, F) stopTimerController(T, F, statisticsTimerStart); +# define STOP_TIMER_NETWORK(T, F) stopTimerNetwork(T, F, statisticsTimerStart); // #define STOP_TIMER_LOADFILE miscStats[LOADFILE_STATS].add(usecPassedSince_fast(statisticsTimerStart)); # define STOP_TIMER(L) stopTimer(TimingStatsElements::L, statisticsTimerStart); @@ -199,6 +206,7 @@ extern unsigned long timingstats_last_reset; # define START_TIMER ; # define STOP_TIMER_TASK(T, F) ; # define STOP_TIMER_CONTROLLER(T, F) ; +# define STOP_TIMER_NETWORK(T, F) ; # define STOP_TIMER(L) ; # define ADD_TIMER_STAT(L, T) ; diff --git a/src/src/DataTypes/ESPEasy_plugin_functions.h b/src/src/DataTypes/ESPEasy_plugin_functions.h index f3e460438..1ad407c7c 100644 --- a/src/src/DataTypes/ESPEasy_plugin_functions.h +++ b/src/src/DataTypes/ESPEasy_plugin_functions.h @@ -118,6 +118,29 @@ public: }; }; +class NWPlugin { +public: + + // As these function values are also used in the timing stats, make sure there is no overlap with the PLUGIN_xxx numbering. + + enum class Function { + NWPLUGIN_ADAPTER_ADD = 192, // Called at boot for letting a network adapter adding itself to list of available controllers + NWPLUGIN_CONNECT_SUCCESS, // Only used for timing stats + NWPLUGIN_CONNECT_FAIL, // Only used for timing stats + NWPLUGIN_ADAPTER_TEMPLATE, + NWPLUGIN_GET_DEVICENAME, + NWPLUGIN_WEBFORM_SAVE, + NWPLUGIN_WEBFORM_LOAD, + NWPLUGIN_GET_ADAPTER_DISPLAY_NAME, + NWPLUGIN_INIT, + NWPLUGIN_TEN_PER_SECOND, // Called 10x per second (typical for checking new data instead of waiting) + NWPLUGIN_FIFTY_PER_SECOND, // Called 50x per second (typical for checking new data instead of waiting) + NWPLUGIN_INIT_ALL, + NWPLUGIN_EXIT, + NWPLUGIN_WRITE, // Send commands to a network adapter. + }; +}; + // ******************************************************************************** // NPlugin (Notification) function calls // ******************************************************************************** diff --git a/src/src/DataTypes/NWPluginID.cpp b/src/src/DataTypes/NWPluginID.cpp new file mode 100644 index 000000000..be48ec49b --- /dev/null +++ b/src/src/DataTypes/NWPluginID.cpp @@ -0,0 +1,3 @@ +#include "../DataTypes/NWPluginID.h" + +const nwpluginID_t INVALID_NW_PLUGIN_ID = 0; diff --git a/src/src/DataTypes/NWPluginID.h b/src/src/DataTypes/NWPluginID.h new file mode 100644 index 000000000..cffec9e3c --- /dev/null +++ b/src/src/DataTypes/NWPluginID.h @@ -0,0 +1,11 @@ +#ifndef DATATYPES_NWPLUGINID_H +#define DATATYPES_NWPLUGINID_H + +#include "../../ESPEasy_common.h" + +typedef uint8_t nwpluginID_t; + +extern const nwpluginID_t INVALID_NW_PLUGIN_ID; + + +#endif // ifndef DATATYPES_NWPLUGINID_H diff --git a/src/src/DataTypes/NetworkAdapterIndex.cpp b/src/src/DataTypes/NetworkAdapterIndex.cpp new file mode 100644 index 000000000..b0de15048 --- /dev/null +++ b/src/src/DataTypes/NetworkAdapterIndex.cpp @@ -0,0 +1,5 @@ +#include "../DataTypes/NetworkAdapterIndex.h" + +#include "../CustomBuild/ESPEasyLimits.h" + +networkAdapterIndex_t INVALID_NETWORKADAPTER_INDEX = NWPLUGIN_MAX; \ No newline at end of file diff --git a/src/src/DataTypes/NetworkAdapterIndex.h b/src/src/DataTypes/NetworkAdapterIndex.h new file mode 100644 index 000000000..daee21217 --- /dev/null +++ b/src/src/DataTypes/NetworkAdapterIndex.h @@ -0,0 +1,11 @@ +#ifndef DATATYPES_NETWORKADAPTERINDEX_H +#define DATATYPES_NETWORKADAPTERINDEX_H + +#include "../../ESPEasy_common.h" + +typedef uint8_t networkAdapterIndex_t; + +extern networkAdapterIndex_t INVALID_NETWORKADAPTER_INDEX; + + +#endif \ No newline at end of file diff --git a/src/src/DataTypes/NetworkIndex.cpp b/src/src/DataTypes/NetworkIndex.cpp new file mode 100644 index 000000000..92daa31f5 --- /dev/null +++ b/src/src/DataTypes/NetworkIndex.cpp @@ -0,0 +1,5 @@ +#include "../DataTypes/NetworkIndex.h" + +#include "../CustomBuild/ESPEasyLimits.h" + +networkIndex_t INVALID_NETWORK_INDEX = NETWORK_MAX; \ No newline at end of file diff --git a/src/src/DataTypes/NetworkIndex.h b/src/src/DataTypes/NetworkIndex.h new file mode 100644 index 000000000..c196de707 --- /dev/null +++ b/src/src/DataTypes/NetworkIndex.h @@ -0,0 +1,10 @@ +#ifndef DATATYPES_NETWORKINDEX_H +#define DATATYPES_NETWORKINDEX_H + +#include "../../ESPEasy_common.h" + +typedef uint8_t networkIndex_t; + +extern networkIndex_t INVALID_NETWORK_INDEX; + +#endif \ No newline at end of file diff --git a/src/src/Globals/NWPlugins.cpp b/src/src/Globals/NWPlugins.cpp new file mode 100644 index 000000000..682e61a41 --- /dev/null +++ b/src/src/Globals/NWPlugins.cpp @@ -0,0 +1,61 @@ +#include "../Globals/NWPlugins.h" + +#include "../../_Plugin_Helper.h" +#include "../DataStructs/ESPEasy_EventStruct.h" +#include "../DataStructs/TimingStats.h" +#include "../DataTypes/ESPEasy_plugin_functions.h" +#include "../ESPEasyCore/ESPEasy_Log.h" + +#include "../Globals/Settings.h" +#include "../Helpers/_NWPlugin_init.h" + + + +bool NWPluginCall(NWPlugin::Function Function, struct EventStruct *event) { + #ifdef USE_SECOND_HEAP + HeapSelectDram ephemeral; + #endif // ifdef USE_SECOND_HEAP + + String dummy; + + return NWPluginCall(Function, event, dummy); +} + +bool NWPluginCall(NWPlugin::Function Function, struct EventStruct *event, String& str) +{ + #ifdef USE_SECOND_HEAP + HeapSelectDram ephemeral; + #endif // ifdef USE_SECOND_HEAP + + struct EventStruct TempEvent; + + if (event == 0) { + event = &TempEvent; + } + + switch (Function) + { + case NWPlugin::Function::NWPLUGIN_ADAPTER_ADD: + // only called from NWPluginSetup() directly using protocolIndex + break; + + // calls to all active controllers + case NWPlugin::Function::NWPLUGIN_INIT_ALL: + case NWPlugin::Function::NWPLUGIN_TEN_PER_SECOND: + case NWPlugin::Function::NWPLUGIN_FIFTY_PER_SECOND: + case NWPlugin::Function::NWPLUGIN_WRITE: +{ + const bool success = Function != NWPlugin::Function::NWPLUGIN_WRITE; + + if (Function == NWPlugin::Function::NWPLUGIN_INIT_ALL) { + Function = NWPlugin::Function::NWPLUGIN_INIT; + } + + // TODO TD-er: Implement + + return success; +} + + } + return false; +} \ No newline at end of file diff --git a/src/src/Globals/NWPlugins.h b/src/src/Globals/NWPlugins.h new file mode 100644 index 000000000..fc6eab895 --- /dev/null +++ b/src/src/Globals/NWPlugins.h @@ -0,0 +1,33 @@ +#ifndef GLOBALS_NWPLUGIN_H +#define GLOBALS_NWPLUGIN_H + +#include "../../ESPEasy_common.h" + +#include "../CustomBuild/ESPEasyLimits.h" +#include "../DataTypes/ESPEasy_plugin_functions.h" +#include "../DataTypes/NWPluginID.h" +#include "../DataTypes/NetworkIndex.h" +#include "../DataTypes/NetworkAdapterIndex.h" + + + + + +bool NWPluginCall(NWPlugin::Function Function, + struct EventStruct *event); +bool NWPluginCall(NWPlugin::Function Function, + struct EventStruct *event, + String & str); +bool NWPluginCall(networkAdapterIndex_t networkAdapterIndex, + NWPlugin::Function Function, + struct EventStruct *event, + String & str); + + + + +#endif + + + + diff --git a/src/src/Helpers/_NWPlugin_init.cpp b/src/src/Helpers/_NWPlugin_init.cpp new file mode 100644 index 000000000..9df9dbc05 --- /dev/null +++ b/src/src/Helpers/_NWPlugin_init.cpp @@ -0,0 +1,2195 @@ +#include "../Helpers/_NWPlugin_init.h" + +#include "../DataStructs/ESPEasy_EventStruct.h" +#include "../DataStructs/TimingStats.h" + +#include "../DataTypes/ESPEasy_plugin_functions.h" + +#include "../Globals/NWPlugins.h" +#include "../Globals/Settings.h" + +#include "../Helpers/Misc.h" + +// ******************************************************************************** +// Initialize all Controller NWPlugins that where defined earlier +// and initialize the function call pointer into the CNWPlugin array +// ******************************************************************************** + +constexpr nwpluginID_t NetworkAdapterIndex_to_NWPlugin_id[] PROGMEM = +{ +#ifdef USES_NW001 + 1, +#endif // ifdef USES_NW001 + +#ifdef USES_NW002 + 2, +#endif // ifdef USES_NW002 + +#ifdef USES_NW003 + 3, +#endif // ifdef USES_NW003 + +#ifdef USES_NW004 + 4, +#endif // ifdef USES_NW004 + +#ifdef USES_NW005 + 5, +#endif // ifdef USES_NW005 + +#ifdef USES_NW006 + 6, +#endif // ifdef USES_NW006 + +#ifdef USES_NW007 + 7, +#endif // ifdef USES_NW007 + +#ifdef USES_NW008 + 8, +#endif // ifdef USES_NW008 + +#ifdef USES_NW009 + 9, +#endif // ifdef USES_NW009 + +#ifdef USES_NW010 + 10, +#endif // ifdef USES_NW010 + +#ifdef USES_NW011 + 11, +#endif // ifdef USES_NW011 + +#ifdef USES_NW012 + 12, +#endif // ifdef USES_NW012 + +#ifdef USES_NW013 + 13, +#endif // ifdef USES_NW013 + +#ifdef USES_NW014 + 14, +#endif // ifdef USES_NW014 + +#ifdef USES_NW015 + 15, +#endif // ifdef USES_NW015 + +#ifdef USES_NW016 + 16, +#endif // ifdef USES_NW016 + +#ifdef USES_NW017 + 17, +#endif // ifdef USES_NW017 + +#ifdef USES_NW018 + 18, +#endif // ifdef USES_NW018 + +#ifdef USES_NW019 + 19, +#endif // ifdef USES_NW019 + +#ifdef USES_NW020 + 20, +#endif // ifdef USES_NW020 + +#ifdef USES_NW021 + 21, +#endif // ifdef USES_NW021 + +#ifdef USES_NW022 + 22, +#endif // ifdef USES_NW022 + +#ifdef USES_NW023 + 23, +#endif // ifdef USES_NW023 + +#ifdef USES_NW024 + 24, +#endif // ifdef USES_NW024 + +#ifdef USES_NW025 + 25, +#endif // ifdef USES_NW025 + +#ifdef USES_NW026 + 26, +#endif // ifdef USES_NW026 + +#ifdef USES_NW027 + 27, +#endif // ifdef USES_NW027 + +#ifdef USES_NW028 + 28, +#endif // ifdef USES_NW028 + +#ifdef USES_NW029 + 29, +#endif // ifdef USES_NW029 + +#ifdef USES_NW030 + 30, +#endif // ifdef USES_NW030 + +#ifdef USES_NW031 + 31, +#endif // ifdef USES_NW031 + +#ifdef USES_NW032 + 32, +#endif // ifdef USES_NW032 + +#ifdef USES_NW033 + 33, +#endif // ifdef USES_NW033 + +#ifdef USES_NW034 + 34, +#endif // ifdef USES_NW034 + +#ifdef USES_NW035 + 35, +#endif // ifdef USES_NW035 + +#ifdef USES_NW036 + 36, +#endif // ifdef USES_NW036 + +#ifdef USES_NW037 + 37, +#endif // ifdef USES_NW037 + +#ifdef USES_NW038 + 38, +#endif // ifdef USES_NW038 + +#ifdef USES_NW039 + 39, +#endif // ifdef USES_NW039 + +#ifdef USES_NW040 + 40, +#endif // ifdef USES_NW040 + +#ifdef USES_NW041 + 41, +#endif // ifdef USES_NW041 + +#ifdef USES_NW042 + 42, +#endif // ifdef USES_NW042 + +#ifdef USES_NW043 + 43, +#endif // ifdef USES_NW043 + +#ifdef USES_NW044 + 44, +#endif // ifdef USES_NW044 + +#ifdef USES_NW045 + 45, +#endif // ifdef USES_NW045 + +#ifdef USES_NW046 + 46, +#endif // ifdef USES_NW046 + +#ifdef USES_NW047 + 47, +#endif // ifdef USES_NW047 + +#ifdef USES_NW048 + 48, +#endif // ifdef USES_NW048 + +#ifdef USES_NW049 + 49, +#endif // ifdef USES_NW049 + +#ifdef USES_NW050 + 50, +#endif // ifdef USES_NW050 + +#ifdef USES_NW051 + 51, +#endif // ifdef USES_NW051 + +#ifdef USES_NW052 + 52, +#endif // ifdef USES_NW052 + +#ifdef USES_NW053 + 53, +#endif // ifdef USES_NW053 + +#ifdef USES_NW054 + 54, +#endif // ifdef USES_NW054 + +#ifdef USES_NW055 + 55, +#endif // ifdef USES_NW055 + +#ifdef USES_NW056 + 56, +#endif // ifdef USES_NW056 + +#ifdef USES_NW057 + 57, +#endif // ifdef USES_NW057 + +#ifdef USES_NW058 + 58, +#endif // ifdef USES_NW058 + +#ifdef USES_NW059 + 59, +#endif // ifdef USES_NW059 + +#ifdef USES_NW060 + 60, +#endif // ifdef USES_NW060 + +#ifdef USES_NW061 + 61, +#endif // ifdef USES_NW061 + +#ifdef USES_NW062 + 62, +#endif // ifdef USES_NW062 + +#ifdef USES_NW063 + 63, +#endif // ifdef USES_NW063 + +#ifdef USES_NW064 + 64, +#endif // ifdef USES_NW064 + +#ifdef USES_NW065 + 65, +#endif // ifdef USES_NW065 + +#ifdef USES_NW066 + 66, +#endif // ifdef USES_NW066 + +#ifdef USES_NW067 + 67, +#endif // ifdef USES_NW067 + +#ifdef USES_NW068 + 68, +#endif // ifdef USES_NW068 + +#ifdef USES_NW069 + 69, +#endif // ifdef USES_NW069 + +#ifdef USES_NW070 + 70, +#endif // ifdef USES_NW070 + +#ifdef USES_NW071 + 71, +#endif // ifdef USES_NW071 + +#ifdef USES_NW072 + 72, +#endif // ifdef USES_NW072 + +#ifdef USES_NW073 + 73, +#endif // ifdef USES_NW073 + +#ifdef USES_NW074 + 74, +#endif // ifdef USES_NW074 + +#ifdef USES_NW075 + 75, +#endif // ifdef USES_NW075 + +#ifdef USES_NW076 + 76, +#endif // ifdef USES_NW076 + +#ifdef USES_NW077 + 77, +#endif // ifdef USES_NW077 + +#ifdef USES_NW078 + 78, +#endif // ifdef USES_NW078 + +#ifdef USES_NW079 + 79, +#endif // ifdef USES_NW079 + +#ifdef USES_NW080 + 80, +#endif // ifdef USES_NW080 + +#ifdef USES_NW081 + 81, +#endif // ifdef USES_NW081 + +#ifdef USES_NW082 + 82, +#endif // ifdef USES_NW082 + +#ifdef USES_NW083 + 83, +#endif // ifdef USES_NW083 + +#ifdef USES_NW084 + 84, +#endif // ifdef USES_NW084 + +#ifdef USES_NW085 + 85, +#endif // ifdef USES_NW085 + +#ifdef USES_NW086 + 86, +#endif // ifdef USES_NW086 + +#ifdef USES_NW087 + 87, +#endif // ifdef USES_NW087 + +#ifdef USES_NW088 + 88, +#endif // ifdef USES_NW088 + +#ifdef USES_NW089 + 89, +#endif // ifdef USES_NW089 + +#ifdef USES_NW090 + 90, +#endif // ifdef USES_NW090 + +#ifdef USES_NW091 + 91, +#endif // ifdef USES_NW091 + +#ifdef USES_NW092 + 92, +#endif // ifdef USES_NW092 + +#ifdef USES_NW093 + 93, +#endif // ifdef USES_NW093 + +#ifdef USES_NW094 + 94, +#endif // ifdef USES_NW094 + +#ifdef USES_NW095 + 95, +#endif // ifdef USES_NW095 + +#ifdef USES_NW096 + 96, +#endif // ifdef USES_NW096 + +#ifdef USES_NW097 + 97, +#endif // ifdef USES_NW097 + +#ifdef USES_NW098 + 98, +#endif // ifdef USES_NW098 + +#ifdef USES_NW099 + 99, +#endif // ifdef USES_NW099 + +#ifdef USES_NW100 + 100, +#endif // ifdef USES_NW100 + +#ifdef USES_NW101 + 101, +#endif // ifdef USES_NW101 + +#ifdef USES_NW102 + 102, +#endif // ifdef USES_NW102 + +#ifdef USES_NW103 + 103, +#endif // ifdef USES_NW103 + +#ifdef USES_NW104 + 104, +#endif // ifdef USES_NW104 + +#ifdef USES_NW105 + 105, +#endif // ifdef USES_NW105 + +#ifdef USES_NW106 + 106, +#endif // ifdef USES_NW106 + +#ifdef USES_NW107 + 107, +#endif // ifdef USES_NW107 + +#ifdef USES_NW108 + 108, +#endif // ifdef USES_NW108 + +#ifdef USES_NW109 + 109, +#endif // ifdef USES_NW109 + +#ifdef USES_NW110 + 110, +#endif // ifdef USES_NW110 + +#ifdef USES_NW111 + 111, +#endif // ifdef USES_NW111 + +#ifdef USES_NW112 + 112, +#endif // ifdef USES_NW112 + +#ifdef USES_NW113 + 113, +#endif // ifdef USES_NW113 + +#ifdef USES_NW114 + 114, +#endif // ifdef USES_NW114 + +#ifdef USES_NW115 + 115, +#endif // ifdef USES_NW115 + +#ifdef USES_NW116 + 116, +#endif // ifdef USES_NW116 + +#ifdef USES_NW117 + 117, +#endif // ifdef USES_NW117 + +#ifdef USES_NW118 + 118, +#endif // ifdef USES_NW118 + +#ifdef USES_NW119 + 119, +#endif // ifdef USES_NW119 + +#ifdef USES_NW120 + 120, +#endif // ifdef USES_NW120 + +#ifdef USES_NW121 + 121, +#endif // ifdef USES_NW121 + +#ifdef USES_NW122 + 122, +#endif // ifdef USES_NW122 + +#ifdef USES_NW123 + 123, +#endif // ifdef USES_NW123 + +#ifdef USES_NW124 + 124, +#endif // ifdef USES_NW124 + +#ifdef USES_NW125 + 125, +#endif // ifdef USES_NW125 + +#ifdef USES_NW126 + 126, +#endif // ifdef USES_NW126 + +#ifdef USES_NW127 + 127, +#endif // ifdef USES_NW127 + +#ifdef USES_NW128 + 128, +#endif // ifdef USES_NW128 + +#ifdef USES_NW129 + 129, +#endif // ifdef USES_NW129 + +#ifdef USES_NW130 + 130, +#endif // ifdef USES_NW130 + +#ifdef USES_NW131 + 131, +#endif // ifdef USES_NW131 + +#ifdef USES_NW132 + 132, +#endif // ifdef USES_NW132 + +#ifdef USES_NW133 + 133, +#endif // ifdef USES_NW133 + +#ifdef USES_NW134 + 134, +#endif // ifdef USES_NW134 + +#ifdef USES_NW135 + 135, +#endif // ifdef USES_NW135 + +#ifdef USES_NW136 + 136, +#endif // ifdef USES_NW136 + +#ifdef USES_NW137 + 137, +#endif // ifdef USES_NW137 + +#ifdef USES_NW138 + 138, +#endif // ifdef USES_NW138 + +#ifdef USES_NW139 + 139, +#endif // ifdef USES_NW139 + +#ifdef USES_NW140 + 140, +#endif // ifdef USES_NW140 + +#ifdef USES_NW141 + 141, +#endif // ifdef USES_NW141 + +#ifdef USES_NW142 + 142, +#endif // ifdef USES_NW142 + +#ifdef USES_NW143 + 143, +#endif // ifdef USES_NW143 + +#ifdef USES_NW144 + 144, +#endif // ifdef USES_NW144 + +#ifdef USES_NW145 + 145, +#endif // ifdef USES_NW145 + +#ifdef USES_NW146 + 146, +#endif // ifdef USES_NW146 + +#ifdef USES_NW147 + 147, +#endif // ifdef USES_NW147 + +#ifdef USES_NW148 + 148, +#endif // ifdef USES_NW148 + +#ifdef USES_NW149 + 149, +#endif // ifdef USES_NW149 + +#ifdef USES_NW150 + 150, +#endif // ifdef USES_NW150 + +#ifdef USES_NW151 + 151, +#endif // ifdef USES_NW151 + +#ifdef USES_NW152 + 152, +#endif // ifdef USES_NW152 + +#ifdef USES_NW153 + 153, +#endif // ifdef USES_NW153 + +#ifdef USES_NW154 + 154, +#endif // ifdef USES_NW154 + +#ifdef USES_NW155 + 155, +#endif // ifdef USES_NW155 + +#ifdef USES_NW156 + 156, +#endif // ifdef USES_NW156 + +#ifdef USES_NW157 + 157, +#endif // ifdef USES_NW157 + +#ifdef USES_NW158 + 158, +#endif // ifdef USES_NW158 + +#ifdef USES_NW159 + 159, +#endif // ifdef USES_NW159 + +#ifdef USES_NW160 + 160, +#endif // ifdef USES_NW160 + +#ifdef USES_NW161 + 161, +#endif // ifdef USES_NW161 + +#ifdef USES_NW162 + 162, +#endif // ifdef USES_NW162 + +#ifdef USES_NW163 + 163, +#endif // ifdef USES_NW163 + +#ifdef USES_NW164 + 164, +#endif // ifdef USES_NW164 + +#ifdef USES_NW165 + 165, +#endif // ifdef USES_NW165 + +#ifdef USES_NW166 + 166, +#endif // ifdef USES_NW166 + +#ifdef USES_NW167 + 167, +#endif // ifdef USES_NW167 + +#ifdef USES_NW168 + 168, +#endif // ifdef USES_NW168 + +#ifdef USES_NW169 + 169, +#endif // ifdef USES_NW169 + +#ifdef USES_NW170 + 170, +#endif // ifdef USES_NW170 + +#ifdef USES_NW171 + 171, +#endif // ifdef USES_NW171 + +#ifdef USES_NW172 + 172, +#endif // ifdef USES_NW172 + +#ifdef USES_NW173 + 173, +#endif // ifdef USES_NW173 + +#ifdef USES_NW174 + 174, +#endif // ifdef USES_NW174 + +#ifdef USES_NW175 + 175, +#endif // ifdef USES_NW175 + +#ifdef USES_NW176 + 176, +#endif // ifdef USES_NW176 + +#ifdef USES_NW177 + 177, +#endif // ifdef USES_NW177 + +#ifdef USES_NW178 + 178, +#endif // ifdef USES_NW178 + +#ifdef USES_NW179 + 179, +#endif // ifdef USES_NW179 + +#ifdef USES_NW180 + 180, +#endif // ifdef USES_NW180 + +#ifdef USES_NW181 + 181, +#endif // ifdef USES_NW181 + +#ifdef USES_NW182 + 182, +#endif // ifdef USES_NW182 + +#ifdef USES_NW183 + 183, +#endif // ifdef USES_NW183 + +#ifdef USES_NW184 + 184, +#endif // ifdef USES_NW184 + +#ifdef USES_NW185 + 185, +#endif // ifdef USES_NW185 + +#ifdef USES_NW186 + 186, +#endif // ifdef USES_NW186 + +#ifdef USES_NW187 + 187, +#endif // ifdef USES_NW187 + +#ifdef USES_NW188 + 188, +#endif // ifdef USES_NW188 + +#ifdef USES_NW189 + 189, +#endif // ifdef USES_NW189 + +#ifdef USES_NW190 + 190, +#endif // ifdef USES_NW190 + +#ifdef USES_NW191 + 191, +#endif // ifdef USES_NW191 + +#ifdef USES_NW192 + 192, +#endif // ifdef USES_NW192 + +#ifdef USES_NW193 + 193, +#endif // ifdef USES_NW193 + +#ifdef USES_NW194 + 194, +#endif // ifdef USES_NW194 + +#ifdef USES_NW195 + 195, +#endif // ifdef USES_NW195 + +#ifdef USES_NW196 + 196, +#endif // ifdef USES_NW196 + +#ifdef USES_NW197 + 197, +#endif // ifdef USES_NW197 + +#ifdef USES_NW198 + 198, +#endif // ifdef USES_NW198 + +#ifdef USES_NW199 + 199, +#endif // ifdef USES_NW199 + +#ifdef USES_NW200 + 200, +#endif // ifdef USES_NW200 + +#ifdef USES_NW201 + 201, +#endif // ifdef USES_NW201 + +#ifdef USES_NW202 + 202, +#endif // ifdef USES_NW202 + +#ifdef USES_NW203 + 203, +#endif // ifdef USES_NW203 + +#ifdef USES_NW204 + 204, +#endif // ifdef USES_NW204 + +#ifdef USES_NW205 + 205, +#endif // ifdef USES_NW205 + +#ifdef USES_NW206 + 206, +#endif // ifdef USES_NW206 + +#ifdef USES_NW207 + 207, +#endif // ifdef USES_NW207 + +#ifdef USES_NW208 + 208, +#endif // ifdef USES_NW208 + +#ifdef USES_NW209 + 209, +#endif // ifdef USES_NW209 + +#ifdef USES_NW210 + 210, +#endif // ifdef USES_NW210 + +#ifdef USES_NW211 + 211, +#endif // ifdef USES_NW211 + +#ifdef USES_NW212 + 212, +#endif // ifdef USES_NW212 + +#ifdef USES_NW213 + 213, +#endif // ifdef USES_NW213 + +#ifdef USES_NW214 + 214, +#endif // ifdef USES_NW214 + +#ifdef USES_NW215 + 215, +#endif // ifdef USES_NW215 + +#ifdef USES_NW216 + 216, +#endif // ifdef USES_NW216 + +#ifdef USES_NW217 + 217, +#endif // ifdef USES_NW217 + +#ifdef USES_NW218 + 218, +#endif // ifdef USES_NW218 + +#ifdef USES_NW219 + 219, +#endif // ifdef USES_NW219 + +#ifdef USES_NW220 + 220, +#endif // ifdef USES_NW220 + +#ifdef USES_NW221 + 221, +#endif // ifdef USES_NW221 + +#ifdef USES_NW222 + 222, +#endif // ifdef USES_NW222 + +#ifdef USES_NW223 + 223, +#endif // ifdef USES_NW223 + +#ifdef USES_NW224 + 224, +#endif // ifdef USES_NW224 + +#ifdef USES_NW225 + 225, +#endif // ifdef USES_NW225 + +#ifdef USES_NW226 + 226, +#endif // ifdef USES_NW226 + +#ifdef USES_NW227 + 227, +#endif // ifdef USES_NW227 + +#ifdef USES_NW228 + 228, +#endif // ifdef USES_NW228 + +#ifdef USES_NW229 + 229, +#endif // ifdef USES_NW229 + +#ifdef USES_NW230 + 230, +#endif // ifdef USES_NW230 + +#ifdef USES_NW231 + 231, +#endif // ifdef USES_NW231 + +#ifdef USES_NW232 + 232, +#endif // ifdef USES_NW232 + +#ifdef USES_NW233 + 233, +#endif // ifdef USES_NW233 + +#ifdef USES_NW234 + 234, +#endif // ifdef USES_NW234 + +#ifdef USES_NW235 + 235, +#endif // ifdef USES_NW235 + +#ifdef USES_NW236 + 236, +#endif // ifdef USES_NW236 + +#ifdef USES_NW237 + 237, +#endif // ifdef USES_NW237 + +#ifdef USES_NW238 + 238, +#endif // ifdef USES_NW238 + +#ifdef USES_NW239 + 239, +#endif // ifdef USES_NW239 + +#ifdef USES_NW240 + 240, +#endif // ifdef USES_NW240 + +#ifdef USES_NW241 + 241, +#endif // ifdef USES_NW241 + +#ifdef USES_NW242 + 242, +#endif // ifdef USES_NW242 + +#ifdef USES_NW243 + 243, +#endif // ifdef USES_NW243 + +#ifdef USES_NW244 + 244, +#endif // ifdef USES_NW244 + +#ifdef USES_NW245 + 245, +#endif // ifdef USES_NW245 + +#ifdef USES_NW246 + 246, +#endif // ifdef USES_NW246 + +#ifdef USES_NW247 + 247, +#endif // ifdef USES_NW247 + +#ifdef USES_NW248 + 248, +#endif // ifdef USES_NW248 + +#ifdef USES_NW249 + 249, +#endif // ifdef USES_NW249 + +#ifdef USES_NW250 + 250, +#endif // ifdef USES_NW250 + +#ifdef USES_NW251 + 251, +#endif // ifdef USES_NW251 + +#ifdef USES_NW252 + 252, +#endif // ifdef USES_NW252 + +#ifdef USES_NW253 + 253, +#endif // ifdef USES_NW253 + +#ifdef USES_NW254 + 254, +#endif // ifdef USES_NW254 + +#ifdef USES_NW255 + 255, +#endif // ifdef USES_NW255 +}; + + +typedef bool (*NWPlugin_ptr_t)(NWPlugin::Function, + struct EventStruct *, + String&); + +const NWPlugin_ptr_t PROGMEM NWPlugin_ptr[] = +{ +#ifdef USES_NW001 + &NWPlugin_001, +#endif // ifdef USES_NW001 + +#ifdef USES_NW002 + &NWPlugin_002, +#endif // ifdef USES_NW002 + +#ifdef USES_NW003 + &NWPlugin_003, +#endif // ifdef USES_NW003 + +#ifdef USES_NW004 + &NWPlugin_004, +#endif // ifdef USES_NW004 + +#ifdef USES_NW005 + &NWPlugin_005, +#endif // ifdef USES_NW005 + +#ifdef USES_NW006 + &NWPlugin_006, +#endif // ifdef USES_NW006 + +#ifdef USES_NW007 + &NWPlugin_007, +#endif // ifdef USES_NW007 + +#ifdef USES_NW008 + &NWPlugin_008, +#endif // ifdef USES_NW008 + +#ifdef USES_NW009 + &NWPlugin_009, +#endif // ifdef USES_NW009 + +#ifdef USES_NW010 + &NWPlugin_010, +#endif // ifdef USES_NW010 + +#ifdef USES_NW011 + &NWPlugin_011, +#endif // ifdef USES_NW011 + +#ifdef USES_NW012 + &NWPlugin_012, +#endif // ifdef USES_NW012 + +#ifdef USES_NW013 + &NWPlugin_013, +#endif // ifdef USES_NW013 + +#ifdef USES_NW014 + &NWPlugin_014, +#endif // ifdef USES_NW014 + +#ifdef USES_NW015 + &NWPlugin_015, +#endif // ifdef USES_NW015 + +#ifdef USES_NW016 + &NWPlugin_016, +#endif // ifdef USES_NW016 + +#ifdef USES_NW017 + &NWPlugin_017, +#endif // ifdef USES_NW017 + +#ifdef USES_NW018 + &NWPlugin_018, +#endif // ifdef USES_NW018 + +#ifdef USES_NW019 + &NWPlugin_019, +#endif // ifdef USES_NW019 + +#ifdef USES_NW020 + &NWPlugin_020, +#endif // ifdef USES_NW020 + +#ifdef USES_NW021 + &NWPlugin_021, +#endif // ifdef USES_NW021 + +#ifdef USES_NW022 + &NWPlugin_022, +#endif // ifdef USES_NW022 + +#ifdef USES_NW023 + &NWPlugin_023, +#endif // ifdef USES_NW023 + +#ifdef USES_NW024 + &NWPlugin_024, +#endif // ifdef USES_NW024 + +#ifdef USES_NW025 + &NWPlugin_025, +#endif // ifdef USES_NW025 + +#ifdef USES_NW026 + &NWPlugin_026, +#endif // ifdef USES_NW026 + +#ifdef USES_NW027 + &NWPlugin_027, +#endif // ifdef USES_NW027 + +#ifdef USES_NW028 + &NWPlugin_028, +#endif // ifdef USES_NW028 + +#ifdef USES_NW029 + &NWPlugin_029, +#endif // ifdef USES_NW029 + +#ifdef USES_NW030 + &NWPlugin_030, +#endif // ifdef USES_NW030 + +#ifdef USES_NW031 + &NWPlugin_031, +#endif // ifdef USES_NW031 + +#ifdef USES_NW032 + &NWPlugin_032, +#endif // ifdef USES_NW032 + +#ifdef USES_NW033 + &NWPlugin_033, +#endif // ifdef USES_NW033 + +#ifdef USES_NW034 + &NWPlugin_034, +#endif // ifdef USES_NW034 + +#ifdef USES_NW035 + &NWPlugin_035, +#endif // ifdef USES_NW035 + +#ifdef USES_NW036 + &NWPlugin_036, +#endif // ifdef USES_NW036 + +#ifdef USES_NW037 + &NWPlugin_037, +#endif // ifdef USES_NW037 + +#ifdef USES_NW038 + &NWPlugin_038, +#endif // ifdef USES_NW038 + +#ifdef USES_NW039 + &NWPlugin_039, +#endif // ifdef USES_NW039 + +#ifdef USES_NW040 + &NWPlugin_040, +#endif // ifdef USES_NW040 + +#ifdef USES_NW041 + &NWPlugin_041, +#endif // ifdef USES_NW041 + +#ifdef USES_NW042 + &NWPlugin_042, +#endif // ifdef USES_NW042 + +#ifdef USES_NW043 + &NWPlugin_043, +#endif // ifdef USES_NW043 + +#ifdef USES_NW044 + &NWPlugin_044, +#endif // ifdef USES_NW044 + +#ifdef USES_NW045 + &NWPlugin_045, +#endif // ifdef USES_NW045 + +#ifdef USES_NW046 + &NWPlugin_046, +#endif // ifdef USES_NW046 + +#ifdef USES_NW047 + &NWPlugin_047, +#endif // ifdef USES_NW047 + +#ifdef USES_NW048 + &NWPlugin_048, +#endif // ifdef USES_NW048 + +#ifdef USES_NW049 + &NWPlugin_049, +#endif // ifdef USES_NW049 + +#ifdef USES_NW050 + &NWPlugin_050, +#endif // ifdef USES_NW050 + +#ifdef USES_NW051 + &NWPlugin_051, +#endif // ifdef USES_NW051 + +#ifdef USES_NW052 + &NWPlugin_052, +#endif // ifdef USES_NW052 + +#ifdef USES_NW053 + &NWPlugin_053, +#endif // ifdef USES_NW053 + +#ifdef USES_NW054 + &NWPlugin_054, +#endif // ifdef USES_NW054 + +#ifdef USES_NW055 + &NWPlugin_055, +#endif // ifdef USES_NW055 + +#ifdef USES_NW056 + &NWPlugin_056, +#endif // ifdef USES_NW056 + +#ifdef USES_NW057 + &NWPlugin_057, +#endif // ifdef USES_NW057 + +#ifdef USES_NW058 + &NWPlugin_058, +#endif // ifdef USES_NW058 + +#ifdef USES_NW059 + &NWPlugin_059, +#endif // ifdef USES_NW059 + +#ifdef USES_NW060 + &NWPlugin_060, +#endif // ifdef USES_NW060 + +#ifdef USES_NW061 + &NWPlugin_061, +#endif // ifdef USES_NW061 + +#ifdef USES_NW062 + &NWPlugin_062, +#endif // ifdef USES_NW062 + +#ifdef USES_NW063 + &NWPlugin_063, +#endif // ifdef USES_NW063 + +#ifdef USES_NW064 + &NWPlugin_064, +#endif // ifdef USES_NW064 + +#ifdef USES_NW065 + &NWPlugin_065, +#endif // ifdef USES_NW065 + +#ifdef USES_NW066 + &NWPlugin_066, +#endif // ifdef USES_NW066 + +#ifdef USES_NW067 + &NWPlugin_067, +#endif // ifdef USES_NW067 + +#ifdef USES_NW068 + &NWPlugin_068, +#endif // ifdef USES_NW068 + +#ifdef USES_NW069 + &NWPlugin_069, +#endif // ifdef USES_NW069 + +#ifdef USES_NW070 + &NWPlugin_070, +#endif // ifdef USES_NW070 + +#ifdef USES_NW071 + &NWPlugin_071, +#endif // ifdef USES_NW071 + +#ifdef USES_NW072 + &NWPlugin_072, +#endif // ifdef USES_NW072 + +#ifdef USES_NW073 + &NWPlugin_073, +#endif // ifdef USES_NW073 + +#ifdef USES_NW074 + &NWPlugin_074, +#endif // ifdef USES_NW074 + +#ifdef USES_NW075 + &NWPlugin_075, +#endif // ifdef USES_NW075 + +#ifdef USES_NW076 + &NWPlugin_076, +#endif // ifdef USES_NW076 + +#ifdef USES_NW077 + &NWPlugin_077, +#endif // ifdef USES_NW077 + +#ifdef USES_NW078 + &NWPlugin_078, +#endif // ifdef USES_NW078 + +#ifdef USES_NW079 + &NWPlugin_079, +#endif // ifdef USES_NW079 + +#ifdef USES_NW080 + &NWPlugin_080, +#endif // ifdef USES_NW080 + +#ifdef USES_NW081 + &NWPlugin_081, +#endif // ifdef USES_NW081 + +#ifdef USES_NW082 + &NWPlugin_082, +#endif // ifdef USES_NW082 + +#ifdef USES_NW083 + &NWPlugin_083, +#endif // ifdef USES_NW083 + +#ifdef USES_NW084 + &NWPlugin_084, +#endif // ifdef USES_NW084 + +#ifdef USES_NW085 + &NWPlugin_085, +#endif // ifdef USES_NW085 + +#ifdef USES_NW086 + &NWPlugin_086, +#endif // ifdef USES_NW086 + +#ifdef USES_NW087 + &NWPlugin_087, +#endif // ifdef USES_NW087 + +#ifdef USES_NW088 + &NWPlugin_088, +#endif // ifdef USES_NW088 + +#ifdef USES_NW089 + &NWPlugin_089, +#endif // ifdef USES_NW089 + +#ifdef USES_NW090 + &NWPlugin_090, +#endif // ifdef USES_NW090 + +#ifdef USES_NW091 + &NWPlugin_091, +#endif // ifdef USES_NW091 + +#ifdef USES_NW092 + &NWPlugin_092, +#endif // ifdef USES_NW092 + +#ifdef USES_NW093 + &NWPlugin_093, +#endif // ifdef USES_NW093 + +#ifdef USES_NW094 + &NWPlugin_094, +#endif // ifdef USES_NW094 + +#ifdef USES_NW095 + &NWPlugin_095, +#endif // ifdef USES_NW095 + +#ifdef USES_NW096 + &NWPlugin_096, +#endif // ifdef USES_NW096 + +#ifdef USES_NW097 + &NWPlugin_097, +#endif // ifdef USES_NW097 + +#ifdef USES_NW098 + &NWPlugin_098, +#endif // ifdef USES_NW098 + +#ifdef USES_NW099 + &NWPlugin_099, +#endif // ifdef USES_NW099 + +#ifdef USES_NW100 + &NWPlugin_100, +#endif // ifdef USES_NW100 + +#ifdef USES_NW101 + &NWPlugin_101, +#endif // ifdef USES_NW101 + +#ifdef USES_NW102 + &NWPlugin_102, +#endif // ifdef USES_NW102 + +#ifdef USES_NW103 + &NWPlugin_103, +#endif // ifdef USES_NW103 + +#ifdef USES_NW104 + &NWPlugin_104, +#endif // ifdef USES_NW104 + +#ifdef USES_NW105 + &NWPlugin_105, +#endif // ifdef USES_NW105 + +#ifdef USES_NW106 + &NWPlugin_106, +#endif // ifdef USES_NW106 + +#ifdef USES_NW107 + &NWPlugin_107, +#endif // ifdef USES_NW107 + +#ifdef USES_NW108 + &NWPlugin_108, +#endif // ifdef USES_NW108 + +#ifdef USES_NW109 + &NWPlugin_109, +#endif // ifdef USES_NW109 + +#ifdef USES_NW110 + &NWPlugin_110, +#endif // ifdef USES_NW110 + +#ifdef USES_NW111 + &NWPlugin_111, +#endif // ifdef USES_NW111 + +#ifdef USES_NW112 + &NWPlugin_112, +#endif // ifdef USES_NW112 + +#ifdef USES_NW113 + &NWPlugin_113, +#endif // ifdef USES_NW113 + +#ifdef USES_NW114 + &NWPlugin_114, +#endif // ifdef USES_NW114 + +#ifdef USES_NW115 + &NWPlugin_115, +#endif // ifdef USES_NW115 + +#ifdef USES_NW116 + &NWPlugin_116, +#endif // ifdef USES_NW116 + +#ifdef USES_NW117 + &NWPlugin_117, +#endif // ifdef USES_NW117 + +#ifdef USES_NW118 + &NWPlugin_118, +#endif // ifdef USES_NW118 + +#ifdef USES_NW119 + &NWPlugin_119, +#endif // ifdef USES_NW119 + +#ifdef USES_NW120 + &NWPlugin_120, +#endif // ifdef USES_NW120 + +#ifdef USES_NW121 + &NWPlugin_121, +#endif // ifdef USES_NW121 + +#ifdef USES_NW122 + &NWPlugin_122, +#endif // ifdef USES_NW122 + +#ifdef USES_NW123 + &NWPlugin_123, +#endif // ifdef USES_NW123 + +#ifdef USES_NW124 + &NWPlugin_124, +#endif // ifdef USES_NW124 + +#ifdef USES_NW125 + &NWPlugin_125, +#endif // ifdef USES_NW125 + +#ifdef USES_NW126 + &NWPlugin_126, +#endif // ifdef USES_NW126 + +#ifdef USES_NW127 + &NWPlugin_127, +#endif // ifdef USES_NW127 + +#ifdef USES_NW128 + &NWPlugin_128, +#endif // ifdef USES_NW128 + +#ifdef USES_NW129 + &NWPlugin_129, +#endif // ifdef USES_NW129 + +#ifdef USES_NW130 + &NWPlugin_130, +#endif // ifdef USES_NW130 + +#ifdef USES_NW131 + &NWPlugin_131, +#endif // ifdef USES_NW131 + +#ifdef USES_NW132 + &NWPlugin_132, +#endif // ifdef USES_NW132 + +#ifdef USES_NW133 + &NWPlugin_133, +#endif // ifdef USES_NW133 + +#ifdef USES_NW134 + &NWPlugin_134, +#endif // ifdef USES_NW134 + +#ifdef USES_NW135 + &NWPlugin_135, +#endif // ifdef USES_NW135 + +#ifdef USES_NW136 + &NWPlugin_136, +#endif // ifdef USES_NW136 + +#ifdef USES_NW137 + &NWPlugin_137, +#endif // ifdef USES_NW137 + +#ifdef USES_NW138 + &NWPlugin_138, +#endif // ifdef USES_NW138 + +#ifdef USES_NW139 + &NWPlugin_139, +#endif // ifdef USES_NW139 + +#ifdef USES_NW140 + &NWPlugin_140, +#endif // ifdef USES_NW140 + +#ifdef USES_NW141 + &NWPlugin_141, +#endif // ifdef USES_NW141 + +#ifdef USES_NW142 + &NWPlugin_142, +#endif // ifdef USES_NW142 + +#ifdef USES_NW143 + &NWPlugin_143, +#endif // ifdef USES_NW143 + +#ifdef USES_NW144 + &NWPlugin_144, +#endif // ifdef USES_NW144 + +#ifdef USES_NW145 + &NWPlugin_145, +#endif // ifdef USES_NW145 + +#ifdef USES_NW146 + &NWPlugin_146, +#endif // ifdef USES_NW146 + +#ifdef USES_NW147 + &NWPlugin_147, +#endif // ifdef USES_NW147 + +#ifdef USES_NW148 + &NWPlugin_148, +#endif // ifdef USES_NW148 + +#ifdef USES_NW149 + &NWPlugin_149, +#endif // ifdef USES_NW149 + +#ifdef USES_NW150 + &NWPlugin_150, +#endif // ifdef USES_NW150 + +#ifdef USES_NW151 + &NWPlugin_151, +#endif // ifdef USES_NW151 + +#ifdef USES_NW152 + &NWPlugin_152, +#endif // ifdef USES_NW152 + +#ifdef USES_NW153 + &NWPlugin_153, +#endif // ifdef USES_NW153 + +#ifdef USES_NW154 + &NWPlugin_154, +#endif // ifdef USES_NW154 + +#ifdef USES_NW155 + &NWPlugin_155, +#endif // ifdef USES_NW155 + +#ifdef USES_NW156 + &NWPlugin_156, +#endif // ifdef USES_NW156 + +#ifdef USES_NW157 + &NWPlugin_157, +#endif // ifdef USES_NW157 + +#ifdef USES_NW158 + &NWPlugin_158, +#endif // ifdef USES_NW158 + +#ifdef USES_NW159 + &NWPlugin_159, +#endif // ifdef USES_NW159 + +#ifdef USES_NW160 + &NWPlugin_160, +#endif // ifdef USES_NW160 + +#ifdef USES_NW161 + &NWPlugin_161, +#endif // ifdef USES_NW161 + +#ifdef USES_NW162 + &NWPlugin_162, +#endif // ifdef USES_NW162 + +#ifdef USES_NW163 + &NWPlugin_163, +#endif // ifdef USES_NW163 + +#ifdef USES_NW164 + &NWPlugin_164, +#endif // ifdef USES_NW164 + +#ifdef USES_NW165 + &NWPlugin_165, +#endif // ifdef USES_NW165 + +#ifdef USES_NW166 + &NWPlugin_166, +#endif // ifdef USES_NW166 + +#ifdef USES_NW167 + &NWPlugin_167, +#endif // ifdef USES_NW167 + +#ifdef USES_NW168 + &NWPlugin_168, +#endif // ifdef USES_NW168 + +#ifdef USES_NW169 + &NWPlugin_169, +#endif // ifdef USES_NW169 + +#ifdef USES_NW170 + &NWPlugin_170, +#endif // ifdef USES_NW170 + +#ifdef USES_NW171 + &NWPlugin_171, +#endif // ifdef USES_NW171 + +#ifdef USES_NW172 + &NWPlugin_172, +#endif // ifdef USES_NW172 + +#ifdef USES_NW173 + &NWPlugin_173, +#endif // ifdef USES_NW173 + +#ifdef USES_NW174 + &NWPlugin_174, +#endif // ifdef USES_NW174 + +#ifdef USES_NW175 + &NWPlugin_175, +#endif // ifdef USES_NW175 + +#ifdef USES_NW176 + &NWPlugin_176, +#endif // ifdef USES_NW176 + +#ifdef USES_NW177 + &NWPlugin_177, +#endif // ifdef USES_NW177 + +#ifdef USES_NW178 + &NWPlugin_178, +#endif // ifdef USES_NW178 + +#ifdef USES_NW179 + &NWPlugin_179, +#endif // ifdef USES_NW179 + +#ifdef USES_NW180 + &NWPlugin_180, +#endif // ifdef USES_NW180 + +#ifdef USES_NW181 + &NWPlugin_181, +#endif // ifdef USES_NW181 + +#ifdef USES_NW182 + &NWPlugin_182, +#endif // ifdef USES_NW182 + +#ifdef USES_NW183 + &NWPlugin_183, +#endif // ifdef USES_NW183 + +#ifdef USES_NW184 + &NWPlugin_184, +#endif // ifdef USES_NW184 + +#ifdef USES_NW185 + &NWPlugin_185, +#endif // ifdef USES_NW185 + +#ifdef USES_NW186 + &NWPlugin_186, +#endif // ifdef USES_NW186 + +#ifdef USES_NW187 + &NWPlugin_187, +#endif // ifdef USES_NW187 + +#ifdef USES_NW188 + &NWPlugin_188, +#endif // ifdef USES_NW188 + +#ifdef USES_NW189 + &NWPlugin_189, +#endif // ifdef USES_NW189 + +#ifdef USES_NW190 + &NWPlugin_190, +#endif // ifdef USES_NW190 + +#ifdef USES_NW191 + &NWPlugin_191, +#endif // ifdef USES_NW191 + +#ifdef USES_NW192 + &NWPlugin_192, +#endif // ifdef USES_NW192 + +#ifdef USES_NW193 + &NWPlugin_193, +#endif // ifdef USES_NW193 + +#ifdef USES_NW194 + &NWPlugin_194, +#endif // ifdef USES_NW194 + +#ifdef USES_NW195 + &NWPlugin_195, +#endif // ifdef USES_NW195 + +#ifdef USES_NW196 + &NWPlugin_196, +#endif // ifdef USES_NW196 + +#ifdef USES_NW197 + &NWPlugin_197, +#endif // ifdef USES_NW197 + +#ifdef USES_NW198 + &NWPlugin_198, +#endif // ifdef USES_NW198 + +#ifdef USES_NW199 + &NWPlugin_199, +#endif // ifdef USES_NW199 + +#ifdef USES_NW200 + &NWPlugin_200, +#endif // ifdef USES_NW200 + +#ifdef USES_NW201 + &NWPlugin_201, +#endif // ifdef USES_NW201 + +#ifdef USES_NW202 + &NWPlugin_202, +#endif // ifdef USES_NW202 + +#ifdef USES_NW203 + &NWPlugin_203, +#endif // ifdef USES_NW203 + +#ifdef USES_NW204 + &NWPlugin_204, +#endif // ifdef USES_NW204 + +#ifdef USES_NW205 + &NWPlugin_205, +#endif // ifdef USES_NW205 + +#ifdef USES_NW206 + &NWPlugin_206, +#endif // ifdef USES_NW206 + +#ifdef USES_NW207 + &NWPlugin_207, +#endif // ifdef USES_NW207 + +#ifdef USES_NW208 + &NWPlugin_208, +#endif // ifdef USES_NW208 + +#ifdef USES_NW209 + &NWPlugin_209, +#endif // ifdef USES_NW209 + +#ifdef USES_NW210 + &NWPlugin_210, +#endif // ifdef USES_NW210 + +#ifdef USES_NW211 + &NWPlugin_211, +#endif // ifdef USES_NW211 + +#ifdef USES_NW212 + &NWPlugin_212, +#endif // ifdef USES_NW212 + +#ifdef USES_NW213 + &NWPlugin_213, +#endif // ifdef USES_NW213 + +#ifdef USES_NW214 + &NWPlugin_214, +#endif // ifdef USES_NW214 + +#ifdef USES_NW215 + &NWPlugin_215, +#endif // ifdef USES_NW215 + +#ifdef USES_NW216 + &NWPlugin_216, +#endif // ifdef USES_NW216 + +#ifdef USES_NW217 + &NWPlugin_217, +#endif // ifdef USES_NW217 + +#ifdef USES_NW218 + &NWPlugin_218, +#endif // ifdef USES_NW218 + +#ifdef USES_NW219 + &NWPlugin_219, +#endif // ifdef USES_NW219 + +#ifdef USES_NW220 + &NWPlugin_220, +#endif // ifdef USES_NW220 + +#ifdef USES_NW221 + &NWPlugin_221, +#endif // ifdef USES_NW221 + +#ifdef USES_NW222 + &NWPlugin_222, +#endif // ifdef USES_NW222 + +#ifdef USES_NW223 + &NWPlugin_223, +#endif // ifdef USES_NW223 + +#ifdef USES_NW224 + &NWPlugin_224, +#endif // ifdef USES_NW224 + +#ifdef USES_NW225 + &NWPlugin_225, +#endif // ifdef USES_NW225 + +#ifdef USES_NW226 + &NWPlugin_226, +#endif // ifdef USES_NW226 + +#ifdef USES_NW227 + &NWPlugin_227, +#endif // ifdef USES_NW227 + +#ifdef USES_NW228 + &NWPlugin_228, +#endif // ifdef USES_NW228 + +#ifdef USES_NW229 + &NWPlugin_229, +#endif // ifdef USES_NW229 + +#ifdef USES_NW230 + &NWPlugin_230, +#endif // ifdef USES_NW230 + +#ifdef USES_NW231 + &NWPlugin_231, +#endif // ifdef USES_NW231 + +#ifdef USES_NW232 + &NWPlugin_232, +#endif // ifdef USES_NW232 + +#ifdef USES_NW233 + &NWPlugin_233, +#endif // ifdef USES_NW233 + +#ifdef USES_NW234 + &NWPlugin_234, +#endif // ifdef USES_NW234 + +#ifdef USES_NW235 + &NWPlugin_235, +#endif // ifdef USES_NW235 + +#ifdef USES_NW236 + &NWPlugin_236, +#endif // ifdef USES_NW236 + +#ifdef USES_NW237 + &NWPlugin_237, +#endif // ifdef USES_NW237 + +#ifdef USES_NW238 + &NWPlugin_238, +#endif // ifdef USES_NW238 + +#ifdef USES_NW239 + &NWPlugin_239, +#endif // ifdef USES_NW239 + +#ifdef USES_NW240 + &NWPlugin_240, +#endif // ifdef USES_NW240 + +#ifdef USES_NW241 + &NWPlugin_241, +#endif // ifdef USES_NW241 + +#ifdef USES_NW242 + &NWPlugin_242, +#endif // ifdef USES_NW242 + +#ifdef USES_NW243 + &NWPlugin_243, +#endif // ifdef USES_NW243 + +#ifdef USES_NW244 + &NWPlugin_244, +#endif // ifdef USES_NW244 + +#ifdef USES_NW245 + &NWPlugin_245, +#endif // ifdef USES_NW245 + +#ifdef USES_NW246 + &NWPlugin_246, +#endif // ifdef USES_NW246 + +#ifdef USES_NW247 + &NWPlugin_247, +#endif // ifdef USES_NW247 + +#ifdef USES_NW248 + &NWPlugin_248, +#endif // ifdef USES_NW248 + +#ifdef USES_NW249 + &NWPlugin_249, +#endif // ifdef USES_NW249 + +#ifdef USES_NW250 + &NWPlugin_250, +#endif // ifdef USES_NW250 + +#ifdef USES_NW251 + &NWPlugin_251, +#endif // ifdef USES_NW251 + +#ifdef USES_NW252 + &NWPlugin_252, +#endif // ifdef USES_NW252 + +#ifdef USES_NW253 + &NWPlugin_253, +#endif // ifdef USES_NW253 + +#ifdef USES_NW254 + &NWPlugin_254, +#endif // ifdef USES_NW254 + +#ifdef USES_NW255 + &NWPlugin_255, +#endif // ifdef USES_NW255 +}; + + +constexpr size_t NetworkAdapterIndex_to_NWPlugin_id_size = sizeof(NetworkAdapterIndex_to_NWPlugin_id); + +// Highest NWPlugin ID included in the build +constexpr size_t Highest_NWPlugin_id = NetworkAdapterIndex_to_NWPlugin_id_size == 0 ? 0 : NetworkAdapterIndex_to_NWPlugin_id[NetworkAdapterIndex_to_NWPlugin_id_size - 1]; + +constexpr size_t NWPlugin_id_to_NetworkAdapterIndex_size = Highest_NWPlugin_id + 1; + +// Array filled during init. +// Valid index: 1 ... Highest_NWPlugin_id +// Returns index to the NetworkAdapterIndex_to_NWPlugin_id array +networkAdapterIndex_t NWPlugin_id_to_NetworkAdapterIndex[NWPlugin_id_to_NetworkAdapterIndex_size]{}; + + +NetworkAdapterStruct NetworkAdapterArray[NetworkAdapterIndex_to_NWPlugin_id_size + 1]{}; + +NetworkAdapterStruct& getNetworkAdapterStruct(networkAdapterIndex_t networkAdapterIndex) +{ + if (networkAdapterIndex >= NetworkAdapterIndex_to_NWPlugin_id_size) { + networkAdapterIndex = NetworkAdapterIndex_to_NWPlugin_id_size; + } + return NetworkAdapterArray[networkAdapterIndex]; +} + + +bool validNetworkAdapterIndex(networkAdapterIndex_t index) +{ + return validNetworkAdapterIndex_init(index); +} + +/* + bool validControllerIndex(controllerIndex_t index) + { + return index < CONTROLLER_MAX; + } + */ +bool validNWPluginID(nwpluginID_t nwpluginID) +{ + return getNetworkAdapterIndex_from_NWPluginID_(nwpluginID) != INVALID_PROTOCOL_INDEX; +} + +bool supportedNWPluginID(nwpluginID_t nwpluginID) +{ + return validNetworkAdapterIndex(getNetworkAdapterIndex_from_NWPluginID_(nwpluginID)); +} + + + +networkAdapterIndex_t getNetworkAdapterIndex_from_NWPluginID_(nwpluginID_t nwpluginID) +{ + if (nwpluginID < NWPlugin_id_to_NetworkAdapterIndex_size) + { + return static_cast(NWPlugin_id_to_NetworkAdapterIndex[nwpluginID]); + } + return INVALID_NETWORKADAPTER_INDEX; +} + +nwpluginID_t getNWPluginID_from_NetworkAdapterIndex_(networkAdapterIndex_t networkAdapterIndex) +{ + if (networkAdapterIndex < NetworkAdapterIndex_to_NWPlugin_id_size) + { + // return static_cast(NetworkAdapterIndex_to_NWPlugin_id[networkAdapterIndex]); + return static_cast(pgm_read_byte(NetworkAdapterIndex_to_NWPlugin_id + networkAdapterIndex)); + } + return INVALID_NW_PLUGIN_ID; +} + +bool validNetworkAdapterIndex_init(networkAdapterIndex_t networkAdapterIndex) +{ + return networkAdapterIndex < NetworkAdapterIndex_to_NWPlugin_id_size; +} + +nwpluginID_t getHighestIncludedNWPluginID() +{ + return Highest_NWPlugin_id; +} + + +bool NWPluginCall(networkAdapterIndex_t networkAdapterIndex, NWPlugin::Function Function, struct EventStruct *event, String& string) +{ + if (networkAdapterIndex < NetworkAdapterIndex_to_NWPlugin_id_size) + { + START_TIMER; + NWPlugin_ptr_t nwplugin_call = (NWPlugin_ptr_t)pgm_read_ptr(NWPlugin_ptr + networkAdapterIndex); + const bool res = nwplugin_call(Function, event, string); + STOP_TIMER_NETWORK(networkAdapterIndex, Function); + return res; + } + return false; +} + +void NWPluginSetup() +{ + static bool setupDone = false; + + if (setupDone) { return; } + + for (size_t id = 0; id < NWPlugin_id_to_NetworkAdapterIndex_size; ++id) + { + NWPlugin_id_to_NetworkAdapterIndex[id] = INVALID_NETWORKADAPTER_INDEX; + } + + for (networkAdapterIndex_t networkAdapterIndex = 0; networkAdapterIndex < NetworkAdapterIndex_to_NWPlugin_id_size; ++networkAdapterIndex) + { + const nwpluginID_t nwpluginID = getNWPluginID_from_NetworkAdapterIndex_(networkAdapterIndex); + + if (INVALID_NW_PLUGIN_ID != nwpluginID) { + NWPlugin_id_to_NetworkAdapterIndex[nwpluginID] = networkAdapterIndex; + struct EventStruct TempEvent; + TempEvent.idx = networkAdapterIndex; + String dummy; + NWPluginCall(networkAdapterIndex, NWPlugin::Function::NWPLUGIN_ADAPTER_ADD, &TempEvent, dummy); + } + } + setupDone = true; +} + +void NWPluginInit() +{ + // Set all not supported nwplugins to disabled. + for (controllerIndex_t controller = 0; controller < CONTROLLER_MAX; ++controller) { +// if (!supportedNWPluginID(Settings.NetworkAdapter[controller])) { +// Settings.ControllerEnabled[controller] = false; +// } + } + NWPluginCall(NWPlugin::Function::NWPLUGIN_INIT_ALL, 0); +} diff --git a/src/src/Helpers/_NWPlugin_init.h b/src/src/Helpers/_NWPlugin_init.h new file mode 100644 index 000000000..0c6918843 --- /dev/null +++ b/src/src/Helpers/_NWPlugin_init.h @@ -0,0 +1,1062 @@ +#ifndef HELPERS__NWPLUGIN_INIT_H +#define HELPERS__NWPLUGIN_INIT_H + +#include "../../ESPEasy_common.h" + +#include "../DataTypes/ESPEasy_plugin_functions.h" + +#include "../DataTypes/NWPluginID.h" +#include "../DataTypes/NetworkAdapterIndex.h" +#include "../DataStructs/NetworkAdapterStruct.h" + +struct EventStruct; + +networkAdapterIndex_t getNetworkAdapterIndex_from_NWPluginID_(nwpluginID_t pluginID); +nwpluginID_t getNWPluginID_from_NetworkAdapterIndex_(networkAdapterIndex_t networkAdapterIndex); +bool validNetworkAdapterIndex_init(networkAdapterIndex_t networkAdapterIndex); + +nwpluginID_t getHighestIncludedNWPluginID(); + +NetworkAdapterStruct& getNetworkAdapterStruct(networkAdapterIndex_t networkAdapterIndex); + +bool NWPluginCall(networkAdapterIndex_t networkAdapterIndex, NWPlugin::Function Function, struct EventStruct *event, String& string); + + +void NWPluginSetup(); +void NWPluginInit(); + +// Macro to forward declare the NWPlugin_NNN functions. +// N.B. Some controllers also have a do_process_cNNN_delay_queue function. +// Forward declaration of these is done in ControllerQueue/ControllerDelayHandlerStruct.h +// +// Uncrustify must not be used on macros, so turn it off. +// *INDENT-OFF* +#define ADDNWPLUGIN_H(NNN) bool NWPlugin_##NNN(NWPlugin::Function function, struct EventStruct *event, String& string); +// Uncrustify must not be used on macros, but we're now done, so turn Uncrustify on again. +// *INDENT-ON* + + +#ifdef USES_NW001 + ADDNWPLUGIN_H(001) +#endif + +#ifdef USES_NW002 + ADDNWPLUGIN_H(002) +#endif + +#ifdef USES_NW003 + ADDNWPLUGIN_H(003) +#endif + +#ifdef USES_NW004 + ADDNWPLUGIN_H(004) +#endif + +#ifdef USES_NW005 + ADDNWPLUGIN_H(005) +#endif + +#ifdef USES_NW006 + ADDNWPLUGIN_H(006) +#endif + +#ifdef USES_NW007 + ADDNWPLUGIN_H(007) +#endif + +#ifdef USES_NW008 + ADDNWPLUGIN_H(008) +#endif + +#ifdef USES_NW009 + ADDNWPLUGIN_H(009) +#endif + +#ifdef USES_NW010 + ADDNWPLUGIN_H(010) +#endif + +#ifdef USES_NW011 + ADDNWPLUGIN_H(011) +#endif + +#ifdef USES_NW012 + ADDNWPLUGIN_H(012) +#endif + +#ifdef USES_NW013 + ADDNWPLUGIN_H(013) +#endif + +#ifdef USES_NW014 + ADDNWPLUGIN_H(014) +#endif + +#ifdef USES_NW015 + ADDNWPLUGIN_H(015) +#endif + +#ifdef USES_NW016 + ADDNWPLUGIN_H(016) +#endif + +#ifdef USES_NW017 + ADDNWPLUGIN_H(017) +#endif + +#ifdef USES_NW018 + ADDNWPLUGIN_H(018) +#endif + +#ifdef USES_NW019 + ADDNWPLUGIN_H(019) +#endif + +#ifdef USES_NW020 + ADDNWPLUGIN_H(020) +#endif + +#ifdef USES_NW021 + ADDNWPLUGIN_H(021) +#endif + +#ifdef USES_NW022 + ADDNWPLUGIN_H(022) +#endif + +#ifdef USES_NW023 + ADDNWPLUGIN_H(023) +#endif + +#ifdef USES_NW024 + ADDNWPLUGIN_H(024) +#endif + +#ifdef USES_NW025 + ADDNWPLUGIN_H(025) +#endif + +#ifdef USES_NW026 + ADDNWPLUGIN_H(026) +#endif + +#ifdef USES_NW027 + ADDNWPLUGIN_H(027) +#endif + +#ifdef USES_NW028 + ADDNWPLUGIN_H(028) +#endif + +#ifdef USES_NW029 + ADDNWPLUGIN_H(029) +#endif + +#ifdef USES_NW030 + ADDNWPLUGIN_H(030) +#endif + +#ifdef USES_NW031 + ADDNWPLUGIN_H(031) +#endif + +#ifdef USES_NW032 + ADDNWPLUGIN_H(032) +#endif + +#ifdef USES_NW033 + ADDNWPLUGIN_H(033) +#endif + +#ifdef USES_NW034 + ADDNWPLUGIN_H(034) +#endif + +#ifdef USES_NW035 + ADDNWPLUGIN_H(035) +#endif + +#ifdef USES_NW036 + ADDNWPLUGIN_H(036) +#endif + +#ifdef USES_NW037 + ADDNWPLUGIN_H(037) +#endif + +#ifdef USES_NW038 + ADDNWPLUGIN_H(038) +#endif + +#ifdef USES_NW039 + ADDNWPLUGIN_H(039) +#endif + +#ifdef USES_NW040 + ADDNWPLUGIN_H(040) +#endif + +#ifdef USES_NW041 + ADDNWPLUGIN_H(041) +#endif + +#ifdef USES_NW042 + ADDNWPLUGIN_H(042) +#endif + +#ifdef USES_NW043 + ADDNWPLUGIN_H(043) +#endif + +#ifdef USES_NW044 + ADDNWPLUGIN_H(044) +#endif + +#ifdef USES_NW045 + ADDNWPLUGIN_H(045) +#endif + +#ifdef USES_NW046 + ADDNWPLUGIN_H(046) +#endif + +#ifdef USES_NW047 + ADDNWPLUGIN_H(047) +#endif + +#ifdef USES_NW048 + ADDNWPLUGIN_H(048) +#endif + +#ifdef USES_NW049 + ADDNWPLUGIN_H(049) +#endif + +#ifdef USES_NW050 + ADDNWPLUGIN_H(050) +#endif + +#ifdef USES_NW051 + ADDNWPLUGIN_H(051) +#endif + +#ifdef USES_NW052 + ADDNWPLUGIN_H(052) +#endif + +#ifdef USES_NW053 + ADDNWPLUGIN_H(053) +#endif + +#ifdef USES_NW054 + ADDNWPLUGIN_H(054) +#endif + +#ifdef USES_NW055 + ADDNWPLUGIN_H(055) +#endif + +#ifdef USES_NW056 + ADDNWPLUGIN_H(056) +#endif + +#ifdef USES_NW057 + ADDNWPLUGIN_H(057) +#endif + +#ifdef USES_NW058 + ADDNWPLUGIN_H(058) +#endif + +#ifdef USES_NW059 + ADDNWPLUGIN_H(059) +#endif + +#ifdef USES_NW060 + ADDNWPLUGIN_H(060) +#endif + +#ifdef USES_NW061 + ADDNWPLUGIN_H(061) +#endif + +#ifdef USES_NW062 + ADDNWPLUGIN_H(062) +#endif + +#ifdef USES_NW063 + ADDNWPLUGIN_H(063) +#endif + +#ifdef USES_NW064 + ADDNWPLUGIN_H(064) +#endif + +#ifdef USES_NW065 + ADDNWPLUGIN_H(065) +#endif + +#ifdef USES_NW066 + ADDNWPLUGIN_H(066) +#endif + +#ifdef USES_NW067 + ADDNWPLUGIN_H(067) +#endif + +#ifdef USES_NW068 + ADDNWPLUGIN_H(068) +#endif + +#ifdef USES_NW069 + ADDNWPLUGIN_H(069) +#endif + +#ifdef USES_NW070 + ADDNWPLUGIN_H(070) +#endif + +#ifdef USES_NW071 + ADDNWPLUGIN_H(071) +#endif + +#ifdef USES_NW072 + ADDNWPLUGIN_H(072) +#endif + +#ifdef USES_NW073 + ADDNWPLUGIN_H(073) +#endif + +#ifdef USES_NW074 + ADDNWPLUGIN_H(074) +#endif + +#ifdef USES_NW075 + ADDNWPLUGIN_H(075) +#endif + +#ifdef USES_NW076 + ADDNWPLUGIN_H(076) +#endif + +#ifdef USES_NW077 + ADDNWPLUGIN_H(077) +#endif + +#ifdef USES_NW078 + ADDNWPLUGIN_H(078) +#endif + +#ifdef USES_NW079 + ADDNWPLUGIN_H(079) +#endif + +#ifdef USES_NW080 + ADDNWPLUGIN_H(080) +#endif + +#ifdef USES_NW081 + ADDNWPLUGIN_H(081) +#endif + +#ifdef USES_NW082 + ADDNWPLUGIN_H(082) +#endif + +#ifdef USES_NW083 + ADDNWPLUGIN_H(083) +#endif + +#ifdef USES_NW084 + ADDNWPLUGIN_H(084) +#endif + +#ifdef USES_NW085 + ADDNWPLUGIN_H(085) +#endif + +#ifdef USES_NW086 + ADDNWPLUGIN_H(086) +#endif + +#ifdef USES_NW087 + ADDNWPLUGIN_H(087) +#endif + +#ifdef USES_NW088 + ADDNWPLUGIN_H(088) +#endif + +#ifdef USES_NW089 + ADDNWPLUGIN_H(089) +#endif + +#ifdef USES_NW090 + ADDNWPLUGIN_H(090) +#endif + +#ifdef USES_NW091 + ADDNWPLUGIN_H(091) +#endif + +#ifdef USES_NW092 + ADDNWPLUGIN_H(092) +#endif + +#ifdef USES_NW093 + ADDNWPLUGIN_H(093) +#endif + +#ifdef USES_NW094 + ADDNWPLUGIN_H(094) +#endif + +#ifdef USES_NW095 + ADDNWPLUGIN_H(095) +#endif + +#ifdef USES_NW096 + ADDNWPLUGIN_H(096) +#endif + +#ifdef USES_NW097 + ADDNWPLUGIN_H(097) +#endif + +#ifdef USES_NW098 + ADDNWPLUGIN_H(098) +#endif + +#ifdef USES_NW099 + ADDNWPLUGIN_H(099) +#endif + +#ifdef USES_NW100 + ADDNWPLUGIN_H(100) +#endif + +#ifdef USES_NW101 + ADDNWPLUGIN_H(101) +#endif + +#ifdef USES_NW102 + ADDNWPLUGIN_H(102) +#endif + +#ifdef USES_NW103 + ADDNWPLUGIN_H(103) +#endif + +#ifdef USES_NW104 + ADDNWPLUGIN_H(104) +#endif + +#ifdef USES_NW105 + ADDNWPLUGIN_H(105) +#endif + +#ifdef USES_NW106 + ADDNWPLUGIN_H(106) +#endif + +#ifdef USES_NW107 + ADDNWPLUGIN_H(107) +#endif + +#ifdef USES_NW108 + ADDNWPLUGIN_H(108) +#endif + +#ifdef USES_NW109 + ADDNWPLUGIN_H(109) +#endif + +#ifdef USES_NW110 + ADDNWPLUGIN_H(110) +#endif + +#ifdef USES_NW111 + ADDNWPLUGIN_H(111) +#endif + +#ifdef USES_NW112 + ADDNWPLUGIN_H(112) +#endif + +#ifdef USES_NW113 + ADDNWPLUGIN_H(113) +#endif + +#ifdef USES_NW114 + ADDNWPLUGIN_H(114) +#endif + +#ifdef USES_NW115 + ADDNWPLUGIN_H(115) +#endif + +#ifdef USES_NW116 + ADDNWPLUGIN_H(116) +#endif + +#ifdef USES_NW117 + ADDNWPLUGIN_H(117) +#endif + +#ifdef USES_NW118 + ADDNWPLUGIN_H(118) +#endif + +#ifdef USES_NW119 + ADDNWPLUGIN_H(119) +#endif + +#ifdef USES_NW120 + ADDNWPLUGIN_H(120) +#endif + +#ifdef USES_NW121 + ADDNWPLUGIN_H(121) +#endif + +#ifdef USES_NW122 + ADDNWPLUGIN_H(122) +#endif + +#ifdef USES_NW123 + ADDNWPLUGIN_H(123) +#endif + +#ifdef USES_NW124 + ADDNWPLUGIN_H(124) +#endif + +#ifdef USES_NW125 + ADDNWPLUGIN_H(125) +#endif + +#ifdef USES_NW126 + ADDNWPLUGIN_H(126) +#endif + +#ifdef USES_NW127 + ADDNWPLUGIN_H(127) +#endif + +#ifdef USES_NW128 + ADDNWPLUGIN_H(128) +#endif + +#ifdef USES_NW129 + ADDNWPLUGIN_H(129) +#endif + +#ifdef USES_NW130 + ADDNWPLUGIN_H(130) +#endif + +#ifdef USES_NW131 + ADDNWPLUGIN_H(131) +#endif + +#ifdef USES_NW132 + ADDNWPLUGIN_H(132) +#endif + +#ifdef USES_NW133 + ADDNWPLUGIN_H(133) +#endif + +#ifdef USES_NW134 + ADDNWPLUGIN_H(134) +#endif + +#ifdef USES_NW135 + ADDNWPLUGIN_H(135) +#endif + +#ifdef USES_NW136 + ADDNWPLUGIN_H(136) +#endif + +#ifdef USES_NW137 + ADDNWPLUGIN_H(137) +#endif + +#ifdef USES_NW138 + ADDNWPLUGIN_H(138) +#endif + +#ifdef USES_NW139 + ADDNWPLUGIN_H(139) +#endif + +#ifdef USES_NW140 + ADDNWPLUGIN_H(140) +#endif + +#ifdef USES_NW141 + ADDNWPLUGIN_H(141) +#endif + +#ifdef USES_NW142 + ADDNWPLUGIN_H(142) +#endif + +#ifdef USES_NW143 + ADDNWPLUGIN_H(143) +#endif + +#ifdef USES_NW144 + ADDNWPLUGIN_H(144) +#endif + +#ifdef USES_NW145 + ADDNWPLUGIN_H(145) +#endif + +#ifdef USES_NW146 + ADDNWPLUGIN_H(146) +#endif + +#ifdef USES_NW147 + ADDNWPLUGIN_H(147) +#endif + +#ifdef USES_NW148 + ADDNWPLUGIN_H(148) +#endif + +#ifdef USES_NW149 + ADDNWPLUGIN_H(149) +#endif + +#ifdef USES_NW150 + ADDNWPLUGIN_H(150) +#endif + +#ifdef USES_NW151 + ADDNWPLUGIN_H(151) +#endif + +#ifdef USES_NW152 + ADDNWPLUGIN_H(152) +#endif + +#ifdef USES_NW153 + ADDNWPLUGIN_H(153) +#endif + +#ifdef USES_NW154 + ADDNWPLUGIN_H(154) +#endif + +#ifdef USES_NW155 + ADDNWPLUGIN_H(155) +#endif + +#ifdef USES_NW156 + ADDNWPLUGIN_H(156) +#endif + +#ifdef USES_NW157 + ADDNWPLUGIN_H(157) +#endif + +#ifdef USES_NW158 + ADDNWPLUGIN_H(158) +#endif + +#ifdef USES_NW159 + ADDNWPLUGIN_H(159) +#endif + +#ifdef USES_NW160 + ADDNWPLUGIN_H(160) +#endif + +#ifdef USES_NW161 + ADDNWPLUGIN_H(161) +#endif + +#ifdef USES_NW162 + ADDNWPLUGIN_H(162) +#endif + +#ifdef USES_NW163 + ADDNWPLUGIN_H(163) +#endif + +#ifdef USES_NW164 + ADDNWPLUGIN_H(164) +#endif + +#ifdef USES_NW165 + ADDNWPLUGIN_H(165) +#endif + +#ifdef USES_NW166 + ADDNWPLUGIN_H(166) +#endif + +#ifdef USES_NW167 + ADDNWPLUGIN_H(167) +#endif + +#ifdef USES_NW168 + ADDNWPLUGIN_H(168) +#endif + +#ifdef USES_NW169 + ADDNWPLUGIN_H(169) +#endif + +#ifdef USES_NW170 + ADDNWPLUGIN_H(170) +#endif + +#ifdef USES_NW171 + ADDNWPLUGIN_H(171) +#endif + +#ifdef USES_NW172 + ADDNWPLUGIN_H(172) +#endif + +#ifdef USES_NW173 + ADDNWPLUGIN_H(173) +#endif + +#ifdef USES_NW174 + ADDNWPLUGIN_H(174) +#endif + +#ifdef USES_NW175 + ADDNWPLUGIN_H(175) +#endif + +#ifdef USES_NW176 + ADDNWPLUGIN_H(176) +#endif + +#ifdef USES_NW177 + ADDNWPLUGIN_H(177) +#endif + +#ifdef USES_NW178 + ADDNWPLUGIN_H(178) +#endif + +#ifdef USES_NW179 + ADDNWPLUGIN_H(179) +#endif + +#ifdef USES_NW180 + ADDNWPLUGIN_H(180) +#endif + +#ifdef USES_NW181 + ADDNWPLUGIN_H(181) +#endif + +#ifdef USES_NW182 + ADDNWPLUGIN_H(182) +#endif + +#ifdef USES_NW183 + ADDNWPLUGIN_H(183) +#endif + +#ifdef USES_NW184 + ADDNWPLUGIN_H(184) +#endif + +#ifdef USES_NW185 + ADDNWPLUGIN_H(185) +#endif + +#ifdef USES_NW186 + ADDNWPLUGIN_H(186) +#endif + +#ifdef USES_NW187 + ADDNWPLUGIN_H(187) +#endif + +#ifdef USES_NW188 + ADDNWPLUGIN_H(188) +#endif + +#ifdef USES_NW189 + ADDNWPLUGIN_H(189) +#endif + +#ifdef USES_NW190 + ADDNWPLUGIN_H(190) +#endif + +#ifdef USES_NW191 + ADDNWPLUGIN_H(191) +#endif + +#ifdef USES_NW192 + ADDNWPLUGIN_H(192) +#endif + +#ifdef USES_NW193 + ADDNWPLUGIN_H(193) +#endif + +#ifdef USES_NW194 + ADDNWPLUGIN_H(194) +#endif + +#ifdef USES_NW195 + ADDNWPLUGIN_H(195) +#endif + +#ifdef USES_NW196 + ADDNWPLUGIN_H(196) +#endif + +#ifdef USES_NW197 + ADDNWPLUGIN_H(197) +#endif + +#ifdef USES_NW198 + ADDNWPLUGIN_H(198) +#endif + +#ifdef USES_NW199 + ADDNWPLUGIN_H(199) +#endif + +#ifdef USES_NW200 + ADDNWPLUGIN_H(200) +#endif + +#ifdef USES_NW201 + ADDNWPLUGIN_H(201) +#endif + +#ifdef USES_NW202 + ADDNWPLUGIN_H(202) +#endif + +#ifdef USES_NW203 + ADDNWPLUGIN_H(203) +#endif + +#ifdef USES_NW204 + ADDNWPLUGIN_H(204) +#endif + +#ifdef USES_NW205 + ADDNWPLUGIN_H(205) +#endif + +#ifdef USES_NW206 + ADDNWPLUGIN_H(206) +#endif + +#ifdef USES_NW207 + ADDNWPLUGIN_H(207) +#endif + +#ifdef USES_NW208 + ADDNWPLUGIN_H(208) +#endif + +#ifdef USES_NW209 + ADDNWPLUGIN_H(209) +#endif + +#ifdef USES_NW210 + ADDNWPLUGIN_H(210) +#endif + +#ifdef USES_NW211 + ADDNWPLUGIN_H(211) +#endif + +#ifdef USES_NW212 + ADDNWPLUGIN_H(212) +#endif + +#ifdef USES_NW213 + ADDNWPLUGIN_H(213) +#endif + +#ifdef USES_NW214 + ADDNWPLUGIN_H(214) +#endif + +#ifdef USES_NW215 + ADDNWPLUGIN_H(215) +#endif + +#ifdef USES_NW216 + ADDNWPLUGIN_H(216) +#endif + +#ifdef USES_NW217 + ADDNWPLUGIN_H(217) +#endif + +#ifdef USES_NW218 + ADDNWPLUGIN_H(218) +#endif + +#ifdef USES_NW219 + ADDNWPLUGIN_H(219) +#endif + +#ifdef USES_NW220 + ADDNWPLUGIN_H(220) +#endif + +#ifdef USES_NW221 + ADDNWPLUGIN_H(221) +#endif + +#ifdef USES_NW222 + ADDNWPLUGIN_H(222) +#endif + +#ifdef USES_NW223 + ADDNWPLUGIN_H(223) +#endif + +#ifdef USES_NW224 + ADDNWPLUGIN_H(224) +#endif + +#ifdef USES_NW225 + ADDNWPLUGIN_H(225) +#endif + +#ifdef USES_NW226 + ADDNWPLUGIN_H(226) +#endif + +#ifdef USES_NW227 + ADDNWPLUGIN_H(227) +#endif + +#ifdef USES_NW228 + ADDNWPLUGIN_H(228) +#endif + +#ifdef USES_NW229 + ADDNWPLUGIN_H(229) +#endif + +#ifdef USES_NW230 + ADDNWPLUGIN_H(230) +#endif + +#ifdef USES_NW231 + ADDNWPLUGIN_H(231) +#endif + +#ifdef USES_NW232 + ADDNWPLUGIN_H(232) +#endif + +#ifdef USES_NW233 + ADDNWPLUGIN_H(233) +#endif + +#ifdef USES_NW234 + ADDNWPLUGIN_H(234) +#endif + +#ifdef USES_NW235 + ADDNWPLUGIN_H(235) +#endif + +#ifdef USES_NW236 + ADDNWPLUGIN_H(236) +#endif + +#ifdef USES_NW237 + ADDNWPLUGIN_H(237) +#endif + +#ifdef USES_NW238 + ADDNWPLUGIN_H(238) +#endif + +#ifdef USES_NW239 + ADDNWPLUGIN_H(239) +#endif + +#ifdef USES_NW240 + ADDNWPLUGIN_H(240) +#endif + +#ifdef USES_NW241 + ADDNWPLUGIN_H(241) +#endif + +#ifdef USES_NW242 + ADDNWPLUGIN_H(242) +#endif + +#ifdef USES_NW243 + ADDNWPLUGIN_H(243) +#endif + +#ifdef USES_NW244 + ADDNWPLUGIN_H(244) +#endif + +#ifdef USES_NW245 + ADDNWPLUGIN_H(245) +#endif + +#ifdef USES_NW246 + ADDNWPLUGIN_H(246) +#endif + +#ifdef USES_NW247 + ADDNWPLUGIN_H(247) +#endif + +#ifdef USES_NW248 + ADDNWPLUGIN_H(248) +#endif + +#ifdef USES_NW249 + ADDNWPLUGIN_H(249) +#endif + +#ifdef USES_NW250 + ADDNWPLUGIN_H(250) +#endif + +#ifdef USES_NW251 + ADDNWPLUGIN_H(251) +#endif + +#ifdef USES_NW252 + ADDNWPLUGIN_H(252) +#endif + +#ifdef USES_NW253 + ADDNWPLUGIN_H(253) +#endif + +#ifdef USES_NW254 + ADDNWPLUGIN_H(254) +#endif + +#ifdef USES_NW255 + ADDNWPLUGIN_H(255) +#endif + +#undef ADDNWPLUGIN_H + + +#endif \ No newline at end of file diff --git a/src/src/WebServer/ESPEasy_WebServer.cpp b/src/src/WebServer/ESPEasy_WebServer.cpp index 9cb7c6917..c14a4642e 100644 --- a/src/src/WebServer/ESPEasy_WebServer.cpp +++ b/src/src/WebServer/ESPEasy_WebServer.cpp @@ -23,6 +23,7 @@ #include "../WebServer/Markup.h" #include "../WebServer/Markup_Buttons.h" #include "../WebServer/Markup_Forms.h" +#include "../WebServer/NetworkPage.h" #include "../WebServer/NotificationPage.h" #include "../WebServer/PinStates.h" #include "../WebServer/RootPage.h" @@ -225,6 +226,9 @@ void WebServerInit() #ifdef WEBSERVER_CONFIG web_server.on(F("/config"), handle_config); #endif // ifdef WEBSERVER_CONFIG + #ifdef WEBSERVER_NETWORK + web_server.on(F("/network"), handle_networks); + #endif // ifdef WEBSERVER_NETWORK #ifdef WEBSERVER_CONTROL web_server.on(F("/control"), handle_control); #endif // ifdef WEBSERVER_CONTROL diff --git a/src/src/WebServer/NetworkPage.cpp b/src/src/WebServer/NetworkPage.cpp new file mode 100644 index 000000000..e9bea1f61 --- /dev/null +++ b/src/src/WebServer/NetworkPage.cpp @@ -0,0 +1,75 @@ +#include "../WebServer/NetworkPage.h" + +#ifdef WEBSERVER_NETWORK + +# include "../WebServer/ESPEasy_WebServer.h" +# include "../WebServer/HTML_wrappers.h" +# include "../WebServer/Markup.h" +# include "../WebServer/Markup_Buttons.h" +# include "../WebServer/Markup_Forms.h" + +void handle_networks() +{ +# ifndef BUILD_NO_RAM_TRACKER + checkRAM(F("handle_networks")); +# endif // ifndef BUILD_NO_RAM_TRACKER + + if (!isLoggedIn()) { return; } + navMenuIndex = MENU_INDEX_NETWORK; + TXBuffer.startStream(); + sendHeadandTail_stdtemplate(_HEAD); + + // 'index' value in the URL + uint8_t networkindex = getFormItemInt(F("index"), 0); + boolean networkNotSet = networkindex == 0; + --networkindex; // Index in URL is starting from 1, but starting from 0 in the array. + + const int protocol_webarg_value = getFormItemInt(F("protocol"), -1); + + // submitted data + if ((protocol_webarg_value != -1) && !networkNotSet) + { + // TODO TD-er: Implement saving submitted settings + + + } + + html_add_form(); + + if (networkNotSet) + { + handle_networks_ShowAllNetworksTable(); + } + else + { + //handle_networks_NetworkSettingsPage(networkindex); + } + + sendHeadandTail_stdtemplate(_TAIL); + TXBuffer.endStream(); +} + + +/* +void handle_networks_clearLoadDefaults(uint8_t networkindex, NetworkSettingsStruct& NetworkSettings) +{} +*/ + +/* +void handle_networks_CopySubmittedSettings(uint8_t networkindex, NetworkSettingsStruct& NetworkSettings) +{} +*/ + +void handle_networks_CopySubmittedSettings_CPluginCall(uint8_t networkindex) +{} + +void handle_networks_ShowAllNetworksTable() +{} + + +void handle_networks_NetworkSettingsPage(networkIndex_t networkindex) +{} + + + +#endif // ifdef WEBSERVER_NETWORK diff --git a/src/src/WebServer/NetworkPage.h b/src/src/WebServer/NetworkPage.h new file mode 100644 index 000000000..9910687f4 --- /dev/null +++ b/src/src/WebServer/NetworkPage.h @@ -0,0 +1,40 @@ +#ifndef WEBSERVER_WEBSERVER_NETWORKPAGE_H +#define WEBSERVER_WEBSERVER_NETWORKPAGE_H + +#include "../WebServer/common.h" + +#ifdef WEBSERVER_NETWORK + +#include "../DataTypes/NetworkIndex.h" + +// ******************************************************************************** +// Web Interface Network page +// ******************************************************************************** +void handle_networks(); + +// ******************************************************************************** +// Selected network has changed. +// Clear all Network settings and load some defaults +// ******************************************************************************** +//void handle_networks_clearLoadDefaults(uint8_t networkindex, NetworkSettingsStruct& NetworkSettings); + +// ******************************************************************************** +// Collect all submitted form data and store in the NetworkSettings +// ******************************************************************************** +//void handle_networks_CopySubmittedSettings(uint8_t networkindex, NetworkSettingsStruct& NetworkSettings); + +void handle_networks_CopySubmittedSettings_CPluginCall(uint8_t networkindex); + +// ******************************************************************************** +// Show table with all selected networks +// ******************************************************************************** +void handle_networks_ShowAllNetworksTable(); + +// ******************************************************************************** +// Show the network settings page +// ******************************************************************************** +void handle_networks_NetworkSettingsPage(networkIndex_t networkindex); + + +#endif +#endif diff --git a/src/src/WebServer/WebTemplateParser.cpp b/src/src/WebServer/WebTemplateParser.cpp index afa20831d..5a0ae54d9 100644 --- a/src/src/WebServer/WebTemplateParser.cpp +++ b/src/src/WebServer/WebTemplateParser.cpp @@ -30,6 +30,15 @@ #endif #endif // ifndef MENU_INDEX_CONFIG_VISIBLE +#ifndef MENU_INDEX_NETWORK_VISIBLE +#ifdef WEBSERVER_NETWORK + # define MENU_INDEX_NETWORK_VISIBLE true +#else + # define MENU_INDEX_NETWORK_VISIBLE false +#endif +#endif // ifndef MENU_INDEX_NETWORK_VISIBLE + + #ifndef MENU_INDEX_CONTROLLERS_VISIBLE #ifdef WEBSERVER_CONTROLLERS # define MENU_INDEX_CONTROLLERS_VISIBLE true @@ -92,6 +101,7 @@ const __FlashStringHelper* getGpMenuIcon(uint8_t index) { switch (index) { case MENU_INDEX_MAIN: return F("⌂"); case MENU_INDEX_CONFIG: return F("⚙"); + case MENU_INDEX_NETWORK: return F("🖧"); case MENU_INDEX_CONTROLLERS: return F("💬"); case MENU_INDEX_HARDWARE: return F("📌"); case MENU_INDEX_DEVICES: return F("🔌"); @@ -106,6 +116,7 @@ const __FlashStringHelper* getGpMenuLabel(uint8_t index) { switch (index) { case MENU_INDEX_MAIN: return F("Main"); case MENU_INDEX_CONFIG: return F("Config"); + case MENU_INDEX_NETWORK: return F("Network"); case MENU_INDEX_CONTROLLERS: return F("Controllers"); case MENU_INDEX_HARDWARE: return F("Hardware"); case MENU_INDEX_DEVICES: return F("Devices"); @@ -120,6 +131,7 @@ const __FlashStringHelper* getGpMenuURL(uint8_t index) { switch (index) { case MENU_INDEX_MAIN: return F("/"); case MENU_INDEX_CONFIG: return F("/config"); + case MENU_INDEX_NETWORK: return F("/network"); case MENU_INDEX_CONTROLLERS: return F("/controllers"); case MENU_INDEX_HARDWARE: return F("/hardware"); case MENU_INDEX_DEVICES: return F("/devices"); @@ -134,6 +146,7 @@ bool GpMenuVisible(uint8_t index) { switch (index) { case MENU_INDEX_MAIN: return MENU_INDEX_MAIN_VISIBLE; case MENU_INDEX_CONFIG: return MENU_INDEX_CONFIG_VISIBLE; + case MENU_INDEX_NETWORK: return MENU_INDEX_NETWORK_VISIBLE; case MENU_INDEX_CONTROLLERS: return MENU_INDEX_CONTROLLERS_VISIBLE; case MENU_INDEX_HARDWARE: return MENU_INDEX_HARDWARE_VISIBLE; case MENU_INDEX_DEVICES: return MENU_INDEX_DEVICES_VISIBLE; @@ -390,7 +403,7 @@ void WebTemplateParser::getWebPageTemplateVar(const String& varName) { addHtml(F("