Skip to content

Commit

Permalink
[BREAKING] wifi: remove pseudo-modes for shutdown, expose `::[resumeF…
Browse files Browse the repository at this point in the history
…rom]shutdown()` (#7956)

* wifi: remove pseudo-modes for shutdown

make shutdown and resumeFromShutdown public
removes extra code from the mode handler and include method description
in the docs

* typo

* dup

* typos

* reference only shutdown() & resumeFromShutdown()

prefer to have some specific function, don't simply chain into sleep
update examples and docs

* safeguard raw sdk config usage
  • Loading branch information
mcspr committed May 15, 2021
1 parent e9820c1 commit b0ece8c
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 100 deletions.
59 changes: 35 additions & 24 deletions doc/esp8266wifi/generic-class.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ Once ``WiFi.persistent(false)`` is called, ``WiFi.begin``, ``WiFi.disconnect``,
mode
~~~~

Regular WiFi modes
__________________

.. code:: cpp
bool mode(WiFiMode_t m)
Expand All @@ -94,25 +91,6 @@ Switches to one of the regular WiFi modes, where ``m`` is one of:
- ``WIFI_AP``: switch to `Access Point (AP) <readme.rst#soft-access-point>`__ mode.
- ``WIFI_AP_STA``: enable both Station (STA) and Access Point (AP) mode.

Pseudo-modes
____________

.. code:: cpp
bool mode(WiFiMode_t m, WiFiState* state)
Used with the following pseudo-modes, where ``m`` is one of:

- ``WIFI_SHUTDOWN``: Fills in the provided ``WiFiState`` structure, switches to ``WIFI_OFF`` mode and puts WiFi into forced sleep, preserving energy.
- ``WIFI_RESUME``: Turns WiFi on and tries to re-establish the WiFi connection stored in the ``WiFiState`` structure.

These modes are used in low-power scenarios, e.g. where ESP.deepSleep is used between actions to preserve battery power.

It is the user's responsibility to preserve the WiFiState between ``WIFI_SHUTDOWN`` and ``WIFI_RESUME``, e.g. by storing it
in RTC user data and/or flash memory.

There is an example sketch `WiFiShutdown.ino <https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiShutdown/WiFiShutdown.ino>`__ available in the examples folder of the ESP8266WiFi library.

getMode
~~~~~~~

Expand Down Expand Up @@ -199,6 +177,41 @@ getPhyMode
Gets the WiFi radio phy mode that is currently set.

forceSleepBegin
~~~~~~~~~~~~~~~

.. code:: cpp
bool forceSleepBegin (uint32 sleepUs=0)
Saves the currently set WiFi mode and starts forced modem sleep for the specified time (us)

forceSleepWake
~~~~~~~~~~~~~~

.. code:: cpp
bool forceSleepWake ()
Called after `forceSleepBegin()`. Restores the previous WiFi mode and attempts reconnection when STA was active.

shutdown and resumeFromShutdown
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code:: cpp
bool shutdown (WiFiState& state)
bool shutdown (WiFiState& state, uint32 sleepUs)
bool resumeFromShutdown (WiFiState& state)
bool shutdownValidCRC (const WiFiState& state)
Stores the STA interface IP configuration in the specified ``state`` struct and calls ``forceSleepBegin(sleepUs)``.
Restores STA interface configuration from the ``state`` and calls ``forceSleepWake()``.

These methods are intended to be used in low-power scenarios, e.g. where ESP.deepSleep is used between actions to preserve battery power. It is the user's responsibility to preserve the WiFiState between ``shutdown()`` and ``resumeFromShutdown()`` by storing it in the RTC user data and/or flash memory.

See `WiFiShutdown.ino <https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiShutdown/WiFiShutdown.ino>`__ for an example of usage.

Other Function Calls
~~~~~~~~~~~~~~~~~~~~

Expand All @@ -208,8 +221,6 @@ Other Function Calls
WiFiSleepType_t getSleepMode ()
bool enableSTA (bool enable)
bool enableAP (bool enable)
bool forceSleepBegin (uint32 sleepUs=0)
bool forceSleepWake ()
int hostByName (const char *aHostname, IPAddress &aResult)
appeared with SDK pre-V3:
Expand Down
8 changes: 4 additions & 4 deletions libraries/ESP8266WiFi/examples/WiFiShutdown/WiFiShutdown.ino
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

// Demonstrate the use of WiFi.mode(WIFI_SHUTDOWN)/WiFi.mode(WIFI_RESUME)
// Demonstrate the use of WiFi.shutdown() and WiFi.resumeFromShutdown()
// Released to public domain

// Current on WEMOS D1 mini (including: LDO, usbserial chip):
Expand Down Expand Up @@ -39,7 +39,7 @@ void setup() {
ESP.rtcUserMemoryRead(RTC_USER_DATA_SLOT_WIFI_STATE, reinterpret_cast<uint32_t *>(&state), sizeof(state));
unsigned long start = millis();

if (!WiFi.mode(WIFI_RESUME, &state)
if (!WiFi.resumeFromShutdown(state)
|| (WiFi.waitForConnectResult(10000) != WL_CONNECTED)) {
Serial.println("Cannot resume WiFi connection, connecting via begin...");
WiFi.persistent(false);
Expand All @@ -63,7 +63,7 @@ void setup() {
// Here you can do whatever you need to do that needs a WiFi connection.
// ---

WiFi.mode(WIFI_SHUTDOWN, &state);
WiFi.shutdown(state);
ESP.rtcUserMemoryWrite(RTC_USER_DATA_SLOT_WIFI_STATE, reinterpret_cast<uint32_t *>(&state), sizeof(state));

// ---
Expand All @@ -77,4 +77,4 @@ void setup() {

void loop() {
// Nothing to do here.
}
}
2 changes: 2 additions & 0 deletions libraries/ESP8266WiFi/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ enableSTA KEYWORD2
enableAP KEYWORD2
forceSleepBegin KEYWORD2
forceSleepWake KEYWORD2
shutdown KEYWORD2
resumeFromShutdown KEYWORD2

#ESP8266WiFi
printDiag KEYWORD2
Expand Down
114 changes: 61 additions & 53 deletions libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,21 +401,10 @@ bool ESP8266WiFiGenericClass::getPersistent(){
* set new mode
* @param m WiFiMode_t
*/
bool ESP8266WiFiGenericClass::mode(WiFiMode_t m, WiFiState* state) {
if (m == WIFI_SHUTDOWN) {
return shutdown(0, state);
}
else if (m == WIFI_RESUME) {
return resumeFromShutdown(state);
}
else if (m & ~(WIFI_STA | WIFI_AP))
bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
if (m & ~(WIFI_STA | WIFI_AP)) {
// any other bits than legacy disallowed
return false;

// m is now WIFI_STA, WIFI_AP or WIFI_AP_STA
if (state)
{
DEBUG_WIFI("core: state is useless without SHUTDOWN or RESUME\n");
}

if(_persistent){
Expand Down Expand Up @@ -719,37 +708,37 @@ void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *ca
esp_schedule(); // break delay in hostByName
}

uint32_t ESP8266WiFiGenericClass::shutdownCRC (const WiFiState* state)
uint32_t ESP8266WiFiGenericClass::shutdownCRC (const WiFiState& state)
{
return state? crc32(&state->state, sizeof(state->state)): 0;
return crc32(&state.state, sizeof(state.state));
}

bool ESP8266WiFiGenericClass::shutdownValidCRC (const WiFiState* state)
bool ESP8266WiFiGenericClass::shutdownValidCRC (const WiFiState& state)
{
return state && (crc32(&state->state, sizeof(state->state)) == state->crc);
return crc32(&state.state, sizeof(state.state)) == state.crc;
}

bool ESP8266WiFiGenericClass::shutdown (uint32 sleepUs, WiFiState* state)
bool ESP8266WiFiGenericClass::shutdown (WiFiState& state, uint32 sleepUs)
{
bool persistent = _persistent;
WiFiMode_t before_off_mode = getMode();

if ((before_off_mode & WIFI_STA) && state)
if (before_off_mode & WIFI_STA)
{
bool ret = wifi_get_ip_info(STATION_IF, &state->state.ip);
bool ret = wifi_get_ip_info(STATION_IF, &state.state.ip);
if (!ret)
{
DEBUG_WIFI("core: error with wifi_get_ip_info(STATION_IF)\n");
return false;
}
memset(state->state.fwconfig.bssid, 0xff, 6);
ret = wifi_station_get_config(&state->state.fwconfig);
memset(state.state.fwconfig.bssid, 0xff, 6);
ret = wifi_station_get_config(&state.state.fwconfig);
if (!ret)
{
DEBUG_WIFI("core: error with wifi_station_get_config\n");
return false;
}
state->state.channel = wifi_get_channel();
state.state.channel = wifi_get_channel();
}

// disable persistence in FW so in case of power failure
Expand All @@ -766,57 +755,63 @@ bool ESP8266WiFiGenericClass::shutdown (uint32 sleepUs, WiFiState* state)
}

// WiFi is now in force-sleep mode
// finish filling state and process crc

state.state.persistent = persistent;
state.state.mode = before_off_mode;

if (state)
uint8_t i = 0;
for (auto& ntp: state.state.ntp)
{
// finish filling state and process crc
ntp = *sntp_getserver(i++);
}
i = 0;

state->state.persistent = persistent;
state->state.mode = before_off_mode;
uint8_t i = 0;
for (auto& ntp: state->state.ntp)
{
ntp = *sntp_getserver(i++);
}
i = 0;
for (auto& dns: state->state.dns)
dns = WiFi.dnsIP(i++);
state->crc = shutdownCRC(state);
DEBUG_WIFI("core: state is saved\n");
for (auto& dns: state.state.dns)
{
dns = WiFi.dnsIP(i++);
}

state.crc = shutdownCRC(state);
DEBUG_WIFI("core: state is saved\n");

return true;
}

bool ESP8266WiFiGenericClass::resumeFromShutdown (WiFiState* state)
bool ESP8266WiFiGenericClass::shutdown (WiFiState& state) {
return shutdown(state, 0);
}

bool ESP8266WiFiGenericClass::resumeFromShutdown (WiFiState& state)
{
if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) {
wifi_fpm_do_wakeup();
wifi_fpm_close();
}

if (!state || shutdownCRC(state) != state->crc)
if (shutdownCRC(state) != state.crc)
{
DEBUG_WIFI("core: resume: no state or bad crc\n");
DEBUG_WIFI("core: resume: bad crc\n");
return false;
}

persistent(state->state.persistent);
persistent(state.state.persistent);

if (!mode(state->state.mode))
if (!mode(state.state.mode))
{
DEBUG_WIFI("core: resume: can't set wifi mode to %d\n", state->state.mode);
DEBUG_WIFI("core: resume: can't set wifi mode to %d\n", state.state.mode);
return false;
}

if (state->state.mode & WIFI_STA)
if (state.state.mode & WIFI_STA)
{
IPAddress local(state->state.ip.ip);
IPAddress local(state.state.ip.ip);
if (local)
{
DEBUG_WIFI("core: resume: static address '%s'\n", local.toString().c_str());
WiFi.config(state->state.ip.ip, state->state.ip.gw, state->state.ip.netmask, state->state.dns[0], state->state.dns[1]);
WiFi.config(state.state.ip.ip, state.state.ip.gw, state.state.ip.netmask, state.state.dns[0], state.state.dns[1]);
uint8_t i = 0;
for (const auto& ntp: state->state.ntp)
for (const auto& ntp: state.state.ntp)
{
IPAddress ip(ntp);
if (ip.isSet())
Expand All @@ -826,10 +821,23 @@ bool ESP8266WiFiGenericClass::resumeFromShutdown (WiFiState* state)
}
}
}
auto beginResult = WiFi.begin((const char*)state->state.fwconfig.ssid,
(const char*)state->state.fwconfig.password,
state->state.channel,
state->state.fwconfig.bssid,

String ssid;
{
const char* ptr = reinterpret_cast<const char*>(state.state.fwconfig.ssid);
ssid.concat(ptr, strnlen(ptr, sizeof(station_config::ssid)));
}

String pass;
{
const char* ptr = reinterpret_cast<const char*>(state.state.fwconfig.password);
pass.concat(ptr, strnlen(ptr, sizeof(station_config::password)));
}

auto beginResult = WiFi.begin(ssid.c_str(),
pass.c_str(),
state.state.channel,
state.state.fwconfig.bssid,
true);
if (beginResult == WL_CONNECT_FAILED)
{
Expand All @@ -843,14 +851,14 @@ bool ESP8266WiFiGenericClass::resumeFromShutdown (WiFiState* state)
}
}

if (state->state.mode & WIFI_AP)
if (state.state.mode & WIFI_AP)
{
DEBUG_WIFI("core: resume AP mode TODO\n");
return false;
}

// success, invalidate saved state
state->crc++;
state.crc++;

return true;
}
Expand Down
20 changes: 11 additions & 9 deletions libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class ESP8266WiFiGenericClass {

static void persistent(bool persistent);

bool mode(WiFiMode_t, WiFiState* state = nullptr);
bool mode(WiFiMode_t);
WiFiMode_t getMode();

bool enableSTA(bool enable);
Expand All @@ -131,21 +131,23 @@ class ESP8266WiFiGenericClass {
bool forceSleepBegin(uint32 sleepUs = 0);
bool forceSleepWake();

static uint32_t shutdownCRC (const WiFiState* state);
static bool shutdownValidCRC (const WiFiState* state);
// wrappers around mode() and forceSleepBegin/Wake
// - sleepUs is WiFi.forceSleepBegin() parameter, 0 means forever
// - saveState is the user's state to hold configuration on restore
bool shutdown(WiFiState& stateSave);
bool shutdown(WiFiState& stateSave, uint32 sleepUs);
bool resumeFromShutdown(WiFiState& savedState);

static bool shutdownValidCRC (const WiFiState& state);
static void preinitWiFiOff () __attribute__((deprecated("WiFi is off by default at boot, use enableWiFiAtBoot() for legacy behavior")));

protected:
static bool _persistent;
static WiFiMode_t _forceSleepLastMode;

static void _eventCallback(void *event);
static uint32_t shutdownCRC (const WiFiState& state);

// called by WiFi.mode(SHUTDOWN/RESTORE, state)
// - sleepUs is WiFi.forceSleepBegin() parameter, 0 = forever
// - saveState is the user's state to hold configuration on restore
bool shutdown (uint32 sleepUs = 0, WiFiState* stateSave = nullptr);
bool resumeFromShutdown (WiFiState* savedState = nullptr);
static void _eventCallback(void *event);

// ----------------------------------------------------------------------------------------------
// ------------------------------------ Generic Network function --------------------------------
Expand Down
3 changes: 1 addition & 2 deletions libraries/ESP8266WiFi/src/ESP8266WiFiType.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@

typedef enum WiFiMode
{
WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3,
/* these two pseudo modes are experimental: */ WIFI_SHUTDOWN = 4, WIFI_RESUME = 8
WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3
} WiFiMode_t;

typedef enum WiFiPhyMode
Expand Down
Loading

0 comments on commit b0ece8c

Please sign in to comment.