blob: c9e4933e3cd5388020bb39f14187c1cd5f225fcf [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
brians343bc112013-02-10 01:53:46 +00006namespace aos {
7namespace time {
8
Brian Silvermandcaa3f72015-11-29 05:32:08 +00009// Handles sleeping until a fixed offset from some time interval.
10class PhasedLoop {
11 public:
12 // For example, with interval = 1s and offset = 0.1s this will fire at:
13 // 0.1s
14 // 1.1s
15 // ...
16 // 10000.1s
Austin Schuhf2a50ba2016-12-24 16:16:26 -080017 // offset must be >= chrono::seconds(0) and < interval.
Austin Schuh8aec1ed2016-05-01 13:29:20 -070018 PhasedLoop(
19 const monotonic_clock::duration interval,
Austin Schuhd32b3622019-06-23 18:49:06 -070020 const monotonic_clock::time_point monotonic_now,
Austin Schuhf257f3c2019-10-27 21:00:43 -070021 const monotonic_clock::duration offset = monotonic_clock::duration(0));
Brian Silvermandcaa3f72015-11-29 05:32:08 +000022
Austin Schuh5d4b0982017-04-08 14:36:08 -070023 // Updates the offset and interval.
24 void set_interval_and_offset(const monotonic_clock::duration interval,
Austin Schuhf257f3c2019-10-27 21:00:43 -070025 const monotonic_clock::duration offset);
Austin Schuh5d4b0982017-04-08 14:36:08 -070026
27 // Computes the offset given an interval and a time that we should trigger.
28 static monotonic_clock::duration OffsetFromIntervalAndTime(
29 const monotonic_clock::duration interval,
Austin Schuhf257f3c2019-10-27 21:00:43 -070030 const monotonic_clock::time_point monotonic_trigger);
Austin Schuh5d4b0982017-04-08 14:36:08 -070031
Brian Silvermandcaa3f72015-11-29 05:32:08 +000032 // Resets the count of skipped iterations.
Austin Schuh8aec1ed2016-05-01 13:29:20 -070033 // Iterate(monotonic_now) will return 1 and set sleep_time() to something
34 // within interval of monotonic_now.
Austin Schuhd32b3622019-06-23 18:49:06 -070035 void Reset(const monotonic_clock::time_point monotonic_now) {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070036 Iterate(monotonic_now - interval_);
37 }
Brian Silvermandcaa3f72015-11-29 05:32:08 +000038
Austin Schuh8aec1ed2016-05-01 13:29:20 -070039 // Calculates the next time to run after monotonic_now.
Brian Silvermandcaa3f72015-11-29 05:32:08 +000040 // The result can be retrieved with sleep_time().
41 // Returns the number of iterations which have passed (1 if this is called
Austin Schuh8aec1ed2016-05-01 13:29:20 -070042 // often enough). This can be < 1 iff monotonic_now goes backwards between
43 // calls.
44 int Iterate(const monotonic_clock::time_point monotonic_now =
45 monotonic_clock::now());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000046
47 // Sleeps until the next time and returns the number of iterations which have
48 // passed.
49 int SleepUntilNext() {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070050 const int r = Iterate(monotonic_clock::now());
51 ::std::this_thread::sleep_until(sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000052 return r;
53 }
54
Austin Schuh8aec1ed2016-05-01 13:29:20 -070055 monotonic_clock::time_point sleep_time() const { return last_time_; }
Brian Silvermandcaa3f72015-11-29 05:32:08 +000056
Austin Schuhde8a8ff2019-11-30 15:25:36 -080057 monotonic_clock::duration interval() const { return interval_; }
58 monotonic_clock::duration offset() const { return offset_; }
59
Brian Silvermandcaa3f72015-11-29 05:32:08 +000060 private:
Austin Schuh5d4b0982017-04-08 14:36:08 -070061 monotonic_clock::duration interval_, offset_;
Brian Silvermandcaa3f72015-11-29 05:32:08 +000062
63 // The time we most recently slept until.
Austin Schuh8aec1ed2016-05-01 13:29:20 -070064 monotonic_clock::time_point last_time_ = monotonic_clock::epoch();
Brian Silvermandcaa3f72015-11-29 05:32:08 +000065};
66
brians343bc112013-02-10 01:53:46 +000067} // namespace time
68} // namespace aos
69
John Park33858a32018-09-28 23:05:48 -070070#endif // AOS_UTIL_PHASED_LOOP_H_