8000 Merge branch 'wifioff' into testall · dok-net/arduino-esp8266@27a033d · GitHub
[go: up one dir, main page]

Skip to content

Commit 27a033d

Browse files
committed
Merge branch 'wifioff' into testall
# Conflicts: # cores/esp8266/Esp.cpp # cores/esp8266/Esp.h # libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
2 parents 90c82ae + e8cab42 commit 27a033d

File tree

16 files changed

+571
-74
lines changed

16 files changed

+571
-74
lines changed

cores/esp8266/Esp.cpp

Lines changed: 166 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,16 @@ void EspClass::wdtFeed(void)
115115
system_soft_wdt_feed();
116116
}
117117

118-
void EspClass::deepSleep(uint64_t time_us, WakeMode mode)
118+
void EspClass::deepSleep(uint64_t time_us)
119119
{
120-
system_deep_sleep_set_option(static_cast<int>(mode));
120+
system_deep_sleep_set_option(__get_rf_mode());
121121
system_deep_sleep(time_us);
122122
esp_suspend();
123123
}
124124

125-
void EspClass::deepSleepInstant(uint64_t time_us, WakeMode mode)
125+
void EspClass::deepSleepInstant(uint64_t time_us)
126126
{
127-
system_deep_sleep_set_option(static_cast<int>(mode));
127+
system_deep_sleep_set_option(__get_rf_mode());
128128
system_deep_sleep_instant(time_us);
129129
esp_suspend();
130130
}
@@ -138,6 +138,168 @@ uint64_t EspClass::deepSleepMax()
138138

139139
}
140140

