Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9a2ed27

Browse files
d-a-vdevyte
authored andcommittedApr 5, 2019
polledTimeout: add option to use CPU count instead of millis() (#5870)
* polledTimeout: add option to use CPU count instead of millis() * use more "using" alias * more c++/clear code, using typename (thanks @devyte) * rename class name to include unit, introduce timeMax() and check it with assert() * remove useless defines * improve api readability, add micro-second unit * update example * mock: emulate getCycleCount, add/fix polledTimeout CI test * + nano-seconds, assert -> message, comments, host test * allow 0 for timeout (enables immediate timeout, fix division by 0) * typo, set member instead of local variable * unify error message * slight change on checkExpired() allows "never expired" also removed printed message, add YieldAndDelay, simplify calculations * remove traces of debug.h/cpp in this PR * include missing <limits> header * back to original expired test, introduce boolean _neverExpires, fix reset(), getTimeout() is invalid * fix expiredOneShot with _timeout==0 check * reenable getTimeout() * expose checkExpired with unit conversion * fix timing comments, move critical code to iram * add member ::neverExpires and use it where relevant * improve clarity * remove exposed checkExpired(), adapt LEAmDNS with equivalent * add API ::resetToNeverExpires(), use it in LEAmDNS * remove offending constness from ::flagged() LEAmDNS (due do API fix in PolledTimeout) * simplify "Fast" base classes * minor variable rename * Fix examples * compliance with good c++ manners * minor changes for consistency * add missing const * expired() and bool() moved to iram * constexpr compensation computing * add/update comments * move neverExpires and alwaysExpired
1 parent f0eb550 commit 9a2ed27

File tree

15 files changed

+344
-92
lines changed

15 files changed

+344
-92
lines changed
 

‎cores/esp8266/Esp.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,15 +200,20 @@ class EspClass {
200200

201201
bool eraseConfig();
202202

203-
inline uint32_t getCycleCount();
203+
#ifndef CORE_MOCK
204+
inline
205+
#endif
206+
uint32_t getCycleCount();
204207
};
205208

209+
#ifndef CORE_MOCK
206210
uint32_t EspClass::getCycleCount()
207211
{
208212
uint32_t ccount;
209213
__asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount));
210214
return ccount;
211215
}
216+
#endif
212217

213218
extern EspClass ESP;
214219

‎cores/esp8266/HardwareSerial.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ size_t HardwareSerial::readBytes(char* buffer, size_t size)
139139

140140
while (got < size)
141141
{
142-
esp8266::polledTimeout::oneShot timeOut(_timeout);
142+
esp8266::polledTimeout::oneShotFastMs timeOut(_timeout);
143143
size_t avail;
144144
while ((avail = available()) == 0 && !timeOut);
145145
if (avail == 0)

‎cores/esp8266/PolledTimeout.h

Lines changed: 173 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2424
*/
2525

26+
#include <limits>
27+
2628
#include <Arduino.h>
2729

2830
namespace esp8266
@@ -45,19 +47,112 @@ struct YieldOrSkip
4547
static void execute() {delay(0);}
4648
};
4749

50+
template <unsigned long delayMs>
51+
struct YieldAndDelayMs
52+
{
53+
static void execute() {delay(delayMs);}
54+
};
55+
4856
} //YieldPolicy
4957

