diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 279e78ff6c..f6c650fcf9 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -17,6 +17,7 @@ */ #include +#include #include "Schedule.h" #include "PolledTimeout.h" @@ -34,6 +35,7 @@ static scheduled_fn_t* sFirst = nullptr; static scheduled_fn_t* sLast = nullptr; static scheduled_fn_t* sUnused = nullptr; static int sCount = 0; +static uint32_t recurrent_max_grain_mS = 0; typedef std::function mRecFuncT; struct recurrent_fn_t @@ -130,9 +132,39 @@ bool schedule_recurrent_function_us(const std::function& fn, } rLast = item; + // grain needs to be recomputed + recurrent_max_grain_mS = 0; + return true; } +uint32_t compute_scheduled_recurrent_grain () +{ + if (recurrent_max_grain_mS == 0) + { + if (rFirst) + { + uint32_t recurrent_max_grain_uS = rFirst->callNow.getTimeout(); + for (auto it = rFirst->mNext; it; it = it->mNext) + recurrent_max_grain_uS = std::gcd(recurrent_max_grain_uS, it->callNow.getTimeout()); + if (recurrent_max_grain_uS) + // round to the upper millis + recurrent_max_grain_mS = recurrent_max_grain_uS <= 1000? 1: (recurrent_max_grain_uS + 999) / 1000; + } + +#ifdef DEBUG_ESP_CORE + static uint32_t last_grain = 0; + if (recurrent_max_grain_mS != last_grain) + { + ::printf(":rsf %u->%u\n", last_grain, recurrent_max_grain_mS); + last_grain = recurrent_max_grain_mS; + } +#endif + } + + return recurrent_max_grain_mS; +} + void run_scheduled_functions() { // prevent scheduling of new functions during this run @@ -226,6 +258,9 @@ void run_scheduled_recurrent_functions() } delete(to_ditch); + + // grain needs to be recomputed + recurrent_max_grain_mS = 0; } else { diff --git a/cores/esp8266/Schedule.h b/cores/esp8266/Schedule.h index da86e5b7f5..362d15b5f3 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -39,6 +39,11 @@ // scheduled function happen more often: every yield() (vs every loop()), // and time resolution is microsecond (vs millisecond). Details are below. +// compute_scheduled_recurrent_grain() is used by delay() to give a chance to +// all recurrent functions to run per their timing requirement. + +uint32_t compute_scheduled_recurrent_grain (); + // scheduled functions called once: // // * internal queue is FIFO. diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index b73d3d3a89..ccacc95e01 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -22,6 +22,9 @@ //This may be used to change user task stack size: //#define CONT_STACKSIZE 4096 + +#include + #include #include "Schedule.h" extern "C" { @@ -165,10 +168,18 @@ extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_de bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) { uint32_t expired = millis() - start_ms; if (expired >= timeout_ms) { - return true; + return true; // expired } - esp_delay(std::min((timeout_ms - expired), intvl_ms)); - return false; + + // compute greatest chunked delay with respect to scheduled recurrent functions + uint32_t grain_ms = std::gcd(intvl_ms, compute_scheduled_recurrent_grain()); + + // recurrent scheduled functions will be called from esp_delay()->esp_suspend() + esp_delay(grain_ms > 0 ? + std::min((timeout_ms - expired), grain_ms): + (timeout_ms - expired)); + + return false; // expiration must be checked again } extern "C" void __yield() { diff --git a/cores/esp8266/core_esp8266_wiring.cpp b/cores/esp8266/core_esp8266_wiring.cpp index 40a996d560..3054d39338 100644 --- a/cores/esp8266/core_esp8266_wiring.cpp +++ b/cores/esp8266/core_esp8266_wiring.cpp @@ -34,7 +34,9 @@ static uint32_t micros_overflow_count = 0; #define REPEAT 1 void __delay(unsigned long ms) { - esp_delay(ms); + // Use API letting recurrent scheduled functions run in background + // but stay blocked in delay until ms is expired. + esp_delay(ms, [](){ return true; }); } void delay(unsigned long ms) __attribute__ ((weak, alias("__delay"))); diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index 368aaf135c..73af6d8cf1 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -1,6 +1,5 @@ -#ifndef __COREDECLS_H -#define __COREDECLS_H +#pragma once #include "core_esp8266_features.h" @@ -55,14 +54,15 @@ inline void esp_suspend(T&& blocked) { // Try to delay until timeout_ms has expired since start_ms. // Returns true if timeout_ms has completely expired on entry. // Otherwise returns false after delaying for the relative -// remainder of timeout_ms, or an absolute intvl_ms, whichever is shorter. +// remainder of timeout_ms, or an absolute intvl_ms, whichever is shorter +// and possibly amended by recurrent scheduled functions timing grain. // The delay may be asynchronously cancelled, before that timeout is reached. bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms); // This overload of esp_delay() delays for a duration of at most timeout_ms milliseconds. -// Whenever it is resumed, as well as every intvl_ms millisconds, it performs -// the blocked callback, and if that returns true, it keeps delaying for the remainder -// of the original timeout_ms period. +// Whenever it is resumed, as well as at most every intvl_ms millisconds and depending on +// recurrent scheduled functions, it performs the blocked callback, and if that returns true, +// it keeps delaying for the remainder of the original timeout_ms period. template inline void esp_delay(const uint32_t timeout_ms, T&& blocked, const uint32_t intvl_ms) { const auto start_ms = millis(); @@ -79,5 +79,3 @@ inline void esp_delay(const uint32_t timeout_ms, T&& blocked) { } #endif // __cplusplus - -#endif // __COREDECLS_H diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index be482737a8..f64e6d3ac5 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -451,9 +451,8 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) { //tasks to wait correctly. constexpr unsigned int timeoutValue = 1000; //1 second if(can_yield()) { - // The final argument, intvl_ms, to esp_delay influences how frequently - // the scheduled recurrent functions (Schedule.h) are probed. - esp_delay(timeoutValue, [m]() { return wifi_get_opmode() != m; }, 5); + // check opmode every 100ms or give up after timeout + esp_delay(timeoutValue, [m]() { return wifi_get_opmode() != m; }, 100); //if at this point mode still hasn't been reached, give up if(wifi_get_opmode() != (uint8) m) { @@ -642,11 +641,8 @@ static int hostByNameImpl(const char* aHostname, IPAddress& aResult, uint32_t ti // We need to wait for c/b to fire *or* we exit on our own timeout // (which also requires us to notify the c/b that it is supposed to delete the pending obj) case ERR_INPROGRESS: - // Re-check every 10ms, we expect this to happen fast - esp_delay(timeout_ms, - [&]() { - return !pending->done; - }, 10); + // sleep until dns_found_callback is called or timeout is reached + esp_delay(timeout_ms, [&]() { return !pending->done; }); if (pending->done) { if ((pending->addr).isSet()) { diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp index dada704ab1..bcd433e1b1 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -84,13 +84,13 @@ static void printWiFiStatus(wl_status_t status) static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs) { wl_status_t status = WL_CONNECT_FAILED; - // The final argument, intvl_ms, to esp_delay influences how frequently - // the scheduled recurrent functions (Schedule.h) are probed. + // Wait for WiFi to connect + // stop waiting upon status checked every 100ms or when timeout is reached esp_delay(connectTimeoutMs, [&status]() { status = WiFi.status(); return status != WL_CONNECTED && status != WL_CONNECT_FAILED; - }, 0); + }, 100); // Check status if (status == WL_CONNECTED) { @@ -236,13 +236,12 @@ int8_t ESP8266WiFiMulti::startScan() WiFi.scanNetworks(true); // Wait for WiFi scan change or timeout - // The final argument, intvl_ms, to esp_delay influences how frequently - // the scheduled recurrent functions (Schedule.h) are probed. + // stop waiting upon status checked every 100ms or when timeout is reached esp_delay(WIFI_SCAN_TIMEOUT_MS, [&scanResult]() { scanResult = WiFi.scanComplete(); return scanResult < 0; - }, 0); + }, 100); // Check for scan timeout which may occur when scan does not report completion if (scanResult < 0) { DEBUG_WIFI_MULTI("[WIFIM] Scan timeout\n"); diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h index 7fcad3678a..5c579c8848 100644 --- a/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -144,8 +144,7 @@ class ClientContext _connect_pending = true; _op_start_time = millis(); // will resume on timeout or when _connected or _notify_error fires - // give scheduled functions a chance to run (e.g. Ethernet uses recurrent) - esp_delay(_timeout_ms, [this]() { return this->_connect_pending; }, 1); + esp_delay(_timeout_ms, [this]() { return this->_connect_pending; }); _connect_pending = false; if (!_pcb) { DEBUGV(":cabrt\r\n"); @@ -485,8 +484,7 @@ class ClientContext _send_waiting = true; // will resume on timeout or when _write_some_from_cb or _notify_error fires - // give scheduled functions a chance to run (e.g. Ethernet uses recurrent) - esp_delay(_timeout_ms, [this]() { return this->_send_waiting; }, 1); + esp_delay(_timeout_ms, [this]() { return this->_send_waiting; }); _send_waiting = false; } while(true); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy