8000 Extending on the new WiFi-less startup and new power saving APIs in ESP class by dok-net · Pull Request #7979 · esp8266/Arduino · GitHub
[go: up one dir, main page]

Skip to content

Extending on the new WiFi-less startup and new power saving APIs in ESP class #7979

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 44 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
810fed9
WiFi is off by default anyway.
dok-net Apr 13, 2021
a1ceef3
Set deep sleep resume and powerup RF modes to OFF.
dok-net Apr 15, 2021
9538ef9
Implement forced light sleep in Esp class
dok-net Apr 15, 2021
1ecdfc1
Add low power forced light sleep demo.
dok-net Apr 15, 2021
ef2bc95
Implement auto light sleep and auto modem sleep in Esp class
dok-net Apr 15, 2021
9891613
Add auto sleep mode demo.
dok-net Apr 15, 2021
ea94626
Refactoring MODEM forced sleep code from ESP8266WiFi to core ESP class.
dok-net Apr 16, 2021
7137d0f
Add new Esp class member functions to host test MockEsp.cpp
dok-net Apr 16, 2021
7fea539
API refactoring.
dok-net Apr 16, 2021
446aea7
Missed that there are different functions for auto and force sleep ty…
dok-net Apr 17, 2021
6a07829
DRY
dok-net Apr 17, 2021
49c2ac0
enable callback in forced light sleep example
dok-net Apr 17, 2021
e7864f1
instead of crude manual mangling and no prototypes, put the weak symb…
dok-net Apr 17, 2021
79a7ee8
Example for a forced modem sleep with timeout and callback.
dok-net Apr 18, 2021
788731e
Save 9ms for force MODEM sleep activation.
dok-net Apr 18, 2021
433cd17
Add timer_list debug dump to forced light sleep
dok-net Apr 19, 2021
24efea2
Auto light sleep is all about WiFi and requires a connection to an AP
dok-net Apr 22, 2021
83e70ee
Some comments from memory of what testing revealed. Independent verif…
dok-net Apr 24, 2021
c0326f0
Copyright notices and clarifying introductory comments in example code.
dok-net Apr 25, 2021
7c4879f
Increase delay time to let example actually show measurable times in …
dok-net Apr 25, 2021
01eb942
Remove unintended copy&paste artifact.
dok-net Apr 25, 2021
382f6fd
Reset ISR to edge triggered mode when back from sleep via timeout ins…
dok-net Apr 25, 2021
213a2e0
AttachInterrupt is not available in ISR (IRAM_ATTR), fix crash on stu…
dok-net Apr 25, 2021
56c40f3
SDK needs idle task to perform mode switching. Reset the callback poi…
dok-net Apr 25, 2021
affc7fc
Fix serial bitrate in example.
dok-net Apr 25, 2021
6015cec
Debounce the button GPIO in order to prevent crashes due to IRQ storms.
dok-net Apr 25, 2021
b6e14f6
Add documentation for the new ESP sleep modes to libraries.rst
dok-net Apr 26, 2021
ad454ea
Fix headline in documentation as well.
dok-net Apr 26, 2021
74951fd
By review comment.
dok-net Apr 26, 2021
0a70272
ESP.deepSleep[Instant] refactoring to match the setting of RF mode in…
dok-net Apr 27, 2021
df7e909
More comprehensive description of the usage of forcedLightSleep.
dok-net Apr 28, 2021
1af1380
Be more specific about ForcedLightSleepEnd.
dok-net Apr 28, 2021
a9d9cda
Describe forced light sleep initiation in more detail.
dok-net Apr 28, 2021
e8798ac
Add neverSleep and neverSleepOff to Esp class, use them in core and l…
dok-net May 17, 2021
3fc7d23
Apply suggested style fixes.
dok-net Mar 13, 2022
abd17a7
There may exist code expecting this macro definition to overwrite the…
dok-net Mar 12, 2023
a6d1f73
Merge branch 'master' into wifioff
dok-net Mar 31, 2023
5a2c2db
Merge branch 'master' into wifioff
dok-net Apr 23, 2023
2d1cb1c
Merge branch 'master' into wifioff
dok-net May 13, 2023
9847e1f
Merge branch 'master' into wifioff
dok-net Jun 17, 2023
b8a95de
Reviewer noticed that esp_suspend is part of the core for awhile now …
dok-net Jun 21, 2023
dd6ea93
Implement RAII-patterned token class for ForcedLightSleep begin()/end().
dok-net Jun 24, 2023
6252680
Code style fixes.
dok-net Jun 24, 2023
cd6d155
Merge branch 'master' into wifioff
dok-net Aug 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement RAII-patterned token class for ForcedLightSleep begin()/end().
  • Loading branch information
