blob: fbfe9542d89c9daf20817468b61208ef02f22f2d [file] [log] [blame]
Brian3afd6fc2014-04-02 20:41:49 -07001#ifndef AOS_COMMON_UTIL_PHASED_LOOP_H_
2#define AOS_COMMON_UTIL_PHASED_LOOP_H_
brians343bc112013-02-10 01:53:46 +00003
Brian Silvermandcaa3f72015-11-29 05:32:08 +00004#include "aos/common/time.h"
5
6#include "aos/common/logging/logging.h"
brians343bc112013-02-10 01:53:46 +00007
8namespace aos {
9namespace time {
10
Brian Silvermandcaa3f72015-11-29 05:32:08 +000011// Handles sleeping until a fixed offset from some time interval.
12class PhasedLoop {
13 public:
14 // For example, with interval = 1s and offset = 0.1s this will fire at:
15 // 0.1s
16 // 1.1s
17 // ...
18 // 10000.1s
Austin Schuhf2a50ba2016-12-24 16:16:26 -080019 // offset must be >= chrono::seconds(0) and < interval.
Austin Schuh8aec1ed2016-05-01 13:29:20 -070020 PhasedLoop(
21 const monotonic_clock::duration interval,
22 const monotonic_clock::duration offset = monotonic_clock::duration(0))
Brian Silvermandcaa3f72015-11-29 05:32:08 +000023 : interval_(interval), offset_(offset), last_time_(offset) {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070024 CHECK_GE(offset, monotonic_clock::duration(0));
25 CHECK_GT(interval, monotonic_clock::duration(0));
Brian Silvermandcaa3f72015-11-29 05:32:08 +000026 CHECK_LT(offset, interval);
27 Reset();
28 }
29
30 // Resets the count of skipped iterations.
Austin Schuh8aec1ed2016-05-01 13:29:20 -070031 // Iterate(monotonic_now) will return 1 and set sleep_time() to something
32 // within interval of monotonic_now.
33 void Reset(const monotonic_clock::time_point monotonic_now =
34 monotonic_clock::now()) {
35 Iterate(monotonic_now - interval_);
36 }
Brian Silvermandcaa3f72015-11-29 05:32:08 +000037
Austin Schuh8aec1ed2016-05-01 13:29:20 -070038 // Calculates the next time to run after monotonic_now.
Brian Silvermandcaa3f72015-11-29 05:32:08 +000039 // The result can be retrieved with sleep_time().
40 // Returns the number of iterations which have passed (1 if this is called
Austin Schuh8aec1ed2016-05-01 13:29:20 -070041 // often enough). This can be < 1 iff monotonic_now goes backwards between
42 // calls.
43 int Iterate(const monotonic_clock::time_point monotonic_now =
44 monotonic_clock::now());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000045
46 // Sleeps until the next time and returns the number of iterations which have
47 // passed.
48 int SleepUntilNext() {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070049 const int r = Iterate(monotonic_clock::now());
50 ::std::this_thread::sleep_until(sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000051 return r;
52 }
53
Austin Schuh8aec1ed2016-05-01 13:29:20 -070054 monotonic_clock::time_point sleep_time() const { return last_time_; }
Brian Silvermandcaa3f72015-11-29 05:32:08 +000055
56 private:
Austin Schuh8aec1ed2016-05-01 13:29:20 -070057 const monotonic_clock::duration interval_, offset_;
Brian Silvermandcaa3f72015-11-29 05:32:08 +000058
59 // The time we most recently slept until.
Austin Schuh8aec1ed2016-05-01 13:29:20 -070060 monotonic_clock::time_point last_time_ = monotonic_clock::epoch();
Brian Silvermandcaa3f72015-11-29 05:32:08 +000061};
62
brians343bc112013-02-10 01:53:46 +000063} // namespace time
64} // namespace aos
65
Brian3afd6fc2014-04-02 20:41:49 -070066#endif // AOS_COMMON_UTIL_PHASED_LOOP_H_