From fca1d5d117b872b9ac49d8ba781efd350f57db64 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Wed, 13 Mar 2019 01:56:26 +0100 Subject: [PATCH 01/35] polledTimeout: add option to use CPU count instead of millis() --- cores/esp8266/PolledTimeout.h | 49 ++++++++++++++++--- .../BlinkPolledTimeout/BlinkPolledTimeout.ino | 2 +- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index d13bae200d..82b5bfb85a 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -47,15 +47,38 @@ struct YieldOrSkip } //YieldPolicy +namespace TimePolicy +{ + +struct TimeMillis +{ + static decltype(millis()) time() {return millis();} + static constexpr decltype(millis()) toMillis = 1; +}; + +#ifdef CORE_MOCK +struct TimeCycle: public TimeMillis {}; +#else + +struct TimeCycle +{ + static decltype(ESP.getCycleCount()) time() {return ESP.getCycleCount();} + static constexpr decltype(ESP.getCycleCount()) toMillis = F_CPU / 1000; +}; + +#endif // cpu cycles + + +} //TimePolicy -template +template class timeoutTemplate { public: - using timeType = decltype(millis()); + using timeType = decltype(TimePolicyT::time()); timeoutTemplate(timeType timeout) - : _timeout(timeout), _start(millis()) + : _timeout(timeout * TimePolicyT::toMillis), _start(TimePolicyT::time()) {} bool expired() @@ -79,7 +102,7 @@ class timeoutTemplate void reset() { - _start = millis(); + _start = TimePolicyT::time(); } timeType getTimeout() const @@ -96,7 +119,7 @@ class timeoutTemplate bool expiredRetrigger() { - timeType current = millis(); + timeType current = TimePolicyT::time(); if(checkExpired(current)) { unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout) @@ -108,15 +131,25 @@ class timeoutTemplate bool expiredOneShot() const { - return checkExpired(millis()); + return checkExpired(TimePolicyT::time()); } timeType _timeout; timeType _start; }; -using oneShot = polledTimeout::timeoutTemplate; -using periodic = polledTimeout::timeoutTemplate; +using oneShotMs = polledTimeout::timeoutTemplate; +using periodicMs = polledTimeout::timeoutTemplate; +using oneShotMsYield = polledTimeout::timeoutTemplate; +using periodicMsYield = polledTimeout::timeoutTemplate; +using oneShotCpu = polledTimeout::timeoutTemplate; +using periodicCpu = polledTimeout::timeoutTemplate; +using oneShotCpuYield = polledTimeout::timeoutTemplate; +using periodicCpuYield = polledTimeout::timeoutTemplate; + +// default / generic / backward compatibility +using oneShot = oneShotMs; +using periodic = periodicMs; } //polledTimeout diff --git a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino index 12aca929f2..2f8906037d 100644 --- a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino +++ b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino @@ -39,7 +39,7 @@ void ledToggle() { -esp8266::polledTimeout::periodic halfPeriod(500); //use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace +esp8266::polledTimeout::periodicCpu halfPeriod(500); //use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace // the setup function runs only once at start void setup() { From 702cea893c881be5e7f197d2b59bfb7f0fe9fead Mon Sep 17 00:00:00 2001 From: david gauchard Date: Wed, 13 Mar 2019 23:54:22 +0100 Subject: [PATCH 02/35] use more "using" alias --- cores/esp8266/PolledTimeout.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 82b5bfb85a..1397a6d519 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -52,8 +52,9 @@ namespace TimePolicy struct TimeMillis { - static decltype(millis()) time() {return millis();} - static constexpr decltype(millis()) toMillis = 1; + using timeType = decltype(millis()); + static timeType time() {return millis();} + static constexpr timeType toMillis = 1; }; #ifdef CORE_MOCK @@ -62,8 +63,9 @@ struct TimeCycle: public TimeMillis {}; struct TimeCycle { - static decltype(ESP.getCycleCount()) time() {return ESP.getCycleCount();} - static constexpr decltype(ESP.getCycleCount()) toMillis = F_CPU / 1000; + using timeType = decltype(ESP.getCycleCount()); + static timeType time() {return ESP.getCycleCount();} + static constexpr timeType toMillis = F_CPU / 1000; }; #endif // cpu cycles From 133c06f192568e37c80cc1bdb336f5c5e6416682 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Thu, 14 Mar 2019 16:14:33 +0100 Subject: [PATCH 03/35] more c++/clear code, using typename (thanks @devyte) --- cores/esp8266/PolledTimeout.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 1397a6d519..4577e6a681 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -77,7 +77,7 @@ template Date: Fri, 15 Mar 2019 01:44:02 +0100 Subject: [PATCH 04/35] rename class name to include unit, introduce timeMax() and check it with assert() --- cores/esp8266/PolledTimeout.h | 47 +++++++++++++------ .../BlinkPolledTimeout/BlinkPolledTimeout.ino | 3 +- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 4577e6a681..6f8dee7f15 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -24,6 +24,7 @@ */ #include +#include namespace esp8266 { @@ -50,22 +51,44 @@ struct YieldOrSkip namespace TimePolicy { +#ifndef MAXSCALAR +#define MAXSCALAR(type,sz_bit) ((type)((((((type)1)<<((sz_bit)-1))-1)<<1)+1)) +#define MAXUSCALAR(type) MAXSCALAR(type,(sizeof(type)<<3)) +#define MAXSSCALAR(type) MAXSCALAR(type,(sizeof(type)<<3)-1) +#define MINSSCALAR(type) ((type)((type)1<<((sizeof(type)<<3)-1))) +#endif + + struct TimeMillis { + // time policy in milli-seconds based on millis() + using timeType = decltype(millis()); static timeType time() {return millis();} static constexpr timeType toMillis = 1; + + // rollover: 48 days, setting max to 24 days to fit in signed scalar (below is = 2^31 - 1) + static constexpr timeType timeMax() { return (((((timeType)1) << ((sizeof(timeType) * 8) - 2)) - 1) << 1) + 1; } }; #ifdef CORE_MOCK -struct TimeCycle: public TimeMillis {}; +struct TimeCycleMs: public TimeMillis {}; #else -struct TimeCycle +struct TimeCycleMs { + // time policy in milli-seconds based on ESP.getCycleCount() + using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} static constexpr timeType toMillis = F_CPU / 1000; + + // rollover: @80Mhz:53.6s @160Mhz:26.8s + // setting max to half of it to ensure full range is never reached + // - this particular time measurement is intended to be called very often + // (every loop, every yield) + // - this max is larger than internal watchdogs + static constexpr timeType timeMax() { return ((((uint64_t)1000) << (sizeof(timeType) * 8)) / F_CPU) / 2; } }; #endif // cpu cycles @@ -81,7 +104,9 @@ class timeoutTemplate timeoutTemplate(timeType timeout) : _timeout(timeout * TimePolicyT::toMillis), _start(TimePolicyT::time()) - {} + { + assert(timeout < TimePolicyT::timeMax()); + } bool expired() { @@ -140,18 +165,10 @@ class timeoutTemplate timeType _start; }; -using oneShotMs = polledTimeout::timeoutTemplate; -using periodicMs = polledTimeout::timeoutTemplate; -using oneShotMsYield = polledTimeout::timeoutTemplate; -using periodicMsYield = polledTimeout::timeoutTemplate; -using oneShotCpu = polledTimeout::timeoutTemplate; -using periodicCpu = polledTimeout::timeoutTemplate; -using oneShotCpuYield = polledTimeout::timeoutTemplate; -using periodicCpuYield = polledTimeout::timeoutTemplate; - -// default / generic / backward compatibility -using oneShot = oneShotMs; -using periodic = periodicMs; +using oneShot = polledTimeout::timeoutTemplate; +using periodic = polledTimeout::timeoutTemplate; +using oneShotCycleMs = polledTimeout::timeoutTemplate; +using periodicCycleMs = polledTimeout::timeoutTemplate; } //polledTimeout diff --git a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino index 2f8906037d..ae4a2364ee 100644 --- a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino +++ b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino @@ -38,8 +38,9 @@ void ledToggle() { } +esp8266::polledTimeout::periodic halfPeriod(500); //use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace -esp8266::polledTimeout::periodicCpu halfPeriod(500); //use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace +// also available: lighter esp8266::polledTimeout::periodicCycleMs for durations shorter than 13000 ms // the setup function runs only once at start void setup() { From f3f7a2d4876be4cba6f8188f8129dfef791e817b Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 15 Mar 2019 02:03:32 +0100 Subject: [PATCH 05/35] remove useless defines --- cores/esp8266/PolledTimeout.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 6f8dee7f15..4dbc0f24b7 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -51,14 +51,6 @@ struct YieldOrSkip namespace TimePolicy { -#ifndef MAXSCALAR -#define MAXSCALAR(type,sz_bit) ((type)((((((type)1)<<((sz_bit)-1))-1)<<1)+1)) -#define MAXUSCALAR(type) MAXSCALAR(type,(sizeof(type)<<3)) -#define MAXSSCALAR(type) MAXSCALAR(type,(sizeof(type)<<3)-1) -#define MINSSCALAR(type) ((type)((type)1<<((sizeof(type)<<3)-1))) -#endif - - struct TimeMillis { // time policy in milli-seconds based on millis() From a21514ad7d387a8b10c9ac96db7955d93893dbd9 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Sat, 16 Mar 2019 00:02:51 +0100 Subject: [PATCH 06/35] improve api readability, add micro-second unit --- cores/esp8266/PolledTimeout.h | 48 +++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 4dbc0f24b7..78b7e04798 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -57,7 +57,7 @@ struct TimeMillis using timeType = decltype(millis()); static timeType time() {return millis();} - static constexpr timeType toMillis = 1; + static constexpr timeType toUnit = 1; // rollover: 48 days, setting max to 24 days to fit in signed scalar (below is = 2^31 - 1) static constexpr timeType timeMax() { return (((((timeType)1) << ((sizeof(timeType) * 8) - 2)) - 1) << 1) + 1; } @@ -67,23 +67,39 @@ struct TimeMillis struct TimeCycleMs: public TimeMillis {}; #else -struct TimeCycleMs +struct TimeFastMillis { // time policy in milli-seconds based on ESP.getCycleCount() using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} - static constexpr timeType toMillis = F_CPU / 1000; + static constexpr timeType toUnit = F_CPU / 1000; // rollover: @80Mhz:53.6s @160Mhz:26.8s // setting max to half of it to ensure full range is never reached // - this particular time measurement is intended to be called very often // (every loop, every yield) // - this max is larger than internal watchdogs - static constexpr timeType timeMax() { return ((((uint64_t)1000) << (sizeof(timeType) * 8)) / F_CPU) / 2; } + static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (F_CPU / 2 / 1000); } }; -#endif // cpu cycles +struct TimeFastMicros +{ + // time policy in micro-seconds based on ESP.getCycleCount() + + using timeType = decltype(ESP.getCycleCount()); + static timeType time() {return ESP.getCycleCount();} + static constexpr timeType toUnit = F_CPU / 1000000; + + // rollover: @80Mhz:53.6s @160Mhz:26.8s + // setting max to half of it to ensure full range is never reached + // - this particular time measurement is intended to be called very often + // (every loop, every yield) + // - this max is larger than internal watchdogs + static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (F_CPU / 2 / 1000000); } +}; + +#endif // !MOCK } //TimePolicy @@ -95,7 +111,7 @@ class timeoutTemplate using timeType = typename TimePolicyT::timeType; timeoutTemplate(timeType timeout) - : _timeout(timeout * TimePolicyT::toMillis), _start(TimePolicyT::time()) + : _timeout(timeout * TimePolicyT::toUnit), _start(TimePolicyT::time()) { assert(timeout < TimePolicyT::timeMax()); } @@ -133,7 +149,12 @@ class timeoutTemplate { return (t - _start) >= _timeout; } - + + static constexpr timeType getTimeMax() + { + return TimePolicyT::timeMax(); + } + protected: bool expiredRetrigger() @@ -157,10 +178,15 @@ class timeoutTemplate timeType _start; }; -using oneShot = polledTimeout::timeoutTemplate; -using periodic = polledTimeout::timeoutTemplate; -using oneShotCycleMs = polledTimeout::timeoutTemplate; -using periodicCycleMs = polledTimeout::timeoutTemplate; +using oneShot = polledTimeout::timeoutTemplate; // legacy, same as oneShotMs +using periodic = polledTimeout::timeoutTemplate; // legacy, same as periodicMs + +using oneShotMs = polledTimeout::timeoutTemplate; +using periodicMs = polledTimeout::timeoutTemplate; +using oneShotFastMs = polledTimeout::timeoutTemplate; +using periodicFastMs = polledTimeout::timeoutTemplate; +using oneShotFastUs = polledTimeout::timeoutTemplate; +using periodicFastUs = polledTimeout::timeoutTemplate; } //polledTimeout From 9b8e40baf51ed052088f3b8c9053520a69799ed5 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Sat, 16 Mar 2019 00:06:37 +0100 Subject: [PATCH 07/35] update example --- .../examples/BlinkPolledTimeout/BlinkPolledTimeout.ino | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino index ae4a2364ee..6b6125d187 100644 --- a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino +++ b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino @@ -38,21 +38,19 @@ void ledToggle() { } -esp8266::polledTimeout::periodic halfPeriod(500); //use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace - -// also available: lighter esp8266::polledTimeout::periodicCycleMs for durations shorter than 13000 ms +esp8266::polledTimeout::periodicFastUs halfPeriod(500000); //use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace // the setup function runs only once at start void setup() { pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output - using esp8266::polledTimeout::oneShot; //import the type to the local namespace + using esp8266::polledTimeout::oneShotMs; //import the type to the local namespace //STEP1; turn the led ON ledOn(); //STEP2: wait for ON timeout - oneShot timeoutOn(2000); + oneShotMs timeoutOn(2000); while (!timeoutOn) { yield(); } @@ -61,7 +59,7 @@ void setup() { ledOff(); //STEP4: wait for OFF timeout to assure the led is kept off for this time before exiting setup - oneShot timeoutOff(2000); + oneShotMs timeoutOff(2000); while (!timeoutOff) { yield(); } From ba105b7cb3437f3633a0bae358256bcf3df50f8e Mon Sep 17 00:00:00 2001 From: david gauchard Date: Mon, 18 Mar 2019 01:24:58 +0100 Subject: [PATCH 08/35] mock: emulate getCycleCount, add/fix polledTimeout CI test --- cores/esp8266/Esp.h | 7 ++- cores/esp8266/PolledTimeout.h | 7 --- tests/host/common/MockEsp.cpp | 8 +++ tests/host/common/mock.h | 4 +- tests/host/core/test_PolledTimeout.cpp | 75 +++++++++++++++++++------- 5 files changed, 72 insertions(+), 29 deletions(-) diff --git a/cores/esp8266/Esp.h b/cores/esp8266/Esp.h index 21dff08523..f717c15881 100644 --- a/cores/esp8266/Esp.h +++ b/cores/esp8266/Esp.h @@ -200,15 +200,20 @@ class EspClass { bool eraseConfig(); - inline uint32_t getCycleCount(); +#ifndef CORE_MOCK + inline +#endif + uint32_t getCycleCount(); }; +#ifndef CORE_MOCK uint32_t EspClass::getCycleCount() { uint32_t ccount; __asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount)); return ccount; } +#endif extern EspClass ESP; diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 78b7e04798..9b9e4e34a8 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -63,10 +63,6 @@ struct TimeMillis static constexpr timeType timeMax() { return (((((timeType)1) << ((sizeof(timeType) * 8) - 2)) - 1) << 1) + 1; } }; -#ifdef CORE_MOCK -struct TimeCycleMs: public TimeMillis {}; -#else - struct TimeFastMillis { // time policy in milli-seconds based on ESP.getCycleCount() @@ -99,9 +95,6 @@ struct TimeFastMicros static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (F_CPU / 2 / 1000000); } }; -#endif // !MOCK - - } //TimePolicy template diff --git a/tests/host/common/MockEsp.cpp b/tests/host/common/MockEsp.cpp index 244debf932..21a124b80d 100644 --- a/tests/host/common/MockEsp.cpp +++ b/tests/host/common/MockEsp.cpp @@ -32,6 +32,8 @@ #include #include +#include + #include unsigned long long operator"" _kHz(unsigned long long x) { @@ -215,3 +217,9 @@ void EspClass::resetFreeContStack() { } +uint32_t EspClass::getCycleCount() +{ + timeval t; + gettimeofday(&t, NULL); + return (((uint64_t)t.tv_sec) * 1000000 + t.tv_usec) * (F_CPU / 1000000); +} diff --git a/tests/host/common/mock.h b/tests/host/common/mock.h index 2db914d783..067411139f 100644 --- a/tests/host/common/mock.h +++ b/tests/host/common/mock.h @@ -29,6 +29,8 @@ DEALINGS WITH THE SOFTWARE. */ +#define CORE_MOCK 1 + // include host's STL before any other include file // because core definition like max() is in the way @@ -138,8 +140,6 @@ void mock_stop_spiffs (); // -#define CORE_MOCK 1 - #define ARDUINO 267 #define ESP8266 1 #define A0 0 diff --git a/tests/host/core/test_PolledTimeout.cpp b/tests/host/core/test_PolledTimeout.cpp index 7746072ecb..6132197327 100644 --- a/tests/host/core/test_PolledTimeout.cpp +++ b/tests/host/core/test_PolledTimeout.cpp @@ -1,6 +1,9 @@ #include #include "PolledTimeout.h" +#define mockverbose printf +#include "common/MockEsp.cpp" // getCycleCount + //This won't work for template inline bool @@ -10,15 +13,49 @@ fuzzycomp(argT a, argT b) return (std::max(a,b) - std::min(a,b) <= epsilon); } +TEST_CASE("OneShot Timeout 3000000us", "[polledTimeout]") +{ + using esp8266::polledTimeout::oneShotFastUs; + using timeType = oneShotFastUs::timeType; + timeType before, after, delta; + + Serial.println("OneShot Timeout 3000000us"); + + oneShotFastUs timeout(3000000); + before = micros(); + while(!timeout.expired()) + yield(); + after = micros(); + + delta = after - before; + Serial.printf("delta = %u\n", delta); + + REQUIRE(fuzzycomp(delta/1000, (timeType)3000)); + + + Serial.print("reset\n"); + + timeout.reset(); + before = micros(); + while(!timeout) + yield(); + after = micros(); + + delta = after - before; + Serial.printf("delta = %u\n", delta); + + REQUIRE(fuzzycomp(delta/1000, (timeType)3000)); +} + TEST_CASE("OneShot Timeout 3000ms", "[polledTimeout]") { - using esp8266::polledTimeout::oneShot; - using timeType = oneShot::timeType; + using esp8266::polledTimeout::oneShotMs; + using timeType = oneShotMs::timeType; timeType before, after, delta; Serial.println("OneShot Timeout 3000ms"); - oneShot timeout(3000); + oneShotMs timeout(3000); before = millis(); while(!timeout.expired()) yield(); @@ -46,13 +83,13 @@ TEST_CASE("OneShot Timeout 3000ms", "[polledTimeout]") TEST_CASE("OneShot Timeout 3000ms reset to 1000ms", "[polledTimeout]") { - using esp8266::polledTimeout::oneShot; - using timeType = oneShot::timeType; + using esp8266::polledTimeout::oneShotMs; + using timeType = oneShotMs::timeType; timeType before, after, delta; Serial.println("OneShot Timeout 3000ms"); - oneShot timeout(3000); + oneShotMs timeout(3000); before = millis(); while(!timeout.expired()) yield(); @@ -80,13 +117,13 @@ TEST_CASE("OneShot Timeout 3000ms reset to 1000ms", "[polledTimeout]") TEST_CASE("Periodic Timeout 1T 3000ms", "[polledTimeout]") { - using esp8266::polledTimeout::periodic; - using timeType = periodic::timeType; + using esp8266::polledTimeout::periodicMs; + using timeType = periodicMs::timeType; timeType before, after, delta; Serial.println("Periodic Timeout 1T 3000ms"); - periodic timeout(3000); + periodicMs timeout(3000); before = millis(); while(!timeout) yield(); @@ -103,7 +140,7 @@ TEST_CASE("Periodic Timeout 1T 3000ms", "[polledTimeout]") while(!timeout) yield(); after = millis(); - + delta = after - before; Serial.printf("delta = %lu\n", delta); @@ -112,15 +149,15 @@ TEST_CASE("Periodic Timeout 1T 3000ms", "[polledTimeout]") TEST_CASE("Periodic Timeout 10T 1000ms", "[polledTimeout]") { - using esp8266::polledTimeout::periodic; - using timeType = periodic::timeType; + using esp8266::polledTimeout::periodicMs; + using timeType = periodicMs::timeType; timeType before, after, delta; Serial.println("Periodic 10T Timeout 1000ms"); int counter = 10; - periodic timeout(1000); + periodicMs timeout(1000); before = millis(); while(1) { @@ -133,7 +170,7 @@ TEST_CASE("Periodic Timeout 10T 1000ms", "[polledTimeout]") } } after = millis(); - + delta = after - before; Serial.printf("\ndelta = %lu\n", delta); REQUIRE(fuzzycomp(delta, (timeType)10000)); @@ -142,18 +179,18 @@ TEST_CASE("Periodic Timeout 10T 1000ms", "[polledTimeout]") TEST_CASE("OneShot Timeout 3000ms reset to 1000ms custom yield", "[polledTimeout]") { using YieldOrSkipPolicy = esp8266::polledTimeout::YieldPolicy::YieldOrSkip; - using oneShotYield = esp8266::polledTimeout::timeoutTemplate; - using timeType = oneShotYield::timeType; + using oneShotMsYield = esp8266::polledTimeout::timeoutTemplate; + using timeType = oneShotMsYield::timeType; timeType before, after, delta; Serial.println("OneShot Timeout 3000ms"); - oneShotYield timeout(3000); + oneShotMsYield timeout(3000); before = millis(); while(!timeout.expired()); after = millis(); - + delta = after - before; Serial.printf("delta = %lu\n", delta); @@ -166,7 +203,7 @@ TEST_CASE("OneShot Timeout 3000ms reset to 1000ms custom yield", "[polledTimeout before = millis(); while(!timeout); after = millis(); - + delta = after - before; Serial.printf("delta = %lu\n", delta); From ebda468fd576615e81844041a3cebe88f1710075 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Tue, 19 Mar 2019 02:36:56 +0100 Subject: [PATCH 09/35] + nano-seconds, assert -> message, comments, host test --- cores/esp8266/HardwareSerial.cpp | 2 +- cores/esp8266/PolledTimeout.h | 58 +++++++++++++++---- libraries/ESP8266mDNS/src/LEAmDNS.h | 34 +++++------ libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp | 12 ++-- libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp | 16 ++--- libraries/SDFS/src/SDFSFormatter.h | 2 +- tests/host/core/test_PolledTimeout.cpp | 34 +++++++++++ 7 files changed, 115 insertions(+), 43 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index ebb23ce0ca..6ec94500db 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -139,7 +139,7 @@ size_t HardwareSerial::readBytes(char* buffer, size_t size) while (got < size) { - esp8266::polledTimeout::oneShot timeOut(_timeout); + esp8266::polledTimeout::oneShotFastMs timeOut(_timeout); size_t avail; while ((avail = available()) == 0 && !timeOut); if (avail == 0) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 9b9e4e34a8..994f4ef008 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -24,7 +24,6 @@ */ #include -#include namespace esp8266 { @@ -57,7 +56,8 @@ struct TimeMillis using timeType = decltype(millis()); static timeType time() {return millis();} - static constexpr timeType toUnit = 1; + static constexpr timeType toUnitMul = 1; + static constexpr timeType toUnitDiv = 1; // rollover: 48 days, setting max to 24 days to fit in signed scalar (below is = 2^31 - 1) static constexpr timeType timeMax() { return (((((timeType)1) << ((sizeof(timeType) * 8) - 2)) - 1) << 1) + 1; } @@ -69,14 +69,15 @@ struct TimeFastMillis using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} - static constexpr timeType toUnit = F_CPU / 1000; + static constexpr timeType toUnitMul = F_CPU / 1000; + static constexpr timeType toUnitDiv = 1; // rollover: @80Mhz:53.6s @160Mhz:26.8s // setting max to half of it to ensure full range is never reached // - this particular time measurement is intended to be called very often // (every loop, every yield) // - this max is larger than internal watchdogs - static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (F_CPU / 2 / 1000); } + static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (toUnitMul / 2); } }; struct TimeFastMicros @@ -85,14 +86,28 @@ struct TimeFastMicros using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} - static constexpr timeType toUnit = F_CPU / 1000000; + static constexpr timeType toUnitMul = F_CPU / 1000000; + static constexpr timeType toUnitDiv = 1; // rollover: @80Mhz:53.6s @160Mhz:26.8s // setting max to half of it to ensure full range is never reached // - this particular time measurement is intended to be called very often // (every loop, every yield) // - this max is larger than internal watchdogs - static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (F_CPU / 2 / 1000000); } + static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (toUnitMul / 2); } +}; + +struct TimeFastNanos +{ + // time policy in nano-seconds based on ESP.getCycleCount() + + using timeType = decltype(ESP.getCycleCount()); + static timeType time() {return ESP.getCycleCount();} + static constexpr timeType toUnitMul = F_CPU / 40000000; + static constexpr timeType toUnitDiv = 25; + + // timeMax is max (signed 32 bits) / toUnitMul = (2^31 / 4(@160MHz)) = 0.536 seconds + static constexpr timeType timeMax() { return (((((timeType)1) << ((sizeof(timeType) * 8) - 2 - 2)) - 1) << 1) + 1; } }; } //TimePolicy @@ -103,10 +118,19 @@ class timeoutTemplate public: using timeType = typename TimePolicyT::timeType; + static constexpr timeType timeMax () + { + return TimePolicyT::timeMax(); + } + timeoutTemplate(timeType timeout) - : _timeout(timeout * TimePolicyT::toUnit), _start(TimePolicyT::time()) + : _timeout((timeout * TimePolicyT::toUnitMul) / TimePolicyT::toUnitDiv), _start(TimePolicyT::time()) { - assert(timeout < TimePolicyT::timeMax()); + if (timeout > timeMax()) + { + timeout = timeMax(); + ::printf((PGM_P)F("polledTimeout: overflow\r\n")); + } } bool expired() @@ -171,15 +195,29 @@ class timeoutTemplate timeType _start; }; -using oneShot = polledTimeout::timeoutTemplate; // legacy, same as oneShotMs -using periodic = polledTimeout::timeoutTemplate; // legacy, same as periodicMs +// legacy type names, deprecated (unit is milliseconds) + +using oneShot = polledTimeout::timeoutTemplate /*__attribute__((deprecated("use oneShotMs")))*/; +using periodic = polledTimeout::timeoutTemplate /*__attribute__((deprecated("use periodicMs")))*/; + +// standard versions (based on millis()) +// timeMax() is 24 days (~ 2000000000 ms) using oneShotMs = polledTimeout::timeoutTemplate; using periodicMs = polledTimeout::timeoutTemplate; + +// "Fast" versions sacrifices time range for improved precision and reduced code size (factor ~100) +// timeMax() values: +// Ms: max is 13421 ms (13.4 s) +// Us: max is 13421772 us (13.4 s) +// Ns: max is 536870911 ns ( 0.536 s) + using oneShotFastMs = polledTimeout::timeoutTemplate; using periodicFastMs = polledTimeout::timeoutTemplate; using oneShotFastUs = polledTimeout::timeoutTemplate; using periodicFastUs = polledTimeout::timeoutTemplate; +using oneShotFastNs = polledTimeout::timeoutTemplate; +using periodicFastNs = polledTimeout::timeoutTemplate; } //polledTimeout diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.h b/libraries/ESP8266mDNS/src/LEAmDNS.h index d35df1fbd3..434f44581b 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS.h @@ -905,12 +905,12 @@ class MDNSResponder { * stcProbeInformation */ struct stcProbeInformation { - enuProbingStatus m_ProbingStatus; - uint8_t m_u8SentCount; // Used for probes and announcements - esp8266::polledTimeout::oneShot m_Timeout; // Used for probes and announcements - //clsMDNSTimeFlag m_TimeFlag; // Used for probes and announcements - bool m_bConflict; - bool m_bTiebreakNeeded; + enuProbingStatus m_ProbingStatus; + uint8_t m_u8SentCount; // Used for probes and announcements + esp8266::polledTimeout::oneShotMs m_Timeout; // Used for probes and announcements + //clsMDNSTimeFlag m_TimeFlag; // Used for probes and announcements + bool m_bConflict; + bool m_bTiebreakNeeded; MDNSHostProbeFn m_fnHostProbeResultCallback; MDNSServiceProbeFn m_fnServiceProbeResultCallback; @@ -974,9 +974,9 @@ class MDNSResponder { const timeoutLevel_t TIMEOUTLEVEL_INTERVAL = 5; const timeoutLevel_t TIMEOUTLEVEL_FINAL = 100; - uint32_t m_u32TTL; - esp8266::polledTimeout::oneShot m_TTLTimeout; - timeoutLevel_t m_timeoutLevel; + uint32_t m_u32TTL; + esp8266::polledTimeout::oneShotMs m_TTLTimeout; + timeoutLevel_t m_timeoutLevel; stcTTL(void); bool set(uint32_t p_u32TTL); @@ -1073,14 +1073,14 @@ class MDNSResponder { #endif }; - stcMDNSServiceQuery* m_pNext; - stcMDNS_RRDomain m_ServiceTypeDomain; // eg. _http._tcp.local - MDNSServiceQueryCallbackFunc m_fnCallback; - bool m_bLegacyQuery; - uint8_t m_u8SentCount; - esp8266::polledTimeout::oneShot m_ResendTimeout; - bool m_bAwaitingAnswers; - stcAnswer* m_pAnswers; + stcMDNSServiceQuery* m_pNext; + stcMDNS_RRDomain m_ServiceTypeDomain; // eg. _http._tcp.local + MDNSServiceQueryCallbackFunc m_fnCallback; + bool m_bLegacyQuery; + uint8_t m_u8SentCount; + esp8266::polledTimeout::oneShotMs m_ResendTimeout; + bool m_bAwaitingAnswers; + stcAnswer* m_pAnswers; stcMDNSServiceQuery(void); ~stcMDNSServiceQuery(void); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp index c95c8d8234..37a68d9d0c 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp @@ -1061,7 +1061,7 @@ bool MDNSResponder::_updateProbeStatus(void) { else { // Probing finished DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host probing.\n"));); m_HostProbeInformation.m_ProbingStatus = ProbingStatus_Done; - m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); if (m_HostProbeInformation.m_fnHostProbeResultCallback) { m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, true); } @@ -1073,7 +1073,7 @@ bool MDNSResponder::_updateProbeStatus(void) { } } // else: Probing already finished OR waiting for next time slot else if ((ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) && - (m_HostProbeInformation.m_Timeout.checkExpired(std::numeric_limits::max()))) { + (m_HostProbeInformation.m_Timeout.checkExpired(std::numeric_limits::max()))) { if ((bResult = _announce(true, false))) { // Don't announce services here ++m_HostProbeInformation.m_u8SentCount; @@ -1083,7 +1083,7 @@ bool MDNSResponder::_updateProbeStatus(void) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%lu).\n\n"), m_HostProbeInformation.m_u8SentCount);); } else { - m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host announcing.\n\n"));); } } @@ -1110,7 +1110,7 @@ bool MDNSResponder::_updateProbeStatus(void) { else { // Probing finished DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service probing %s.%s.%s\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_Done; - pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); if (pService->m_ProbeInformation.m_fnServiceProbeResultCallback) { pService->m_ProbeInformation.m_fnServiceProbeResultCallback(pService->m_pcName, pService, true); } @@ -1131,7 +1131,7 @@ bool MDNSResponder::_updateProbeStatus(void) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing service %s.%s.%s (%lu)\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount);); } else { - pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service announcing for %s.%s.%s\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); } } @@ -1449,7 +1449,7 @@ bool MDNSResponder::_checkServiceQueryCache(void) { ++pServiceQuery->m_u8SentCount; pServiceQuery->m_ResendTimeout.reset((MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) ? (MDNS_DYNAMIC_QUERY_RESEND_DELAY * (pServiceQuery->m_u8SentCount - 1)) - : std::numeric_limits::max()); + : std::numeric_limits::max()); } DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: %s to resend service query!"), (bResult ? "Succeeded" : "FAILED")); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp index 41c38fe6b1..f60add695a 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp @@ -1159,7 +1159,7 @@ bool MDNSResponder::stcMDNS_RRAnswerGeneric::clear(void) { MDNSResponder::stcProbeInformation::stcProbeInformation(void) : m_ProbingStatus(ProbingStatus_WaitingForData), m_u8SentCount(0), - m_Timeout(std::numeric_limits::max()), + m_Timeout(std::numeric_limits::max()), m_bConflict(false), m_bTiebreakNeeded(false), m_fnHostProbeResultCallback(0), @@ -1173,7 +1173,7 @@ bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/ m_ProbingStatus = ProbingStatus_WaitingForData; m_u8SentCount = 0; - m_Timeout.reset(std::numeric_limits::max()); + m_Timeout.reset(std::numeric_limits::max()); m_bConflict = false; m_bTiebreakNeeded = false; if (p_bClearUserdata) { @@ -1421,7 +1421,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated(void) con */ MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(void) : m_u32TTL(0), - m_TTLTimeout(std::numeric_limits::max()), + m_TTLTimeout(std::numeric_limits::max()), m_timeoutLevel(TIMEOUTLEVEL_UNSET) { } @@ -1438,7 +1438,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TT } else { m_timeoutLevel = TIMEOUTLEVEL_UNSET; // undef - m_TTLTimeout.reset(std::numeric_limits::max()); + m_TTLTimeout.reset(std::numeric_limits::max()); } return true; } @@ -1468,7 +1468,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart(void) { } else { bResult = false; - m_TTLTimeout.reset(std::numeric_limits::max()); + m_TTLTimeout.reset(std::numeric_limits::max()); m_timeoutLevel = TIMEOUTLEVEL_UNSET; } return bResult; @@ -1498,7 +1498,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel(vo */ unsigned long MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout(void) const { - uint32_t u32Timeout = std::numeric_limits::max(); + uint32_t u32Timeout = std::numeric_limits::max(); if (TIMEOUTLEVEL_BASE == m_timeoutLevel) { // 80% u32Timeout = (m_u32TTL * 800); // to milliseconds @@ -1922,7 +1922,7 @@ MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery(void) m_fnCallback(0), m_bLegacyQuery(false), m_u8SentCount(0), - m_ResendTimeout(std::numeric_limits::max()), + m_ResendTimeout(std::numeric_limits::max()), m_bAwaitingAnswers(true), m_pAnswers(0) { @@ -1945,7 +1945,7 @@ bool MDNSResponder::stcMDNSServiceQuery::clear(void) { m_fnCallback = 0; m_bLegacyQuery = false; m_u8SentCount = 0; - m_ResendTimeout.reset(std::numeric_limits::max()); + m_ResendTimeout.reset(std::numeric_limits::max()); m_bAwaitingAnswers = true; while (m_pAnswers) { stcAnswer* pNext = m_pAnswers->m_pNext; diff --git a/libraries/SDFS/src/SDFSFormatter.h b/libraries/SDFS/src/SDFSFormatter.h index a911a76543..d1fe6c94a7 100644 --- a/libraries/SDFS/src/SDFSFormatter.h +++ b/libraries/SDFS/src/SDFSFormatter.h @@ -73,7 +73,7 @@ class SDFSFormatter { DEBUGV("SDFS: Clear FAT/DIR writeStart failed"); return false; } - esp8266::polledTimeout::periodic timeToYield(5); // Yield every 5ms of runtime + esp8266::polledTimeout::periodicFastMs timeToYield(5); // Yield every 5ms of runtime for (uint32_t i = 0; i < count; i++) { if (timeToYield) { delay(0); // WDT feed diff --git a/tests/host/core/test_PolledTimeout.cpp b/tests/host/core/test_PolledTimeout.cpp index 6132197327..37b31d8544 100644 --- a/tests/host/core/test_PolledTimeout.cpp +++ b/tests/host/core/test_PolledTimeout.cpp @@ -13,6 +13,40 @@ fuzzycomp(argT a, argT b) return (std::max(a,b) - std::min(a,b) <= epsilon); } +TEST_CASE("OneShot Timeout 500000000ns (0.5s)", "[polledTimeout]") +{ + using esp8266::polledTimeout::oneShotFastNs; + using timeType = oneShotFastNs::timeType; + timeType before, after, delta; + + Serial.println("OneShot Timeout 500000000ns (0.5s)"); + + oneShotFastNs timeout(500000000); + before = micros(); + while(!timeout.expired()) + yield(); + after = micros(); + + delta = after - before; + Serial.printf("delta = %u\n", delta); + + REQUIRE(fuzzycomp(delta/1000, (timeType)500)); + + + Serial.print("reset\n"); + + timeout.reset(); + before = micros(); + while(!timeout) + yield(); + after = micros(); + + delta = after - before; + Serial.printf("delta = %u\n", delta); + + REQUIRE(fuzzycomp(delta/1000, (timeType)500)); +} + TEST_CASE("OneShot Timeout 3000000us", "[polledTimeout]") { using esp8266::polledTimeout::oneShotFastUs; From 7a4c4de9ce1993e64d1743db241a586ad5dc5daf Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Tue, 19 Mar 2019 15:33:47 +0100 Subject: [PATCH 10/35] allow 0 for timeout (enables immediate timeout, fix division by 0) --- cores/esp8266/PolledTimeout.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 994f4ef008..445cea7ace 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -176,6 +176,8 @@ class timeoutTemplate bool expiredRetrigger() { + if (!_timeout) + return true; timeType current = TimePolicyT::time(); if(checkExpired(current)) { From aa6b2d935c64a05b39dfd904a2e4c6fb05216e56 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Tue, 19 Mar 2019 16:34:59 +0100 Subject: [PATCH 11/35] typo, set member instead of local variable --- cores/esp8266/PolledTimeout.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 445cea7ace..75d58b8aeb 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -128,7 +128,7 @@ class timeoutTemplate { if (timeout > timeMax()) { - timeout = timeMax(); + _timeout = timeMax(); ::printf((PGM_P)F("polledTimeout: overflow\r\n")); } } From e98c41cf0b4b0c3ef84df22e3246d72a930ef85a Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Tue, 19 Mar 2019 17:28:39 +0100 Subject: [PATCH 12/35] unify error message --- cores/esp8266/PolledTimeout.h | 8 ++++++-- cores/esp8266/debug.cpp | 2 ++ cores/esp8266/debug.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 75d58b8aeb..720163be54 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -24,6 +24,7 @@ */ #include +#include // polledTimeoutOverflowMessage namespace esp8266 { @@ -123,13 +124,16 @@ class timeoutTemplate return TimePolicyT::timeMax(); } - timeoutTemplate(timeType timeout) + timeoutTemplate(const timeType timeout) : _timeout((timeout * TimePolicyT::toUnitMul) / TimePolicyT::toUnitDiv), _start(TimePolicyT::time()) { if (timeout > timeMax()) { _timeout = timeMax(); - ::printf((PGM_P)F("polledTimeout: overflow\r\n")); +#ifndef NDEBUG + // not displayed when NoAssert-NDEBUG is enabled + ::printf(polledTimeoutOverflowMessage); +#endif } } diff --git a/cores/esp8266/debug.cpp b/cores/esp8266/debug.cpp index d8bf8bb11d..b6c1513dce 100644 --- a/cores/esp8266/debug.cpp +++ b/cores/esp8266/debug.cpp @@ -21,6 +21,8 @@ #include "Arduino.h" #include "debug.h" +const char* polledTimeoutOverflowMessage PROGMEM = "polledTimeout: overflow\r\n"; + void ICACHE_RAM_ATTR hexdump(const void *mem, uint32_t len, uint8_t cols) { const uint8_t* src = (const uint8_t*) mem; os_printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); diff --git a/cores/esp8266/debug.h b/cores/esp8266/debug.h index fab128253c..a32f22070b 100644 --- a/cores/esp8266/debug.h +++ b/cores/esp8266/debug.h @@ -29,5 +29,6 @@ void __panic_func(const char* file, int line, const char* func) __attribute__((n } #endif +extern const char* polledTimeoutOverflowMessage; #endif//ARD_DEBUG_H From 714beb30b68ed0b09885fef32e50a3fc78ed82d3 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Tue, 19 Mar 2019 22:55:20 +0100 Subject: [PATCH 13/35] slight change on checkExpired() allows "never expired" also removed printed message, add YieldAndDelay, simplify calculations --- cores/esp8266/PolledTimeout.h | 67 +++++++++++++++++++---------------- cores/esp8266/debug.cpp | 2 -- cores/esp8266/debug.h | 2 -- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 720163be54..c5825a8c9e 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -46,6 +46,12 @@ struct YieldOrSkip static void execute() {delay(0);} }; +template +struct YieldAndDelayMs +{ + static void execute() {delay(delayMs);} +}; + } //YieldPolicy namespace TimePolicy @@ -57,11 +63,12 @@ struct TimeMillis using timeType = decltype(millis()); static timeType time() {return millis();} - static constexpr timeType toUnitMul = 1; - static constexpr timeType toUnitDiv = 1; - // rollover: 48 days, setting max to 24 days to fit in signed scalar (below is = 2^31 - 1) - static constexpr timeType timeMax() { return (((((timeType)1) << ((sizeof(timeType) * 8) - 2)) - 1) << 1) + 1; } + // millis to millis + static timeType toTimeTypeUnit (const timeType t) { return t; } + + // rollover on 32 bits: 49.7 days (::max() is a "never expires"-reserved value) + static constexpr timeType timeMax() { return std::numeric_limits::max() - 1; } }; struct TimeFastMillis @@ -70,15 +77,17 @@ struct TimeFastMillis using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} - static constexpr timeType toUnitMul = F_CPU / 1000; - static constexpr timeType toUnitDiv = 1; + static constexpr timeType toTimeTypeUnitMul = F_CPU / 1000; + + // millis to CPU cycles: + static timeType toTimeTypeUnit (const timeType t) { return t * toTimeTypeUnitMul; } // rollover: @80Mhz:53.6s @160Mhz:26.8s - // setting max to half of it to ensure full range is never reached + // setting max to half of min to ensure full range is never reached // - this particular time measurement is intended to be called very often // (every loop, every yield) // - this max is larger than internal watchdogs - static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (toUnitMul / 2); } + static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (toTimeTypeUnitMul / 2); } }; struct TimeFastMicros @@ -87,15 +96,17 @@ struct TimeFastMicros using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} - static constexpr timeType toUnitMul = F_CPU / 1000000; - static constexpr timeType toUnitDiv = 1; + static constexpr timeType toTimeTypeUnitMul = F_CPU / 1000000; + + // micros to CPU cycles: + static timeType toTimeTypeUnit (const timeType t) { return t * toTimeTypeUnitMul; } // rollover: @80Mhz:53.6s @160Mhz:26.8s - // setting max to half of it to ensure full range is never reached + // setting max to half of min to ensure full range is never reached // - this particular time measurement is intended to be called very often // (every loop, every yield) // - this max is larger than internal watchdogs - static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (toUnitMul / 2); } + static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (toTimeTypeUnitMul / 2); } }; struct TimeFastNanos @@ -104,10 +115,11 @@ struct TimeFastNanos using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} - static constexpr timeType toUnitMul = F_CPU / 40000000; - static constexpr timeType toUnitDiv = 25; - // timeMax is max (signed 32 bits) / toUnitMul = (2^31 / 4(@160MHz)) = 0.536 seconds + // nanos to CPU cycles (best, within 32bits range) + static timeType toTimeTypeUnit (const timeType t) { return (t * (F_CPU / 40000000)) / 25; } + + // given toTimeTypeUnit(), timeMax is (2^31 / 4(@160MHz)) = 0.536 seconds static constexpr timeType timeMax() { return (((((timeType)1) << ((sizeof(timeType) * 8) - 2 - 2)) - 1) << 1) + 1; } }; @@ -119,21 +131,13 @@ class timeoutTemplate public: using timeType = typename TimePolicyT::timeType; - static constexpr timeType timeMax () - { - return TimePolicyT::timeMax(); - } - timeoutTemplate(const timeType timeout) - : _timeout((timeout * TimePolicyT::toUnitMul) / TimePolicyT::toUnitDiv), _start(TimePolicyT::time()) + : _timeout(TimePolicyT::toTimeTypeUnit(timeout)), _start(TimePolicyT::time()) { if (timeout > timeMax()) { - _timeout = timeMax(); -#ifndef NDEBUG - // not displayed when NoAssert-NDEBUG is enabled - ::printf(polledTimeoutOverflowMessage); -#endif + // "never expires" (checkExpired() condition "(t - _start) > _timeout;" is never reached) + _timeout = std::numeric_limits::max(); } } @@ -168,10 +172,11 @@ class timeoutTemplate bool checkExpired(const timeType t) const { - return (t - _start) >= _timeout; + // always returns false when _timeout is ::max() + return (t - _start) > _timeout; } - static constexpr timeType getTimeMax() + static constexpr timeType timeMax() { return TimePolicyT::timeMax(); } @@ -180,8 +185,10 @@ class timeoutTemplate bool expiredRetrigger() { - if (!_timeout) + if (_timeout == 0) + // "always expired" return true; + timeType current = TimePolicyT::time(); if(checkExpired(current)) { @@ -207,7 +214,7 @@ using oneShot = polledTimeout::timeoutTemplate /*__attribute__((deprecate using periodic = polledTimeout::timeoutTemplate /*__attribute__((deprecated("use periodicMs")))*/; // standard versions (based on millis()) -// timeMax() is 24 days (~ 2000000000 ms) +// timeMax() is 49.7 days (2^32 ms) using oneShotMs = polledTimeout::timeoutTemplate; using periodicMs = polledTimeout::timeoutTemplate; diff --git a/cores/esp8266/debug.cpp b/cores/esp8266/debug.cpp index b6c1513dce..d8bf8bb11d 100644 --- a/cores/esp8266/debug.cpp +++ b/cores/esp8266/debug.cpp @@ -21,8 +21,6 @@ #include "Arduino.h" #include "debug.h" -const char* polledTimeoutOverflowMessage PROGMEM = "polledTimeout: overflow\r\n"; - void ICACHE_RAM_ATTR hexdump(const void *mem, uint32_t len, uint8_t cols) { const uint8_t* src = (const uint8_t*) mem; os_printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); diff --git a/cores/esp8266/debug.h b/cores/esp8266/debug.h index a32f22070b..bae427fff1 100644 --- a/cores/esp8266/debug.h +++ b/cores/esp8266/debug.h @@ -29,6 +29,4 @@ void __panic_func(const char* file, int line, const char* func) __attribute__((n } #endif -extern const char* polledTimeoutOverflowMessage; - #endif//ARD_DEBUG_H From 925408ecb9676724ea6fab81bb1f3c83e2c6d4db Mon Sep 17 00:00:00 2001 From: david gauchard Date: Tue, 19 Mar 2019 23:01:57 +0100 Subject: [PATCH 14/35] remove traces of debug.h/cpp in this PR --- cores/esp8266/PolledTimeout.h | 1 - cores/esp8266/debug.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index c5825a8c9e..644c4b245c 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -24,7 +24,6 @@ */ #include -#include // polledTimeoutOverflowMessage namespace esp8266 { diff --git a/cores/esp8266/debug.h b/cores/esp8266/debug.h index bae427fff1..fab128253c 100644 --- a/cores/esp8266/debug.h +++ b/cores/esp8266/debug.h @@ -29,4 +29,5 @@ void __panic_func(const char* file, int line, const char* func) __attribute__((n } #endif + #endif//ARD_DEBUG_H From 412a241fd60b13fc086e61b1aa89ab803fc12508 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Wed, 20 Mar 2019 01:06:59 +0100 Subject: [PATCH 15/35] include missing header --- cores/esp8266/PolledTimeout.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 644c4b245c..8b4e8092ed 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include namespace esp8266 From 273306a3ee249d6bca9d4c355b2097b4edd563a4 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 20 Mar 2019 13:42:45 +0100 Subject: [PATCH 16/35] back to original expired test, introduce boolean _neverExpires, fix reset(), getTimeout() is invalid --- cores/esp8266/PolledTimeout.h | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 8b4e8092ed..187a2fa036 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -132,14 +132,9 @@ class timeoutTemplate public: using timeType = typename TimePolicyT::timeType; - timeoutTemplate(const timeType timeout) - : _timeout(TimePolicyT::toTimeTypeUnit(timeout)), _start(TimePolicyT::time()) + timeoutTemplate(const timeType userTimeout) { - if (timeout > timeMax()) - { - // "never expires" (checkExpired() condition "(t - _start) > _timeout;" is never reached) - _timeout = std::numeric_limits::max(); - } + reset(userTimeout); } bool expired() @@ -155,10 +150,11 @@ class timeoutTemplate return expired(); } - void reset(const timeType newTimeout) + void reset(const timeType newUserTimeout) { - _timeout = newTimeout; + _timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout); reset(); + _neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax()); } void reset() @@ -166,24 +162,28 @@ class timeoutTemplate _start = TimePolicyT::time(); } +#if 0 timeType getTimeout() const { return _timeout; } +#endif - bool checkExpired(const timeType t) const - { - // always returns false when _timeout is ::max() - return (t - _start) > _timeout; - } - static constexpr timeType timeMax() { return TimePolicyT::timeMax(); } protected: + + // internal time unit not exposed to user + bool checkExpired(const timeType t) const + { + bool ongoing = _neverExpires || ((t - _start) < _timeout); + return !ongoing; + } + bool expiredRetrigger() { if (_timeout == 0) @@ -207,6 +207,7 @@ class timeoutTemplate timeType _timeout; timeType _start; + bool _neverExpires; }; // legacy type names, deprecated (unit is milliseconds) From 531e08efe97c690c94414f1078b69761192082d2 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 20 Mar 2019 14:19:41 +0100 Subject: [PATCH 17/35] fix expiredOneShot with _timeout==0 check --- cores/esp8266/PolledTimeout.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 187a2fa036..d0c78a6f9d 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -174,16 +174,19 @@ class timeoutTemplate return TimePolicyT::timeMax(); } -protected: +private: - // internal time unit not exposed to user - bool checkExpired(const timeType t) const { - bool ongoing = _neverExpires || ((t - _start) < _timeout); + // internal time unit API not exposed to user + // (_timeout == 0) is not checked here + + bool ongoing = (_neverExpires || ((t - _start) < _timeout)); return !ongoing; } +protected: + bool expiredRetrigger() { if (_timeout == 0) @@ -202,7 +205,7 @@ class timeoutTemplate bool expiredOneShot() const { - return checkExpired(TimePolicyT::time()); + return _timeout == 0 || checkExpired(TimePolicyT::time()); } timeType _timeout; From a041a6693c54f7fd8d0ca54c815520cc86ecdaec Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 20 Mar 2019 14:34:04 +0100 Subject: [PATCH 18/35] reenable getTimeout() --- cores/esp8266/PolledTimeout.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index d0c78a6f9d..e414f16570 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -67,6 +67,7 @@ struct TimeMillis // millis to millis static timeType toTimeTypeUnit (const timeType t) { return t; } + static timeType toUserUnit (const timeType t) { return t; } // rollover on 32 bits: 49.7 days (::max() is a "never expires"-reserved value) static constexpr timeType timeMax() { return std::numeric_limits::max() - 1; } @@ -81,7 +82,8 @@ struct TimeFastMillis static constexpr timeType toTimeTypeUnitMul = F_CPU / 1000; // millis to CPU cycles: - static timeType toTimeTypeUnit (const timeType t) { return t * toTimeTypeUnitMul; } + static timeType toTimeTypeUnit (const timeType user) { return user * toTimeTypeUnitMul; } + static timeType toUserUnit (const timeType internal) { return internal / toTimeTypeUnitMul; } // rollover: @80Mhz:53.6s @160Mhz:26.8s // setting max to half of min to ensure full range is never reached @@ -100,7 +102,8 @@ struct TimeFastMicros static constexpr timeType toTimeTypeUnitMul = F_CPU / 1000000; // micros to CPU cycles: - static timeType toTimeTypeUnit (const timeType t) { return t * toTimeTypeUnitMul; } + static timeType toTimeTypeUnit (const timeType user) { return user * toTimeTypeUnitMul; } + static timeType toUserUnit (const timeType internal) { return internal / toTimeTypeUnitMul; } // rollover: @80Mhz:53.6s @160Mhz:26.8s // setting max to half of min to ensure full range is never reached @@ -118,7 +121,8 @@ struct TimeFastNanos static timeType time() {return ESP.getCycleCount();} // nanos to CPU cycles (best, within 32bits range) - static timeType toTimeTypeUnit (const timeType t) { return (t * (F_CPU / 40000000)) / 25; } + static timeType toTimeTypeUnit (const timeType user) { return (user * (F_CPU / 40000000)) / 25; } + static timeType toUserUnit (const timeType internal) { return (internal * 25) / (F_CPU / 40000000); } // given toTimeTypeUnit(), timeMax is (2^31 / 4(@160MHz)) = 0.536 seconds static constexpr timeType timeMax() { return (((((timeType)1) << ((sizeof(timeType) * 8) - 2 - 2)) - 1) << 1) + 1; } @@ -152,8 +156,8 @@ class timeoutTemplate void reset(const timeType newUserTimeout) { - _timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout); reset(); + _timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout); _neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax()); } @@ -162,12 +166,10 @@ class timeoutTemplate _start = TimePolicyT::time(); } -#if 0 timeType getTimeout() const { - return _timeout; + return TimePolicyT::toUserUnit(_timeout); } -#endif static constexpr timeType timeMax() { From 70ac79443e2ffe34ccd78eb941c66b749c78c595 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 20 Mar 2019 15:27:17 +0100 Subject: [PATCH 19/35] expose checkExpired with unit conversion --- cores/esp8266/PolledTimeout.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index e414f16570..859d27c688 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -176,14 +176,19 @@ class timeoutTemplate return TimePolicyT::timeMax(); } + bool checkExpired(const timeType userUnit) const + { + return (/*always expired*/ _timeout == 0) || internalCheckExpired(TimePolicyT::toTimeTypeUnit(userUnit)); + } + private: - bool checkExpired(const timeType t) const + bool internalCheckExpired(const timeType internalUnit) const { // internal time unit API not exposed to user // (_timeout == 0) is not checked here - bool ongoing = (_neverExpires || ((t - _start) < _timeout)); + bool ongoing = (_neverExpires || ((internalUnit - _start) < _timeout)); return !ongoing; } @@ -196,7 +201,7 @@ class timeoutTemplate return true; timeType current = TimePolicyT::time(); - if(checkExpired(current)) + if(internalCheckExpired(current)) { unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout) _start += n * _timeout; @@ -207,7 +212,7 @@ class timeoutTemplate bool expiredOneShot() const { - return _timeout == 0 || checkExpired(TimePolicyT::time()); + return (/*always expired*/ _timeout == 0) || internalCheckExpired(TimePolicyT::time()); } timeType _timeout; @@ -226,11 +231,12 @@ using periodic = polledTimeout::timeoutTemplate /*__attribute__((deprecate using oneShotMs = polledTimeout::timeoutTemplate; using periodicMs = polledTimeout::timeoutTemplate; -// "Fast" versions sacrifices time range for improved precision and reduced code size (factor ~100) +// "Fast" versions sacrifices time range for improved precision and reduced code execution (by 30%) // timeMax() values: // Ms: max is 13421 ms (13.4 s) // Us: max is 13421772 us (13.4 s) // Ns: max is 536870911 ns ( 0.536 s) +// cpu cycles for ::expired(): 1069 (w/millis()) vs 736 (w/Fast/getCycleCount) using oneShotFastMs = polledTimeout::timeoutTemplate; using periodicFastMs = polledTimeout::timeoutTemplate; From e25b880b09e09c35ec56175e81e2d597eb77b220 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 20 Mar 2019 17:42:05 +0100 Subject: [PATCH 20/35] fix timing comments, move critical code to iram --- cores/esp8266/PolledTimeout.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 859d27c688..99dda5634e 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -183,6 +183,7 @@ class timeoutTemplate private: + ICACHE_RAM_ATTR bool internalCheckExpired(const timeType internalUnit) const { // internal time unit API not exposed to user @@ -194,6 +195,7 @@ class timeoutTemplate protected: + ICACHE_RAM_ATTR bool expiredRetrigger() { if (_timeout == 0) @@ -210,6 +212,7 @@ class timeoutTemplate return false; } + ICACHE_RAM_ATTR bool expiredOneShot() const { return (/*always expired*/ _timeout == 0) || internalCheckExpired(TimePolicyT::time()); @@ -231,12 +234,12 @@ using periodic = polledTimeout::timeoutTemplate /*__attribute__((deprecate using oneShotMs = polledTimeout::timeoutTemplate; using periodicMs = polledTimeout::timeoutTemplate; -// "Fast" versions sacrifices time range for improved precision and reduced code execution (by 30%) +// "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%) +// (cpu cycles for ::expired(): 372 (millis()) vs 52 (getCycleCount)) // timeMax() values: // Ms: max is 13421 ms (13.4 s) // Us: max is 13421772 us (13.4 s) // Ns: max is 536870911 ns ( 0.536 s) -// cpu cycles for ::expired(): 1069 (w/millis()) vs 736 (w/Fast/getCycleCount) using oneShotFastMs = polledTimeout::timeoutTemplate; using periodicFastMs = polledTimeout::timeoutTemplate; From a20f8f61ca28e6a85408d4b564730049a292fa18 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 20 Mar 2019 18:03:16 +0100 Subject: [PATCH 21/35] add member ::neverExpires and use it where relevant --- cores/esp8266/PolledTimeout.h | 4 +++- libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp | 12 ++++++------ libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp | 16 ++++++++-------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 99dda5634e..8389c2ed5a 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -135,7 +135,9 @@ class timeoutTemplate { public: using timeType = typename TimePolicyT::timeType; - + + static constexpr timeType neverExpires = std::numeric_limits::max(); + timeoutTemplate(const timeType userTimeout) { reset(userTimeout); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp index 37a68d9d0c..d6627ece3b 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp @@ -1061,7 +1061,7 @@ bool MDNSResponder::_updateProbeStatus(void) { else { // Probing finished DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host probing.\n"));); m_HostProbeInformation.m_ProbingStatus = ProbingStatus_Done; - m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + m_HostProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); if (m_HostProbeInformation.m_fnHostProbeResultCallback) { m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, true); } @@ -1073,7 +1073,7 @@ bool MDNSResponder::_updateProbeStatus(void) { } } // else: Probing already finished OR waiting for next time slot else if ((ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) && - (m_HostProbeInformation.m_Timeout.checkExpired(std::numeric_limits::max()))) { + (m_HostProbeInformation.m_Timeout.checkExpired(esp8266::polledTimeout::oneShotMs::neverExpires))) { if ((bResult = _announce(true, false))) { // Don't announce services here ++m_HostProbeInformation.m_u8SentCount; @@ -1083,7 +1083,7 @@ bool MDNSResponder::_updateProbeStatus(void) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%lu).\n\n"), m_HostProbeInformation.m_u8SentCount);); } else { - m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + m_HostProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host announcing.\n\n"));); } } @@ -1110,7 +1110,7 @@ bool MDNSResponder::_updateProbeStatus(void) { else { // Probing finished DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service probing %s.%s.%s\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_Done; - pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + pService->m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); if (pService->m_ProbeInformation.m_fnServiceProbeResultCallback) { pService->m_ProbeInformation.m_fnServiceProbeResultCallback(pService->m_pcName, pService, true); } @@ -1131,7 +1131,7 @@ bool MDNSResponder::_updateProbeStatus(void) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing service %s.%s.%s (%lu)\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount);); } else { - pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + pService->m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service announcing for %s.%s.%s\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); } } @@ -1449,7 +1449,7 @@ bool MDNSResponder::_checkServiceQueryCache(void) { ++pServiceQuery->m_u8SentCount; pServiceQuery->m_ResendTimeout.reset((MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) ? (MDNS_DYNAMIC_QUERY_RESEND_DELAY * (pServiceQuery->m_u8SentCount - 1)) - : std::numeric_limits::max()); + : esp8266::polledTimeout::oneShotMs::neverExpires); } DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: %s to resend service query!"), (bResult ? "Succeeded" : "FAILED")); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp index f60add695a..0642c37d76 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp @@ -1159,7 +1159,7 @@ bool MDNSResponder::stcMDNS_RRAnswerGeneric::clear(void) { MDNSResponder::stcProbeInformation::stcProbeInformation(void) : m_ProbingStatus(ProbingStatus_WaitingForData), m_u8SentCount(0), - m_Timeout(std::numeric_limits::max()), + m_Timeout(esp8266::polledTimeout::oneShotMs::neverExpires), m_bConflict(false), m_bTiebreakNeeded(false), m_fnHostProbeResultCallback(0), @@ -1173,7 +1173,7 @@ bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/ m_ProbingStatus = ProbingStatus_WaitingForData; m_u8SentCount = 0; - m_Timeout.reset(std::numeric_limits::max()); + m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); m_bConflict = false; m_bTiebreakNeeded = false; if (p_bClearUserdata) { @@ -1421,7 +1421,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated(void) con */ MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(void) : m_u32TTL(0), - m_TTLTimeout(std::numeric_limits::max()), + m_TTLTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), m_timeoutLevel(TIMEOUTLEVEL_UNSET) { } @@ -1438,7 +1438,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TT } else { m_timeoutLevel = TIMEOUTLEVEL_UNSET; // undef - m_TTLTimeout.reset(std::numeric_limits::max()); + m_TTLTimeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); } return true; } @@ -1468,7 +1468,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart(void) { } else { bResult = false; - m_TTLTimeout.reset(std::numeric_limits::max()); + m_TTLTimeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); m_timeoutLevel = TIMEOUTLEVEL_UNSET; } return bResult; @@ -1498,7 +1498,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel(vo */ unsigned long MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout(void) const { - uint32_t u32Timeout = std::numeric_limits::max(); + uint32_t u32Timeout = esp8266::polledTimeout::oneShotMs::neverExpires; if (TIMEOUTLEVEL_BASE == m_timeoutLevel) { // 80% u32Timeout = (m_u32TTL * 800); // to milliseconds @@ -1922,7 +1922,7 @@ MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery(void) m_fnCallback(0), m_bLegacyQuery(false), m_u8SentCount(0), - m_ResendTimeout(std::numeric_limits::max()), + m_ResendTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), m_bAwaitingAnswers(true), m_pAnswers(0) { @@ -1945,7 +1945,7 @@ bool MDNSResponder::stcMDNSServiceQuery::clear(void) { m_fnCallback = 0; m_bLegacyQuery = false; m_u8SentCount = 0; - m_ResendTimeout.reset(std::numeric_limits::max()); + m_ResendTimeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); m_bAwaitingAnswers = true; while (m_pAnswers) { stcAnswer* pNext = m_pAnswers->m_pNext; From 8d4c3853939dd536d7397e3afcdcf94b16201455 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 20 Mar 2019 18:39:05 +0100 Subject: [PATCH 22/35] improve clarity --- cores/esp8266/PolledTimeout.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 8389c2ed5a..6eadd9f422 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -191,8 +191,8 @@ class timeoutTemplate // internal time unit API not exposed to user // (_timeout == 0) is not checked here - bool ongoing = (_neverExpires || ((internalUnit - _start) < _timeout)); - return !ongoing; + // returns "can expire" and "time expired" + return (!_neverExpires) && ((internalUnit - _start) >= _timeout); } protected: From ce7e9b9d7b08d0fac69950ddcd98ab62bbb72a58 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 20 Mar 2019 22:55:42 +0100 Subject: [PATCH 23/35] remove exposed checkExpired(), adapt LEAmDNS with equivalent --- cores/esp8266/PolledTimeout.h | 8 ++------ libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp | 10 +++++----- libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 6eadd9f422..506688ac5f 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -178,11 +178,6 @@ class timeoutTemplate return TimePolicyT::timeMax(); } - bool checkExpired(const timeType userUnit) const - { - return (/*always expired*/ _timeout == 0) || internalCheckExpired(TimePolicyT::toTimeTypeUnit(userUnit)); - } - private: ICACHE_RAM_ATTR @@ -217,7 +212,8 @@ class timeoutTemplate ICACHE_RAM_ATTR bool expiredOneShot() const { - return (/*always expired*/ _timeout == 0) || internalCheckExpired(TimePolicyT::time()); + // returns "always expired" or "has expired" + return (_timeout == 0) || internalCheckExpired(TimePolicyT::time()); } timeType _timeout; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp index d6627ece3b..79857c0196 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp @@ -1049,7 +1049,7 @@ bool MDNSResponder::_updateProbeStatus(void) { m_HostProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; } else if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing AND - (m_HostProbeInformation.m_Timeout.checkExpired(millis()))) { // Time for next probe + (m_HostProbeInformation.m_Timeout.expired())) { // Time for next probe if (MDNS_PROBE_COUNT > m_HostProbeInformation.m_u8SentCount) { // Send next probe if ((bResult = _sendHostProbe())) { @@ -1073,7 +1073,7 @@ bool MDNSResponder::_updateProbeStatus(void) { } } // else: Probing already finished OR waiting for next time slot else if ((ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) && - (m_HostProbeInformation.m_Timeout.checkExpired(esp8266::polledTimeout::oneShotMs::neverExpires))) { + (m_HostProbeInformation.m_Timeout.expired())) { if ((bResult = _announce(true, false))) { // Don't announce services here ++m_HostProbeInformation.m_u8SentCount; @@ -1098,7 +1098,7 @@ bool MDNSResponder::_updateProbeStatus(void) { pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; } else if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND - (pService->m_ProbeInformation.m_Timeout.checkExpired(millis()))) { // Time for next probe + (pService->m_ProbeInformation.m_Timeout.expired())) { // Time for next probe if (MDNS_PROBE_COUNT > pService->m_ProbeInformation.m_u8SentCount) { // Send next probe if ((bResult = _sendServiceProbe(*pService))) { @@ -1121,7 +1121,7 @@ bool MDNSResponder::_updateProbeStatus(void) { } } // else: Probing already finished OR waiting for next time slot else if ((ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) && - (pService->m_ProbeInformation.m_Timeout.checkExpired(millis()))) { + (pService->m_ProbeInformation.m_Timeout.expired())) { if ((bResult = _announceService(*pService))) { // Announce service ++pService->m_ProbeInformation.m_u8SentCount; @@ -1443,7 +1443,7 @@ bool MDNSResponder::_checkServiceQueryCache(void) { // Resend dynamic service queries, if not already done often enough if ((!pServiceQuery->m_bLegacyQuery) && (MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) && - (pServiceQuery->m_ResendTimeout.checkExpired(millis()))) { + (pServiceQuery->m_ResendTimeout.expired())) { if ((bResult = _sendMDNSServiceQuery(*pServiceQuery))) { ++pServiceQuery->m_u8SentCount; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp index 0642c37d76..12c3083442 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp @@ -1450,7 +1450,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) const return ((m_u32TTL) && (TIMEOUTLEVEL_UNSET != m_timeoutLevel) && - (m_TTLTimeout.checkExpired(millis()))); + (m_TTLTimeout.expired())); } /* From 0ca22cec5f2c412064d6a7abb4761fd2b0e74871 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 20 Mar 2019 23:05:50 +0100 Subject: [PATCH 24/35] add API ::resetToNeverExpires(), use it in LEAmDNS --- cores/esp8266/PolledTimeout.h | 13 +++++++++---- libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp | 8 ++++---- libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 506688ac5f..737ae1a2ed 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -168,6 +168,12 @@ class timeoutTemplate _start = TimePolicyT::time(); } + void resetToNeverExpires () + { + _timeout = 1; // because _timeout==0 has precedence + _neverExpires = true; + } + timeType getTimeout() const { return TimePolicyT::toUserUnit(_timeout); @@ -181,9 +187,8 @@ class timeoutTemplate private: ICACHE_RAM_ATTR - bool internalCheckExpired(const timeType internalUnit) const + bool checkExpired(const timeType internalUnit) const { - // internal time unit API not exposed to user // (_timeout == 0) is not checked here // returns "can expire" and "time expired" @@ -200,7 +205,7 @@ class timeoutTemplate return true; timeType current = TimePolicyT::time(); - if(internalCheckExpired(current)) + if(checkExpired(current)) { unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout) _start += n * _timeout; @@ -213,7 +218,7 @@ class timeoutTemplate bool expiredOneShot() const { // returns "always expired" or "has expired" - return (_timeout == 0) || internalCheckExpired(TimePolicyT::time()); + return (_timeout == 0) || checkExpired(TimePolicyT::time()); } timeType _timeout; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp index 79857c0196..503a254fc5 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp @@ -1061,7 +1061,7 @@ bool MDNSResponder::_updateProbeStatus(void) { else { // Probing finished DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host probing.\n"));); m_HostProbeInformation.m_ProbingStatus = ProbingStatus_Done; - m_HostProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + m_HostProbeInformation.m_Timeout.resetToNeverExpires(); if (m_HostProbeInformation.m_fnHostProbeResultCallback) { m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, true); } @@ -1083,7 +1083,7 @@ bool MDNSResponder::_updateProbeStatus(void) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%lu).\n\n"), m_HostProbeInformation.m_u8SentCount);); } else { - m_HostProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + m_HostProbeInformation.m_Timeout.resetToNeverExpires(); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host announcing.\n\n"));); } } @@ -1110,7 +1110,7 @@ bool MDNSResponder::_updateProbeStatus(void) { else { // Probing finished DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service probing %s.%s.%s\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_Done; - pService->m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); if (pService->m_ProbeInformation.m_fnServiceProbeResultCallback) { pService->m_ProbeInformation.m_fnServiceProbeResultCallback(pService->m_pcName, pService, true); } @@ -1131,7 +1131,7 @@ bool MDNSResponder::_updateProbeStatus(void) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing service %s.%s.%s (%lu)\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount);); } else { - pService->m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service announcing for %s.%s.%s\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); } } diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp index 12c3083442..ae850c19fa 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp @@ -1173,7 +1173,7 @@ bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/ m_ProbingStatus = ProbingStatus_WaitingForData; m_u8SentCount = 0; - m_Timeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + m_Timeout.resetToNeverExpires(); m_bConflict = false; m_bTiebreakNeeded = false; if (p_bClearUserdata) { @@ -1438,7 +1438,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TT } else { m_timeoutLevel = TIMEOUTLEVEL_UNSET; // undef - m_TTLTimeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + m_TTLTimeout.resetToNeverExpires(); } return true; } @@ -1468,7 +1468,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart(void) { } else { bResult = false; - m_TTLTimeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + m_TTLTimeout.resetToNeverExpires(); m_timeoutLevel = TIMEOUTLEVEL_UNSET; } return bResult; @@ -1945,7 +1945,7 @@ bool MDNSResponder::stcMDNSServiceQuery::clear(void) { m_fnCallback = 0; m_bLegacyQuery = false; m_u8SentCount = 0; - m_ResendTimeout.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + m_ResendTimeout.resetToNeverExpires(); m_bAwaitingAnswers = true; while (m_pAnswers) { stcAnswer* pNext = m_pAnswers->m_pNext; From ff660ae9514ed3c5ba7f29cce1a6a9eceba6db51 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Thu, 21 Mar 2019 01:23:59 +0100 Subject: [PATCH 25/35] remove offending constness from ::flagged() LEAmDNS (due do API fix in PolledTimeout) --- libraries/ESP8266mDNS/src/LEAmDNS.h | 2 +- libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.h b/libraries/ESP8266mDNS/src/LEAmDNS.h index 434f44581b..03abcdbb88 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS.h @@ -981,7 +981,7 @@ class MDNSResponder { stcTTL(void); bool set(uint32_t p_u32TTL); - bool flagged(void) const; + bool flagged(void); bool restart(void); bool prepareDeletion(void); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp index ae850c19fa..e54beb50db 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp @@ -1446,7 +1446,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TT /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged */ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) const { +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) { return ((m_u32TTL) && (TIMEOUTLEVEL_UNSET != m_timeoutLevel) && From 393d40f6de2c275f36afe844d13e0dca5d9a7522 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Thu, 21 Mar 2019 11:55:34 +0100 Subject: [PATCH 26/35] simplify "Fast" base classes --- cores/esp8266/PolledTimeout.h | 70 +++++++++++++++-------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 737ae1a2ed..e71954faf9 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -73,59 +73,44 @@ struct TimeMillis static constexpr timeType timeMax() { return std::numeric_limits::max() - 1; } }; -struct TimeFastMillis +struct TimeFastCyclesBase { - // time policy in milli-seconds based on ESP.getCycleCount() + // time policy based on ESP.getCycleCount() using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} - static constexpr timeType toTimeTypeUnitMul = F_CPU / 1000; - // millis to CPU cycles: - static timeType toTimeTypeUnit (const timeType user) { return user * toTimeTypeUnitMul; } - static timeType toUserUnit (const timeType internal) { return internal / toTimeTypeUnitMul; } - - // rollover: @80Mhz:53.6s @160Mhz:26.8s - // setting max to half of min to ensure full range is never reached - // - this particular time measurement is intended to be called very often - // (every loop, every yield) - // - this max is larger than internal watchdogs - static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (toTimeTypeUnitMul / 2); } + // this particular time measurement is intended to be called very often + // (every loop, every yield) }; -struct TimeFastMicros +template struct TimeFastCycles: TimeFastCyclesBase { - // time policy in micro-seconds based on ESP.getCycleCount() - - using timeType = decltype(ESP.getCycleCount()); - static timeType time() {return ESP.getCycleCount();} - static constexpr timeType toTimeTypeUnitMul = F_CPU / 1000000; + static constexpr timeType toTimeTypeUnitMulMax = 160000000 / second_th; + static constexpr timeType toTimeTypeUnitMul = F_CPU / second_th; - // micros to CPU cycles: static timeType toTimeTypeUnit (const timeType user) { return user * toTimeTypeUnitMul; } static timeType toUserUnit (const timeType internal) { return internal / toTimeTypeUnitMul; } - - // rollover: @80Mhz:53.6s @160Mhz:26.8s - // setting max to half of min to ensure full range is never reached - // - this particular time measurement is intended to be called very often - // (every loop, every yield) - // - this max is larger than internal watchdogs - static constexpr timeType timeMax() { return (((timeType)1) << ((sizeof(timeType) * 8) - 2)) / (toTimeTypeUnitMul / 2); } + static constexpr timeType timeMax() { return std::numeric_limits::max() / toTimeTypeUnitMulMax; } }; -struct TimeFastNanos +struct TimeFastMillis: TimeFastCycles<1000> { - // time policy in nano-seconds based on ESP.getCycleCount() +}; - using timeType = decltype(ESP.getCycleCount()); - static timeType time() {return ESP.getCycleCount();} +struct TimeFastMicros: TimeFastCycles<1000000> +{ +}; - // nanos to CPU cycles (best, within 32bits range) - static timeType toTimeTypeUnit (const timeType user) { return (user * (F_CPU / 40000000)) / 25; } - static timeType toUserUnit (const timeType internal) { return (internal * 25) / (F_CPU / 40000000); } +struct TimeFastNanos: TimeFastCyclesBase +{ + static constexpr timeType toTimeTypeUnitMulMax = 160000000 / 40000000; // 4 + static constexpr timeType toTimeTypeUnitMul = F_CPU / 40000000; // 2 or 4 (smallest possible) + static constexpr timeType toTimeTypeUnitDiv = 25; // (mul/div=F_CPU/10^9) - // given toTimeTypeUnit(), timeMax is (2^31 / 4(@160MHz)) = 0.536 seconds - static constexpr timeType timeMax() { return (((((timeType)1) << ((sizeof(timeType) * 8) - 2 - 2)) - 1) << 1) + 1; } + static timeType toTimeTypeUnit (const timeType user) { return (user * toTimeTypeUnitMul) / toTimeTypeUnitDiv; } + static timeType toUserUnit (const timeType internal) { return (internal * toTimeTypeUnitDiv) / toTimeTypeUnitMul; } + static constexpr timeType timeMax() { return std::numeric_limits::max() / toTimeTypeUnitMulMax; } }; } //TimePolicy @@ -156,6 +141,11 @@ class timeoutTemplate return expired(); } + bool canExpire () + { + return !_neverExpires; + } + void reset(const timeType newUserTimeout) { reset(); @@ -232,7 +222,7 @@ using oneShot = polledTimeout::timeoutTemplate /*__attribute__((deprecate using periodic = polledTimeout::timeoutTemplate /*__attribute__((deprecated("use periodicMs")))*/; // standard versions (based on millis()) -// timeMax() is 49.7 days (2^32 ms) +// timeMax() is 49.7 days ((2^32)-2 ms) using oneShotMs = polledTimeout::timeoutTemplate; using periodicMs = polledTimeout::timeoutTemplate; @@ -240,9 +230,9 @@ using periodicMs = polledTimeout::timeoutTemplate; // "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%) // (cpu cycles for ::expired(): 372 (millis()) vs 52 (getCycleCount)) // timeMax() values: -// Ms: max is 13421 ms (13.4 s) -// Us: max is 13421772 us (13.4 s) -// Ns: max is 536870911 ns ( 0.536 s) +// Ms: max is 26843 ms (26.8 s) +// Us: max is 26843545 us (26.8 s) +// Ns: max is 1073741823 ns ( 1.07 s) using oneShotFastMs = polledTimeout::timeoutTemplate; using periodicFastMs = polledTimeout::timeoutTemplate; From 96c7fb7afacede2e95085d5fd85981e26185a5a9 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Mon, 25 Mar 2019 22:43:55 +0100 Subject: [PATCH 27/35] minor variable rename --- cores/esp8266/PolledTimeout.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index e71954faf9..1fe5baf9b4 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -66,8 +66,8 @@ struct TimeMillis static timeType time() {return millis();} // millis to millis - static timeType toTimeTypeUnit (const timeType t) { return t; } - static timeType toUserUnit (const timeType t) { return t; } + static timeType toTimeTypeUnit (const timeType ms) { return ms; } + static timeType toUserUnit (const timeType ms) { return ms; } // rollover on 32 bits: 49.7 days (::max() is a "never expires"-reserved value) static constexpr timeType timeMax() { return std::numeric_limits::max() - 1; } @@ -89,8 +89,8 @@ template struct TimeFastCycles: T static constexpr timeType toTimeTypeUnitMulMax = 160000000 / second_th; static constexpr timeType toTimeTypeUnitMul = F_CPU / second_th; - static timeType toTimeTypeUnit (const timeType user) { return user * toTimeTypeUnitMul; } - static timeType toUserUnit (const timeType internal) { return internal / toTimeTypeUnitMul; } + static timeType toTimeTypeUnit (const timeType userUnit) { return userUnit * toTimeTypeUnitMul; } + static timeType toUserUnit (const timeType cycles) { return cycles / toTimeTypeUnitMul; } static constexpr timeType timeMax() { return std::numeric_limits::max() / toTimeTypeUnitMulMax; } }; @@ -108,8 +108,8 @@ struct TimeFastNanos: TimeFastCyclesBase static constexpr timeType toTimeTypeUnitMul = F_CPU / 40000000; // 2 or 4 (smallest possible) static constexpr timeType toTimeTypeUnitDiv = 25; // (mul/div=F_CPU/10^9) - static timeType toTimeTypeUnit (const timeType user) { return (user * toTimeTypeUnitMul) / toTimeTypeUnitDiv; } - static timeType toUserUnit (const timeType internal) { return (internal * toTimeTypeUnitDiv) / toTimeTypeUnitMul; } + static timeType toTimeTypeUnit (const timeType nanos) { return (nanos * toTimeTypeUnitMul) / toTimeTypeUnitDiv; } + static timeType toUserUnit (const timeType cycles) { return (cycles * toTimeTypeUnitDiv) / toTimeTypeUnitMul; } static constexpr timeType timeMax() { return std::numeric_limits::max() / toTimeTypeUnitMulMax; } }; From 4930ed017fce6e77128723da072b7f0296c353ec Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Thu, 28 Mar 2019 11:07:25 +0100 Subject: [PATCH 28/35] Fix examples --- cores/esp8266/PolledTimeout.h | 2 +- libraries/ESP8266WiFi/examples/IPv6/IPv6.ino | 6 +++--- .../ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino | 2 +- libraries/Wire/examples/master_reader/master_reader.ino | 2 +- libraries/Wire/examples/master_writer/master_writer.ino | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 1fe5baf9b4..17b9885a5d 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -245,7 +245,7 @@ using periodicFastNs = polledTimeout::timeoutTemplate; + * using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate; * * Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file. */ diff --git a/libraries/ESP8266WiFi/examples/IPv6/IPv6.ino b/libraries/ESP8266WiFi/examples/IPv6/IPv6.ino index 1257fb778f..1c7b1c081c 100644 --- a/libraries/ESP8266WiFi/examples/IPv6/IPv6.ino +++ b/libraries/ESP8266WiFi/examples/IPv6/IPv6.ino @@ -35,7 +35,7 @@ WiFiServer statusServer(TCP_PORT); WiFiUDP udp; -esp8266::polledTimeout::periodic statusPeriod(STATUSDELAY_MS); +esp8266::polledTimeout::periodicMs showStatusOnSerialNow(STATUSDELAY_MS); void fqdn(Print& out, const String& fqdn) { out.print(F("resolving ")); @@ -149,7 +149,7 @@ void setup() { Serial.print(F(" - UDP server on port ")); Serial.println(UDP_PORT); - statusPeriod.reset(); + showStatusOnSerialNow.reset(); } unsigned long statusTimeMs = 0; @@ -182,7 +182,7 @@ void loop() { } - if (statusPeriod) { + if (showStatusOnSerialNow) { status(Serial); } diff --git a/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino b/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino index 0c6f24ca87..8ea7237f54 100644 --- a/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino +++ b/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino @@ -268,7 +268,7 @@ void loop(void) { // Allow MDNS processing MDNS.update(); - static esp8266::polledTimeout::periodic timeout(UPDATE_CYCLE); + static esp8266::polledTimeout::periodicMs timeout(UPDATE_CYCLE); if (timeout.expired()) { if (hMDNSService) { diff --git a/libraries/Wire/examples/master_reader/master_reader.ino b/libraries/Wire/examples/master_reader/master_reader.ino index fb1316c1d3..323830f847 100644 --- a/libraries/Wire/examples/master_reader/master_reader.ino +++ b/libraries/Wire/examples/master_reader/master_reader.ino @@ -23,7 +23,7 @@ void setup() { } void loop() { - using periodic = esp8266::polledTimeout::periodic; + using periodic = esp8266::polledTimeout::periodicMs; static periodic nextPing(1000); if (nextPing) { diff --git a/libraries/Wire/examples/master_writer/master_writer.ino b/libraries/Wire/examples/master_writer/master_writer.ino index d2a6da8420..1e9719e23c 100644 --- a/libraries/Wire/examples/master_writer/master_writer.ino +++ b/libraries/Wire/examples/master_writer/master_writer.ino @@ -24,7 +24,7 @@ void setup() { byte x = 0; void loop() { - using periodic = esp8266::polledTimeout::periodic; + using periodic = esp8266::polledTimeout::periodicMs; static periodic nextPing(1000); if (nextPing) { From f11c6e652fe4f2f112d023c5bad99c2162360fb7 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Tue, 2 Apr 2019 16:10:50 +0200 Subject: [PATCH 29/35] compliance with good c++ manners --- cores/esp8266/PolledTimeout.h | 64 ++++++++----------- .../BlinkPolledTimeout/BlinkPolledTimeout.ino | 8 +++ 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 17b9885a5d..48cd5f39b5 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -58,60 +58,48 @@ struct YieldAndDelayMs namespace TimePolicy { -struct TimeMillis +struct TimeSourceMillis { // time policy in milli-seconds based on millis() using timeType = decltype(millis()); static timeType time() {return millis();} - - // millis to millis - static timeType toTimeTypeUnit (const timeType ms) { return ms; } - static timeType toUserUnit (const timeType ms) { return ms; } - - // rollover on 32 bits: 49.7 days (::max() is a "never expires"-reserved value) - static constexpr timeType timeMax() { return std::numeric_limits::max() - 1; } + static constexpr timeType ticksPerSecond = 1000; + static constexpr timeType ticksPerSecondMax = 1000; }; -struct TimeFastCyclesBase +struct TimeSourceCycles { // time policy based on ESP.getCycleCount() + // this particular time measurement is intended to be called very often + // (every loop, every yield) using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} - - // this particular time measurement is intended to be called very often - // (every loop, every yield) + static constexpr timeType ticksPerSecond = F_CPU; + static constexpr timeType ticksPerSecondMax = 160000000; // Mhz }; -template struct TimeFastCycles: TimeFastCyclesBase +template +struct TimeUnit { - static constexpr timeType toTimeTypeUnitMulMax = 160000000 / second_th; - static constexpr timeType toTimeTypeUnitMul = F_CPU / second_th; + using timeType = typename TimeSourceType::timeType; - static timeType toTimeTypeUnit (const timeType userUnit) { return userUnit * toTimeTypeUnitMul; } - static timeType toUserUnit (const timeType cycles) { return cycles / toTimeTypeUnitMul; } - static constexpr timeType timeMax() { return std::numeric_limits::max() / toTimeTypeUnitMulMax; } -}; + static constexpr timeType user2UnitMultiplierMax = (TimeSourceType::ticksPerSecondMax * rangeCompensate) / second_th; + static constexpr timeType user2UnitMultiplier = (TimeSourceType::ticksPerSecond * rangeCompensate) / second_th; + static constexpr timeType user2UnitDivider = rangeCompensate; + static constexpr timeType timeMax = (std::numeric_limits::max() - 1) / user2UnitMultiplierMax; + static constexpr timeType neverExpires = std::numeric_limits::max(); -struct TimeFastMillis: TimeFastCycles<1000> -{ -}; - -struct TimeFastMicros: TimeFastCycles<1000000> -{ + static timeType toTimeTypeUnit (const timeType userUnit) { return (userUnit * user2UnitMultiplier) / user2UnitDivider; } + static timeType toUserUnit (const timeType internalUnit) { return (internalUnit * user2UnitDivider) / user2UnitMultiplier; } + static timeType time () {return TimeSourceType::time(); } }; -struct TimeFastNanos: TimeFastCyclesBase -{ - static constexpr timeType toTimeTypeUnitMulMax = 160000000 / 40000000; // 4 - static constexpr timeType toTimeTypeUnitMul = F_CPU / 40000000; // 2 or 4 (smallest possible) - static constexpr timeType toTimeTypeUnitDiv = 25; // (mul/div=F_CPU/10^9) - - static timeType toTimeTypeUnit (const timeType nanos) { return (nanos * toTimeTypeUnitMul) / toTimeTypeUnitDiv; } - static timeType toUserUnit (const timeType cycles) { return (cycles * toTimeTypeUnitDiv) / toTimeTypeUnitMul; } - static constexpr timeType timeMax() { return std::numeric_limits::max() / toTimeTypeUnitMulMax; } -}; +using TimeMillis = TimeUnit< TimeSourceMillis, 1000 >; +using TimeFastMillis = TimeUnit< TimeSourceCycles, 1000 >; +using TimeFastMicros = TimeUnit< TimeSourceCycles, 1000000 >; +using TimeFastNanos = TimeUnit< TimeSourceCycles, 1000000000, 25>; } //TimePolicy @@ -121,7 +109,7 @@ class timeoutTemplate public: using timeType = typename TimePolicyT::timeType; - static constexpr timeType neverExpires = std::numeric_limits::max(); + static constexpr timeType neverExpires = TimePolicyT::neverExpires; timeoutTemplate(const timeType userTimeout) { @@ -171,7 +159,7 @@ class timeoutTemplate static constexpr timeType timeMax() { - return TimePolicyT::timeMax(); + return TimePolicyT::timeMax; } private: @@ -245,7 +233,7 @@ using periodicFastNs = polledTimeout::timeoutTemplate; + * using oneShotYield = esp8266::polledTimeout::timeoutTemplate; * * Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file. */ diff --git a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino index 6b6125d187..4473fa4e0d 100644 --- a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino +++ b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino @@ -42,6 +42,14 @@ esp8266::polledTimeout::periodicFastUs halfPeriod(500000); //use fully qualified // the setup function runs only once at start void setup() { + Serial.begin(115200); + + Serial.println(); + Serial.printf("periodic/oneShotMs::timeMax() = %u ms\n", (uint32_t)esp8266::polledTimeout::periodicMs::timeMax()); + Serial.printf("periodic/oneShotFastMs::timeMax() = %u ms\n", (uint32_t)esp8266::polledTimeout::periodicFastMs::timeMax()); + Serial.printf("periodic/oneShotFastUs::timeMax() = %u us\n", (uint32_t)esp8266::polledTimeout::periodicFastUs::timeMax()); + Serial.printf("periodic/oneShotFastNs::timeMax() = %u ns\n", (uint32_t)esp8266::polledTimeout::periodicFastNs::timeMax()); + pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output using esp8266::polledTimeout::oneShotMs; //import the type to the local namespace From f971d42e2da917f2d76c1b904085b032354a3cd0 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Tue, 2 Apr 2019 16:56:55 +0200 Subject: [PATCH 30/35] minor changes for consistency --- cores/esp8266/PolledTimeout.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 48cd5f39b5..16481e7386 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -90,6 +90,7 @@ struct TimeUnit static constexpr timeType user2UnitDivider = rangeCompensate; static constexpr timeType timeMax = (std::numeric_limits::max() - 1) / user2UnitMultiplierMax; static constexpr timeType neverExpires = std::numeric_limits::max(); + static constexpr timeType alwaysExpired = 0; static timeType toTimeTypeUnit (const timeType userUnit) { return (userUnit * user2UnitMultiplier) / user2UnitDivider; } static timeType toUserUnit (const timeType internalUnit) { return (internalUnit * user2UnitDivider) / user2UnitMultiplier; } @@ -110,6 +111,7 @@ class timeoutTemplate using timeType = typename TimePolicyT::timeType; static constexpr timeType neverExpires = TimePolicyT::neverExpires; + static constexpr timeType alwaysExpired = TimePolicyT::alwaysExpired; timeoutTemplate(const timeType userTimeout) { @@ -134,6 +136,11 @@ class timeoutTemplate return !_neverExpires; } + bool canWait () + { + return _timeout != alwaysExpired; + } + void reset(const timeType newUserTimeout) { reset(); @@ -148,7 +155,7 @@ class timeoutTemplate void resetToNeverExpires () { - _timeout = 1; // because _timeout==0 has precedence + _timeout = alwaysExpired + 1; // because canWait() has precedence _neverExpires = true; } @@ -167,8 +174,7 @@ class timeoutTemplate ICACHE_RAM_ATTR bool checkExpired(const timeType internalUnit) const { - // (_timeout == 0) is not checked here - + // canWait() is not checked here // returns "can expire" and "time expired" return (!_neverExpires) && ((internalUnit - _start) >= _timeout); } @@ -178,8 +184,7 @@ class timeoutTemplate ICACHE_RAM_ATTR bool expiredRetrigger() { - if (_timeout == 0) - // "always expired" + if (!canWait()) return true; timeType current = TimePolicyT::time(); @@ -196,7 +201,7 @@ class timeoutTemplate bool expiredOneShot() const { // returns "always expired" or "has expired" - return (_timeout == 0) || checkExpired(TimePolicyT::time()); + return !canWait() || checkExpired(TimePolicyT::time()); } timeType _timeout; @@ -216,7 +221,7 @@ using oneShotMs = polledTimeout::timeoutTemplate; using periodicMs = polledTimeout::timeoutTemplate; // "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%) -// (cpu cycles for ::expired(): 372 (millis()) vs 52 (getCycleCount)) +// (cpu cycles for ::expired(): 372 (millis()) vs 52 (ESP.getCycleCount())) // timeMax() values: // Ms: max is 26843 ms (26.8 s) // Us: max is 26843545 us (26.8 s) From b028ea898653b2ebe72d0393b3777d765e286ca1 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Tue, 2 Apr 2019 17:02:11 +0200 Subject: [PATCH 31/35] add missing const --- cores/esp8266/PolledTimeout.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 16481e7386..e0eb3d78e6 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -131,12 +131,12 @@ class timeoutTemplate return expired(); } - bool canExpire () + bool canExpire () const { return !_neverExpires; } - bool canWait () + bool canWait () const { return _timeout != alwaysExpired; } From a02f8897a2f3b7f1e017de568f8e9ead3ec97afe Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Tue, 2 Apr 2019 17:10:43 +0200 Subject: [PATCH 32/35] expired() and bool() moved to iram --- cores/esp8266/PolledTimeout.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index e0eb3d78e6..5442817879 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -118,6 +118,7 @@ class timeoutTemplate reset(userTimeout); } + ICACHE_RAM_ATTR bool expired() { YieldPolicyT::execute(); //in case of DoNothing: gets optimized away @@ -126,6 +127,7 @@ class timeoutTemplate return expiredOneShot(); } + ICACHE_RAM_ATTR operator bool() { return expired(); From 40d31a554d43af596d46045a24f6f4213a27a3bc Mon Sep 17 00:00:00 2001 From: david gauchard Date: Wed, 3 Apr 2019 00:49:13 +0200 Subject: [PATCH 33/35] constexpr compensation computing --- cores/esp8266/PolledTimeout.h | 53 +++++++++++++++---- .../BlinkPolledTimeout/BlinkPolledTimeout.ino | 7 +++ 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 5442817879..e0aab00d85 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -76,31 +76,61 @@ struct TimeSourceCycles using timeType = decltype(ESP.getCycleCount()); static timeType time() {return ESP.getCycleCount();} - static constexpr timeType ticksPerSecond = F_CPU; - static constexpr timeType ticksPerSecondMax = 160000000; // Mhz + static constexpr timeType ticksPerSecond = F_CPU; // 80'000'000 or 160'000'000 Hz + static constexpr timeType ticksPerSecondMax = 160000000; // 160MHz }; -template +template + // "second_th" units of time for one second struct TimeUnit { using timeType = typename TimeSourceType::timeType; - static constexpr timeType user2UnitMultiplierMax = (TimeSourceType::ticksPerSecondMax * rangeCompensate) / second_th; - static constexpr timeType user2UnitMultiplier = (TimeSourceType::ticksPerSecond * rangeCompensate) / second_th; +#if __GNUC__ < 5 + static constexpr timeType computeRangeCompensation () + { + return ({ + #define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond) + #define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick) + fractional == 0? + 1: // no need for compensation + (number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division + #undef number_of_secondTh_in_one_tick + #undef fractional + }); + } +#else + static constexpr timeType computeRangeCompensation () + { + return ({ + constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond; + constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick; + fractional == 0? + 1: // no need for compensation + (number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division + }); + } +#endif + + static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond; + static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax; + static constexpr timeType rangeCompensate = computeRangeCompensation(); + static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th; + static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th; static constexpr timeType user2UnitDivider = rangeCompensate; - static constexpr timeType timeMax = (std::numeric_limits::max() - 1) / user2UnitMultiplierMax; - static constexpr timeType neverExpires = std::numeric_limits::max(); static constexpr timeType alwaysExpired = 0; + static constexpr timeType neverExpires = std::numeric_limits::max(); + static constexpr timeType timeMax = (neverExpires - 1) / user2UnitMultiplierMax; - static timeType toTimeTypeUnit (const timeType userUnit) { return (userUnit * user2UnitMultiplier) / user2UnitDivider; } - static timeType toUserUnit (const timeType internalUnit) { return (internalUnit * user2UnitDivider) / user2UnitMultiplier; } - static timeType time () {return TimeSourceType::time(); } + static timeType toTimeTypeUnit (const timeType userUnit) {return (userUnit * user2UnitMultiplier) / user2UnitDivider;} + static timeType toUserUnit (const timeType internalUnit) {return (internalUnit * user2UnitDivider) / user2UnitMultiplier;} + static timeType time () {return TimeSourceType::time();} }; using TimeMillis = TimeUnit< TimeSourceMillis, 1000 >; using TimeFastMillis = TimeUnit< TimeSourceCycles, 1000 >; using TimeFastMicros = TimeUnit< TimeSourceCycles, 1000000 >; -using TimeFastNanos = TimeUnit< TimeSourceCycles, 1000000000, 25>; +using TimeFastNanos = TimeUnit< TimeSourceCycles, 1000000000 >; } //TimePolicy @@ -112,6 +142,7 @@ class timeoutTemplate static constexpr timeType neverExpires = TimePolicyT::neverExpires; static constexpr timeType alwaysExpired = TimePolicyT::alwaysExpired; + static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug timeoutTemplate(const timeType userTimeout) { diff --git a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino index 4473fa4e0d..11e2aff482 100644 --- a/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino +++ b/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino @@ -50,6 +50,13 @@ void setup() { Serial.printf("periodic/oneShotFastUs::timeMax() = %u us\n", (uint32_t)esp8266::polledTimeout::periodicFastUs::timeMax()); Serial.printf("periodic/oneShotFastNs::timeMax() = %u ns\n", (uint32_t)esp8266::polledTimeout::periodicFastNs::timeMax()); +#if 0 // 1 for debugging polledTimeout + Serial.printf("periodic/oneShotMs::rangeCompensate = %u\n", (uint32_t)esp8266::polledTimeout::periodicMs::rangeCompensate); + Serial.printf("periodic/oneShotFastMs::rangeCompensate = %u\n", (uint32_t)esp8266::polledTimeout::periodicFastMs::rangeCompensate); + Serial.printf("periodic/oneShotFastUs::rangeCompensate = %u\n", (uint32_t)esp8266::polledTimeout::periodicFastUs::rangeCompensate); + Serial.printf("periodic/oneShotFastNs::rangeCompensate = %u\n", (uint32_t)esp8266::polledTimeout::periodicFastNs::rangeCompensate); +#endif + pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output using esp8266::polledTimeout::oneShotMs; //import the type to the local namespace From 75f36a75e87e9f2e57871805d1aa3fd3490c3ce2 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 3 Apr 2019 09:48:33 +0200 Subject: [PATCH 34/35] add/update comments --- cores/esp8266/PolledTimeout.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index e0aab00d85..831de90ec4 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -80,24 +80,28 @@ struct TimeSourceCycles static constexpr timeType ticksPerSecondMax = 160000000; // 160MHz }; -template - // "second_th" units of time for one second +template + // "second_th" units of timeType for one second struct TimeUnit { using timeType = typename TimeSourceType::timeType; #if __GNUC__ < 5 + // gcc-4.8 cannot compile the constexpr-only version of this function + // using #defines instead luckily works static constexpr timeType computeRangeCompensation () { + #define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond) + #define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick) + return ({ - #define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond) - #define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick) fractional == 0? 1: // no need for compensation (number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division - #undef number_of_secondTh_in_one_tick - #undef fractional }); + + #undef number_of_secondTh_in_one_tick + #undef fractional } #else static constexpr timeType computeRangeCompensation () @@ -121,6 +125,7 @@ struct TimeUnit static constexpr timeType alwaysExpired = 0; static constexpr timeType neverExpires = std::numeric_limits::max(); static constexpr timeType timeMax = (neverExpires - 1) / user2UnitMultiplierMax; + // timeMax is defined by neverExpires static timeType toTimeTypeUnit (const timeType userUnit) {return (userUnit * user2UnitMultiplier) / user2UnitDivider;} static timeType toUserUnit (const timeType internalUnit) {return (internalUnit * user2UnitDivider) / user2UnitMultiplier;} @@ -253,12 +258,14 @@ using periodic = polledTimeout::timeoutTemplate /*__attribute__((deprecate using oneShotMs = polledTimeout::timeoutTemplate; using periodicMs = polledTimeout::timeoutTemplate; +// Time policy based on ESP.getCycleCount(), and intended to be called very often: // "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%) // (cpu cycles for ::expired(): 372 (millis()) vs 52 (ESP.getCycleCount())) // timeMax() values: // Ms: max is 26843 ms (26.8 s) // Us: max is 26843545 us (26.8 s) // Ns: max is 1073741823 ns ( 1.07 s) +// (time policy based on ESP.getCycleCount() is intended to be called very often) using oneShotFastMs = polledTimeout::timeoutTemplate; using periodicFastMs = polledTimeout::timeoutTemplate; @@ -271,7 +278,7 @@ using periodicFastNs = polledTimeout::timeoutTemplate; + * using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate; * * Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file. */ From 0969feed171ae42f7cf92c7da1f0405fa290cb38 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Thu, 4 Apr 2019 21:58:43 +0200 Subject: [PATCH 35/35] move neverExpires and alwaysExpired --- cores/esp8266/PolledTimeout.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index 831de90ec4..91bebaa79b 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -122,10 +122,8 @@ struct TimeUnit static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th; static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th; static constexpr timeType user2UnitDivider = rangeCompensate; - static constexpr timeType alwaysExpired = 0; - static constexpr timeType neverExpires = std::numeric_limits::max(); - static constexpr timeType timeMax = (neverExpires - 1) / user2UnitMultiplierMax; - // timeMax is defined by neverExpires + // std::numeric_limits::max() is reserved + static constexpr timeType timeMax = (std::numeric_limits::max() - 1) / user2UnitMultiplierMax; static timeType toTimeTypeUnit (const timeType userUnit) {return (userUnit * user2UnitMultiplier) / user2UnitDivider;} static timeType toUserUnit (const timeType internalUnit) {return (internalUnit * user2UnitDivider) / user2UnitMultiplier;} @@ -145,8 +143,8 @@ class timeoutTemplate public: using timeType = typename TimePolicyT::timeType; - static constexpr timeType neverExpires = TimePolicyT::neverExpires; - static constexpr timeType alwaysExpired = TimePolicyT::alwaysExpired; + static constexpr timeType alwaysExpired = 0; + static constexpr timeType neverExpires = std::numeric_limits::max(); static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug timeoutTemplate(const timeType userTimeout)