58+
namespace TimePolicy
59+
{
60+
61+
struct TimeSourceMillis
62+
{
63+
// time policy in milli-seconds based on millis()
64+
65+
using timeType = decltype(millis());
66+
static timeType time() {return millis();}
67+
static constexpr timeType ticksPerSecond = 1000;
68+
static constexpr timeType ticksPerSecondMax = 1000;
69+
};
70+
71+
struct TimeSourceCycles
72+
{
73+
// time policy based on ESP.getCycleCount()
74+
// this particular time measurement is intended to be called very often
75+
// (every loop, every yield)
76+
77+
using timeType = decltype(ESP.getCycleCount());
78+
static timeType time() {return ESP.getCycleCount();}
79+
static constexpr timeType ticksPerSecond = F_CPU; // 80'000'000 or 160'000'000 Hz
80+
static constexpr timeType ticksPerSecondMax = 160000000; // 160MHz
81+
};
82+
83+
template <typename TimeSourceType, unsigned long long second_th>
84+
// "second_th" units of timeType for one second
85+
struct TimeUnit
86+
{
87+
using timeType = typename TimeSourceType::timeType;
88+
89+
#if __GNUC__ < 5
90+
// gcc-4.8 cannot compile the constexpr-only version of this function
91+
// using #defines instead luckily works
92+
static constexpr timeType computeRangeCompensation ()
93+
{
94+
#define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond)
95+
#define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick)
96+
97+
return ({
98+
fractional == 0?
99+
1: // no need for compensation
100+
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
101+
});
50102

51-
template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing>
103+
#undef number_of_secondTh_in_one_tick
104+
#undef fractional
105+
}
106+
#else
107+
static constexpr timeType computeRangeCompensation ()
108+
{
109+
return ({
110+
constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond;
111+
constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
112+
fractional == 0?
113+
1: // no need for compensation
114+
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
115+
});
116+
}
117+
#endif
118+
119+
static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond;
120+
static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax;
121+
static constexpr timeType rangeCompensate = computeRangeCompensation();
122+
static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th;
123+
static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th;
124+
static constexpr timeType user2UnitDivider = rangeCompensate;
125+
// std::numeric_limits<timeType>::max() is reserved
126+
static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
127+
128+
static timeType toTimeTypeUnit (const timeType userUnit) {return (userUnit * user2UnitMultiplier) / user2UnitDivider;}
129+
static timeType toUserUnit (const timeType internalUnit) {return (internalUnit * user2UnitDivider) / user2UnitMultiplier;}
130+
static timeType time () {return TimeSourceType::time();}
131+
};
132+
133+
using TimeMillis = TimeUnit< TimeSourceMillis, 1000 >;
134+
using TimeFastMillis = TimeUnit< TimeSourceCycles, 1000 >;
135+
using TimeFastMicros = TimeUnit< TimeSourceCycles, 1000000 >;
136+
using TimeFastNanos = TimeUnit< TimeSourceCycles, 1000000000 >;
137+
138+
} //TimePolicy
139+
140+
template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing, typename TimePolicyT = TimePolicy::TimeMillis>
52141
class timeoutTemplate
53142
{
54143
public:
55-
using timeType = decltype(millis());
56-
57-
timeoutTemplate(timeType timeout)
58-
: _timeout(timeout), _start(millis())
59-
{}
144+
using timeType = typename TimePolicyT::timeType;
145+
146+
static constexpr timeType alwaysExpired = 0;
147+
static constexpr timeType neverExpires = std::numeric_limits<timeType>::max();
148+
static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug
149+
150+
timeoutTemplate(const timeType userTimeout)
151+
{
152+
reset(userTimeout);
153+
}
60154

155+
ICACHE_RAM_ATTR
61156
bool expired()
62157
{
63158
YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
@@ -66,37 +161,69 @@ class timeoutTemplate
66161
return expiredOneShot();
67162
}
68163

164+
ICACHE_RAM_ATTR
69165
operator bool()
70166
{
71167
return expired();
72168
}
73169

74-
void reset(const timeType newTimeout)
170+
bool canExpire () const
171+
{
172+
return !_neverExpires;
173+
}
174+
175+
bool canWait () const
176+
{
177+
return _timeout != alwaysExpired;
178+
}
179+
180+
void reset(const timeType newUserTimeout)
75181
{
76-
_timeout = newTimeout;
77182
reset();
183+
_timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout);
184+
_neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax());
78185
}
79186

80187
void reset()
81188
{
82-
_start = millis();
189+
_start = TimePolicyT::time();
190+
}
191+
192+
void resetToNeverExpires ()
193+
{
194+
_timeout = alwaysExpired + 1; // because canWait() has precedence
195+
_neverExpires = true;
83196
}
84197

85198
timeType getTimeout() const
86199
{
87-
return _timeout;
200+
return TimePolicyT::toUserUnit(_timeout);
88201
}
89202

90-
bool checkExpired(const timeType t) const
203+
static constexpr timeType timeMax()
91204
{
92-
return (t - _start) >= _timeout;
205+
return TimePolicyT::timeMax;
93206
}
94-
207+
208+
private:
209+
210+
ICACHE_RAM_ATTR
211+
bool checkExpired(const timeType internalUnit) const
212+
{
213+
// canWait() is not checked here
214+
// returns "can expire" and "time expired"
215+
return (!_neverExpires) && ((internalUnit - _start) >= _timeout);
Code has comments. Press enter to view.
216+
}
217+
95218
protected:
96-
219+
220+
ICACHE_RAM_ATTR
97221
bool expiredRetrigger()
98222
{
99-
timeType current = millis();
223+
if (!canWait())
224+
return true;
225+
226+
timeType current = TimePolicyT::time();
100227
if(checkExpired(current))
101228
{
102229
unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
Code has comments. Press enter to view.
@@ -106,23 +233,50 @@ class timeoutTemplate
106233
return false;
107234
}
108235

236+
ICACHE_RAM_ATTR
109237
bool expiredOneShot() const
110238
{
111-
return checkExpired(millis());
239+
// returns "always expired" or "has expired"
240+
return !canWait() || checkExpired(TimePolicyT::time());
112241
}
113242

114243
timeType _timeout;
115244
timeType _start;
245+
bool _neverExpires;
116246
};
117247

