diff --git a/cores/esp8266/core_esp8266_eboot_command.cpp b/cores/esp8266/core_esp8266_eboot_command.cpp index 44d65a8c3e..2ddc65933e 100644 --- a/cores/esp8266/core_esp8266_eboot_command.cpp +++ b/cores/esp8266/core_esp8266_eboot_command.cpp @@ -21,36 +21,15 @@ #include #include +#include "coredecls.h" #include "eboot_command.h" -extern "C" { -static uint32_t crc_update(uint32_t crc, const uint8_t *data, size_t length) -{ - uint32_t i; - bool bit; - uint8_t c; - - while (length--) { - c = *data++; - for (i = 0x80; i > 0; i >>= 1) { - bit = crc & 0x80000000; - if (c & i) { - bit = !bit; - } - crc <<= 1; - if (bit) { - crc ^= 0x04c11db7; - } - } - } - return crc; -} +extern "C" { static uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd) { - return crc_update(0xffffffff, (const uint8_t*) cmd, - offsetof(struct eboot_command, crc32)); + return crc32((const uint8_t*) cmd, offsetof(struct eboot_command, crc32)); } int eboot_command_read(struct eboot_command* cmd) diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index 3ac87eee9f..4a70609bff 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -8,6 +8,7 @@ extern "C" { // TODO: put declarations here, get rid of -Wno-implicit-function-declaration +#include #include #include // g_pcont declaration @@ -20,6 +21,7 @@ void settimeofday_cb (void (*cb)(void)); void disable_extra4k_at_link_time (void) __attribute__((noinline)); uint32_t sqrt32 (uint32_t n); +uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff); #ifdef __cplusplus } diff --git a/cores/esp8266/crc32.cpp b/cores/esp8266/crc32.cpp new file mode 100644 index 0000000000..cc2a2ee64e --- /dev/null +++ b/cores/esp8266/crc32.cpp @@ -0,0 +1,42 @@ +/* + crc32.cpp + + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "coredecls.h" + +// moved from core_esp8266_eboot_command.cpp +uint32_t crc32 (const void* data, size_t length, uint32_t crc /*= 0xffffffff*/) +{ + const uint8_t* ldata = (const uint8_t*)data; + while (length--) + { + uint8_t c = *ldata++; + for (uint32_t i = 0x80; i > 0; i >>= 1) + { + bool bit = crc & 0x80000000; + if (c & i) + bit = !bit; + crc <<= 1; + if (bit) + crc ^= 0x04c11db7; + } + } + return crc; +} diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index 31daf370a0..ed49ca9d6a 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "ESP8266WiFi.h" #include "ESP8266WiFiGeneric.h" @@ -38,12 +39,19 @@ extern "C" { #include "lwip/opt.h" #include "lwip/err.h" #include "lwip/dns.h" +#include "lwip/dhcp.h" #include "lwip/init.h" // LWIP_VERSION_ +#if LWIP_VERSION_MAJOR == 1 +#include "lwip/sntp.h" +#else +#include "lwip/apps/sntp.h" +#endif } #include "WiFiClient.h" #include "WiFiUdp.h" #include "debug.h" +#include "include/WiFiState.h" extern "C" void esp_schedule(); extern "C" void esp_yield(); @@ -200,15 +208,15 @@ WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeProbeRequestReceived(std:: return handler; } -// WiFiEventHandler ESP8266WiFiGenericClass::onWiFiModeChange(std::function f) -// { -// WiFiEventHandler handler = std::make_shared(WIFI_EVENT_MODE_CHANGE, [f](System_Event_t* e){ -// WiFiEventModeChange& dst = *reinterpret_cast(&e->event_info); -// f(dst); -// }); -// sCbEventList.push_back(handler); -// return handler; -// } +WiFiEventHandler ESP8266WiFiGenericClass::onWiFiModeChange(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_MODE_CHANGE, [f](System_Event_t* e){ + WiFiEventModeChange& dst = *reinterpret_cast(&e->event_info); + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} /** * callback for WiFi events @@ -386,7 +394,29 @@ bool ESP8266WiFiGenericClass::getPersistent(){ * set new mode * @param m WiFiMode_t */ -bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) { +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)) + // 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 (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; @@ -396,12 +426,6 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) { } bool ret = false; - - if (m != WIFI_STA && m != WIFI_AP_STA) - // calls lwIP's dhcp_stop(), - // safe to call even if not started - wifi_station_dhcpc_stop(); - ETS_UART_INTR_DISABLE(); if(_persistent) { ret = wifi_set_opmode(m); @@ -431,15 +455,13 @@ bool ESP8266WiFiGenericClass::enableSTA(bool enable) { WiFiMode_t currentMode = getMode(); bool isEnabled = ((currentMode & WIFI_STA) != 0); - if(isEnabled != enable) { - if(enable) { - return mode((WiFiMode_t)(currentMode | WIFI_STA)); - } else { - return mode((WiFiMode_t)(currentMode & (~WIFI_STA))); - } - } else { + if (isEnabled == enable) return true; - } + + if (enable) + return mode((WiFiMode_t)(currentMode | WIFI_STA)); + + return mode((WiFiMode_t)(currentMode & (~WIFI_STA))); } /** @@ -472,16 +494,29 @@ bool ESP8266WiFiGenericClass::enableAP(bool enable){ bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) { _forceSleepLastMode = getMode(); if(!mode(WIFI_OFF)) { + DEBUG_WIFI("core: error with mode(WIFI_OFF)\n"); return false; } - if(sleepUs == 0) { + if(sleepUs == 0 || sleepUs > 0xFFFFFFF) { sleepUs = 0xFFFFFFF; } wifi_fpm_set_sleep_type(MODEM_SLEEP_T); + delay(0); wifi_fpm_open(); - return (wifi_fpm_do_sleep(sleepUs) == 0); + delay(0); + auto ret = wifi_fpm_do_sleep(sleepUs); + if (ret != 0) + { + DEBUG_WIFI("core: error %d with wifi_fpm_do_sleep: (-1=sleep status error, -2=force sleep not enabled)\n", ret); + return false; + } + // fpm_is_open() is always 1 here, with or without delay + // wifi_fpm_set_wakeup_cb(cb): callback is never called + // no power reduction without this delay + delay(10); + return true; } /** @@ -489,8 +524,10 @@ bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) { * @return ok */ bool ESP8266WiFiGenericClass::forceSleepWake() { - wifi_fpm_do_wakeup(); - wifi_fpm_close(); + if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { + wifi_fpm_do_wakeup(); + wifi_fpm_close(); + } // restore last mode if(mode(_forceSleepLastMode)) { @@ -600,7 +637,142 @@ void wifi_dns_found_callback(const char *name, CONST ip_addr_t *ipaddr, void *ca esp_schedule(); // resume the hostByName function } -//meant to be called from user-defined preinit() +uint32_t ESP8266WiFiGenericClass::shutdownCRC (const WiFiState* state) +{ + return state? crc32(&state->state, sizeof(state->state)): 0; +} + +bool ESP8266WiFiGenericClass::shutdownValidCRC (const WiFiState* state) +{ + return state && (crc32(&state->state, sizeof(state->state)) == state->crc); +} + +bool ESP8266WiFiGenericClass::shutdown (uint32 sleepUs, WiFiState* state) +{ + bool persistent = _persistent; + WiFiMode_t before_off_mode = getMode(); + + if ((before_off_mode & WIFI_STA) && state) + { + 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); + if (!ret) + { + DEBUG_WIFI("core: error with wifi_station_get_config\n"); + return false; + } + state->state.channel = wifi_get_channel(); + } + + // disable persistence in FW so in case of power failure + // it doesn't wake up in off mode. + // persistence state will be restored on WiFi resume. + WiFi.persistent(false); + if (!WiFi.forceSleepBegin(sleepUs)) + { + // WIFI_OFF mode set by forceSleepBegin() + DEBUG_WIFI("core: error with forceSleepBegin()\n"); + WiFi.mode(before_off_mode); + WiFi.persistent(persistent); + return false; + } + + // WiFi is now in force-sleep mode + + if (state) + { + // finish filling state and process crc + + state->state.persistent = persistent; + state->state.mode = before_off_mode; + uint8_t i = 0; + for (auto& ntp: state->state.ntp) + { +#if LWIP_VERSION_MAJOR == 1 + ntp = sntp_getserver(i++); +#else + ntp = *sntp_getserver(i++); +#endif + } + i = 0; + 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) +{ + if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { + wifi_fpm_do_wakeup(); + wifi_fpm_close(); + } + + if (!state || shutdownCRC(state) != state->crc) + { + DEBUG_WIFI("core: resume: no state or bad crc\n"); + return false; + } + + persistent(state->state.persistent); + + if (!mode(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) + { + 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]); + uint8_t i = 0; + for (CONST auto& ntp: state->state.ntp) + { + IPAddress ip(ntp); + if (ip.isSet()) + { + DEBUG_WIFI("core: resume: start SNTP, server='%s'\n", ip.toString().c_str()); + sntp_setserver(i++, &ntp); + } + } + } + // state->state.fwconfig.bssid is not real bssid (it's what user may have provided when bssid_set==1) + if (WiFi.begin((const char*)state->state.fwconfig.ssid, + (const char*)state->state.fwconfig.password, + state->state.channel, + nullptr/*(const uint8_t*)state->state.fwconfig.bssid*/, // <- try with gw's mac address? + true) == WL_CONNECT_FAILED) + { + DEBUG_WIFI("core: resume: WiFi.begin failed\n"); + return false; + } + } + + if (state->state.mode & WIFI_AP) + { + DEBUG_WIFI("core: resume AP mode TODO\n"); + return false; + } + + // success, invalidate saved state + state->crc++; + + 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); diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h index 60fdad5785..1f5ec5c995 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h @@ -42,6 +42,8 @@ typedef std::shared_ptr WiFiEventHandler; typedef void (*WiFiEventCb)(WiFiEvent_t); +struct WiFiState; + class ESP8266WiFiGenericClass { // ---------------------------------------------------------------------------------------------- // -------------------------------------- Generic WiFi function --------------------------------- @@ -62,7 +64,7 @@ class ESP8266WiFiGenericClass { WiFiEventHandler onSoftAPModeStationConnected(std::function); WiFiEventHandler onSoftAPModeStationDisconnected(std::function); WiFiEventHandler onSoftAPModeProbeRequestReceived(std::function); - // WiFiEventHandler onWiFiModeChange(std::function); + WiFiEventHandler onWiFiModeChange(std::function); int32_t channel(void); @@ -79,7 +81,7 @@ class ESP8266WiFiGenericClass { void persistent(bool persistent); - bool mode(WiFiMode_t); + bool mode(WiFiMode_t, WiFiState* state = nullptr); WiFiMode_t getMode(); bool enableSTA(bool enable); @@ -88,6 +90,8 @@ class ESP8266WiFiGenericClass { bool forceSleepBegin(uint32 sleepUs = 0); bool forceSleepWake(); + static uint32_t shutdownCRC (const WiFiState* state); + static bool shutdownValidCRC (const WiFiState* state); static void preinitWiFiOff (); //meant to be called in user-defined preinit() protected: @@ -96,17 +100,22 @@ class ESP8266WiFiGenericClass { static void _eventCallback(void *event); + // 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); + // ---------------------------------------------------------------------------------------------- // ------------------------------------ Generic Network function -------------------------------- // ---------------------------------------------------------------------------------------------- public: - int hostByName(const char* aHostname, IPAddress& aResult); int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms); bool getPersistent(); - protected: + protected: friend class ESP8266WiFiSTAClass; friend class ESP8266WiFiScanClass; friend class ESP8266WiFiAPClass; diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp index aaca892cdc..8f52942b74 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp @@ -369,18 +369,24 @@ bool ESP8266WiFiSTAClass::reconnect() { * @return one value of wl_status_t enum */ bool ESP8266WiFiSTAClass::disconnect(bool wifioff) { - bool ret; + bool ret = false; struct station_config conf; *conf.ssid = 0; *conf.password = 0; + // API Reference: wifi_station_disconnect() need to be called after system initializes and the ESP8266 Station mode is enabled. + if (WiFi.getMode() & WIFI_STA) + ret = wifi_station_disconnect(); + else + ret = true; + ETS_UART_INTR_DISABLE(); if(WiFi._persistent) { wifi_station_set_config(&conf); } else { wifi_station_set_config_current(&conf); } - ret = wifi_station_disconnect(); + ETS_UART_INTR_ENABLE(); if(wifioff) { diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiType.h b/libraries/ESP8266WiFi/src/ESP8266WiFiType.h index c1fb2985be..86803edce4 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiType.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiType.h @@ -34,7 +34,8 @@ typedef enum WiFiMode { - WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3 + 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 } WiFiMode_t; typedef enum WiFiPhyMode @@ -58,9 +59,10 @@ typedef enum WiFiEvent WIFI_EVENT_SOFTAPMODE_STACONNECTED, WIFI_EVENT_SOFTAPMODE_STADISCONNECTED, WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED, + WIFI_EVENT_MODE_CHANGE, + WIFI_EVENT_SOFTAPMODE_DISTRIBUTE_STA_IP, WIFI_EVENT_MAX, WIFI_EVENT_ANY = WIFI_EVENT_MAX, - WIFI_EVENT_MODE_CHANGE } WiFiEvent_t; enum WiFiDisconnectReason diff --git a/libraries/ESP8266WiFi/src/include/WiFiState.h b/libraries/ESP8266WiFi/src/include/WiFiState.h new file mode 100644 index 0000000000..caceb6f0bc --- /dev/null +++ b/libraries/ESP8266WiFi/src/include/WiFiState.h @@ -0,0 +1,23 @@ + +#ifndef WIFISTATE_H_ +#define WIFISTATE_H_ + +#include +#include + +struct WiFiState +{ + uint32_t crc; + struct + { + station_config fwconfig; + ip_info ip; + ip_addr_t dns[2]; + ip_addr_t ntp[2]; + WiFiMode_t mode; + uint8_t channel; + bool persistent; + } state; +}; + +#endif // WIFISTATE_H_ diff --git a/libraries/esp8266/examples/WiFiShutdown/WiFiShutdown.ino b/libraries/esp8266/examples/WiFiShutdown/WiFiShutdown.ino new file mode 100644 index 0000000000..1c0624fd60 --- /dev/null +++ b/libraries/esp8266/examples/WiFiShutdown/WiFiShutdown.ino @@ -0,0 +1,258 @@ + +// demonstrate the use of WiFi.mode(SHUTDOWN/RESUME) +// released to public domain + +// current on wemos d1 mini (including: ldo, usbserial chip): +// ~85mA during normal operations +// ~30mA during wifi shutdown +// ~5mA during deepsleep + +#ifndef STASSID +#define STASSID "mynetwork" +#define STAPSK "mynetworkpasswd" +#endif + +#define WAIT_NTP 0 // define this to 1 for NTP check too + +#include +#include // crc32() +#include // WiFiState structure details + +enum state_e { + e_initial, + e_start_resume, + e_start_normal, + e_off_restart, + e_wait_connected, + e_wait_ntp, + e_shutdown, + e_wait_shutdown, + e_wait_off +}; + +static state_e step = e_initial; // step +static int wifi_timeout = 0; // wifi timeout counter +static bool time_is_set = false; // WAIT_NTP=1: wait for network - dhcp packet must have ntp server + +// non volatile data +struct nv_s { + WiFiState wss; // core's wifi save state + + uint32_t crc; + struct { + int rstcounter[7]; + } data; +}; +static nv_s* nv = (nv_s*)RTC_USER_MEM; // user non volatile area + +#define SEP "###### " +#define EV "!!!!!! " +#define NFO "------ " + +void resetUserCrc() { + nv->crc = crc32(&nv->data, sizeof(nv->data)); +} + +void printNv() { + Serial.printf(NFO "nfo1/2 wifi-nv-state: valid=%d, " + "persistent=%d, " + "mode=%d, " + "channel=%d, " + "ip=%s, " + "dns=%s, " + "ntp=%s\n", + WiFi.shutdownValidCRC(&nv->wss), + nv->wss.state.persistent, + nv->wss.state.mode, + nv->wss.state.channel, + IPAddress(&nv->wss.state.ip.ip).toString().c_str(), + IPAddress(&nv->wss.state.dns[0]).toString().c_str(), + IPAddress(&nv->wss.state.ntp[0]).toString().c_str()); + + Serial.printf(NFO "nfo2/2 rst reason counters: default:%d wdt:%d exception:%d softwdt:%d reset:%d deepsleep:%d extsys:%d\n", + nv->data.rstcounter[0], + nv->data.rstcounter[1], + nv->data.rstcounter[2], + nv->data.rstcounter[3], + nv->data.rstcounter[4], + nv->data.rstcounter[5], + nv->data.rstcounter[6]); +} + +void timeset_cb() { + time_is_set = true; + + static bool first = true; + if (first) { + first = false; + } +} + +decltype(millis()) startup; + + +WiFiEventHandler evOff = WiFi.onWiFiModeChange([](const WiFiEventModeChange& event) { + Serial.printf(EV "mode changed event: ev:%d->%d getMode=%d\n", event.oldMode, event.newMode, wifi_get_opmode()); +}); + +void preinit() { + ESP8266WiFiClass::preinitWiFiOff(); +} + +void setup() { + WiFi.persistent(false); + startup = millis(); + Serial.begin(115200); + settimeofday_cb(timeset_cb); + + // prepare non volatile user structure + if (crc32(&nv->data, sizeof(nv->data)) != nv->crc) { + memset(&nv->data, 0, sizeof(nv->data)); + Serial.printf(SEP "reset NV user data\n"); + } + // update reset reason + nv->data.rstcounter[system_get_rst_info()->reason]++; + // recalculate crc + resetUserCrc(); + // nfo + printNv(); + + Serial.println("setup()"); +} + +#define TEST(x...) ({ auto v = x; Serial.printf(SEP "'%s': result = %d\n", #x, v); v; }) + +void loop() { + + static int prev = 255; + if (step != prev) { + prev = step; + Serial.printf(NFO "step %d - wifi getMode=%d=%d heap=%d freeheap=%d\n", + prev, + WiFi.getMode(), + wifi_get_opmode(), + ESP.getFreeHeap(), + ESP.getFreeHeap()); + printNv(); + } + + switch (step) { + + case e_initial: { + if (WiFi.shutdownValidCRC(&nv->wss)) { + step = e_start_resume; + } else { + step = e_start_normal; + } + break; + } + + + case e_start_resume: + Serial.println(SEP "CRC valid => WIFI_RESUME"); + startup = millis(); + + if (!TEST(WiFi.mode(WIFI_RESUME, &nv->wss))) { + Serial.printf(SEP "issue resuming WiFi\n"); + step = e_off_restart; + } else { + Serial.printf(SEP "waiting for connected\\n"); + step = e_wait_connected; + } + break; + + + case e_start_normal: + Serial.printf(SEP "CRC NOT valid, begin/WIFI_STA (current mode = %d)\n", wifi_get_opmode()); + startup = millis(); + if (!TEST(WiFi.mode(WIFI_STA)) || !TEST(WiFi.begin(STASSID, STAPSK))) { + Serial.printf(SEP "issue setting up STA\n"); + step = e_off_restart; + } else { + Serial.printf(SEP "waiting for connected\n"); + step = e_wait_connected; + } + break; + + + case e_wait_connected: + if (WiFi.status() == WL_CONNECTED) { + Serial.printf(SEP "connected! ---- startup time: %ld ms ----\n\n\n", millis() - startup); + wifi_timeout = 0; + if (WAIT_NTP) { + step = e_wait_ntp; + Serial.printf(SEP "wait for NTP\n"); + } else { + step = e_shutdown; + } + } else if ((millis() - startup > 10000)) { + Serial.printf(SEP "connected TIMEOUT! status=%d\n", WiFi.status()); + wifi_timeout++; + step = e_off_restart; + } + break; + + + case e_off_restart: + Serial.printf(SEP "OFF -> wait 2s\n"); + (void)TEST(WiFi.mode(WIFI_OFF)); + delay(2000); // test - mad wifi loop until :oom if delay not there - to verify + step = e_initial; + break; + + + case e_wait_ntp: + // check when NTP has set time + if (time_is_set) { + Serial.printf(SEP "NTP is set\n"); + time_is_set = false; + step = e_shutdown; + } + break; + + + case e_shutdown: { + static int deepsleep = 0; + switch (++deepsleep) { + case 1: { + Serial.println(SEP "WIFI_OFF for 5s"); + TEST(WiFi.mode(WIFI_OFF)); + step = e_wait_off; + break; + } + case 2: // several loop on shutdown + case 3: // to check if it affects + case 4: { // reconnection duration + Serial.println(SEP "WIFI_SHUTDOWN for 5s"); + TEST(WiFi.mode(WIFI_SHUTDOWN, &nv->wss)); + step = e_wait_shutdown; + break; + } + default: { + Serial.println(SEP "DEEPSLEEP for 5s (bind GPIO16 <=> RST)"); + TEST(WiFi.mode(WIFI_SHUTDOWN, &nv->wss)); + Serial.flush(); + ESP.deepSleep(5000000); + // will reboot, GPIO16 must be connected to reset + } + } + + startup = millis(); + break; + } + + + case e_wait_shutdown: + if (millis() - startup > 5000) { + step = e_start_resume; + } + break; + + + case e_wait_off: + if (millis() - startup > 5000) { + step = e_start_normal; + } + break; + } +} diff --git a/tests/host/Makefile b/tests/host/Makefile index 3768c11b5e..aaf8a88d91 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -69,6 +69,7 @@ CORE_CPP_FILES := $(addprefix $(CORE_PATH)/,\ libb64/cdecode.cpp \ Schedule.cpp \ HardwareSerial.cpp \ + crc32.cpp \ ) \ $(addprefix $(LIBRARIES_PATH)/ESP8266SdFat/src/, \ FatLib/FatFile.cpp \ diff --git a/tests/host/common/MocklwIP.cpp b/tests/host/common/MocklwIP.cpp index a4b9bbcad4..52e13473b9 100644 --- a/tests/host/common/MocklwIP.cpp +++ b/tests/host/common/MocklwIP.cpp @@ -12,4 +12,13 @@ err_t dhcp_renew(struct netif *netif) return ERR_OK; } +void sntp_setserver(u8_t, const ip_addr_t) +{ +} + +const ip_addr_t* sntp_getserver(u8_t) +{ + return IP_ADDR_ANY; +} + } // extern "C" diff --git a/tests/host/common/user_interface.cpp b/tests/host/common/user_interface.cpp index ceba51de73..2a999e3c31 100644 --- a/tests/host/common/user_interface.cpp +++ b/tests/host/common/user_interface.cpp @@ -461,7 +461,9 @@ bool smartconfig_stop (void) return true; } - - +sleep_type_t wifi_fpm_get_sleep_type(void) +{ + return NONE_SLEEP_T; +} } // extern "C"