blob: 6c2d254a11b9668a531c6c0aa463ca74ce7efd0e [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/time/time.h"
brians343bc112013-02-10 01:53:46 +00002
Brian Silvermand0575692015-02-21 16:24:02 -05003#include <inttypes.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08004#include <string.h>
5
6#include <atomic>
7#include <chrono>
Brian Silvermand0575692015-02-21 16:24:02 -05008
Brian Silvermanc03a30c2019-02-16 18:21:56 -08009#ifdef __linux__
10
John Park33858a32018-09-28 23:05:48 -070011#include "aos/mutex/mutex.h"
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 {
56namespace time {
57
Brian Silvermanc03a30c2019-02-16 18:21:56 -080058#ifdef __linux__
59
Austin Schuhd78ab542013-03-01 22:22:19 -080060// State required to enable and use mock time.
61namespace {
62// True if mock time is enabled.
63// This does not need to be checked with the mutex held because setting time to
64// be enabled or disabled is atomic, and all future operations are atomic
65// anyways. If there is a race condition setting or clearing whether time is
66// enabled or not, it will still be a race condition if current_mock_time is
67// also set atomically with enabled.
Brian Silverman0308f162016-01-02 13:32:49 -080068::std::atomic<bool> mock_time_enabled{false};
Austin Schuhd78ab542013-03-01 22:22:19 -080069// Mutex to make time reads and writes thread safe.
70Mutex time_mutex;
71// Current time when time is mocked.
Austin Schuh6a6f90c2016-11-25 21:36:42 -080072monotonic_clock::time_point current_mock_time = monotonic_clock::epoch();
Austin Schuhd78ab542013-03-01 22:22:19 -080073
Brian Silvermanb407c672014-04-09 11:58:37 -070074} // namespace
75
Austin Schuh6a6f90c2016-11-25 21:36:42 -080076void EnableMockTime(monotonic_clock::time_point now) {
Austin Schuhd78ab542013-03-01 22:22:19 -080077 MutexLocker time_mutex_locker(&time_mutex);
Brian Silvermanb407c672014-04-09 11:58:37 -070078 mock_time_enabled = true;
Austin Schuhd78ab542013-03-01 22:22:19 -080079 current_mock_time = now;
80}
81
Austin Schuh6a6f90c2016-11-25 21:36:42 -080082void UpdateMockTime() { SetMockTime(monotonic_clock::now()); }
Brian Silvermanb407c672014-04-09 11:58:37 -070083
Austin Schuh6a6f90c2016-11-25 21:36:42 -080084void DisableMockTime() {
Austin Schuhd78ab542013-03-01 22:22:19 -080085 MutexLocker time_mutex_locker(&time_mutex);
86 mock_time_enabled = false;
87}
88
Austin Schuh6a6f90c2016-11-25 21:36:42 -080089void SetMockTime(monotonic_clock::time_point now) {
Austin Schuhd78ab542013-03-01 22:22:19 -080090 MutexLocker time_mutex_locker(&time_mutex);
Austin Schuhf257f3c2019-10-27 21:00:43 -070091 CHECK(mock_time_enabled)
92 << ": Tried to set mock time and mock time is not enabled";
Austin Schuhd78ab542013-03-01 22:22:19 -080093 current_mock_time = now;
94}
95
Austin Schuh6a6f90c2016-11-25 21:36:42 -080096void IncrementMockTime(monotonic_clock::duration amount) {
Brian Silverman6659bc32013-10-16 10:31:32 -070097 static ::aos::Mutex mutex;
98 ::aos::MutexLocker sync(&mutex);
Austin Schuh6a6f90c2016-11-25 21:36:42 -080099 SetMockTime(monotonic_clock::now() + amount);
Brian Silverman6659bc32013-10-16 10:31:32 -0700100}
101
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800102#endif // __linux__
103
Neil Balch229001a2018-01-07 18:22:52 -0800104struct timespec to_timespec(
105 const ::aos::monotonic_clock::duration duration) {
106 struct timespec time_timespec;
107 ::std::chrono::seconds sec =
108 ::std::chrono::duration_cast<::std::chrono::seconds>(duration);
109 ::std::chrono::nanoseconds nsec =
110 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(duration - sec);
111 time_timespec.tv_sec = sec.count();
112 time_timespec.tv_nsec = nsec.count();
113 return time_timespec;
114}
115
116struct timespec to_timespec(
117 const ::aos::monotonic_clock::time_point time) {
118 return to_timespec(time.time_since_epoch());
119}
brians343bc112013-02-10 01:53:46 +0000120} // namespace time
Austin Schuh858c0212016-11-25 17:23:30 -0800121
122constexpr monotonic_clock::time_point monotonic_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -0800123constexpr monotonic_clock::time_point monotonic_clock::max_time;
Brian Silverman2eb89762019-02-17 15:16:37 -0800124constexpr realtime_clock::time_point realtime_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -0800125constexpr realtime_clock::time_point realtime_clock::max_time;
Austin Schuh858c0212016-11-25 17:23:30 -0800126
127monotonic_clock::time_point monotonic_clock::now() noexcept {
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800128#ifdef __linux__
129
130 if (time::mock_time_enabled.load(::std::memory_order_relaxed)) {
131 MutexLocker time_mutex_locker(&time::time_mutex);
132 return time::current_mock_time;
Austin Schuh858c0212016-11-25 17:23:30 -0800133 }
134
135 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700136 PCHECK(clock_gettime(CLOCK_MONOTONIC, &current_time) == 0)
137 << ": clock_gettime(" << static_cast<uintmax_t>(CLOCK_MONOTONIC) << ", "
138 << &current_time << ") failed";
139
Austin Schuh858c0212016-11-25 17:23:30 -0800140 return time_point(::std::chrono::seconds(current_time.tv_sec) +
Alex Perrycb7da4b2019-08-28 19:35:56 -0700141 ::std::chrono::nanoseconds(current_time.tv_nsec));
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800142
143#else // __linux__
144
145 __disable_irq();
146 const uint32_t current_counter = SYST_CVR;
147 uint32_t ms_count = systick_millis_count;
148 const uint32_t istatus = SCB_ICSR;
149 __enable_irq();
150 // If the interrupt is pending and the timer has already wrapped from 0 back
151 // up to its max, then add another ms.
152 if ((istatus & SCB_ICSR_PENDSTSET) && current_counter > 50) {
153 ++ms_count;
154 }
155
156 // It counts down, but everything we care about counts up.
157 const uint32_t counter_up = ((F_CPU / 1000) - 1) - current_counter;
158
159 // "3.2.1.2 System Tick Timer" in the TRM says "The System Tick Timer's clock
160 // source is always the core clock, FCLK".
161 using systick_duration =
162 std::chrono::duration<uint32_t, std::ratio<1, F_CPU>>;
163
164 return time_point(aos::time::round<std::chrono::nanoseconds>(
165 std::chrono::milliseconds(ms_count) + systick_duration(counter_up)));
166
167#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800168}
169
Brian Silvermana3688802019-02-16 19:31:26 -0800170#ifdef __linux__
171realtime_clock::time_point realtime_clock::now() noexcept {
172 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700173 PCHECK(clock_gettime(CLOCK_REALTIME, &current_time) == 0)
174 << "clock_gettime(" << static_cast<uintmax_t>(CLOCK_REALTIME) << ", "
175 << &current_time << ") failed";
Brian Silvermana3688802019-02-16 19:31:26 -0800176
177 return time_point(::std::chrono::seconds(current_time.tv_sec) +
178 ::std::chrono::nanoseconds(current_time.tv_nsec));
179}
180#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800181
brians343bc112013-02-10 01:53:46 +0000182} // namespace aos