118-
using oneShot = polledTimeout::timeoutTemplate<false>;
119-
using periodic = polledTimeout::timeoutTemplate<true>;
248+
// legacy type names, deprecated (unit is milliseconds)
249+
250+
using oneShot = polledTimeout::timeoutTemplate<false> /*__attribute__((deprecated("use oneShotMs")))*/;
251+
using periodic = polledTimeout::timeoutTemplate<true> /*__attribute__((deprecated("use periodicMs")))*/;
252+
253+
// standard versions (based on millis())
254+
// timeMax() is 49.7 days ((2^32)-2 ms)
255+
256+
using oneShotMs = polledTimeout::timeoutTemplate<false>;
257+
using periodicMs = polledTimeout::timeoutTemplate<true>;
258+
259+
// Time policy based on ESP.getCycleCount(), and intended to be called very often:
260+
// "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%)
261+
// (cpu cycles for ::expired(): 372 (millis()) vs 52 (ESP.getCycleCount()))
262+
// timeMax() values:
263+
// Ms: max is 26843 ms (26.8 s)
264+
// Us: max is 26843545 us (26.8 s)
265+
// Ns: max is 1073741823 ns ( 1.07 s)
266+
// (time policy based on ESP.getCycleCount() is intended to be called very often)
267+
268+
using oneShotFastMs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
269+
using periodicFastMs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
270+
using oneShotFastUs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
271+
using periodicFastUs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
272+
using oneShotFastNs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
273+
using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
120274

121275
} //polledTimeout
122276

123277

124278
/* A 1-shot timeout that auto-yields when in CONT can be built as follows:
125-
* using oneShotYield = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
279+
* using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
126280
*
127281
* 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.
128282
*/

‎libraries/ESP8266WiFi/examples/IPv6/IPv6.ino

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
WiFiServer statusServer(TCP_PORT);
3737
WiFiUDP udp;
38-
esp8266::polledTimeout::periodic statusPeriod(STATUSDELAY_MS);
38+
esp8266::polledTimeout::periodicMs showStatusOnSerialNow(STATUSDELAY_MS);
3939

