blob: 6ba9543654206a7d2b398e1207ce176c052c63f4 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/time/time.h"
brians343bc112013-02-10 01:53:46 +00002
Austin Schuh3ce0a922020-07-21 21:08:54 -07003#include <algorithm>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08004#include <chrono>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07005#include <cinttypes>
6#include <cstring>
James Kuszmaul38735e82019-12-07 16:42:06 -08007#include <ctime>
Austin Schuhe92f7e62019-12-25 13:54:41 -08008#include <iomanip>
Brian Silvermand0575692015-02-21 16:24:02 -05009
Brian Silvermanc03a30c2019-02-16 18:21:56 -080010#ifdef __linux__
11
Austin Schuhd90499f2023-03-24 15:10:51 -070012#include "absl/strings/numbers.h"
Austin Schuhf257f3c2019-10-27 21:00:43 -070013#include "glog/logging.h"
brians343bc112013-02-10 01:53:46 +000014
Brian Silvermanc03a30c2019-02-16 18:21:56 -080015#else // __linux__
16
17#include "motors/core/kinetis.h"
18
19// The systick interrupt increments this every 1ms.
20extern "C" volatile uint32_t systick_millis_count;
21
22#endif // __linux__
23
Austin Schuhf2a50ba2016-12-24 16:16:26 -080024namespace chrono = ::std::chrono;
25
Philipp Schradera7878b92023-10-16 17:33:40 -070026namespace {
27
28void PrintToStream(std::ostream &stream, chrono::nanoseconds duration) {
29 chrono::seconds seconds = chrono::duration_cast<chrono::seconds>(duration);
30 if (duration < chrono::nanoseconds(0)) {
31 stream << "-" << -seconds.count() << "." << std::setfill('0')
32 << std::setw(9)
33 << chrono::duration_cast<chrono::nanoseconds>(seconds - duration)
34 .count()
35 << "sec";
36 } else {
37 stream << seconds.count() << "." << std::setfill('0') << std::setw(9)
38 << chrono::duration_cast<chrono::nanoseconds>(duration - seconds)
39 .count()
40 << "sec";
41 }
42}
43
44} // namespace
45
Brian Silvermanc03a30c2019-02-16 18:21:56 -080046#ifdef __linux__
47
Austin Schuh793d6b92016-05-01 13:28:14 -070048namespace std {
49namespace this_thread {
50template <>
51void sleep_until(const ::aos::monotonic_clock::time_point &end_time) {
52 struct timespec end_time_timespec;
53 ::std::chrono::seconds sec =
54 ::std::chrono::duration_cast<::std::chrono::seconds>(
55 end_time.time_since_epoch());
56 ::std::chrono::nanoseconds nsec =
57 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
58 end_time.time_since_epoch() - sec);
59 end_time_timespec.tv_sec = sec.count();
60 end_time_timespec.tv_nsec = nsec.count();
61 int returnval;
62 do {
63 returnval = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
64 &end_time_timespec, nullptr);
Austin Schuhf257f3c2019-10-27 21:00:43 -070065 PCHECK(returnval == 0 || returnval == EINTR)
66 << ": clock_nanosleep(" << static_cast<uintmax_t>(CLOCK_MONOTONIC)
67 << ", TIMER_ABSTIME, " << &end_time_timespec << ", nullptr) failed";
Austin Schuh793d6b92016-05-01 13:28:14 -070068 } while (returnval != 0);
69}
70
71} // namespace this_thread
72} // namespace std
73
Brian Silvermanc03a30c2019-02-16 18:21:56 -080074#endif // __linux__
Austin Schuh793d6b92016-05-01 13:28:14 -070075
brians343bc112013-02-10 01:53:46 +000076namespace aos {
Austin Schuhde8a8ff2019-11-30 15:25:36 -080077
James Kuszmaul38735e82019-12-07 16:42:06 -080078std::ostream &operator<<(std::ostream &stream,
79 const aos::monotonic_clock::time_point &now) {
Philipp Schradera7878b92023-10-16 17:33:40 -070080 PrintToStream(stream, now.time_since_epoch());
Austin Schuh40102d22019-12-27 23:30:06 -080081 return stream;
82}
83
Austin Schuhd90499f2023-03-24 15:10:51 -070084#ifdef __linux__
Austin Schuh3ce0a922020-07-21 21:08:54 -070085std::optional<monotonic_clock::time_point> monotonic_clock::FromString(
86 const std::string_view now) {
87 // This should undo the operator << above.
88 if (now.size() < 14) {
89 return std::nullopt;
90 }
91
92 if (now.substr(now.size() - 3, now.size()) != "sec") {
93 return std::nullopt;
94 }
95
Brian J Griglak259048b2022-01-27 12:30:55 -070096 if (now[now.size() - 13] != '.') {
Austin Schuh3ce0a922020-07-21 21:08:54 -070097 return std::nullopt;
98 }
99
Brian J Griglak259048b2022-01-27 12:30:55 -0700100 bool negative = now[0] == '-';
Austin Schuh3ce0a922020-07-21 21:08:54 -0700101
Austin Schuhd90499f2023-03-24 15:10:51 -0700102 std::string_view sec(
Austin Schuh3ce0a922020-07-21 21:08:54 -0700103 now.substr(negative ? 1 : 0, now.size() - (negative ? 14 : 13)));
Austin Schuhd90499f2023-03-24 15:10:51 -0700104 std::string_view nsec(now.substr(now.size() - 12, 9));
Austin Schuh3ce0a922020-07-21 21:08:54 -0700105
106 if (!std::all_of(sec.begin(), sec.end(), ::isdigit) ||
107 !std::all_of(nsec.begin(), nsec.end(), ::isdigit)) {
108 return std::nullopt;
109 }
110
Austin Schuhd90499f2023-03-24 15:10:51 -0700111 std::chrono::seconds::rep seconds_data;
112 if (!absl::SimpleAtoi(sec, &seconds_data)) {
113 return std::nullopt;
114 }
115
116 std::chrono::nanoseconds::rep nanoseconds_data;
117 if (!absl::SimpleAtoi(nsec, &nanoseconds_data)) {
118 return std::nullopt;
119 }
120
Austin Schuh3ce0a922020-07-21 21:08:54 -0700121 return monotonic_clock::time_point(
Austin Schuhd90499f2023-03-24 15:10:51 -0700122 std::chrono::seconds((negative ? -1 : 1) * seconds_data) +
123 std::chrono::nanoseconds((negative ? -1 : 1) * nanoseconds_data));
Austin Schuh3ce0a922020-07-21 21:08:54 -0700124}
125
126std::optional<realtime_clock::time_point> realtime_clock::FromString(
127 const std::string_view now) {
128 // This should undo the operator << above.
129
130 if (now.size() < 25) {
131 return std::nullopt;
132 }
133
Brian J Griglak259048b2022-01-27 12:30:55 -0700134 if (now[now.size() - 10] != '.') {
Austin Schuh3ce0a922020-07-21 21:08:54 -0700135 return std::nullopt;
136 }
137
Austin Schuhd90499f2023-03-24 15:10:51 -0700138 std::string_view nsec(now.substr(now.size() - 9, 9));
Austin Schuh3ce0a922020-07-21 21:08:54 -0700139
140 if (!std::all_of(nsec.begin(), nsec.end(), ::isdigit)) {
141 return std::nullopt;
142 }
143
144 struct tm tm;
145 std::istringstream ss(std::string(now.substr(0, now.size() - 10)));
146 ss >> std::get_time(&tm, "%Y-%m-%d_%H-%M-%S");
Austin Schuh76a313c2021-11-30 19:16:35 -0800147 if (ss.fail()) {
148 return std::nullopt;
149 }
Austin Schuh3ce0a922020-07-21 21:08:54 -0700150 tm.tm_isdst = -1;
151
152 time_t seconds = mktime(&tm);
153
Austin Schuhd90499f2023-03-24 15:10:51 -0700154 std::chrono::nanoseconds::rep nanoseconds_data;
155 if (!absl::SimpleAtoi(nsec, &nanoseconds_data)) {
156 return std::nullopt;
157 }
158
Philipp Schrader790cb542023-07-05 21:06:52 -0700159 return realtime_clock::time_point(std::chrono::seconds(seconds) +
160 std::chrono::nanoseconds(nanoseconds_data));
Austin Schuh3ce0a922020-07-21 21:08:54 -0700161}
Austin Schuhd90499f2023-03-24 15:10:51 -0700162#endif
Austin Schuh3ce0a922020-07-21 21:08:54 -0700163
Austin Schuh40102d22019-12-27 23:30:06 -0800164std::ostream &operator<<(std::ostream &stream,
165 const aos::realtime_clock::time_point &now) {
166 std::tm tm;
167 std::chrono::seconds seconds =
168 now < realtime_clock::epoch()
Austin Schuhb2ac0562021-09-13 23:23:33 -0700169 ? (std::chrono::duration_cast<std::chrono::seconds>(
170 now.time_since_epoch() + std::chrono::nanoseconds(1)) -
171 std::chrono::seconds(1))
Austin Schuh40102d22019-12-27 23:30:06 -0800172 : std::chrono::duration_cast<std::chrono::seconds>(
Austin Schuhe92f7e62019-12-25 13:54:41 -0800173 now.time_since_epoch());
174
Austin Schuh40102d22019-12-27 23:30:06 -0800175 std::time_t seconds_t = seconds.count();
176 stream << std::put_time(localtime_r(&seconds_t, &tm), "%Y-%m-%d_%H-%M-%S.")
177 << std::setfill('0') << std::setw(9)
178 << std::chrono::duration_cast<std::chrono::nanoseconds>(
179 now.time_since_epoch() - seconds)
180 .count();
181 return stream;
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800182}
183
brians343bc112013-02-10 01:53:46 +0000184namespace time {
185
Austin Schuh40102d22019-12-27 23:30:06 -0800186struct timespec to_timespec(const ::aos::monotonic_clock::duration duration) {
Neil Balch229001a2018-01-07 18:22:52 -0800187 struct timespec time_timespec;
188 ::std::chrono::seconds sec =
189 ::std::chrono::duration_cast<::std::chrono::seconds>(duration);
190 ::std::chrono::nanoseconds nsec =
191 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(duration - sec);
192 time_timespec.tv_sec = sec.count();
193 time_timespec.tv_nsec = nsec.count();
194 return time_timespec;
195}
196
Austin Schuh40102d22019-12-27 23:30:06 -0800197struct timespec to_timespec(const ::aos::monotonic_clock::time_point time) {
Neil Balch229001a2018-01-07 18:22:52 -0800198 return to_timespec(time.time_since_epoch());
199}
Brian Silverman967e5df2020-02-09 16:43:34 -0800200
201::aos::monotonic_clock::time_point from_timeval(struct timeval t) {
202 return monotonic_clock::epoch() + std::chrono::seconds(t.tv_sec) +
203 std::chrono::microseconds(t.tv_usec);
204}
205
brians343bc112013-02-10 01:53:46 +0000206} // namespace time
Austin Schuh858c0212016-11-25 17:23:30 -0800207
208constexpr monotonic_clock::time_point monotonic_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -0800209constexpr monotonic_clock::time_point monotonic_clock::max_time;
Brian Silverman2eb89762019-02-17 15:16:37 -0800210constexpr realtime_clock::time_point realtime_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -0800211constexpr realtime_clock::time_point realtime_clock::max_time;
Austin Schuh858c0212016-11-25 17:23:30 -0800212
213monotonic_clock::time_point monotonic_clock::now() noexcept {
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800214#ifdef __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800215 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700216 PCHECK(clock_gettime(CLOCK_MONOTONIC, &current_time) == 0)
217 << ": clock_gettime(" << static_cast<uintmax_t>(CLOCK_MONOTONIC) << ", "
218 << &current_time << ") failed";
219
Austin Schuh858c0212016-11-25 17:23:30 -0800220 return time_point(::std::chrono::seconds(current_time.tv_sec) +
Alex Perrycb7da4b2019-08-28 19:35:56 -0700221 ::std::chrono::nanoseconds(current_time.tv_nsec));
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800222
223#else // __linux__
224
225 __disable_irq();
226 const uint32_t current_counter = SYST_CVR;
227 uint32_t ms_count = systick_millis_count;
228 const uint32_t istatus = SCB_ICSR;
229 __enable_irq();
230 // If the interrupt is pending and the timer has already wrapped from 0 back
231 // up to its max, then add another ms.
232 if ((istatus & SCB_ICSR_PENDSTSET) && current_counter > 50) {
233 ++ms_count;
234 }
235
236 // It counts down, but everything we care about counts up.
237 const uint32_t counter_up = ((F_CPU / 1000) - 1) - current_counter;
238
239 // "3.2.1.2 System Tick Timer" in the TRM says "The System Tick Timer's clock
240 // source is always the core clock, FCLK".
241 using systick_duration =
242 std::chrono::duration<uint32_t, std::ratio<1, F_CPU>>;
243
Milo Linfd40acb2021-11-06 14:51:36 -0700244 return time_point(std::chrono::round<std::chrono::nanoseconds>(
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800245 std::chrono::milliseconds(ms_count) + systick_duration(counter_up)));
246
247#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800248}
249
Brian Silvermana3688802019-02-16 19:31:26 -0800250#ifdef __linux__
251realtime_clock::time_point realtime_clock::now() noexcept {
252 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700253 PCHECK(clock_gettime(CLOCK_REALTIME, &current_time) == 0)
254 << "clock_gettime(" << static_cast<uintmax_t>(CLOCK_REALTIME) << ", "
255 << &current_time << ") failed";
Brian Silvermana3688802019-02-16 19:31:26 -0800256
257 return time_point(::std::chrono::seconds(current_time.tv_sec) +
258 ::std::chrono::nanoseconds(current_time.tv_nsec));
259}
260#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800261
brians343bc112013-02-10 01:53:46 +0000262} // namespace aos