141+
extern os_timer_t* timer_list;
142+
namespace {
143+
sleep_type_t saved_sleep_type = NONE_SLEEP_T;
144+
os_timer_t* saved_timer_list = nullptr;
145+
fpm_wakeup_cb saved_wakeupCb = nullptr;
146+
}
147+
148+
bool EspClass::forcedModemSleep(uint32_t duration_us, fpm_wakeup_cb wakeupCb)
149+
{
150+
// Setting duration to 0xFFFFFFF, it disconnects the RTC timer
151+
if (!duration_us || duration_us > 0xFFFFFFF) {
152+
duration_us = 0xFFFFFFF;
153+
}
154+
wifi_fpm_close();
155+
saved_sleep_type = wifi_fpm_get_sleep_type();
156+
wifi_set_opmode(NULL_MODE);
157+
wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
158+
wifi_fpm_open();
159+
saved_wakeupCb = nullptr;
160+
if (wakeupCb) wifi_fpm_set_wakeup_cb(wakeupCb);
161+
auto ret_do_sleep = wifi_fpm_do_sleep(duration_us);
162+
if (ret_do_sleep != 0)
163+
{
164+
#ifdef DEBUG_SERIAL
165+
DEBUG_SERIAL.printf("core: error %d with wifi_fpm_do_sleep: (-1=sleep status error, -2=force sleep not enabled)\n", ret_do_sleep);
166+
#endif
167+
return false;
168+
}
169+
// SDK turns on forced modem sleep in idle task
170+
#ifdef HAVE_ESP_SUSPEND
171+
esp_delay(10);
172+
#else
173+
delay(10);
174+
#endif
175+
return true;
176+
}
177+
178+
void EspClass::forcedModemSleepOff()
179+
{
180+
const sleep_type_t sleepType = wifi_fpm_get_sleep_type();
181+
if (sleepType != NONE_SLEEP_T) {
182+
if (sleepType == MODEM_SLEEP_T) wifi_fpm_do_wakeup();
183+
wifi_fpm_close();
184+
}
185+
wifi_fpm_set_sleep_type(saved_sleep_type);
186+
saved_sleep_type = NONE_SLEEP_T;
187+
}
188+
189+
#ifdef DEBUG_SERIAL
190+
namespace {
191+
void walk_timer_list() {
192+
os_timer_t* timer_root;
193+
{
194+
esp8266::InterruptLock lock;
195+
auto src = timer_list;
196+
auto dest = src ? new os_timer_t : nullptr;
197+
timer_root = dest;
198+
while (dest) {
199+
*dest = *src;
200+
src = src->timer_next;
201+
dest->timer_next = src ? new os_timer_t(*timer_list) : nullptr;
202+
dest = dest->timer_next;
203+
}
204+
}
205+
DEBUG_SERIAL.printf("=============\n");
206+
for (os_timer_t* timer_node = timer_root; nullptr != timer_node; timer_node = timer_node->timer_next) {
207+
DEBUG_SERIAL.printf("timer_address = %p\n", timer_node);
208+
DEBUG_SERIAL.printf("timer_expire = %u\n", timer_node->timer_expire);
209+
DEBUG_SERIAL.printf("timer_period = %u\n", timer_node->timer_period);
210+
DEBUG_SERIAL.printf("timer_func = %p\n", timer_node->timer_func);
211+
DEBUG_SERIAL.printf("timer_next = %p\n", timer_node->timer_next);
212+
if (timer_node->timer_next) DEBUG_SERIAL.printf("=============\n");
213+
}
214+
DEBUG_SERIAL.printf("=============\n");
215+
DEBUG_SERIAL.flush();
216+
while (timer_root) {
217+
auto next = timer_root->timer_next;
218+
delete timer_root;
219+
timer_root = next;
220+
}
221+
}
222+
}
223+
#endif
224+
225+
bool EspClass::forcedLightSleepBegin(uint32_t duration_us, fpm_wakeup_cb wakeupCb)
226+
{
227+
// Setting duration to 0xFFFFFFF, it disconnects the RTC timer
228+
if (!duration_us || duration_us > 0xFFFFFFF) {
229+
duration_us = 0xFFFFFFF;
230+
}
231+
wifi_fpm_close();
232+
saved_sleep_type = wifi_fpm_get_sleep_type();
233+
wifi_set_opmode(NULL_MODE);
234+
wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);
235+
wifi_fpm_open();
236+
saved_wakeupCb = wakeupCb;
237+
wifi_fpm_set_wakeup_cb([]() {
238+
if (saved_wakeupCb) {
239+
saved_wakeupCb();
240+
saved_wakeupCb = nullptr;
241+
}
242+
esp_schedule();
243+
});
244+
#ifdef DEBUG_SERIAL
245+
walk_timer_list();
246+
#endif
247+
{
248+
esp8266::InterruptLock lock;
249+
saved_timer_list = timer_list;
250+
timer_list = nullptr;
251+
}
252+
return wifi_fpm_do_sleep(duration_us) == 0;
253+
}
254+
255+
void EspClass::forcedLightSleepEnd(bool cancel)
256+
{
257+
if (!cancel) {
258+
// SDK turns on forced light sleep in idle task
259+
#ifdef HAVE_ESP_SUSPEND
260+
esp_suspend();
261+
#else
262+
esp_yield();
263+
#endif
264+
}
265+
#ifdef DEBUG_SERIAL
266+
walk_timer_list();
267+
#endif
268+
{
269+
esp8266::InterruptLock lock;
270+
timer_list = saved_timer_list;
271+
}
272+
saved_wakeupCb = nullptr;
273+
wifi_fpm_close();
274+
wifi_fpm_set_sleep_type(saved_sleep_type);
275+
saved_sleep_type = NONE_SLEEP_T;
276+
if (cancel) {
277+
// let the SDK catch up in idle task
278+
#ifdef HAVE_ESP_SUSPEND
279+
esp_delay(10);
280+
#else
281+
delay(10);
282+
#endif
283+
}
284+
}
285+
286+
void EspClass::autoModemSleep() {
287+
wifi_fpm_close();
288+
saved_sleep_type = wifi_get_sleep_type();
289+
wifi_set_sleep_type(MODEM_SLEEP_T);
290+
}
291+
292+
void EspClass::autoLightSleep() {
293+
wifi_fpm_close();
294+
saved_sleep_type = wifi_get_sleep_type();
295+
wifi_set_sleep_type(LIGHT_SLEEP_T);
296+
}
297+
298+
void EspClass::autoSleepOff() {
299+
wifi_set_sleep_type(saved_sleep_type);
300+
saved_sleep_type = NONE_SLEEP_T;
301+
}
302+
141303
/*
142304
Layout of RTC Memory is as follows:
143305
Ref: Espressif doc 2C-ESP8266_Non_OS_SDK_API_Reference, section 3.3.23 (system_rtc_mem_write)

cores/esp8266/Esp.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,6 @@ enum RFMode {
5757
RF_DISABLED = 4 // disable RF after deep-sleep wake up, just like modem sleep, there will be the smallest current.
5858
};
5959

60-
#define RF_MODE(mode) int __get_rf_mode() { return mode; }
61-
#define RF_PRE_INIT() void __run_user_rf_pre_init()
62-
6360
// compatibility definitions
6461
#define WakeMode RFMode
6562
#define WAKE_RF_DEFAULT RF_DEFAULT
@@ -94,10 +91,29 @@ class EspClass {
9491
static void wdtDisable();
9592
static void wdtFeed();
9693

97-
static void deepSleep(uint64_t time_us, RFMode mode = RF_DEFAULT);
98-
static void deepSleepInstant(uint64_t time_us, RFMode mode = RF_DEFAULT);
94+
static void deepSleep(uint64_t time_us);
95+
static void deepSleepInstant(uint64_t time_us);
9996
static uint64_t deepSleepMax();
10097

98+
static bool forcedModemSleep(uint32_t duration_us = 0, void (*wakeupCb)() = nullptr);
99+
/// The prior sleep type is restored, but only as automatic.
100+
/// If any forced sleep mode was effective before forcedModemSleep,
101+
/// it would have to be restored explicitly.
102+
static void forcedModemSleepOff();
103+
104+
static bool forcedLightSleepBegin(uint32_t duration_us = 0, void (*wakeupCb)() = nullptr);
105+
/// The prior sleep type is restored, but only as automatic.
106+
/// If any forced sleep mode was effective before forcedLightSleepBegin,
107+
/// it would have to be restored explicitly.
108+
static void forcedLightSleepEnd(bool cancel = false);
109+
110+
static void autoModemSleep();
111+
static void autoLightSleep();
112+
/// The prior sleep type is restored, but only as automatic.
113+
/// If any forced sleep mode was effective before auto{Modem,Light}Sleep,
114+
/// it would have to be restored explicitly.
115+
static void autoSleepOff();
116+
101117
static bool rtcUserMemoryRead(uint32_t offset, uint32_t *data, size_t size);
102118
static bool rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t size);
103119

cores/esp8266/core_esp8266_main.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,10 +387,7 @@ extern "C" void __disableWiFiAtBootTime (void)
387387
{
388388
// Starting from arduino core v3: wifi is disabled at boot time
389389
// WiFi.begin() or WiFi.softAP() will wake WiFi up
390-
wifi_set_opmode_current(0/*WIFI_OFF*/);
391-
wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
392-
wifi_fpm_open();
393-
wifi_fpm_do_sleep(0xFFFFFFF);
390+
ESP.forcedModemSleep();
394391
}
395392

