1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Experimental: add new WiFi (pseudo) modes: WIFI_SHUTDOWN & WIFI_RESUME (#6356)

* add new WiFimodes: WIFI_SHUTDOWN & WIFI_RESUME with example
* restore WiFi.onWiFiModeChange()
This commit is contained in:
david gauchard 2019-09-05 03:01:01 +02:00 committed by GitHub
parent db460388cd
commit 273f4000f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 568 additions and 63 deletions

View File

@ -21,36 +21,15 @@
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include "coredecls.h"
#include "eboot_command.h" #include "eboot_command.h"
extern "C" { 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;
}
static uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd) static uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd)
{ {
return crc_update(0xffffffff, (const uint8_t*) cmd, return crc32((const uint8_t*) cmd, offsetof(struct eboot_command, crc32));
offsetof(struct eboot_command, crc32));
} }
int eboot_command_read(struct eboot_command* cmd) int eboot_command_read(struct eboot_command* cmd)

View File

@ -8,6 +8,7 @@ extern "C" {
// TODO: put declarations here, get rid of -Wno-implicit-function-declaration // TODO: put declarations here, get rid of -Wno-implicit-function-declaration
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <cont.h> // g_pcont declaration #include <cont.h> // g_pcont declaration
@ -20,6 +21,7 @@ void settimeofday_cb (void (*cb)(void));
void disable_extra4k_at_link_time (void) __attribute__((noinline)); void disable_extra4k_at_link_time (void) __attribute__((noinline));
uint32_t sqrt32 (uint32_t n); uint32_t sqrt32 (uint32_t n);
uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff);
#ifdef __cplusplus #ifdef __cplusplus
} }

42
cores/esp8266/crc32.cpp Normal file
View File

@ -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;
}

View File

