blob: 7aa51d23c6d2019d3db675c4ff640f9b89d00cb0 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_UTIL_PHASED_LOOP_H_
2#define AOS_UTIL_PHASED_LOOP_H_
brians343bc112013-02-10 01:53:46 +00003
John Park33858a32018-09-28 23:05:48 -07004#include "aos/time/time.h"
Brian Silvermandcaa3f72015-11-29 05:32:08 +00005
John Park33858a32018-09-28 23:05:48 -07006#include "aos/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,
Austin Schuhd32b3622019-06-23 18:49:06 -070022 const monotonic_clock::time_point monotonic_now,
Austin Schuh8aec1ed2016-05-01 13:29:20 -070023 const monotonic_clock::duration offset = monotonic_clock::duration(0))
Brian Silvermandcaa3f72015-11-29 05:32:08 +000024 : interval_(interval), offset_(offset), last_time_(offset) {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070025 CHECK_GE(offset, monotonic_clock::duration(0));
26 CHECK_GT(interval, monotonic_clock::duration(0));
Brian Silvermandcaa3f72015-11-29 05:32:08 +000027 CHECK_LT(offset, interval);
Austin Schuhd32b3622019-06-23 18:49:06 -070028 Reset(monotonic_now);
Brian Silvermandcaa3f72015-11-29 05:32:08 +000029 }
30
Austin Schuh5d4b0982017-04-08 14:36:08 -070031 // Updates the offset and interval.
32 void set_interval_and_offset(const monotonic_clock::duration interval,
33 const monotonic_clock::duration offset) {
34 interval_ = interval;
35 offset_ = offset;
36 CHECK_GE(offset_, monotonic_clock::duration(0));
37 CHECK_GT(interval_, monotonic_clock::duration(0));
38 CHECK_LT(offset_, interval_);
39 }
40
41 // Computes the offset given an interval and a time that we should trigger.
42 static monotonic_clock::duration OffsetFromIntervalAndTime(
43 const monotonic_clock::duration interval,
44 const monotonic_clock::time_point monotonic_trigger) {
45 CHECK_GT(interval, monotonic_clock::duration(0));
46 return monotonic_trigger.time_since_epoch() -
47 (monotonic_trigger.time_since_epoch() / interval) * interval +
48 ((monotonic_trigger.time_since_epoch() >= monotonic_clock::zero())
49 ? monotonic_clock::zero()
50 : interval);
51 }
52
Brian Silvermandcaa3f72015-11-29 05:32:08 +000053 // Resets the count of skipped iterations.
Austin Schuh8aec1ed2016-05-01 13:29:20 -070054 // Iterate(monotonic_now) will return 1 and set sleep_time() to something
55 // within interval of monotonic_now.
Austin Schuhd32b3622019-06-23 18:49:06 -070056 void Reset(const monotonic_clock::time_point monotonic_now) {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070057 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
John Park33858a32018-09-28 23:05:48 -070088#endif // AOS_UTIL_PHASED_LOOP_H_