396393
extern "C" void user_init(void) {

cores/esp8266/core_esp8266_phy.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "ets_sys.h"
2828
#include "spi_flash.h"
2929
#include "user_interface.h"
30+
#include "coredecls.h"
3031

3132
extern "C" {
3233

@@ -288,20 +289,10 @@ static const uint8_t ICACHE_FLASH_ATTR phy_init_data[128] =
288289
/*[114] =*/ 1
289290
};
290291

291-
292-
// These functions will be overriden from C++ code.
293-
// Unfortunately, we can't use extern "C" because Arduino preprocessor
294-
// doesn't generate forward declarations for extern "C" functions correctly,
295-
// so we use mangled names here.
296-
#define __get_adc_mode _Z14__get_adc_modev
297-
#define __get_rf_mode _Z13__get_rf_modev
298-
#define __run_user_rf_pre_init _Z22__run_user_rf_pre_initv
299-
300292
static bool spoof_init_data = false;
301293

302294
extern int __real_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size);
303295
extern int IRAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size);
304-
extern int __get_adc_mode();
305296

306297
extern int IRAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size)
307298
{
@@ -314,19 +305,43 @@ extern int IRAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t
314305
return 0;
315306
}
316307

317-
extern int __get_rf_mode(void) __attribute__((weak));
308+
extern int __get_rf_disable_mode(void) __attribute__((noinline, weak));
309+
extern int __get_rf_disable_mode(void)
310+
{
311+
// Starting from arduino core v3: wifi is disabled at boot time
312+
// mode == 4: Disable RF after deep-sleep wake up, just like modem sleep; this has the least current
313+
// consumption; the device is not able to transmit or receive data after wake up.
314+
return 4;
315+
}
316+
317+
extern int __get_rf_powerup_disable_mode(void) __attribute__((noinline, weak));
318+
extern int __get_rf_powerup_disable_mode(void)
319+
{
320+
// Starting from arduino core v3: wifi is disabled at boot time
321+
// mode == 2: RF initialization only calibrates VDD33 which will take about 2 ms;
322+
// this has the least current consumption.
323+
return 2;
324+
}
325+
326+
extern int __get_rf_mode(void) __attribute__((noinline, weak));
318327
extern int __get_rf_mode(void)
319328
{
320-
return -1; // mode not set
329+
return __get_rf_disable_mode();
330+
}
331+
332+
extern int __get_rf_powerup_mode(void) __attribute__((noinline, weak));
333+
extern int __get_rf_powerup_mode(void)
334+
{
335+
return __get_rf_powerup_disable_mode();
321336
}
322337