dok-net committed Jun 24, 2023
commit dd6ea93254a9497f72d2da5bf5786d680910256d
30 changes: 30 additions & 0 deletions cores/esp8266/Esp.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,4 +293,34 @@ class EspClass {

extern EspClass ESP;

/// RAII helper token class for forcedLightSleepBegin()/End().
/// Cast to bool to check that forced light sleep can commence.
/// The forced light sleep is entered when the token goes out of scope.
/// Call cancel() to prevent sleeping.
class ESPForcedLightSleepToken {
private:
ESPForcedLightSleepToken() = delete;
ESPForcedLightSleepToken(const ESPForcedLightSleepToken&) = delete;
ESPForcedLightSleepToken& operator=(const ESPForcedLightSleepToken&) = delete;

bool isArmed = false;

public:
ESPForcedLightSleepToken(uint32_t duration_us, void (*wakeupCb)()) {
isArmed = ESP.forcedLightSleepBegin(10 * 1000 * 1000, wakeupCb);
}
~ESPForcedLightSleepToken() {
if (isArmed) ESP.forcedLightSleepEnd(false);
}
operator bool() {
return isArmed;
}
void cancel() {
if (isArmed) {
ESP.forcedLightSleepEnd(true);
isArmed = false;
}
}
};

#endif //ESP_H
107 changes: 57 additions & 50 deletions libraries/esp8266/examples/ForcedLightSleep/ForcedLightSleep.ino
Original file line number Diff line number Diff line change
Expand Up @@ -26,70 +26,77 @@
// you can use any GPIO for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts

void IRAM_ATTR wakeupPinIsr() {
// For edge-triggered IRQ.
detachInterrupt(WAKE_UP_PIN);
schedule_function([]() {
Serial.println("GPIO went from HI to LO");
});
// For edge-triggered IRQ.
detachInterrupt(WAKE_UP_PIN);
schedule_function([]() {
Serial.println("GPIO went from HI to LO");
});
}

void IRAM_ATTR wakeupPinIsrWE() {
// Wakeup IRQs are available as level-triggered only.
detachInterrupt(WAKE_UP_PIN);
schedule_function([]() {
Serial.println("GPIO wakeup IRQ");
});
wakeupPinIsr();
// reattach falling edge IRQ in loop
// Wakeup IRQs are available as level-triggered only.
detachInterrupt(WAKE_UP_PIN);
schedule_function([]() {
Serial.println("GPIO wakeup IRQ");
});
wakeupPinIsr();
// reattach falling edge IRQ in loop
}

void wakeupCallback() {
schedule_function([]() {
Serial.println("wakeup callback was performed");
});
// return to falling edge IRQ, otherwise level-triggered IRQ with wakeup
// would get called unexpectedly while awake.
attachInterrupt(WAKE_UP_PIN, wakeupPinIsr, FALLING);
schedule_function([]() {
Serial.println("wakeup callback was performed");
});
// return to falling edge IRQ, otherwise level-triggered IRQ with wakeup
// would get called unexpectedly while awake.
attachInterrupt(WAKE_UP_PIN, wakeupPinIsr, FALLING);
}

void setup() {
Serial.begin(74880);
while (!Serial)
;
delay(100);
pinMode(LED_BUILTIN, OUTPUT); // activity and status indicator
digitalWrite(LED_BUILTIN, LOW); // turn on the LED
pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, interrupt for Forced Light Sleep
attachInterrupt(WAKE_UP_PIN, wakeupPinIsr, FALLING);
Serial.begin(74880);
while (!Serial)
;
delay(100);
pinMode(LED_BUILTIN, OUTPUT); // activity and status indicator
digitalWrite(LED_BUILTIN, LOW); // turn on the LED
pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, interrupt for Forced Light Sleep
attachInterrupt(WAKE_UP_PIN, wakeupPinIsr, FALLING);
}

using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
oneShotYieldMs gotoSleep(2000);

void loop() {
if (gotoSleep && ESP.forcedLightSleepBegin(10 * 1000 * 1000, wakeupCallback)) {
// No new timers, no delay(), between forcedLightSleepBegin() and forcedLightSleepEnd().
// Only ONLOW_WE or ONHIGH_WE interrupts work, no edge, that's an SDK or CPU limitation.
// If the GPIO is in the state that will cause a wakeup on attaching the interrupt,
// it cannot trigger a wakeup later, but any sleep duration will be honored.
bool wakeupPinIsHigh = digitalRead(WAKE_UP_PIN);
delayMicroseconds(5000);
wakeupPinIsHigh &= digitalRead(WAKE_UP_PIN);
delayMicroseconds(5000);
wakeupPinIsHigh &= digitalRead(WAKE_UP_PIN);
// the GPIO might still bounce to LOW after this but before sleep is full engaged,
// disabling wakeup after all
if (wakeupPinIsHigh) {
attachInterrupt(WAKE_UP_PIN, wakeupPinIsrWE, ONLOW_WE);
if (gotoSleep) {
// No new timers, no delay(), while RAII ForcedLightSleepToken exists.
// Only ONLOW_WE or ONHIGH_WE interrupts work, no edge, that's an SDK or CPU limitation.
// If the GPIO is in the state that will cause a wakeup on attaching the interrupt,
// it cannot trigger a wakeup later, but any sleep duration will be honored.
bool wakeupPinIsHigh = digitalRead(WAKE_UP_PIN);
{
ESPForcedLightSleepToken token(10 * 1000 * 1000, wakeupCallback);
if (token) { // if true, run user code to set up forced light sleep details
// debouncing the wake up pin
delayMicroseconds(5000);
wakeupPinIsHigh &= digitalRead(WAKE_UP_PIN);
delayMicroseconds(5000);
wakeupPinIsHigh &= digitalRead(WAKE_UP_PIN);
// the GPIO might still bounce to LOW after this but before sleep is full engaged,
// disabling wakeup after all
if (wakeupPinIsHigh) {
attachInterrupt(WAKE_UP_PIN, wakeupPinIsrWE, ONLOW_WE);
}
digitalWrite(LED_BUILTIN, HIGH); // turn the LED off so they know the CPU isn't running
if (!wakeupPinIsHigh) token.cancel();
}
// RAII token gets destructed, going to sleep if all went well
}
digitalWrite(LED_BUILTIN, LOW); // turn on the LED
// retry immediately if the GPIO was found not ready for entering sleep
if (wakeupPinIsHigh) {
gotoSleep.reset();
}
// restore falling edge IRQ
attachInterrupt(WAKE_UP_PIN, wakeupPinIsr, FALLING);
}
digitalWrite(LED_BUILTIN, HIGH); // turn the LED off so they know the CPU isn't running
ESP.forcedLightSleepEnd(!wakeupPinIsHigh);
digitalWrite(LED_BUILTIN, LOW); // turn on the LED
// retry immediately if the GPIO was found not ready for entering sleep
if (wakeupPinIsHigh) {
gotoSleep.reset();
}
// restore falling edge IRQ
attachInterrupt(WAKE_UP_PIN, wakeupPinIsr, FALLING);
}
}
0