@ -24,6 +24,7 @@
#include <list> #include <list>
#include <string.h> #include <string.h>
#include <coredecls.h>
#include "ESP8266WiFi.h" #include "ESP8266WiFi.h"
#include "ESP8266WiFiGeneric.h" #include "ESP8266WiFiGeneric.h"
@ -38,12 +39,19 @@ extern "C" {
#include "lwip/opt.h" #include "lwip/opt.h"
#include "lwip/err.h" #include "lwip/err.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "lwip/dhcp.h"
#include "lwip/init.h" // LWIP_VERSION_ #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 "WiFiClient.h"
#include "WiFiUdp.h" #include "WiFiUdp.h"
#include "debug.h" #include "debug.h"
#include "include/WiFiState.h"
extern "C" void esp_schedule(); extern "C" void esp_schedule();
extern "C" void esp_yield(); extern "C" void esp_yield();
@ -200,15 +208,15 @@ WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeProbeRequestReceived(std::
return handler; return handler;
} }
// WiFiEventHandler ESP8266WiFiGenericClass::onWiFiModeChange(std::function<void(const WiFiEventModeChange&)> f) WiFiEventHandler ESP8266WiFiGenericClass::onWiFiModeChange(std::function<void(const WiFiEventModeChange&)> f)
// { {
// WiFiEventHandler handler = std::make_shared<WiFiEventHandlerOpaque>(WIFI_EVENT_MODE_CHANGE, [f](System_Event_t* e){ WiFiEventHandler handler = std::make_shared<WiFiEventHandlerOpaque>(WIFI_EVENT_MODE_CHANGE, [f](System_Event_t* e){
// WiFiEventModeChange& dst = *reinterpret_cast<WiFiEventModeChange*>(&e->event_info); WiFiEventModeChange& dst = *reinterpret_cast<WiFiEventModeChange*>(&e->event_info);
// f(dst); f(dst);
// }); });
// sCbEventList.push_back(handler); sCbEventList.push_back(handler);
// return handler; return handler;
// } }
/** /**
* callback for WiFi events * callback for WiFi events
@ -386,7 +394,29 @@ bool ESP8266WiFiGenericClass::getPersistent(){
* set new mode * set new mode
* @param m WiFiMode_t * @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(_persistent){
if(wifi_get_opmode() == (uint8) m && wifi_get_opmode_default() == (uint8) m){ if(wifi_get_opmode() == (uint8) m && wifi_get_opmode_default() == (uint8) m){
return true; return true;
@ -396,12 +426,6 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
} }
bool ret = false; 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(); ETS_UART_INTR_DISABLE();
if(_persistent) { if(_persistent) {
ret = wifi_set_opmode(m); ret = wifi_set_opmode(m);
@ -431,15 +455,13 @@ bool ESP8266WiFiGenericClass::enableSTA(bool enable) {
WiFiMode_t currentMode = getMode(); WiFiMode_t currentMode = getMode();
bool isEnabled = ((currentMode & WIFI_STA) != 0); bool isEnabled = ((currentMode & WIFI_STA) != 0);
if(isEnabled != enable) { if (isEnabled == enable)
if(enable) {
return mode((WiFiMode_t)(currentMode | WIFI_STA));
} else {
return mode((WiFiMode_t)(currentMode & (~WIFI_STA)));
}
} else {
return true; 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) { bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) {
_forceSleepLastMode = getMode(); _forceSleepLastMode = getMode();
if(!mode(WIFI_OFF)) { if(!mode(WIFI_OFF)) {
DEBUG_WIFI("core: error with mode(WIFI_OFF)\n");
return false; return false;
} }
if(sleepUs == 0) { if(sleepUs == 0 || sleepUs > 0xFFFFFFF) {
sleepUs = 0xFFFFFFF; sleepUs = 0xFFFFFFF;
} }
wifi_fpm_set_sleep_type(MODEM_SLEEP_T); wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
delay(0);
wifi_fpm_open(); 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 * @return ok
*/ */
bool ESP8266WiFiGenericClass::forceSleepWake() { bool ESP8266WiFiGenericClass::forceSleepWake() {
if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) {
wifi_fpm_do_wakeup(); wifi_fpm_do_wakeup();
wifi_fpm_close(); wifi_fpm_close();
}
// restore last mode // restore last mode
if(mode(_forceSleepLastMode)) { 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 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 () { void ESP8266WiFiGenericClass::preinitWiFiOff () {
// https://github.com/esp8266/Arduino/issues/2111#issuecomment-224251391 // https://github.com/esp8266/Arduino/issues/2111#issuecomment-224251391
// WiFi.persistent(false); // WiFi.persistent(false);

View File

@ -42,6 +42,8 @@ typedef std::shared_ptr<WiFiEventHandlerOpaque> WiFiEventHandler;
typedef void (*WiFiEventCb)(WiFiEvent_t); typedef void (*WiFiEventCb)(WiFiEvent_t);
struct WiFiState;
class ESP8266WiFiGenericClass { class ESP8266WiFiGenericClass {
// ---------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------
// -------------------------------------- Generic WiFi function --------------------------------- // -------------------------------------- Generic WiFi function ---------------------------------
@ -62,7 +64,7 @@ class ESP8266WiFiGenericClass {
WiFiEventHandler onSoftAPModeStationConnected(std::function<void(const WiFiEventSoftAPModeStationConnected&)>); WiFiEventHandler onSoftAPModeStationConnected(std::function<void(const WiFiEventSoftAPModeStationConnected&)>);
WiFiEventHandler onSoftAPModeStationDisconnected(std::function<void(const WiFiEventSoftAPModeStationDisconnected&)>); WiFiEventHandler onSoftAPModeStationDisconnected(std::function<void(const WiFiEventSoftAPModeStationDisconnected&)>);
WiFiEventHandler onSoftAPModeProbeRequestReceived(std::function<void(const WiFiEventSoftAPModeProbeRequestReceived&)>); WiFiEventHandler onSoftAPModeProbeRequestReceived(std::function<void(const WiFiEventSoftAPModeProbeRequestReceived&)>);
// WiFiEventHandler onWiFiModeChange(std::function<void(const WiFiEventModeChange&)>); WiFiEventHandler onWiFiModeChange(std::function<void(const WiFiEventModeChange&)>);
int32_t channel(void); int32_t channel(void);
@ -79,7 +81,7 @@ class ESP8266WiFiGenericClass {
void persistent(bool persistent); void persistent(bool persistent);
bool mode(WiFiMode_t); bool mode(WiFiMode_t, WiFiState* state = nullptr);
WiFiMode_t getMode(); WiFiMode_t getMode();
bool enableSTA(bool enable); bool enableSTA(bool enable);
@ -88,6 +90,8 @@ class ESP8266WiFiGenericClass {
bool forceSleepBegin(uint32 sleepUs = 0); bool forceSleepBegin(uint32 sleepUs = 0);
bool forceSleepWake(); 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() static void preinitWiFiOff (); //meant to be called in user-defined preinit()
protected: protected:
@ -96,17 +100,22 @@ class ESP8266WiFiGenericClass {
static void _eventCallback(void *event); 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 -------------------------------- // ------------------------------------ Generic Network function --------------------------------
// ---------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------
public: public:
int hostByName(const char* aHostname, IPAddress& aResult); int hostByName(const char* aHostname, IPAddress& aResult);
int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms); int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms);
bool getPersistent(); bool getPersistent();
protected:
protected:
friend class ESP8266WiFiSTAClass; friend class ESP8266WiFiSTAClass;
friend class ESP8266WiFiScanClass; friend class ESP8266WiFiScanClass;
friend class ESP8266WiFiAPClass; friend class ESP8266WiFiAPClass;

View File

@ -369,18 +369,24 @@ bool ESP8266WiFiSTAClass::reconnect() {
* @return one value of wl_status_t enum * @return one value of wl_status_t enum
*/ */
bool ESP8266WiFiSTAClass::disconnect(bool wifioff) { bool ESP8266WiFiSTAClass::disconnect(bool wifioff) {
bool ret; bool ret = false;
struct station_config conf; struct station_config conf;
*conf.ssid = 0; *conf.ssid = 0;
*conf.password = 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(); ETS_UART_INTR_DISABLE();
if(WiFi._persistent) { if(WiFi._persistent) {
wifi_station_set_config(&conf); wifi_station_set_config(&conf);
} else { } else {
wifi_station_set_config_current(&conf); wifi_station_set_config_current(&conf);
} }
ret = wifi_station_disconnect();
ETS_UART_INTR_ENABLE(); ETS_UART_INTR_ENABLE();
if(wifioff) { if(wifioff) {

View File

@ -34,7 +34,8 @@
typedef enum WiFiMode 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; } WiFiMode_t;
typedef enum WiFiPhyMode typedef enum WiFiPhyMode
@ -58,9 +59,10 @@ typedef enum WiFiEvent
WIFI_EVENT_SOFTAPMODE_STACONNECTED, WIFI_EVENT_SOFTAPMODE_STACONNECTED,
WIFI_EVENT_SOFTAPMODE_STADISCONNECTED, WIFI_EVENT_SOFTAPMODE_STADISCONNECTED,
WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED, WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED,
WIFI_EVENT_MODE_CHANGE,
WIFI_EVENT_SOFTAPMODE_DISTRIBUTE_STA_IP,
WIFI_EVENT_MAX, WIFI_EVENT_MAX,
WIFI_EVENT_ANY = WIFI_EVENT_MAX, WIFI_EVENT_ANY = WIFI_EVENT_MAX,
WIFI_EVENT_MODE_CHANGE
} WiFiEvent_t; } WiFiEvent_t;
enum WiFiDisconnectReason enum WiFiDisconnectReason

View File

@ -0,0 +1,23 @@
#ifndef WIFISTATE_H_
#define WIFISTATE_H_
#include <user_interface.h>
#include <ESP8266WiFiType.h>
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_

View File

@ -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 <ESP8266WiFi.h>
#include <coredecls.h> // crc32()
#include <include/WiFiState.h> // 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;
}
}

View File

@ -69,6 +69,7 @@ CORE_CPP_FILES := $(addprefix $(CORE_PATH)/,\
libb64/cdecode.cpp \ libb64/cdecode.cpp \
Schedule.cpp \ Schedule.cpp \
HardwareSerial.cpp \ HardwareSerial.cpp \
crc32.cpp \
) \ ) \
$(addprefix $(LIBRARIES_PATH)/ESP8266SdFat/src/, \ $(addprefix $(LIBRARIES_PATH)/ESP8266SdFat/src/, \
FatLib/FatFile.cpp \ FatLib/FatFile.cpp \

View File

@ -12,4 +12,13 @@ err_t dhcp_renew(struct netif *netif)
return ERR_OK; 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" } // extern "C"

View File

@ -461,7 +461,9 @@ bool smartconfig_stop (void)
return true; return true;
} }
sleep_type_t wifi_fpm_get_sleep_type(void)
{
return NONE_SLEEP_T;
}
} // extern "C" } // extern "C"