323-
extern int __get_adc_mode(void) __attribute__((weak));
338+
extern int __get_adc_mode(void) __attribute__((noinline, weak));
324339
extern int __get_adc_mode(void)
325340
{
326341
return 33; // default ADC mode
327342
}
328343

329-
extern void __run_user_rf_pre_init(void) __attribute__((weak));
344+
extern void __run_user_rf_pre_init(void) __attribute__((noinline, weak));
330345
extern void __run_user_rf_pre_init(void)
331346
{
332347
return; // default do noting
@@ -350,6 +365,10 @@ void user_rf_pre_init()
350365
if (rf_mode >= 0) {
351366
system_phy_set_rfoption(rf_mode);
352367
}
368+
rf_mode = __get_rf_powerup_mode();
369+
if (rf_mode >= 0) {
370+
system_phy_set_powerup_option(rf_mode);
371+
}
353372
__run_user_rf_pre_init();
354373
}
355374

cores/esp8266/coredecls.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ void disable_extra4k_at_link_time (void) __attribute__((noinline));
2424
bool sntp_set_timezone_in_seconds(int32_t timezone);
2525
void __disableWiFiAtBootTime (void) __attribute__((noinline));
2626
void __real_system_restart_local() __attribute__((noreturn));
27+
int __get_adc_mode();
28+
int __get_rf_mode();
29+
int __get_rf_powerup_mode();
30+
void __run_user_rf_pre_init();
2731

2832
uint32_t sqrt32 (uint32_t n);
2933
uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff);

doc/libraries.rst

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,26 @@ An ESP8266 port of SoftwareSerial library done by Peter Lerup (@plerup) supports
7171
ESP-specific APIs
7272
-----------------
7373

74-
Some ESP-specific APIs related to deep sleep, RTC and flash memories are available in the ``ESP`` object.
74+
Some ESP-specific APIs related to the deep, modem, and light sleep modes, RTC and flash memory are available in the ``ESP`` object.
7575

7676
``ESP.deepSleep(microseconds, mode)`` will put the chip into deep sleep. ``mode`` is one of ``WAKE_RF_DEFAULT``, ``WAKE_RFCAL``, ``WAKE_NO_RFCAL``, ``WAKE_RF_DISABLED``. (GPIO16 needs to be tied to RST to wake from deepSleep.) The chip can sleep for at most ``ESP.deepSleepMax()`` microseconds. If you implement deep sleep with ``WAKE_RF_DISABLED`` and require WiFi functionality on wake up, you will need to implement an additional ``WAKE_RF_DEFAULT`` before WiFi functionality is available.
7777

