diff --git a/cores/esp8266/core_esp8266_features.h b/cores/esp8266/core_esp8266_features.h index 5dea897bc..3eba0ac7d 100644 --- a/cores/esp8266/core_esp8266_features.h +++ b/cores/esp8266/core_esp8266_features.h @@ -31,6 +31,7 @@ #define CORE_HAS_UMM #define WIFI_HAS_EVENT_CALLBACK +#define WIFI_IS_OFF_AT_BOOT #include // malloc() #include // size_t @@ -104,6 +105,8 @@ uint64_t micros64(void); void delay(unsigned long); void delayMicroseconds(unsigned int us); +void enableWiFiAtBootTime (void) __attribute__((noinline)); + #if defined(F_CPU) || defined(CORE_MOCK) #ifdef __cplusplus constexpr diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 1fa132247..f25cd296e 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -332,7 +332,18 @@ extern "C" void app_entry (void) extern "C" void preinit (void) __attribute__((weak)); extern "C" void preinit (void) { - /* do nothing by default */ + /* does nothing, kept for backward compatibility */ +} + +extern "C" void __disableWiFiAtBootTime (void) __attribute__((weak)); +extern "C" void __disableWiFiAtBootTime (void) +{ + // Starting from arduino core v3: wifi is disabled at boot time + // WiFi.begin() or WiFi.softAP() will wake WiFi up + wifi_set_opmode_current(0/*WIFI_OFF*/); + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); } extern "C" void user_init(void) { @@ -365,6 +376,7 @@ extern "C" void user_init(void) { umm_init_iram(); #endif preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable. + __disableWiFiAtBootTime(); // default weak function disables WiFi ets_task(loop_task, LOOP_TASK_PRIORITY, s_loop_queue, diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index 7186662f0..b9c771df7 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -18,6 +18,7 @@ void esp_schedule(); void tune_timeshift64 (uint64_t now_us); void disable_extra4k_at_link_time (void) __attribute__((noinline)); bool sntp_set_timezone_in_seconds(int32_t timezone); +void __disableWiFiAtBootTime (void) __attribute__((noinline)); void __real_system_restart_local() __attribute__((noreturn)); uint32_t sqrt32 (uint32_t n); @@ -34,6 +35,6 @@ using TrivialCB = std::function; void settimeofday_cb (const BoolCB& cb); void settimeofday_cb (const TrivialCB& cb); -#endif +#endif // __cplusplus #endif // __COREDECLS_H diff --git a/doc/esp8266wifi/generic-class.rst b/doc/esp8266wifi/generic-class.rst index c75ae231f..bf6228d4e 100644 --- a/doc/esp8266wifi/generic-class.rst +++ b/doc/esp8266wifi/generic-class.rst @@ -42,6 +42,33 @@ persistent WiFi.persistent(persistent) +Starting from version 3 of this core, **persistence is disabled by default +and WiFi does not start automatically at boot** (see PR `#7902 `__). + +Previously, SDK was automatically starting WiFi at boot. This was probably +intended for the Espressif AT FW which is interactive and preserves WiFi +state accross reboots. This behavior is generally irrelevant with the +Arduino API because sketches start with ``WiFi.begin()`` or +``WiFi.softAP()``. + +This change is harmless with standard sketches: Calls to ``WiFi.mode()`` do +enable radio as usual. It also smooths current spikes at boot and decreases +DHCP stress. + +Legacy behavior can be restored by calling ``enableWiFiAtBootTime()`` from +anywhere in the code (it is a weak void function intended to play with the +linker). + +.. code:: cpp + + void setup () { + #ifdef WIFI_IS_OFF_AT_BOOT + enableWiFiAtBootTime(); // can be called from anywhere with the same effect + #endif + .... + } + +When legacy behavior is restored thanks to this call, ESP8266 is able to reconnect to the last used WiFi network or establishes the same Access Point upon power up or reset. By default, these settings are written to specific sectors of flash memory every time they are changed in ``WiFi.begin(ssid, passphrase)`` or ``WiFi.softAP(ssid, passphrase, channel)``, and when ``WiFi.disconnect`` or ``WiFi.softAPdisconnect`` is invoked. Frequently calling these functions could cause wear on the flash memory (see issue `#1054 `__). diff --git a/doc/esp8266wifi/readme.rst b/doc/esp8266wifi/readme.rst index a2fdea701..b9d309d5f 100644 --- a/doc/esp8266wifi/readme.rst +++ b/doc/esp8266wifi/readme.rst @@ -164,6 +164,7 @@ WiFi Multi Example: .. code:: cpp + #include ESP8266WiFiMulti wifiMulti; diff --git a/doc/faq/a01-espcomm_sync-failed.rst b/doc/faq/a01-espcomm_sync-failed.rst index a0d575e8e..df4d0aa17 100644 --- a/doc/faq/a01-espcomm_sync-failed.rst +++ b/doc/faq/a01-espcomm_sync-failed.rst @@ -41,9 +41,8 @@ following three things right: 1. Module is provided with enough power, 2. GPIO0, GPIO15 and CH\_PD are connected using pull up / pull down resistors, 3. Module is put into boot loader mode. -For specific details please refer to section on `Generic ESP8266 -modules <../boards.rst#generic-esp8266-modules>`__. Example modules -without USB to serial converter on board are shown below. +For specific details please refer to section on `Generic ESP8266 module <../boards.rst#generic-esp8266-module>`__. +Example modules without USB to serial converter on board are shown below. .. figure:: pictures/a01-example-boards-without-usb.png :alt: Example ESP8266 modules without USB to serial converter diff --git a/doc/faq/a04-board-generic-is-unknown.rst b/doc/faq/a04-board-generic-is-unknown.rst index b33f75edb..88e2f3e7b 100644 --- a/doc/faq/a04-board-generic-is-unknown.rst +++ b/doc/faq/a04-board-generic-is-unknown.rst @@ -48,7 +48,7 @@ follows: Error compiling for board Generic ESP8266 Module. Below is an example messages for -`WeMos <../boards.rst#wemos-d1-r2-mini>`__: +`WeMos <../boards.rst#lolin-wemos-d1-r2-mini>`__: :: diff --git a/doc/faq/readme.rst b/doc/faq/readme.rst index 74e221196..4fb065a38 100644 --- a/doc/faq/readme.rst +++ b/doc/faq/readme.rst @@ -177,3 +177,12 @@ will need to implement an additional (short) deep sleep using ``WAKE_RF_DEFAULT``. Ref. `#3072 `__ + +My WiFi was previously automatically connected right after booting, but isn't anymore +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This was WiFi persistence. Starting from version 3 of this core, WiFi is +indeed off at boot and is powered on only when starting to be used with the +regular API. + +Read more at `former WiFi persistent mode <../esp8266wifi/generic-class.rst#persistent>`__. diff --git a/doc/filesystem.rst b/doc/filesystem.rst index a5a3cffbb..cc6c51280 100644 --- a/doc/filesystem.rst +++ b/doc/filesystem.rst @@ -474,8 +474,8 @@ Performs the same operation as ``info`` but allows for reporting greater than 4GB for filesystem size/used/etc. Should be used with the SD and SDFS filesystems since most SD cards today are greater than 4GB in size. -setTimeCallback(time_t (*cb)(void)) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +setTimeCallback(time_t (\*cb)(void)) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code:: cpp @@ -574,8 +574,8 @@ rewind Resets the internal pointer to the start of the directory. -setTimeCallback(time_t (*cb)(void)) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +setTimeCallback(time_t (\*cb)(void)) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the time callback for any files accessed from this Dir object via openNextFile. Note that the SD and SDFS filesystems only support a filesystem-wide callback and @@ -693,7 +693,7 @@ Close the file. No other operations should be performed on *File* object after ``close`` function was called. openNextFile (compatibiity method, not recommended for new code) -~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code:: cpp @@ -705,7 +705,7 @@ Opens the next file in the directory pointed to by the File. Only valid when ``File.isDirectory() == true``. rewindDirectory (compatibiity method, not recommended for new code) -~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code:: cpp @@ -718,8 +718,8 @@ rewindDirectory (compatibiity method, not recommended for new code) Resets the ``openNextFile`` pointer to the top of the directory. Only valid when ``File.isDirectory() == true``. -setTimeCallback(time_t (*cb)(void)) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +setTimeCallback(time_t (\*cb)(void)) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the time callback for this specific file. Note that the SD and SDFS filesystems only support a filesystem-wide callback and calls to diff --git a/doc/libraries.rst b/doc/libraries.rst index bfdc05d95..2c283814d 100644 --- a/doc/libraries.rst +++ b/doc/libraries.rst @@ -87,7 +87,7 @@ Some ESP-specific APIs related to deep sleep, RTC and flash memories are availab ``ESP.getHeapFragmentation()`` returns the fragmentation metric (0% is clean, more than ~50% is not harmless) -``ESP.getMaxFreeBlockSize()`` returns the largest contiguous free RAM block in the heap, useful for checking heap fragmentation. **NOTE:** Maximum ``malloc()``able block will be smaller due to memory manager overheads. +``ESP.getMaxFreeBlockSize()`` returns the largest contiguous free RAM block in the heap, useful for checking heap fragmentation. **NOTE:** Maximum ``malloc()`` -able block will be smaller due to memory manager overheads. ``ESP.getChipId()`` returns the ESP8266 chip ID as a 32-bit integer. diff --git a/doc/mmu.rst b/doc/mmu.rst index 41446cf76..9c3ec48ac 100644 --- a/doc/mmu.rst +++ b/doc/mmu.rst @@ -233,5 +233,3 @@ address range of IRAM or DRAM. uint8_t mmu_set_uint8(void *p8, const uint8_t val); uint16_t mmu_set_uint16(uint16_t *p16, const uint16_t val); int16_t mmu_set_int16(int16_t *p16, const int16_t val); - -:: diff --git a/doc/ota_updates/readme.rst b/doc/ota_updates/readme.rst index 5575d45f2..3ab136cf3 100755 --- a/doc/ota_updates/readme.rst +++ b/doc/ota_updates/readme.rst @@ -161,7 +161,7 @@ If signing is desired, sign the gzip compressed file *after* compression. Updating apps in the field to support compression ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you have applications deployed in the field and wish to update them to support compressed OTA uploads, you will need to first recompile the application, then _upload the uncompressed `.bin` file once_. Attempting to upload a `gzip` compressed binary to a legacy app will result in the Updater rejecting the upload as it does not understand the `gzip` format. After this initial upload, which will include the new bootloader and `Updater` class with compression support, compressed updates can then be used. +If you have applications deployed in the field and wish to update them to support compressed OTA uploads, you will need to first recompile the application, then _upload the uncompressed `.bin` file once. Attempting to upload a `gzip` compressed binary to a legacy app will result in the Updater rejecting the upload as it does not understand the `gzip` format. After this initial upload, which will include the new bootloader and `Updater` class with compression support, compressed updates can then be used. Safety diff --git a/libraries/ESP8266WiFi/examples/EarlyDisableWiFi/EarlyDisableWiFi.ino b/libraries/ESP8266WiFi/examples/EarlyDisableWiFi/EarlyDisableWiFi.ino deleted file mode 100644 index 2025246f3..000000000 --- a/libraries/ESP8266WiFi/examples/EarlyDisableWiFi/EarlyDisableWiFi.ino +++ /dev/null @@ -1,59 +0,0 @@ - -#include -#include - -#ifndef STASSID -#define STASSID "your-ssid" -#define STAPSK "your-password" -#endif - -// preinit() is called before system startup -// from nonos-sdk's user entry point user_init() - -void preinit() { - // Global WiFi constructors are not called yet - // (global class instances like WiFi, Serial... are not yet initialized).. - // No global object methods or C++ exceptions can be called in here! - //The below is a static class method, which is similar to a function, so it's ok. - ESP8266WiFiClass::preinitWiFiOff(); -} - -void setup() { - Serial.begin(115200); - Serial.setDebugOutput(true); - Serial.println("sleeping 5s"); - - // during this period, a simple amp meter shows - // an average of 20mA with a Wemos D1 mini - // a DSO is needed to check #2111 - delay(5000); - - Serial.println("waking WiFi up, sleeping 5s"); - WiFi.forceSleepWake(); - - // amp meter raises to 75mA - delay(5000); - - Serial.println("connecting to AP " STASSID); - WiFi.mode(WIFI_STA); - WiFi.begin(STASSID, STAPSK); - - for (bool configured = false; !configured;) { - for (auto addr : addrList) - if ((configured = !addr.isLocal() && addr.ifnumber() == STATION_IF)) { - Serial.printf("STA: IF='%s' hostname='%s' addr= %s\n", - addr.ifname().c_str(), - addr.ifhostname(), - addr.toString().c_str()); - break; - } - Serial.print('.'); - delay(500); - } - - // amp meter cycles within 75-80 mA - -} - -void loop() { -} diff --git a/libraries/ESP8266WiFi/examples/WiFiShutdown/WiFiShutdown.ino b/libraries/ESP8266WiFi/examples/WiFiShutdown/WiFiShutdown.ino index 34f26a8b5..7fac16b45 100644 --- a/libraries/ESP8266WiFi/examples/WiFiShutdown/WiFiShutdown.ino +++ b/libraries/ESP8266WiFi/examples/WiFiShutdown/WiFiShutdown.ino @@ -24,11 +24,6 @@ WiFiState state; const char* ssid = STASSID; const char* password = STAPSK; -void preinit(void) { - // Make sure, wifi stays off after boot. - ESP8266WiFiClass::preinitWiFiOff(); -} - void setup() { Serial.begin(74880); //Serial.setDebugOutput(true); // If you need debug output diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index cbb0fe36c..7518f3c59 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -83,7 +83,7 @@ struct WiFiEventHandlerOpaque static std::list sCbEventList; -bool ESP8266WiFiGenericClass::_persistent = true; +bool ESP8266WiFiGenericClass::_persistent = false; WiFiMode_t ESP8266WiFiGenericClass::_forceSleepLastMode = WIFI_OFF; ESP8266WiFiGenericClass::ESP8266WiFiGenericClass() @@ -418,12 +418,6 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m, WiFiState* state) { DEBUG_WIFI("core: state is useless without SHUTDOWN or RESUME\n"); } - if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { - // wifi may have been put asleep by ESP8266WiFiGenericClass::preinitWiFiOff - wifi_fpm_do_wakeup(); - wifi_fpm_close(); - } - if(_persistent){ if(wifi_get_opmode() == (uint8) m && wifi_get_opmode_default() == (uint8) m){ return true; @@ -432,6 +426,12 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m, WiFiState* state) { return true; } + if (m != WIFI_OFF && wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { + // wifi starts asleep by default + wifi_fpm_do_wakeup(); + wifi_fpm_close(); + } + bool ret = false; ETS_UART_INTR_DISABLE(); if(_persistent) { @@ -855,25 +855,7 @@ bool ESP8266WiFiGenericClass::resumeFromShutdown (WiFiState* state) return true; } -//meant to be called from user-defined ::preinit() void ESP8266WiFiGenericClass::preinitWiFiOff () { - // https://github.com/esp8266/Arduino/issues/2111#issuecomment-224251391 - // WiFi.persistent(false); - // WiFi.mode(WIFI_OFF); - // WiFi.forceSleepBegin(); - - //WiFi.mode(WIFI_OFF) equivalent: - // datasheet: - // Set Wi-Fi working mode to Station mode, SoftAP - // or Station + SoftAP, and do not update flash - // (not persistent) - wifi_set_opmode_current(WIFI_OFF); - - //WiFi.forceSleepBegin(/*default*/0) equivalent: - // sleep forever until wifi_fpm_do_wakeup() is called - wifi_fpm_set_sleep_type(MODEM_SLEEP_T); - wifi_fpm_open(); - wifi_fpm_do_sleep(0xFFFFFFF); - - // use WiFi.forceSleepWake() to wake WiFi up + // It was meant to be called from user-defined ::preinit() + // It is now deprecated by enableWiFiAtBootTime() and __disableWiFiAtBootTime() } diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h index ec15f6f58..0e6a11e39 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h @@ -120,7 +120,7 @@ class ESP8266WiFiGenericClass { void setOutputPower(float dBm); - void persistent(bool persistent); + static void persistent(bool persistent); bool mode(WiFiMode_t, WiFiState* state = nullptr); WiFiMode_t getMode(); @@ -133,7 +133,7 @@ class ESP8266WiFiGenericClass { static uint32_t shutdownCRC (const WiFiState* state); static bool shutdownValidCRC (const WiFiState* state); - static void preinitWiFiOff (); //meant to be called in user-defined preinit() + static void preinitWiFiOff () __attribute__((deprecated("WiFi is off by default at boot, use enableWiFiAtBoot() for legacy behavior"))); protected: static bool _persistent; diff --git a/libraries/ESP8266WiFi/src/enable_wifi_at_boot_time.cpp b/libraries/ESP8266WiFi/src/enable_wifi_at_boot_time.cpp new file mode 100644 index 000000000..575d0317e --- /dev/null +++ b/libraries/ESP8266WiFi/src/enable_wifi_at_boot_time.cpp @@ -0,0 +1,28 @@ +/* + * empty wrappers to play with linker and reenable wifi at boot time + */ + +#include "coredecls.h" + +#include + +extern "C" void enableWiFiAtBootTime() +{ + /* + * Called by user from anywhere, does nothing and allows overriding + * the core_esp8266_main.cpp's default disableWiFiAtBootTime() by the + * one below, at link time. + */ +} + +extern "C" void __disableWiFiAtBootTime() +{ + // overrides the default __disableWiFiAtBootTime: + // Does (almost) nothing: WiFi is enabled by default in nonos-sdk + + // ... but restores legacy WiFi credentials persistence to true at boot time + // (can be still overriden by user before setting up WiFi, like before) + + // (note: c++ ctors not called yet at this point) + ESP8266WiFiClass::persistent(true); +} diff --git a/libraries/esp8266/examples/SerialStress/SerialStress.ino b/libraries/esp8266/examples/SerialStress/SerialStress.ino index 1412abd2b..b06b38e30 100644 --- a/libraries/esp8266/examples/SerialStress/SerialStress.ino +++ b/libraries/esp8266/examples/SerialStress/SerialStress.ino @@ -57,12 +57,6 @@ void error(const char* what) { } } -void preinit() { - // (no C++ in function) - // disable wifi - ESP8266WiFiClass::preinitWiFiOff(); -} - void setup() { pinMode(LED_BUILTIN, OUTPUT); diff --git a/libraries/esp8266/examples/UartDownload/UartDownload.ino b/libraries/esp8266/examples/UartDownload/UartDownload.ino index fa8ea0d61..cf581c889 100644 --- a/libraries/esp8266/examples/UartDownload/UartDownload.ino +++ b/libraries/esp8266/examples/UartDownload/UartDownload.ino @@ -98,12 +98,6 @@ void proxyEspSync() { // //////////////////////////////////////////////////////////////////////////////// -void preinit() { - // (no C++ in function) - // disable wifi - ESP8266WiFiClass::preinitWiFiOff(); -} - void setup() { // For `proxyEspSync()` to work, the Serial.begin() speed needs to be // 115200bps. This is the data rate used by esptool.py. It expects the Boot diff --git a/libraries/lwIP_w5500/examples/TCPClient/TCPClient.ino b/libraries/lwIP_w5500/examples/TCPClient/TCPClient.ino index 56dcb8092..bdece2d88 100644 --- a/libraries/lwIP_w5500/examples/TCPClient/TCPClient.ino +++ b/libraries/lwIP_w5500/examples/TCPClient/TCPClient.ino @@ -9,7 +9,6 @@ //or #include #include // WiFiClient (-> TCPClient) -#include // ESP8266WiFiClass::preinitWiFiOff() const char* host = "djxmmx.net"; const uint16_t port = 17; @@ -19,12 +18,6 @@ using TCPClient = WiFiClient; #define CSPIN 16 // wemos/lolin/nodemcu D0 Wiznet5500lwIP eth(CSPIN); -void preinit() { - // (no C++ in function) - // disable wifi - ESP8266WiFiClass::preinitWiFiOff(); -} - void setup() { Serial.begin(115200); diff --git a/tests/device/test_serial/test_serial.ino b/tests/device/test_serial/test_serial.ino index 6cdf2b267..66ec15406 100644 --- a/tests/device/test_serial/test_serial.ino +++ b/tests/device/test_serial/test_serial.ino @@ -33,12 +33,6 @@ static uint64_t in_total = 0, in_prev = 0; static uint64_t start_ms, last_ms; static uint64_t timeout; -void preinit() { - // (no C++ in function) - // disable wifi - ESP8266WiFiClass::preinitWiFiOff(); -} - void setup() { Serial.begin(SSBAUD); diff --git a/tests/device/test_spi_flash/test_spi_flash.ino b/tests/device/test_spi_flash/test_spi_flash.ino index fa7ea767b..b1e18241f 100644 --- a/tests/device/test_spi_flash/test_spi_flash.ino +++ b/tests/device/test_spi_flash/test_spi_flash.ino @@ -3,12 +3,6 @@ BS_ENV_DECLARE(); -void preinit() { - // (no C++ in function) - // disable wifi - ESP8266WiFiClass::preinitWiFiOff(); -} - void setup() { Serial.begin(115200);