From bde2c4c5d33d68059cf7d7818a3907a07024b63e Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 11 Jan 2023 00:28:35 +0100 Subject: [PATCH 1/8] wip --- cores/esp8266/Schedule.cpp | 27 +++++++++++++++++++++++++++ cores/esp8266/Schedule.h | 7 +++++++ cores/esp8266/core_esp8266_wiring.cpp | 12 +++++++++++- cores/esp8266/coredecls.h | 17 +++++++++++++---- 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 279e78ff6c..4fd353b188 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -35,6 +35,8 @@ static scheduled_fn_t* sLast = nullptr; static scheduled_fn_t* sUnused = nullptr; static int sCount = 0; +uint32_t recurrent_max_grain_mS = 0; + typedef std::function mRecFuncT; struct recurrent_fn_t { @@ -130,9 +132,31 @@ bool schedule_recurrent_function_us(const std::function& fn, } rLast = item; + // grain needs to be recomputed + recurrent_max_grain_mS = 0; + return true; } +void update_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 = compute_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; + } + if (recurrent_max_grain_mS == 0) + // no recurrent function, set grain to max + recurrent_max_grain_mS = std::numeric_limits::max(); + } +} + void run_scheduled_functions() { // prevent scheduling of new functions during this run @@ -226,6 +250,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..83e1a90a8d 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -39,6 +39,13 @@ // scheduled function happen more often: every yield() (vs every loop()), // and time resolution is microsecond (vs millisecond). Details are below. +// recurrent_max_grain_mS is used by delay() to let a chance to all +// recurrent functions to accomplish their duty per their timing +// requirement. +// When it is 0, update_recurrent_grain() can be called to recalculate it +extern uint32_t recurrent_max_grain_mS; +void update_recurrent_grain (); + // scheduled functions called once: // // * internal queue is FIFO. diff --git a/cores/esp8266/core_esp8266_wiring.cpp b/cores/esp8266/core_esp8266_wiring.cpp index 40a996d560..ba5c36a0fd 100644 --- a/cores/esp8266/core_esp8266_wiring.cpp +++ b/cores/esp8266/core_esp8266_wiring.cpp @@ -34,7 +34,17 @@ static uint32_t micros_overflow_count = 0; #define REPEAT 1 void __delay(unsigned long ms) { - esp_delay(ms); + + // default "userland" delay() will call recurrent scheduled functions + // based on best effort according to their respective requirements + + if (recurrent_max_grain_mS == 0) + update_recurrent_grain(); + const auto start_ms = millis(); + do + { + run_scheduled_recurrent_functions(); + } while (!esp_try_delay(start_ms, ms, recurrent_max_grain_mS)); } void delay(unsigned long ms) __attribute__ ((weak, alias("__delay"))); diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index 1e2776d71b..34c6a57cf1 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" @@ -76,6 +75,16 @@ inline void esp_delay(const uint32_t timeout_ms, T&& blocked) { esp_delay(timeout_ms, std::forward(blocked), timeout_ms); } -#endif // __cplusplus +template +auto compute_gcd (T a, T b) +{ + while (b) + { + auto t = b; + b = a % b; + a = t; + } + return a; +} -#endif // __COREDECLS_H +#endif // __cplusplus From 0effb78cdee6f9b517c70d90372816757d57b32c Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 11 Jan 2023 23:35:27 +0100 Subject: [PATCH 2/8] wip --- cores/esp8266/core_esp8266_main.cpp | 13 ++++++++++++- cores/esp8266/core_esp8266_wiring.cpp | 13 ++----------- cores/esp8266/coredecls.h | 5 +++-- libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp | 2 +- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index b73d3d3a89..9db8aa09a6 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -162,11 +162,22 @@ extern "C" void __esp_delay(unsigned long ms) { extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_delay"))); -bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) { +bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, uint32_t intvl_ms) { uint32_t expired = millis() - start_ms; if (expired >= timeout_ms) { return true; } + + if (intvl_ms == 0) + { + // run_recurrent_scheduled_functions() is called from esp_delay()->esp_suspend() + // intvl_ms is set according to recurrent schedule functions + // intervals based on their respective requirements + if (recurrent_max_grain_mS == 0) + update_recurrent_grain(); + intvl_ms = recurrent_max_grain_mS; + } + esp_delay(std::min((timeout_ms - expired), intvl_ms)); return false; } diff --git a/cores/esp8266/core_esp8266_wiring.cpp b/cores/esp8266/core_esp8266_wiring.cpp index ba5c36a0fd..b27d52a431 100644 --- a/cores/esp8266/core_esp8266_wiring.cpp +++ b/cores/esp8266/core_esp8266_wiring.cpp @@ -34,17 +34,8 @@ static uint32_t micros_overflow_count = 0; #define REPEAT 1 void __delay(unsigned long ms) { - - // default "userland" delay() will call recurrent scheduled functions - // based on best effort according to their respective requirements - - if (recurrent_max_grain_mS == 0) - update_recurrent_grain(); - const auto start_ms = millis(); - do - { - run_scheduled_recurrent_functions(); - } while (!esp_try_delay(start_ms, ms, recurrent_max_grain_mS)); + // use API letting recurrent scheduled functions run in background + 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 34c6a57cf1..9a0f4c92ad 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -54,7 +54,8 @@ inline void esp_suspend(T&& blocked) { // Otherwise returns false after delaying for the relative // remainder of timeout_ms, or an absolute intvl_ms, whichever is shorter. // 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); +// intvl_ms==0 will adapt to recurrent scheduled functions and run them accordingly +bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, 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 @@ -72,7 +73,7 @@ inline void esp_delay(const uint32_t timeout_ms, T&& blocked, const uint32_t int // it keeps delaying for the remainder of the original timeout_ms period. template inline void esp_delay(const uint32_t timeout_ms, T&& blocked) { - esp_delay(timeout_ms, std::forward(blocked), timeout_ms); + esp_delay(timeout_ms, std::forward(blocked), 0); } template diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index be482737a8..0bf8473ece 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -646,7 +646,7 @@ static int hostByNameImpl(const char* aHostname, IPAddress& aResult, uint32_t ti esp_delay(timeout_ms, [&]() { return !pending->done; - }, 10); + }); if (pending->done) { if ((pending->addr).isSet()) { From 508214ac192ad0dd84317d426a6fcd8d5dfb24c7 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Fri, 13 Jan 2023 22:13:40 +0100 Subject: [PATCH 3/8] debug --- cores/esp8266/Schedule.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 4fd353b188..76bbc392ee 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -155,6 +155,15 @@ void update_recurrent_grain () // no recurrent function, set grain to max recurrent_max_grain_mS = std::numeric_limits::max(); } + +#if 1 + static uint32_t last_grain = 0; + if (recurrent_max_grain_mS != last_grain) + { + ::printf("grain4rsf: %u -> %u\n", last_grain, recurrent_max_grain_mS); + last_grain = recurrent_max_grain_mS; + } +#endif } void run_scheduled_functions() From 0c8f70554db985b5ff12297f7e6bc31b3fb8331e Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Sat, 14 Jan 2023 15:51:11 +0100 Subject: [PATCH 4/8] simplify api --- cores/esp8266/Schedule.cpp | 19 +++++++-------- cores/esp8266/core_esp8266_main.cpp | 24 +++++++++---------- cores/esp8266/core_esp8266_wiring.cpp | 1 + cores/esp8266/coredecls.h | 16 +++++++------ .../ESP8266WiFi/src/ESP8266WiFiGeneric.cpp | 13 ++++------ .../ESP8266WiFi/src/ESP8266WiFiMulti.cpp | 4 ++-- .../ESP8266WiFi/src/include/ClientContext.h | 6 ++--- 7 files changed, 38 insertions(+), 45 deletions(-) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 76bbc392ee..6069599ea0 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -151,19 +151,16 @@ void update_recurrent_grain () // round to the upper millis recurrent_max_grain_mS = recurrent_max_grain_uS <= 1000? 1: (recurrent_max_grain_uS + 999) / 1000; } - if (recurrent_max_grain_mS == 0) - // no recurrent function, set grain to max - recurrent_max_grain_mS = std::numeric_limits::max(); - } -#if 1 - static uint32_t last_grain = 0; - if (recurrent_max_grain_mS != last_grain) - { - ::printf("grain4rsf: %u -> %u\n", last_grain, recurrent_max_grain_mS); - last_grain = recurrent_max_grain_mS; - } +#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 + } } void run_scheduled_functions() diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 9db8aa09a6..3b3f8383da 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -162,24 +162,22 @@ extern "C" void __esp_delay(unsigned long ms) { extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_delay"))); -bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, uint32_t intvl_ms) { +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 } - if (intvl_ms == 0) - { - // run_recurrent_scheduled_functions() is called from esp_delay()->esp_suspend() - // intvl_ms is set according to recurrent schedule functions - // intervals based on their respective requirements - if (recurrent_max_grain_mS == 0) - update_recurrent_grain(); - intvl_ms = recurrent_max_grain_mS; - } + // possibly recompute recurrent scheduled function common timing grain + update_recurrent_grain(); + + // update intvl_ms according to this grain + uint32_t ms = compute_gcd(intvl_ms, recurrent_max_grain_mS); + + // recurrent scheduled functions will be called from esp_delay()->esp_suspend() + esp_delay(ms? std::min((timeout_ms - expired), ms): (timeout_ms - expired)); - esp_delay(std::min((timeout_ms - expired), intvl_ms)); - return false; + 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 b27d52a431..daf67c3299 100644 --- a/cores/esp8266/core_esp8266_wiring.cpp +++ b/cores/esp8266/core_esp8266_wiring.cpp @@ -35,6 +35,7 @@ static uint32_t micros_overflow_count = 0; void __delay(unsigned long ms) { // use API letting recurrent scheduled functions run in background + // but stay blocked in delay until ms is expired esp_delay(ms, [](){ return true; }); } diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index 9a0f4c92ad..a51f7e37d8 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -52,15 +52,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 fuctions timing grain. // The delay may be asynchronously cancelled, before that timeout is reached. -// intvl_ms==0 will adapt to recurrent scheduled functions and run them accordingly -bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, uint32_t intvl_ms); +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(); @@ -73,9 +73,11 @@ inline void esp_delay(const uint32_t timeout_ms, T&& blocked, const uint32_t int // it keeps delaying for the remainder of the original timeout_ms period. template inline void esp_delay(const uint32_t timeout_ms, T&& blocked) { - esp_delay(timeout_ms, std::forward(blocked), 0); + esp_delay(timeout_ms, std::forward(blocked), timeout_ms); } +// Greatest Common Divisor Euclidian algorithm +// one entry may be 0, the other is returned template auto compute_gcd (T a, T b) { diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index 0bf8473ece..5501128aef 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -451,9 +451,9 @@ 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); + // The final argument, intvl_ms, to esp_delay determines at least + // how frequently wifi_get_opmode() is checked + 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 +642,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; - }); + // esp_delay will be interrupted by found callback + 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..2bc4d02391 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -90,7 +90,7 @@ static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs) [&status]() { status = WiFi.status(); return status != WL_CONNECTED && status != WL_CONNECT_FAILED; - }, 0); + }, 100); // Check status if (status == WL_CONNECTED) { @@ -242,7 +242,7 @@ int8_t ESP8266WiFiMulti::startScan() [&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); From a1e43b81f4c78496b6085c58b435c701b0318648 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Sat, 14 Jan 2023 16:06:00 +0100 Subject: [PATCH 5/8] fix comments --- cores/esp8266/Schedule.h | 2 +- cores/esp8266/core_esp8266_main.cpp | 2 +- cores/esp8266/core_esp8266_wiring.cpp | 4 ++-- cores/esp8266/coredecls.h | 2 +- libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cores/esp8266/Schedule.h b/cores/esp8266/Schedule.h index 83e1a90a8d..3095286b6e 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -42,7 +42,7 @@ // recurrent_max_grain_mS is used by delay() to let a chance to all // recurrent functions to accomplish their duty per their timing // requirement. -// When it is 0, update_recurrent_grain() can be called to recalculate it +// When it is 0, update_recurrent_grain() can be called to recalculate it. extern uint32_t recurrent_max_grain_mS; void update_recurrent_grain (); diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 3b3f8383da..b8fd16d218 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -168,7 +168,7 @@ bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uin return true; // expired } - // possibly recompute recurrent scheduled function common timing grain + // possibly recompute recurrent scheduled functions common timing grain update_recurrent_grain(); // update intvl_ms according to this grain diff --git a/cores/esp8266/core_esp8266_wiring.cpp b/cores/esp8266/core_esp8266_wiring.cpp index daf67c3299..3054d39338 100644 --- a/cores/esp8266/core_esp8266_wiring.cpp +++ b/cores/esp8266/core_esp8266_wiring.cpp @@ -34,8 +34,8 @@ static uint32_t micros_overflow_count = 0; #define REPEAT 1 void __delay(unsigned long ms) { - // use API letting recurrent scheduled functions run in background - // but stay blocked in delay until ms is expired + // Use API letting recurrent scheduled functions run in background + // but stay blocked in delay until ms is expired. esp_delay(ms, [](){ return true; }); } diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index a51f7e37d8..87ab5f0b45 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -53,7 +53,7 @@ inline void esp_suspend(T&& blocked) { // 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 -// and possibly amended by recurrent scheduled fuctions timing grain. +// 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); diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp index 2bc4d02391..a2bbb919bc 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -84,8 +84,8 @@ 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. + // The final argument, intvl_ms, to esp_delay determines + // the max ms interval at which status is checked esp_delay(connectTimeoutMs, [&status]() { status = WiFi.status(); @@ -236,8 +236,8 @@ 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. + // The final argument, intvl_ms, to esp_delay determines + // the max ms interval at which status is checked esp_delay(WIFI_SCAN_TIMEOUT_MS, [&scanResult]() { scanResult = WiFi.scanComplete(); From 4d17f1b8084d87144b362ec9796507adb888ed08 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Sat, 14 Jan 2023 21:09:16 +0100 Subject: [PATCH 6/8] fixes per review --- cores/esp8266/Schedule.cpp | 10 ++++++---- cores/esp8266/Schedule.h | 10 ++++------ cores/esp8266/core_esp8266_main.cpp | 14 ++++++++------ cores/esp8266/coredecls.h | 14 -------------- libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp | 5 ++--- 5 files changed, 20 insertions(+), 33 deletions(-) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 6069599ea0..767a1b8f82 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -17,6 +17,7 @@ */ #include +#include #include "Schedule.h" #include "PolledTimeout.h" @@ -34,8 +35,7 @@ static scheduled_fn_t* sFirst = nullptr; static scheduled_fn_t* sLast = nullptr; static scheduled_fn_t* sUnused = nullptr; static int sCount = 0; - -uint32_t recurrent_max_grain_mS = 0; +static uint32_t recurrent_max_grain_mS = 0; typedef std::function mRecFuncT; struct recurrent_fn_t @@ -138,7 +138,7 @@ bool schedule_recurrent_function_us(const std::function& fn, return true; } -void update_recurrent_grain () +uint32_t compute_recurrent_grain () { if (recurrent_max_grain_mS == 0) { @@ -146,7 +146,7 @@ void update_recurrent_grain () { uint32_t recurrent_max_grain_uS = rFirst->callNow.getTimeout(); for (auto it = rFirst->mNext; it; it = it->mNext) - recurrent_max_grain_uS = compute_gcd(recurrent_max_grain_uS, it->callNow.getTimeout()); + 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; @@ -161,6 +161,8 @@ void update_recurrent_grain () } #endif } + + return recurrent_max_grain_mS; } void run_scheduled_functions() diff --git a/cores/esp8266/Schedule.h b/cores/esp8266/Schedule.h index 3095286b6e..f9ae45b8e2 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -39,12 +39,10 @@ // scheduled function happen more often: every yield() (vs every loop()), // and time resolution is microsecond (vs millisecond). Details are below. -// recurrent_max_grain_mS is used by delay() to let a chance to all -// recurrent functions to accomplish their duty per their timing -// requirement. -// When it is 0, update_recurrent_grain() can be called to recalculate it. -extern uint32_t recurrent_max_grain_mS; -void update_recurrent_grain (); +// compute_recurrent_grain() is used by delay() to give a chance to all +// recurrent functions to run per their timing requirement. + +uint32_t compute_recurrent_grain (); // scheduled functions called once: // diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index b8fd16d218..b991eb8e0f 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" { @@ -168,14 +171,13 @@ bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uin return true; // expired } - // possibly recompute recurrent scheduled functions common timing grain - update_recurrent_grain(); - - // update intvl_ms according to this grain - uint32_t ms = compute_gcd(intvl_ms, recurrent_max_grain_mS); + // compute greatest chunked delay with respect to scheduled recurrent functions + uint32_t grain_ms = std::gcd(intvl_ms, compute_recurrent_grain()); // recurrent scheduled functions will be called from esp_delay()->esp_suspend() - esp_delay(ms? std::min((timeout_ms - expired), ms): (timeout_ms - expired)); + esp_delay(grain_ms > 0 ? + std::min((timeout_ms - expired), grain_ms): + (timeout_ms - expired)); return false; // expiration must be checked again } diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index c060c7bb1e..73af6d8cf1 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -78,18 +78,4 @@ inline void esp_delay(const uint32_t timeout_ms, T&& blocked) { esp_delay(timeout_ms, std::forward(blocked), timeout_ms); } -// Greatest Common Divisor Euclidian algorithm -// one entry may be 0, the other is returned -template -auto compute_gcd (T a, T b) -{ - while (b) - { - auto t = b; - b = a % b; - a = t; - } - return a; -} - #endif // __cplusplus diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index 5501128aef..f64e6d3ac5 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -451,8 +451,7 @@ 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 determines at least - // how frequently wifi_get_opmode() is checked + // 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 @@ -642,7 +641,7 @@ 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: - // esp_delay will be interrupted by found callback + // sleep until dns_found_callback is called or timeout is reached esp_delay(timeout_ms, [&]() { return !pending->done; }); if (pending->done) { From 01240fc5673339f93362735436f49ed0bd74658c Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Sat, 14 Jan 2023 21:22:25 +0100 Subject: [PATCH 7/8] update comments --- libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp index a2bbb919bc..bcd433e1b1 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -84,8 +84,8 @@ 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 determines - // the max ms interval at which status is checked + // Wait for WiFi to connect + // stop waiting upon status checked every 100ms or when timeout is reached esp_delay(connectTimeoutMs, [&status]() { status = WiFi.status(); @@ -236,8 +236,7 @@ int8_t ESP8266WiFiMulti::startScan() WiFi.scanNetworks(true); // Wait for WiFi scan change or timeout - // The final argument, intvl_ms, to esp_delay determines - // the max ms interval at which status is checked + // stop waiting upon status checked every 100ms or when timeout is reached esp_delay(WIFI_SCAN_TIMEOUT_MS, [&scanResult]() { scanResult = WiFi.scanComplete(); From 4f5eb32ca0bedddf7c4d0da8f166178635b67a1d Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Sat, 14 Jan 2023 21:31:20 +0100 Subject: [PATCH 8/8] rename global function --- cores/esp8266/Schedule.cpp | 2 +- cores/esp8266/Schedule.h | 6 +++--- cores/esp8266/core_esp8266_main.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 767a1b8f82..f6c650fcf9 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -138,7 +138,7 @@ bool schedule_recurrent_function_us(const std::function& fn, return true; } -uint32_t compute_recurrent_grain () +uint32_t compute_scheduled_recurrent_grain () { if (recurrent_max_grain_mS == 0) { diff --git a/cores/esp8266/Schedule.h b/cores/esp8266/Schedule.h index f9ae45b8e2..362d15b5f3 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -39,10 +39,10 @@ // scheduled function happen more often: every yield() (vs every loop()), // and time resolution is microsecond (vs millisecond). Details are below. -// compute_recurrent_grain() is used by delay() to give a chance to all -// recurrent functions to run per their timing requirement. +// 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_recurrent_grain (); +uint32_t compute_scheduled_recurrent_grain (); // scheduled functions called once: // diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index b991eb8e0f..ccacc95e01 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -172,7 +172,7 @@ bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uin } // compute greatest chunked delay with respect to scheduled recurrent functions - uint32_t grain_ms = std::gcd(intvl_ms, compute_recurrent_grain()); + 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 ? 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