7878
``ESP.deepSleepInstant(microseconds, mode)`` works similarly to ``ESP.deepSleep`` but sleeps instantly without waiting for WiFi to shutdown.
7979

80+
``ESP.forcedModemSleep(microseconds, callback)`` immediately puts the chip into forced ``MODEM_SLEEP``. A microseconds duration after which the sleep mode returns to the automatic sleep mode that was effective before this call can be given, a value of 0 or 0xFFFFFFF turns off that timeout. The optional callback function will be invoked when the forced modem sleep ends.
81+
82+
``ESP.forcedModemSleepOff()`` immediately returns the chip to the automatic sleep mode in effect before the preceeding call to ``ESP.forcedModemSleep``.
83+
84+
``ESP.forcedLightSleepBegin(microseconds, callback)`` works in tandem with ``ESP.forcedLightSleepEnd(cancel)`` to put the chip into forced ``LIGHT_SLEEP``. A microseconds duration after which the sleep mode returns can be given, a value of 0 or 0xFFFFFFF turns off that timeout. The optional callback function will be invoked when the forced light sleep ends. Forced light sleep halts the CPU, in addition to the timeout, it can be awakened via GPIO input. Between the calls to ``ESP.forcedLightSleepBegin`` and ``ESP.forcedLightSleepEnd`` any GPIOs except GPIO16 to use for wakeup can be set up. Care must be taken not to allow the chip to enter the idle task before the call to ``ESP.forcedLightSleepEnd(cancel)``, so for instance no direct or indirect calls to ``delay()`` are possible. Otherwise the forced light sleep may engange too early, breaking the required logic of the tandem calls.
85+
86+
``ESP.forcedLightSleepEnd(cancel)`` causes the chip to enter the forced light sleep mode that was prepared by the preceeding ``ESP.forcedLightSleepBegin``. The optional cancel argument, if true, prevents the sleep mode transition from occuring. This can be used, for instance, to return immediately if setting up the level-triggered GPIO interrupts for wakeup fails. Otherwise, it returns after waking up from forced light sleep. On return, the automatic sleep mode that was effective before the call to ``ESP.forcedLightSleepBegin`` is activated.
87+
88+
``ESP.autoModemSleep()`` immediately puts the chip into automatic ``MODEM_SLEEP``.
89+
90+
``ESP.autoLightSleep()`` immediately puts the chip into automatic ``LIGHT_SLEEP``.
91+
92+
``ESP.autoSleepOff()`` returns the chip to the automatic sleep mode that was effective before the preceding call to either ``ESP.autoModemSleep`` or ``ESP.autoLightSleep``.
93+
8094
``ESP.rtcUserMemoryWrite(offset, &data, sizeof(data))`` and ``ESP.rtcUserMemoryRead(offset, &data, sizeof(data))`` allow data to be stored in and retrieved from the RTC user memory of the chip respectively. ``offset`` is measured in blocks of 4 bytes and can range from 0 to 127 blocks (total size of RTC memory is 512 bytes). ``data`` should be 4-byte aligned. The stored data can be retained between deep sleep cycles, but might be lost after power cycling the chip. Data stored in the first 32 blocks will be lost after performing an OTA update, because they are used by the Core internals.
8195

8296
``ESP.restart()`` restarts the CPU.

libraries/ESP8266WiFi/examples/WiFiShutdown/WiFiShutdown.ino

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void setup() {
5050
WiFi.mode(WIFI_OFF);
5151
Serial.println("Cannot connect!");
5252
Serial.flush();
53-
ESP.deepSleep(10e6, RF_DISABLED);
53+
ESP.deepSleep(10e6);
5454
return;
5555
}
5656
}
@@ -72,9 +72,9 @@ void setup() {
7272

7373
Serial.println("Done.");
7474
Serial.flush();
75-
ESP.deepSleep(10e6, RF_DISABLED);
75+
ESP.deepSleep(10e6);
7676
}
7777

7878
void loop() {
7979
// Nothing to do here.
80-
}
80+
}

0 commit comments

Comments
 (0)
0