PolledTimer.h
Go to the documentation of this file.
1 /****
2  * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development.
3  * Created 2015 by Skurydin Alexey
4  * http://github.com/SmingHub/Sming
5  * All files of the Sming Core are provided under the LGPL v3 license.
6  *
7  * PolledTimer.h - template class to assist with measurement of elapsed time periods
8  *
9  * @author mikee47 <mike@sillyhouse.net>
10  *
11  * Developed from the excellent esp8266 Arduino project's PolledTimer.h
12  * Copyright (c) 2018 Daniel Salazar. All rights reserved.
13  * https://github.com/esp8266/Arduino/blob/master/cores/esp8266/PolledTimeout.h
14  *
15  * Generally Sming uses timer callbacks but for some applications a polled timer
16  * is more appropriate, especially if timer intervals are less than few hundred
17  * microseconds, or even in nanoseconds.
18  *
19  * Here we have the `PolledTimer` template class. See `Platform/Timers.h` for implementations.
20  *
21  ****/
22 
23 #pragma once
24 
25 #include <cstdint>
26 #include <esp_attr.h>
27 #include <sming_attr.h>
28 #include <Platform/Clocks.h>
29 
41 #ifndef POLLED_TIMER_MARGIN_US
42 #define POLLED_TIMER_MARGIN_US 250000
43 #endif
44 
45 namespace PolledTimer
46 {
66 template <class Clock, NanoTime::Unit unit_, bool IsPeriodic, typename TimeType>
67 class Timer : public NanoTime::TimeSource<Clock, unit_, TimeType>
68 {
69 public:
70  static_assert(std::is_unsigned<TimeType>::value == true, "TimeType must be unsigned");
71 
72  using TickType = typename Clock::TickType;
73  using Clock::ticks;
75 
76  static constexpr NanoTime::Unit unit()
77  {
78  return unit_;
79  }
80 
81  static constexpr TickType maxInterval()
82  {
83  return Clock::maxTicks() - Margin::ticks();
84  }
85 
86  static constexpr Margin margin()
87  {
88  return Margin();
89  }
90 
95  IRAM_ATTR Timer(const TimeType& timeInterval = 0)
96  {
97  reset(timeInterval);
98  }
99 
103  __forceinline void IRAM_ATTR start()
104  {
105  startTicks = ticks();
106  if(!IsPeriodic) {
107  // One-shot timers require manual reset
108  hasExpired = false;
109  }
110  }
111 
116  template <uint64_t timeInterval> __forceinline void IRAM_ATTR reset()
117  {
118  auto ticks = checkTime<timeInterval>();
119  resetTicks(ticks);
120  }
121 
128  template <uint64_t timeInterval> constexpr uint32_t checkTime()
129  {
130  auto time = this->template timeConst<timeInterval>();
131  time.check();
132  constexpr auto ticks = time.ticks();
133  static_assert(ticks < maxInterval(), "Polled time interval too long");
134  return ticks;
135  }
136 
143  __forceinline bool IRAM_ATTR reset(const TimeType& timeInterval)
144  {
145  return resetTicks(this->template timeToTicks(timeInterval));
146  }
147 
155  __forceinline bool IRAM_ATTR resetTicks(const TimeType& interval)
156  {
157  start();
158  this->interval = interval;
159  neverExpires = (interval > maxInterval());
160  return !neverExpires;
161  }
162 
166  __forceinline void IRAM_ATTR cancel()
167  {
168  interval = 1; // Ensure canWait() returns true
169  neverExpires = true;
170  if(!IsPeriodic) {
171  hasExpired = true;
172  }
173  }
174 
178  __forceinline TickType elapsedTicks() const
179  {
180  return ticks() - startTicks;
181  }
182 
186  __forceinline NanoTime::Time<TimeType> elapsedTime() const
187  {
188  return this->template ticksToTime(elapsedTicks());
189  }
190 
194  __forceinline TickType remainingTicks() const
195  {
196  auto ticks = elapsedTicks();
197  return (ticks < interval) ? interval - ticks : 0;
198  }
199 
204  {
205  return this->template ticksToTime(remainingTicks());
206  }
207 
208  __forceinline bool canExpire() const
209  {
210  return !neverExpires;
211  }
212 
213  __forceinline bool canWait() const
214  {
215  return interval != 0;
216  }
217 
222  __forceinline bool expired()
223  {
224  return IsPeriodic ? expiredRetrigger() : expiredOneShot();
225  }
226 
227 private:
228  __forceinline bool IRAM_ATTR checkExpired(const TickType& ticks) const
229  {
230  // canWait() is not checked here
231  // returns "can expire" and "time expired"
232  return !neverExpires && (TickType(ticks - startTicks) >= interval);
233  }
234 
235  bool IRAM_ATTR expiredRetrigger()
236  {
237  if(!canWait()) {
238  return true;
239  }
240 
241  bool result = false;
242  TickType current = ticks();
243  while(checkExpired(current)) {
244  result = true;
245  startTicks += interval;
246  }
247 
248  return result;
249  }
250 
251  __forceinline bool IRAM_ATTR expiredOneShot()
252  {
253  // Remain triggered until manually reset or cancelled
254  if(!canWait() || hasExpired) {
255  return true;
256  }
257  hasExpired = checkExpired(ticks());
258  return hasExpired;
259  }
260 
261  TickType startTicks;
262  TickType interval;
263  bool neverExpires;
264  bool hasExpired;
265 };
266 
267 // Standard timer types
268 template <typename Clock, NanoTime::Unit unit> using OneShot = Timer<Clock, unit, false, uint32_t>;
269 template <typename Clock, NanoTime::Unit unit> using Periodic = Timer<Clock, unit, true, uint32_t>;
270 
271 } // namespace PolledTimer
272 
Template class to implement a polled timer.
Definition: PolledTimer.h:68
constexpr uint32_t checkTime()
Check the given time interval is valid and return the corresponding tick count.
Definition: PolledTimer.h:128
bool canExpire() const
Definition: PolledTimer.h:208
void cancel()
Cancelling a timer means it will never expire.
Definition: PolledTimer.h:166
TickType remainingTicks() const
Get ticks remaining until expiry.
Definition: PolledTimer.h:194
typename Clock::TickType TickType
Definition: PolledTimer.h:72
static constexpr Margin margin()
Definition: PolledTimer.h:86
NanoTime::TimeConst< Clock, NanoTime::Microseconds, POLLED_TIMER_MARGIN_US > Margin
Definition: PolledTimer.h:74
Timer(const TimeType &timeInterval=0)
Create a Timer with optional expiry time.
Definition: PolledTimer.h:95
bool resetTicks(const TimeType &interval)
Start the timer with a new expiry interval.
Definition: PolledTimer.h:155
bool expired()
Determine if timer has expired.
Definition: PolledTimer.h:222
void reset()
Start the timer with a new expiry interval.
Definition: PolledTimer.h:116
void start()
Start the timer.
Definition: PolledTimer.h:103
static constexpr NanoTime::Unit unit()
Definition: PolledTimer.h:76
static constexpr TickType maxInterval()
Definition: PolledTimer.h:81
NanoTime::Time< TimeType > remainingTime() const
Get time remaining until expiry.
Definition: PolledTimer.h:203
NanoTime::Time< TimeType > elapsedTime() const
Get elapsed time since start() was last called.
Definition: PolledTimer.h:186
bool canWait() const
Definition: PolledTimer.h:213
bool reset(const TimeType &timeInterval)
Start the timer with a new expiry interval.
Definition: PolledTimer.h:143
TickType elapsedTicks() const
Get elapsed ticks since start() was last called.
Definition: PolledTimer.h:178
Time< T > time(Unit unit, T value)
Helper function to create a Time and deduce the type.
Definition: NanoTime.h:423
Unit
Identify units for a scalar quantity of time.
Definition: NanoTime.h:45
Definition: PolledTimer.h:46
TickType_ TickType
Definition: NanoTime.h:132
Class template to represent a fixed time value for a specific Clock.
Definition: NanoTime.h:468
static constexpr uint64_t ticks()
Return the corresponding tick value for the time interval.
Definition: NanoTime.h:505
Class template for accessing a Clock in specific time units.
Definition: NanoTime.h:630
static constexpr uint64_t ticksToTime()
Get the time for a given number of clock ticks.
Definition: NanoTime.h:728
static constexpr uint64_t timeToTicks()
Get the number of ticks for a given time.
Definition: NanoTime.h:718
TimeType TimeType
Definition: NanoTime.h:632
Class to handle a simple time value with associated unit.
Definition: NanoTime.h:364