blob: 0a633ef8376e00194ccda0ddd6b7fbc9ef6e3b4b [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 Schuhf257f3c2019-10-27 21:00:43 -070012#include "glog/logging.h"
brians343bc112013-02-10 01:53:46 +000013
Brian Silvermanc03a30c2019-02-16 18:21:56 -080014#else // __linux__
15
16#include "motors/core/kinetis.h"
17
18// The systick interrupt increments this every 1ms.
19extern "C" volatile uint32_t systick_millis_count;
20
21#endif // __linux__
22
Austin Schuhf2a50ba2016-12-24 16:16:26 -080023namespace chrono = ::std::chrono;
24
Brian Silvermanc03a30c2019-02-16 18:21:56 -080025#ifdef __linux__
26
Austin Schuh793d6b92016-05-01 13:28:14 -070027namespace std {
28namespace this_thread {
29template <>
30void sleep_until(const ::aos::monotonic_clock::time_point &end_time) {
31 struct timespec end_time_timespec;
32 ::std::chrono::seconds sec =
33 ::std::chrono::duration_cast<::std::chrono::seconds>(
34 end_time.time_since_epoch());
35 ::std::chrono::nanoseconds nsec =
36 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
37 end_time.time_since_epoch() - sec);
38 end_time_timespec.tv_sec = sec.count();
39 end_time_timespec.tv_nsec = nsec.count();
40 int returnval;
41 do {
42 returnval = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
43 &end_time_timespec, nullptr);
Austin Schuhf257f3c2019-10-27 21:00:43 -070044 PCHECK(returnval == 0 || returnval == EINTR)
45 << ": clock_nanosleep(" << static_cast<uintmax_t>(CLOCK_MONOTONIC)
46 << ", TIMER_ABSTIME, " << &end_time_timespec << ", nullptr) failed";
Austin Schuh793d6b92016-05-01 13:28:14 -070047 } while (returnval != 0);
48}
49
50} // namespace this_thread
51} // namespace std
52
Brian Silvermanc03a30c2019-02-16 18:21:56 -080053#endif // __linux__
Austin Schuh793d6b92016-05-01 13:28:14 -070054
brians343bc112013-02-10 01:53:46 +000055namespace aos {
Austin Schuhde8a8ff2019-11-30 15:25:36 -080056
James Kuszmaul38735e82019-12-07 16:42:06 -080057std::ostream &operator<<(std::ostream &stream,
58 const aos::monotonic_clock::time_point &now) {
Austin Schuh40102d22019-12-27 23:30:06 -080059 if (now < monotonic_clock::epoch()) {
60 std::chrono::seconds seconds =
61 std::chrono::duration_cast<std::chrono::seconds>(
62 now.time_since_epoch());
63
64 stream << "-" << -seconds.count() << "." << std::setfill('0')
65 << std::setw(9)
66 << std::chrono::duration_cast<std::chrono::nanoseconds>(
67 seconds - now.time_since_epoch())
68 .count()
69 << "sec";
70 } else {
71 std::chrono::seconds seconds =
72 std::chrono::duration_cast<std::chrono::seconds>(
73 now.time_since_epoch());
74 stream << seconds.count() << "." << std::setfill('0') << std::setw(9)
75 << std::chrono::duration_cast<std::chrono::nanoseconds>(
76 now.time_since_epoch() - seconds)
77 .count()
78 << "sec";
79 }
80 return stream;
81}
82
Austin Schuh3ce0a922020-07-21 21:08:54 -070083std::optional<monotonic_clock::time_point> monotonic_clock::FromString(
84 const std::string_view now) {
85 // This should undo the operator << above.
86 if (now.size() < 14) {
87 return std::nullopt;
88 }
89
90 if (now.substr(now.size() - 3, now.size()) != "sec") {
91 return std::nullopt;
92 }
93
94 if (now.substr(now.size() - 13, 1) != ".") {
95 return std::nullopt;
96 }
97
98 bool negative = now.substr(0, 1) == "-";
99
100 std::string sec(
101 now.substr(negative ? 1 : 0, now.size() - (negative ? 14 : 13)));
102 std::string nsec(now.substr(now.size() - 12, 9));
103
104 if (!std::all_of(sec.begin(), sec.end(), ::isdigit) ||
105 !std::all_of(nsec.begin(), nsec.end(), ::isdigit)) {
106 return std::nullopt;
107 }
108
109 return monotonic_clock::time_point(
110 std::chrono::seconds((negative ? -1 : 1) * atoll(sec.c_str())) +
111 std::chrono::nanoseconds((negative ? -1 : 1) * atoll(nsec.c_str())));
112}
113
114std::optional<realtime_clock::time_point> realtime_clock::FromString(
115 const std::string_view now) {
116 // This should undo the operator << above.
117
118 if (now.size() < 25) {
119 return std::nullopt;
120 }
121
122 if (now.substr(now.size() - 10, 1) != ".") {
123 return std::nullopt;
124 }
125
126 std::string nsec(now.substr(now.size() - 9, 9));
127
128 if (!std::all_of(nsec.begin(), nsec.end(), ::isdigit)) {
129 return std::nullopt;
130 }
131
132 struct tm tm;
133 std::istringstream ss(std::string(now.substr(0, now.size() - 10)));
134 ss >> std::get_time(&tm, "%Y-%m-%d_%H-%M-%S");
135 tm.tm_isdst = -1;
136
137 time_t seconds = mktime(&tm);
138
139 return realtime_clock::time_point(
140 std::chrono::seconds(seconds) +
141 std::chrono::nanoseconds(atoll(nsec.c_str())));
142}
143
Austin Schuh40102d22019-12-27 23:30:06 -0800144std::ostream &operator<<(std::ostream &stream,
145 const aos::realtime_clock::time_point &now) {
146 std::tm tm;
147 std::chrono::seconds seconds =
148 now < realtime_clock::epoch()
Austin Schuhb2ac0562021-09-13 23:23:33 -0700149 ? (std::chrono::duration_cast<std::chrono::seconds>(
150 now.time_since_epoch() + std::chrono::nanoseconds(1)) -
151 std::chrono::seconds(1))
Austin Schuh40102d22019-12-27 23:30:06 -0800152 : std::chrono::duration_cast<std::chrono::seconds>(
Austin Schuhe92f7e62019-12-25 13:54:41 -0800153 now.time_since_epoch());
154
Austin Schuh40102d22019-12-27 23:30:06 -0800155 std::time_t seconds_t = seconds.count();
156 stream << std::put_time(localtime_r(&seconds_t, &tm), "%Y-%m-%d_%H-%M-%S.")
157 << std::setfill('0') << std::setw(9)
158 << std::chrono::duration_cast<std::chrono::nanoseconds>(
159 now.time_since_epoch() - seconds)
160 .count();
161 return stream;
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800162}
163
brians343bc112013-02-10 01:53:46 +0000164namespace time {
165
Austin Schuh40102d22019-12-27 23:30:06 -0800166struct timespec to_timespec(const ::aos::monotonic_clock::duration duration) {
Neil Balch229001a2018-01-07 18:22:52 -0800167 struct timespec time_timespec;
168 ::std::chrono::seconds sec =
169 ::std::chrono::duration_cast<::std::chrono::seconds>(duration);
170 ::std::chrono::nanoseconds nsec =
171 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(duration - sec);
172 time_timespec.tv_sec = sec.count();
173 time_timespec.tv_nsec = nsec.count();
174 return time_timespec;
175}
176
Austin Schuh40102d22019-12-27 23:30:06 -0800177struct timespec to_timespec(const ::aos::monotonic_clock::time_point time) {
Neil Balch229001a2018-01-07 18:22:52 -0800178 return to_timespec(time.time_since_epoch());
179}
Brian Silverman967e5df2020-02-09 16:43:34 -0800180
181::aos::monotonic_clock::time_point from_timeval(struct timeval t) {
182 return monotonic_clock::epoch() + std::chrono::seconds(t.tv_sec) +
183 std::chrono::microseconds(t.tv_usec);
184}
185
brians343bc112013-02-10 01:53:46 +0000186} // namespace time
Austin Schuh858c0212016-11-25 17:23:30 -0800187
188constexpr monotonic_clock::time_point monotonic_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -0800189constexpr monotonic_clock::time_point monotonic_clock::max_time;
Brian Silverman2eb89762019-02-17 15:16:37 -0800190constexpr realtime_clock::time_point realtime_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -0800191constexpr realtime_clock::time_point realtime_clock::max_time;
Austin Schuh858c0212016-11-25 17:23:30 -0800192
193monotonic_clock::time_point monotonic_clock::now() noexcept {
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800194#ifdef __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800195 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700196 PCHECK(clock_gettime(CLOCK_MONOTONIC, &current_time) == 0)
197 << ": clock_gettime(" << static_cast<uintmax_t>(CLOCK_MONOTONIC) << ", "
198 << &current_time << ") failed";
199
Austin Schuh858c0212016-11-25 17:23:30 -0800200 return time_point(::std::chrono::seconds(current_time.tv_sec) +
Alex Perrycb7da4b2019-08-28 19:35:56 -0700201 ::std::chrono::nanoseconds(current_time.tv_nsec));
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800202
203#else // __linux__
204
205 __disable_irq();
206 const uint32_t current_counter = SYST_CVR;
207 uint32_t ms_count = systick_millis_count;
208 const uint32_t istatus = SCB_ICSR;
209 __enable_irq();
210 // If the interrupt is pending and the timer has already wrapped from 0 back
211 // up to its max, then add another ms.
212 if ((istatus & SCB_ICSR_PENDSTSET) && current_counter > 50) {
213 ++ms_count;
214 }
215
216 // It counts down, but everything we care about counts up.
217 const uint32_t counter_up = ((F_CPU / 1000) - 1) - current_counter;
218
219 // "3.2.1.2 System Tick Timer" in the TRM says "The System Tick Timer's clock
220 // source is always the core clock, FCLK".
221 using systick_duration =
222 std::chrono::duration<uint32_t, std::ratio<1, F_CPU>>;
223
224 return time_point(aos::time::round<std::chrono::nanoseconds>(
225 std::chrono::milliseconds(ms_count) + systick_duration(counter_up)));
226
227#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800228}
229
Brian Silvermana3688802019-02-16 19:31:26 -0800230#ifdef __linux__
231realtime_clock::time_point realtime_clock::now() noexcept {
232 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700233 PCHECK(clock_gettime(CLOCK_REALTIME, &current_time) == 0)
234 << "clock_gettime(" << static_cast<uintmax_t>(CLOCK_REALTIME) << ", "
235 << &current_time << ") failed";
Brian Silvermana3688802019-02-16 19:31:26 -0800236
237 return time_point(::std::chrono::seconds(current_time.tv_sec) +
238 ::std::chrono::nanoseconds(current_time.tv_nsec));
239}
240#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800241
brians343bc112013-02-10 01:53:46 +0000242} // namespace aos