Skip to content

polledTimeout: add option to use CPU count instead of millis() #5870

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 47 commits into from
Apr 5, 2019
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
fca1d5d
polledTimeout: add option to use CPU count instead of millis()
d-a-v Mar 13, 2019
6cd506b
Merge branch 'master' into polledcpu
d-a-v Mar 13, 2019
702cea8
use more "using" alias
d-a-v Mar 13, 2019
2afa570
Merge branch 'master' into polledcpu
d-a-v Mar 14, 2019
133c06f
more c++/clear code, using typename (thanks @devyte)
d-a-v Mar 14, 2019
d675eeb
rename class name to include unit, introduce timeMax() and check it w…
d-a-v Mar 15, 2019
f3f7a2d
remove useless defines
d-a-v Mar 15, 2019
a21514a
improve api readability, add micro-second unit
d-a-v Mar 15, 2019
9b8e40b
update example
d-a-v Mar 15, 2019
ba105b7
mock: emulate getCycleCount, add/fix polledTimeout CI test
d-a-v Mar 18, 2019
02909f8
Merge branch 'master' into polledcpu
d-a-v Mar 18, 2019
d1785c6
Merge branch 'master' into polledcpu
d-a-v Mar 18, 2019
ebda468
+ nano-seconds, assert -> message, comments, host test
d-a-v Mar 19, 2019
7a4c4de
allow 0 for timeout (enables immediate timeout, fix division by 0)
d-a-v Mar 19, 2019
2249315
Merge branch 'master' into polledcpu
d-a-v Mar 19, 2019
aa6b2d9
typo, set member instead of local variable
d-a-v Mar 19, 2019
e98c41c
unify error message
d-a-v Mar 19, 2019
714beb3
slight change on checkExpired() allows "never expired"
d-a-v Mar 19, 2019
925408e
remove traces of debug.h/cpp in this PR
d-a-v Mar 19, 2019
412a241
include missing <limits> header
d-a-v Mar 20, 2019
273306a
back to original expired test, introduce boolean _neverExpires, fix r…
d-a-v Mar 20, 2019
531e08e
fix expiredOneShot with _timeout==0 check
d-a-v Mar 20, 2019
a041a66
reenable getTimeout()
d-a-v Mar 20, 2019
70ac794
expose checkExpired with unit conversion
d-a-v Mar 20, 2019
e25b880
fix timing comments, move critical code to iram
d-a-v Mar 20, 2019
a20f8f6
add member ::neverExpires and use it where relevant
d-a-v Mar 20, 2019
8d4c385
improve clarity
d-a-v Mar 20, 2019
ce7e9b9
remove exposed checkExpired(), adapt LEAmDNS with equivalent
d-a-v Mar 20, 2019
0ca22ce
add API ::resetToNeverExpires(), use it in LEAmDNS
d-a-v Mar 20, 2019
3d4b369
Merge branch 'master' into polledcpu
d-a-v Mar 20, 2019
ff660ae
remove offending constness from ::flagged() LEAmDNS (due do API fix i…
d-a-v Mar 21, 2019
393d40f
simplify "Fast" base classes
d-a-v Mar 21, 2019
1f4f73c
Merge branch 'master' into polledcpu
d-a-v Mar 25, 2019
daa5e85
Merge branch 'polledcpu' of github.com:d-a-v/Arduino into polledcpu
d-a-v Mar 25, 2019
96c7fb7
minor variable rename
d-a-v Mar 25, 2019
45c5da2
Merge branch 'master' into polledcpu
d-a-v Mar 28, 2019
4930ed0
Fix examples
d-a-v Mar 28, 2019
f11c6e6
compliance with good c++ manners
d-a-v Apr 2, 2019
9d73d18
Merge branch 'master' into polledcpu
d-a-v Apr 2, 2019
f971d42
minor changes for consistency
d-a-v Apr 2, 2019
b028ea8
add missing const
d-a-v Apr 2, 2019
a02f889
expired() and bool() moved to iram
d-a-v Apr 2, 2019
40d31a5
constexpr compensation computing
d-a-v Apr 2, 2019
75f36a7
add/update comments
d-a-v Apr 3, 2019
0e72db2
Merge branch 'master' into polledcpu
d-a-v Apr 4, 2019
4470ca2
Merge branch 'polledcpu' of github.com:d-a-v/Arduino into polledcpu
d-a-v Apr 4, 2019
0969fee
move neverExpires and alwaysExpired
d-a-v Apr 4, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion cores/esp8266/Esp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion cores/esp8266/HardwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
139 changes: 127 additions & 12 deletions cores/esp8266/PolledTimeout.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <limits>

#include <Arduino.h>

namespace esp8266
Expand All @@ -45,18 +47,100 @@ struct YieldOrSkip
static void execute() {delay(0);}
};