4040
void fqdn(Print& out, const String& fqdn) {
4141
out.print(F("resolving "));
@@ -149,7 +149,7 @@ void setup() {
149149
Serial.print(F(" - UDP server on port "));
150150
Serial.println(UDP_PORT);
151151

152-
statusPeriod.reset();
152+
showStatusOnSerialNow.reset();
153153
}
154154

155155
unsigned long statusTimeMs = 0;
@@ -182,7 +182,7 @@ void loop() {
182182
}
183183

184184

185-
if (statusPeriod) {
185+
if (showStatusOnSerialNow) {
186186
status(Serial);
187187
}
188188

‎libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ void loop(void) {
268268
// Allow MDNS processing
269269
MDNS.update();
270270

271-
static esp8266::polledTimeout::periodic timeout(UPDATE_CYCLE);
271+
static esp8266::polledTimeout::periodicMs timeout(UPDATE_CYCLE);
272272
if (timeout.expired()) {
273273

274274
if (hMDNSService) {

‎libraries/ESP8266mDNS/src/LEAmDNS.h

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -905,12 +905,12 @@ class MDNSResponder {
905905
* stcProbeInformation
906906
*/
907907
struct stcProbeInformation {
908-
enuProbingStatus m_ProbingStatus;
909-
uint8_t m_u8SentCount; // Used for probes and announcements
910-
esp8266::polledTimeout::oneShot m_Timeout; // Used for probes and announcements
911-
//clsMDNSTimeFlag m_TimeFlag; // Used for probes and announcements
912-
bool m_bConflict;
913-
bool m_bTiebreakNeeded;
908+
enuProbingStatus m_ProbingStatus;
909+
uint8_t m_u8SentCount; // Used for probes and announcements
910+
esp8266::polledTimeout::oneShotMs m_Timeout; // Used for probes and announcements
911+
//clsMDNSTimeFlag m_TimeFlag; // Used for probes and announcements
912+
bool m_bConflict;
913+
bool m_bTiebreakNeeded;
914914
MDNSHostProbeFn m_fnHostProbeResultCallback;
915915
MDNSServiceProbeFn m_fnServiceProbeResultCallback;
916916

@@ -974,14 +974,14 @@ class MDNSResponder {
974974
const timeoutLevel_t TIMEOUTLEVEL_INTERVAL = 5;
975975
const timeoutLevel_t TIMEOUTLEVEL_FINAL = 100;
976976

977-
uint32_t m_u32TTL;
978-
esp8266::polledTimeout::oneShot m_TTLTimeout;
979-
timeoutLevel_t m_timeoutLevel;
977+
uint32_t m_u32TTL;
978+
esp8266::polledTimeout::oneShotMs m_TTLTimeout;
979+
timeoutLevel_t m_timeoutLevel;
980980

981981
stcTTL(void);
982982
bool set(uint32_t p_u32TTL);
983983

984-
bool flagged(void) const;
984+
bool flagged(void);
985985
bool restart(void);
986986

987987
bool prepareDeletion(void);
@@ -1073,14 +1073,14 @@ class MDNSResponder {
10731073
#endif
10741074
};
10751075

1076-
stcMDNSServiceQuery* m_pNext;
1077-
stcMDNS_RRDomain m_ServiceTypeDomain; // eg. _http._tcp.local
1078-
MDNSServiceQueryCallbackFunc m_fnCallback;
1079-
bool m_bLegacyQuery;
1080-
uint8_t m_u8SentCount;
1081-
esp8266::polledTimeout::oneShot m_ResendTimeout;
1082-
bool m_bAwaitingAnswers;
1083-
stcAnswer* m_pAnswers;
1076+
stcMDNSServiceQuery* m_pNext;
1077+
stcMDNS_RRDomain m_ServiceTypeDomain; // eg. _http._tcp.local
1078+
MDNSServiceQueryCallbackFunc m_fnCallback;
1079+
bool m_bLegacyQuery;
1080+
uint8_t m_u8SentCount;
1081+
esp8266::polledTimeout::oneShotMs m_ResendTimeout;
1082+
bool m_bAwaitingAnswers;
1083+
stcAnswer* m_pAnswers;
10841084

10851085
stcMDNSServiceQuery(void);
10861086
~stcMDNSServiceQuery(void);

‎libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
10471047
m_HostProbeInformation.m_ProbingStatus = ProbingStatus_InProgress;
10481048
}
10491049
else if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing AND
1050-
(m_HostProbeInformation.m_Timeout.checkExpired(millis()))) { // Time for next probe
1050+
(m_HostProbeInformation.m_Timeout.expired())) { // Time for next probe
10511051

10521052
if (MDNS_PROBE_COUNT > m_HostProbeInformation.m_u8SentCount) { // Send next probe
10531053
if ((bResult = _sendHostProbe())) {
@@ -1059,7 +1059,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
10591059
else { // Probing finished
10601060
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host probing.\n")););
10611061
m_HostProbeInformation.m_ProbingStatus = ProbingStatus_Done;
1062-
m_HostProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
1062+
m_HostProbeInformation.m_Timeout.resetToNeverExpires();
10631063
if (m_HostProbeInformation.m_fnHostProbeResultCallback) {
10641064
m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, true);
10651065
}
@@ -1071,7 +1071,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
10711071
}
10721072
} // else: Probing already finished OR waiting for next time slot
10731073
else if ((ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) &&
1074-
(m_HostProbeInformation.m_Timeout.checkExpired(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()))) {
1074+
(m_HostProbeInformation.m_Timeout.expired())) {
10751075

10761076
if ((bResult = _announce(true, false))) { // Don't announce services here
10771077
++m_HostProbeInformation.m_u8SentCount;
@@ -1081,7 +1081,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
10811081
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%lu).\n\n"), m_HostProbeInformation.m_u8SentCount););
10821082
}
10831083
else {
1084-
m_HostProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
1084+
m_HostProbeInformation.m_Timeout.resetToNeverExpires();
10851085
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host announcing.\n\n")););
10861086
}
10871087
}
@@ -1096,7 +1096,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
10961096
pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_InProgress;
10971097
}
10981098
else if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND
1099-
(pService->m_ProbeInformation.m_Timeout.checkExpired(millis()))) { // Time for next probe
1099+
(pService->m_ProbeInformation.m_Timeout.expired())) { // Time for next probe
11001100

11011101
if (MDNS_PROBE_COUNT > pService->m_ProbeInformation.m_u8SentCount) { // Send next probe
11021102
if ((bResult = _sendServiceProbe(*pService))) {
@@ -1108,7 +1108,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
11081108
else { // Probing finished
11091109
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););
11101110
pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_Done;
1111-
pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
1111+
pService->m_ProbeInformation.m_Timeout.resetToNeverExpires();
11121112
if (pService->m_ProbeInformation.m_fnServiceProbeResultCallback) {
11131113
pService->m_ProbeInformation.m_fnServiceProbeResultCallback(pService->m_pcName, pService, true);
11141114
}
@@ -1119,7 +1119,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
11191119
}
11201120
} // else: Probing already finished OR waiting for next time slot
11211121
else if ((ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) &&
1122-
(pService->m_ProbeInformation.m_Timeout.checkExpired(millis()))) {
1122+
(pService->m_ProbeInformation.m_Timeout.expired())) {
11231123

11241124
if ((bResult = _announceService(*pService))) { // Announce service
11251125
++pService->m_ProbeInformation.m_u8SentCount;
@@ -1129,7 +1129,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
11291129
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););
11301130
}
11311131
else {
1132-
pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
1132+
pService->m_ProbeInformation.m_Timeout.resetToNeverExpires();
11331133
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););
11341134
}
11351135
}
@@ -1441,13 +1441,13 @@ bool MDNSResponder::_checkServiceQueryCache(void) {
14411441
// Resend dynamic service queries, if not already done often enough
14421442
if ((!pServiceQuery->m_bLegacyQuery) &&
14431443
(MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) &&
1444-
(pServiceQuery->m_ResendTimeout.checkExpired(millis()))) {
1444+
(pServiceQuery->m_ResendTimeout.expired())) {
14451445

14461446
if ((bResult = _sendMDNSServiceQuery(*pServiceQuery))) {
14471447
++pServiceQuery->m_u8SentCount;
14481448
pServiceQuery->m_ResendTimeout.reset((MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount)
14491449
? (MDNS_DYNAMIC_QUERY_RESEND_DELAY * (pServiceQuery->m_u8SentCount - 1))
1450-
: std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
1450+
: esp8266::polledTimeout::oneShotMs::neverExpires);
14511451
}
14521452
DEBUG_EX_INFO(
14531453
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: %s to resend service query!"), (bResult ? "Succeeded" : "FAILED"));

‎libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,7 +1159,7 @@ bool MDNSResponder::stcMDNS_RRAnswerGeneric::clear(void) {
11591159
MDNSResponder::stcProbeInformation::stcProbeInformation(void)
11601160
: m_ProbingStatus(ProbingStatus_WaitingForData),
11611161
m_u8SentCount(0),
1162-
m_Timeout(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
1162+
m_Timeout(esp8266::polledTimeout::oneShotMs::neverExpires),
11631163
m_bConflict(false),
11641164
m_bTiebreakNeeded(false),
11651165
m_fnHostProbeResultCallback(0),
@@ -1173,7 +1173,7 @@ bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/
11731173

11741174
m_ProbingStatus = ProbingStatus_WaitingForData;
11751175
m_u8SentCount = 0;
1176-
m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
1176+
m_Timeout.resetToNeverExpires();
11771177
m_bConflict = false;
11781178
m_bTiebreakNeeded = false;
11791179
if (p_bClearUserdata) {
@@ -1421,7 +1421,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated(void) con
14211421
*/
14221422
MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(void)
14231423
: m_u32TTL(0),
1424-
m_TTLTimeout(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
1424+
m_TTLTimeout(esp8266::polledTimeout::oneShotMs::neverExpires),
14251425
m_timeoutLevel(TIMEOUTLEVEL_UNSET) {
14261426

14271427
}
@@ -1438,19 +1438,19 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TT
14381438
}
14391439
else {
14401440
m_timeoutLevel = TIMEOUTLEVEL_UNSET; // undef
1441-
m_TTLTimeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
1441+
m_TTLTimeout.resetToNeverExpires();
14421442
}
14431443
return true;
14441444
}
14451445

14461446
/*
14471447
* MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged
14481448
*/
1449-
bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) const {
1449+
bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) {
14501450

14511451
return ((m_u32TTL) &&
14521452
(TIMEOUTLEVEL_UNSET != m_timeoutLevel) &&
1453-
(m_TTLTimeout.checkExpired(millis())));
1453+
(m_TTLTimeout.expired()));
14541454
}
14551455

14561456
/*
@@ -1468,7 +1468,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart(void) {
14681468
}
14691469
else {
14701470
bResult = false;
1471-
m_TTLTimeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
1471+
m_TTLTimeout.resetToNeverExpires();
14721472
m_timeoutLevel = TIMEOUTLEVEL_UNSET;
14731473
}
14741474
return bResult;
@@ -1498,7 +1498,7 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel(vo
14981498
*/
14991499
unsigned long MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout(void) const {
15001500

1501-
uint32_t u32Timeout = std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max();
1501+
uint32_t u32Timeout = esp8266::polledTimeout::oneShotMs::neverExpires;
15021502

15031503
if (TIMEOUTLEVEL_BASE == m_timeoutLevel) { // 80%
15041504
u32Timeout = (m_u32TTL * 800); // to milliseconds
@@ -1922,7 +1922,7 @@ MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery(void)
19221922
m_fnCallback(0),
19231923
m_bLegacyQuery(false),
19241924
m_u8SentCount(0),
1925-
m_ResendTimeout(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
1925+
m_ResendTimeout(esp8266::polledTimeout::oneShotMs::neverExpires),
19261926
m_bAwaitingAnswers(true),
19271927
m_pAnswers(0) {
19281928

@@ -1945,7 +1945,7 @@ bool MDNSResponder::stcMDNSServiceQuery::clear(void) {
19451945
m_fnCallback = 0;
19461946
m_bLegacyQuery = false;
19471947
m_u8SentCount = 0;
1948-
m_ResendTimeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
1948+
m_ResendTimeout.resetToNeverExpires();
19491949
m_bAwaitingAnswers = true;
19501950
while (m_pAnswers) {
19511951
stcAnswer* pNext = m_pAnswers->m_pNext;

‎libraries/SDFS/src/SDFSFormatter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class SDFSFormatter {
7373
DEBUGV("SDFS: Clear FAT/DIR writeStart failed");
7474
return false;
7575
}
76-
esp8266::polledTimeout::periodic timeToYield(5); // Yield every 5ms of runtime
76+
esp8266::polledTimeout::periodicFastMs timeToYield(5); // Yield every 5ms of runtime
7777
for (uint32_t i = 0; i < count; i++) {
7878
if (timeToYield) {
7979
delay(0); // WDT feed

‎libraries/Wire/examples/master_reader/master_reader.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ void setup() {
2323
}
2424

2525
void loop() {
26-
using periodic = esp8266::polledTimeout::periodic;
26+
using periodic = esp8266::polledTimeout::periodicMs;
2727
static periodic nextPing(1000);
2828

2929
if (nextPing) {

‎libraries/Wire/examples/master_writer/master_writer.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ void setup() {
2424
byte x = 0;
2525

2626
void loop() {
27-
using periodic = esp8266::polledTimeout::periodic;
27+
using periodic = esp8266::polledTimeout::periodicMs;
2828
static periodic nextPing(1000);
2929

3030
if (nextPing) {

‎libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,34 @@ void ledToggle() {
3838
}
3939

4040

41-
42-
esp8266::polledTimeout::periodic halfPeriod(500); //use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace
41+
esp8266::polledTimeout::periodicFastUs halfPeriod(500000); //use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace
4342

4443
// the setup function runs only once at start
4544
void setup() {
45+
Serial.begin(115200);
46+
47+
Serial.println();
48+
Serial.printf("periodic/oneShotMs::timeMax() = %u ms\n", (uint32_t)esp8266::polledTimeout::periodicMs::timeMax());
49+
Serial.printf("periodic/oneShotFastMs::timeMax() = %u ms\n", (uint32_t)esp8266::polledTimeout::periodicFastMs::timeMax());
50+
Serial.printf("periodic/oneShotFastUs::timeMax() = %u us\n", (uint32_t)esp8266::polledTimeout::periodicFastUs::timeMax());
51+
Serial.printf("periodic/oneShotFastNs::timeMax() = %u ns\n", (uint32_t)esp8266::polledTimeout::periodicFastNs::timeMax());
52+
53+
#if 0 // 1 for debugging polledTimeout
54+
Serial.printf("periodic/oneShotMs::rangeCompensate = %u\n", (uint32_t)esp8266::polledTimeout::periodicMs::rangeCompensate);
55+
Serial.printf("periodic/oneShotFastMs::rangeCompensate = %u\n", (uint32_t)esp8266::polledTimeout::periodicFastMs::rangeCompensate);
56+
Serial.printf("periodic/oneShotFastUs::rangeCompensate = %u\n", (uint32_t)esp8266::polledTimeout::periodicFastUs::rangeCompensate);
57+
Serial.printf("periodic/oneShotFastNs::rangeCompensate = %u\n", (uint32_t)esp8266::polledTimeout::periodicFastNs::rangeCompensate);
58+
#endif
59+
4660
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
4761

48-
using esp8266::polledTimeout::oneShot; //import the type to the local namespace
62+
using esp8266::polledTimeout::oneShotMs; //import the type to the local namespace
4963

5064
//STEP1; turn the led ON
5165
ledOn();
5266

5367
//STEP2: wait for ON timeout
54-
oneShot timeoutOn(2000);
68+
oneShotMs timeoutOn(2000);
5569
while (!timeoutOn) {
5670
yield();
5771
}
@@ -60,7 +74,7 @@ void setup() {
6074
ledOff();
6175

6276
//STEP4: wait for OFF timeout to assure the led is kept off for this time before exiting setup
63-
oneShot timeoutOff(2000);
77+
oneShotMs timeoutOff(2000);
6478
while (!timeoutOff) {
6579
yield();
6680
}

‎tests/host/common/MockEsp.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include <Esp.h>
3333
#include <eboot_command.h>
3434

35+
#include <sys/time.h>
36+
3537
#include <stdlib.h>
3638

3739
unsigned long long operator"" _kHz(unsigned long long x) {
@@ -215,3 +217,9 @@ void EspClass::resetFreeContStack()
215217
{
216218
}
217219

220+
uint32_t EspClass::getCycleCount()
221+
{
222+
timeval t;
223+
gettimeofday(&t, NULL);
224+
return (((uint64_t)t.tv_sec) * 1000000 + t.tv_usec) * (F_CPU / 1000000);
225+
}

‎tests/host/common/mock.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
DEALINGS WITH THE SOFTWARE.
3030
*/
3131

32+
#define CORE_MOCK 1
33+
3234
// include host's STL before any other include file
3335
// because core definition like max() is in the way
3436

@@ -138,8 +140,6 @@ void mock_stop_spiffs ();
138140

139141
//
140142

141-
#define CORE_MOCK 1
142-
143143
#define ARDUINO 267
144144
#define ESP8266 1
145145
#define A0 0

‎tests/host/core/test_PolledTimeout.cpp

Lines changed: 90 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#include <catch.hpp>
22
#include "PolledTimeout.h"
33

4+
#define mockverbose printf
5+
#include "common/MockEsp.cpp" // getCycleCount
6+
47
//This won't work for
58
template<typename argT>
69
inline bool
@@ -10,15 +13,83 @@ fuzzycomp(argT a, argT b)
1013
return (std::max(a,b) - std::min(a,b) <= epsilon);
1114
}
1215

16+
TEST_CASE("OneShot Timeout 500000000ns (0.5s)", "[polledTimeout]")
17+
{
18+
using esp8266::polledTimeout::oneShotFastNs;
19+
using timeType = oneShotFastNs::timeType;
20+
timeType before, after, delta;
21+
22+
Serial.println("OneShot Timeout 500000000ns (0.5s)");
23+
24+
oneShotFastNs timeout(500000000);
25+
before = micros();
26+
while(!timeout.expired())
27+
yield();
28+
after = micros();
29+
30+
delta = after - before;
31+
Serial.printf("delta = %u\n", delta);
32+
33+
REQUIRE(fuzzycomp(delta/1000, (timeType)500));
34+
35+
36+
Serial.print("reset\n");
37+
38+
timeout.reset();
39+
before = micros();
40+
while(!timeout)
41+
yield();
42+
after = micros();
43+
44+
delta = after - before;
45+
Serial.printf("delta = %u\n", delta);
46+
47+
REQUIRE(fuzzycomp(delta/1000, (timeType)500));
48+
}
49+
50+
TEST_CASE("OneShot Timeout 3000000us", "[polledTimeout]")
51+
{
52+
using esp8266::polledTimeout::oneShotFastUs;
53+
using timeType = oneShotFastUs::timeType;
54+
timeType before, after, delta;
55+
56+
Serial.println("OneShot Timeout 3000000us");
57+
58+
oneShotFastUs timeout(3000000);
59+
before = micros();
60+
while(!timeout.expired())
61+
yield();
62+
after = micros();
63+
64+
delta = after - before;
65+
Serial.printf("delta = %u\n", delta);
66+
67+
REQUIRE(fuzzycomp(delta/1000, (timeType)3000));
68+
69+
70+
Serial.print("reset\n");
71+
72+
timeout.reset();
73+
before = micros();
74+
while(!timeout)
75+
yield();
76+
after = micros();
77+
78+
delta = after - before;
79+
Serial.printf("delta = %u\n", delta);
80+
81+
REQUIRE(fuzzycomp(delta/1000, (timeType)3000));
82+
}
83+
1384
TEST_CASE("OneShot Timeout 3000ms", "[polledTimeout]")
1485
{
15-
using esp8266::polledTimeout::oneShot;
16-
using timeType = oneShot::timeType;
86+
using esp8266::polledTimeout::oneShotMs;
87+
using timeType = oneShotMs::timeType;
1788
timeType before, after, delta;
1889

1990
Serial.println("OneShot Timeout 3000ms");
2091

21-
oneShot timeout(3000);
92+
oneShotMs timeout(3000);
2293
before = millis();
2394
while(!timeout.expired())
2495
yield();
@@ -46,13 +117,13 @@ TEST_CASE("OneShot Timeout 3000ms", "[polledTimeout]")
46117

47118
TEST_CASE("OneShot Timeout 3000ms reset to 1000ms", "[polledTimeout]")
48119
{
49-
using esp8266::polledTimeout::oneShot;
50-
using timeType = oneShot::timeType;
120+
using esp8266::polledTimeout::oneShotMs;
121+
using timeType = oneShotMs::timeType;
51122
timeType before, after, delta;
52123

53124
Serial.println("OneShot Timeout 3000ms");
54125

55-
oneShot timeout(3000);
126+
oneShotMs timeout(3000);
56127
before = millis();
57128
while(!timeout.expired())
58129
yield();
@@ -80,13 +151,13 @@ TEST_CASE("OneShot Timeout 3000ms reset to 1000ms", "[polledTimeout]")
80151

81152
TEST_CASE("Periodic Timeout 1T 3000ms", "[polledTimeout]")
82153
{
83-
using esp8266::polledTimeout::periodic;
84-
using timeType = periodic::timeType;
154+
using esp8266::polledTimeout::periodicMs;
155+
using timeType = periodicMs::timeType;
85156
timeType before, after, delta;
86157

87158
Serial.println("Periodic Timeout 1T 3000ms");
88159

89-
periodic timeout(3000);
160+
periodicMs timeout(3000);
90161
before = millis();
91162
while(!timeout)
92163
yield();
@@ -103,7 +174,7 @@ TEST_CASE("Periodic Timeout 1T 3000ms", "[polledTimeout]")
103174
while(!timeout)
104175
yield();
105176
after = millis();
106-
177+
107178
delta = after - before;
108179
Serial.printf("delta = %lu\n", delta);
109180

@@ -112,15 +183,15 @@ TEST_CASE("Periodic Timeout 1T 3000ms", "[polledTimeout]")
112183

113184
TEST_CASE("Periodic Timeout 10T 1000ms", "[polledTimeout]")
114185
{
115-
using esp8266::polledTimeout::periodic;
116-
using timeType = periodic::timeType;
186+
using esp8266::polledTimeout::periodicMs;
187+
using timeType = periodicMs::timeType;
117188
timeType before, after, delta;
118189

119190
Serial.println("Periodic 10T Timeout 1000ms");
120191

121192
int counter = 10;
122193

123-
periodic timeout(1000);
194+
periodicMs timeout(1000);
124195
before = millis();
125196
while(1)
126197
{
@@ -133,7 +204,7 @@ TEST_CASE("Periodic Timeout 10T 1000ms", "[polledTimeout]")
133204
}
134205
}
135206
after = millis();
136-
207+
137208
delta = after - before;
138209
Serial.printf("\ndelta = %lu\n", delta);
139210
REQUIRE(fuzzycomp(delta, (timeType)10000));
@@ -142,18 +213,18 @@ TEST_CASE("Periodic Timeout 10T 1000ms", "[polledTimeout]")
142213
TEST_CASE("OneShot Timeout 3000ms reset to 1000ms custom yield", "[polledTimeout]")
143214
{
144215
using YieldOrSkipPolicy = esp8266::polledTimeout::YieldPolicy::YieldOrSkip;
145-
using oneShotYield = esp8266::polledTimeout::timeoutTemplate<false, YieldOrSkipPolicy>;
146-
using timeType = oneShotYield::timeType;
216+
using oneShotMsYield = esp8266::polledTimeout::timeoutTemplate<false, YieldOrSkipPolicy>;
217+
using timeType = oneShotMsYield::timeType;
147218
timeType before, after, delta;
148219

149220
Serial.println("OneShot Timeout 3000ms");
150221

151222

152-
oneShotYield timeout(3000);
223+
oneShotMsYield timeout(3000);
153224
before = millis();
154225
while(!timeout.expired());
155226
after = millis();
156-
227+
157228
delta = after - before;
158229
Serial.printf("delta = %lu\n", delta);
159230

@@ -166,7 +237,7 @@ TEST_CASE("OneShot Timeout 3000ms reset to 1000ms custom yield", "[polledTimeout
166237
before = millis();
167238
while(!timeout);
168239
after = millis();
169-
240+
170241
delta = after - before;
171242
Serial.printf("delta = %lu\n", delta);
172243

0 commit comments

Comments
 (0)
Please sign in to comment.