blob: 958bd0140f629ddbc6a6a023c2fc88479eeb728a [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
Austin Schuh5d4b0982017-04-08 14:36:08 -070030 // Updates the offset and interval.
31 void set_interval_and_offset(const monotonic_clock::duration interval,
32 const monotonic_clock::duration offset) {
33 interval_ = interval;
34 offset_ = offset;
35 CHECK_GE(offset_, monotonic_clock::duration(0));
36 CHECK_GT(interval_, monotonic_clock::duration(0));
37 CHECK_LT(offset_, interval_);
38 }
39
40 // Computes the offset given an interval and a time that we should trigger.
41 static monotonic_clock::duration OffsetFromIntervalAndTime(
42 const monotonic_clock::duration interval,
43 const monotonic_clock::time_point monotonic_trigger) {
44 CHECK_GT(interval, monotonic_clock::duration(0));
45 return monotonic_trigger.time_since_epoch() -
46 (monotonic_trigger.time_since_epoch() / interval) * interval +
47 ((monotonic_trigger.time_since_epoch() >= monotonic_clock::zero())
48 ? monotonic_clock::zero()
49 : interval);
50 }
51
Brian Silvermandcaa3f72015-11-29 05:32:08 +000052 // Resets the count of skipped iterations.
Austin Schuh8aec1ed2016-05-01 13:29:20 -070053 // Iterate(monotonic_now) will return 1 and set sleep_time() to something
54 // within interval of monotonic_now.
55 void Reset(const monotonic_clock::time_point monotonic_now =
56 monotonic_clock::now()) {
57 Iterate(monotonic_now - interval_);
58 }
Brian Silvermandcaa3f72015-11-29 05:32:08 +000059
Austin Schuh8aec1ed2016-05-01 13:29:20 -070060 // Calculates the next time to run after monotonic_now.
Brian Silvermandcaa3f72015-11-29 05:32:08 +000061 // The result can be retrieved with sleep_time().
62 // Returns the number of iterations which have passed (1 if this is called
Austin Schuh8aec1ed2016-05-01 13:29:20 -070063 // often enough). This can be < 1 iff monotonic_now goes backwards between
64 // calls.
65 int Iterate(const monotonic_clock::time_point monotonic_now =
66 monotonic_clock::now());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000067
68 // Sleeps until the next time and returns the number of iterations which have
69 // passed.
70 int SleepUntilNext() {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070071 const int r = Iterate(monotonic_clock::now());
72 ::std::this_thread::sleep_until(sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000073 return r;
74 }
75
Austin Schuh8aec1ed2016-05-01 13:29:20 -070076 monotonic_clock::time_point sleep_time() const { return last_time_; }
Brian Silvermandcaa3f72015-11-29 05:32:08 +000077
78 private:
Austin Schuh5d4b0982017-04-08 14:36:08 -070079 monotonic_clock::duration interval_, offset_;
Brian Silvermandcaa3f72015-11-29 05:32:08 +000080
81 // The time we most recently slept until.
Austin Schuh8aec1ed2016-05-01 13:29:20 -070082 monotonic_clock::time_point last_time_ = monotonic_clock::epoch();
Brian Silvermandcaa3f72015-11-29 05:32:08 +000083};
84
brians343bc112013-02-10 01:53:46 +000085} // namespace time
86} // namespace aos
87
Brian3afd6fc2014-04-02 20:41:49 -070088#endif // AOS_COMMON_UTIL_PHASED_LOOP_H_