template <unsigned long delayMs>
struct YieldAndDelayMs
{
static void execute() {delay(delayMs);}
};

} //YieldPolicy

namespace TimePolicy
{

struct TimeMillis
{
// 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 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<timeType>::max() - 1; }
};

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 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 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); }
};

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 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 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); }
};

struct TimeFastNanos
{
// time policy in nano-seconds based on ESP.getCycleCount()

using timeType = decltype(ESP.getCycleCount());
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; }

// 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; }
};

} //TimePolicy

template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing>
template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing, typename TimePolicyT = TimePolicy::TimeMillis>
class timeoutTemplate
{
public:
using timeType = decltype(millis());
using timeType = typename TimePolicyT::timeType;

timeoutTemplate(timeType timeout)
: _timeout(timeout), _start(millis())
{}
timeoutTemplate(const timeType timeout)
: _timeout(TimePolicyT::toTimeTypeUnit(timeout)), _start(TimePolicyT::time())
{
if (timeout > timeMax())
{
// "never expires" (checkExpired() condition "(t - _start) > _timeout;" is never reached)
_timeout = std::numeric_limits<timeType>::max();
}
}

bool expired()
{
Expand All @@ -79,7 +163,7 @@ class timeoutTemplate

void reset()
{
_start = millis();
_start = TimePolicyT::time();
}

timeType getTimeout() const
Expand All @@ -89,14 +173,24 @@ 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 timeMax()
{
return TimePolicyT::timeMax();
}

protected:

bool expiredRetrigger()
{
timeType current = millis();
if (_timeout == 0)
// "always expired"
return true;

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)
Expand All @@ -108,15 +202,36 @@ class timeoutTemplate

bool expiredOneShot() const
{
return checkExpired(millis());
return checkExpired(TimePolicyT::time());
}

timeType _timeout;
timeType _start;
};

using oneShot = polledTimeout::timeoutTemplate<false>;
using periodic = polledTimeout::timeoutTemplate<true>;
// legacy type names, deprecated (unit is milliseconds)

using oneShot = polledTimeout::timeoutTemplate<false> /*__attribute__((deprecated("use oneShotMs")))*/;
using periodic = polledTimeout::timeoutTemplate<true> /*__attribute__((deprecated("use periodicMs")))*/;

// standard versions (based on millis())
// timeMax() is 49.7 days (2^32 ms)

using oneShotMs = polledTimeout::timeoutTemplate<false>;
using periodicMs = polledTimeout::timeoutTemplate<true>;

// "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<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
using periodicFastMs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
using oneShotFastUs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
using periodicFastUs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
using oneShotFastNs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;

} //polledTimeout

Expand Down
34 changes: 17 additions & 17 deletions libraries/ESP8266mDNS/src/LEAmDNS.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 6 additions & 6 deletions libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<esp8266::polledTimeout::oneShot::timeType>::max());
m_HostProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShotMs::timeType>::max());
if (m_HostProbeInformation.m_fnHostProbeResultCallback) {
m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, true);
}
Expand All @@ -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<esp8266::polledTimeout::oneShot::timeType>::max()))) {
(m_HostProbeInformation.m_Timeout.checkExpired(std::numeric_limits<esp8266::polledTimeout::oneShotMs::timeType>::max()))) {

if ((bResult = _announce(true, false))) { // Don't announce services here
++m_HostProbeInformation.m_u8SentCount;
Expand All @@ -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<esp8266::polledTimeout::oneShot::timeType>::max());
m_HostProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShotMs::timeType>::max());
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host announcing.\n\n")););
}
}
Expand All @@ -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<esp8266::polledTimeout::oneShot::timeType>::max());
pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShotMs::timeType>::max());
if (pService->m_ProbeInformation.m_fnServiceProbeResultCallback) {
pService->m_ProbeInformation.m_fnServiceProbeResultCallback(pService->m_pcName, pService, true);
}
Expand All @@ -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<esp8266::polledTimeout::oneShot::timeType>::max());
pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShotMs::timeType>::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););
}
}
Expand Down Expand Up @@ -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<esp8266::polledTimeout::oneShot::timeType>::max());
: std::numeric_limits<esp8266::polledTimeout::oneShotMs::timeType>::max());
}
DEBUG_EX_INFO(
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: %s to resend service query!"), (bResult ? "Succeeded" : "FAILED"));
Expand Down
Loading