blob: 97360091fb8fefd9003dc5f4127c7f414ff0cb33 [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
Brian Silvermand0575692015-02-21 16:24:02 -050011// We only use global_core from here, which is weak, so we don't really have a
12// dependency on it.
John Park398c74a2018-10-20 21:17:39 -070013#include "aos/ipc_lib/shared_mem.h"
brians343bc112013-02-10 01:53:46 +000014
John Park33858a32018-09-28 23:05:48 -070015#include "aos/mutex/mutex.h"
Austin Schuhf257f3c2019-10-27 21:00:43 -070016#include "glog/logging.h"
brians343bc112013-02-10 01:53:46 +000017
Brian Silvermanc03a30c2019-02-16 18:21:56 -080018#else // __linux__
19
20#include "motors/core/kinetis.h"
21
22// The systick interrupt increments this every 1ms.
23extern "C" volatile uint32_t systick_millis_count;
24
25#endif // __linux__
26
Austin Schuhf2a50ba2016-12-24 16:16:26 -080027namespace chrono = ::std::chrono;
28
Brian Silvermanc03a30c2019-02-16 18:21:56 -080029#ifdef __linux__
30
Austin Schuh793d6b92016-05-01 13:28:14 -070031namespace std {
32namespace this_thread {
33template <>
34void sleep_until(const ::aos::monotonic_clock::time_point &end_time) {
35 struct timespec end_time_timespec;
36 ::std::chrono::seconds sec =
37 ::std::chrono::duration_cast<::std::chrono::seconds>(
38 end_time.time_since_epoch());
39 ::std::chrono::nanoseconds nsec =
40 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
41 end_time.time_since_epoch() - sec);
42 end_time_timespec.tv_sec = sec.count();
43 end_time_timespec.tv_nsec = nsec.count();
44 int returnval;
45 do {
46 returnval = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
47 &end_time_timespec, nullptr);
Austin Schuhf257f3c2019-10-27 21:00:43 -070048 PCHECK(returnval == 0 || returnval == EINTR)
49 << ": clock_nanosleep(" << static_cast<uintmax_t>(CLOCK_MONOTONIC)
50 << ", TIMER_ABSTIME, " << &end_time_timespec << ", nullptr) failed";
Austin Schuh793d6b92016-05-01 13:28:14 -070051 } while (returnval != 0);
52}
53
54} // namespace this_thread
55} // namespace std
56
Brian Silvermanc03a30c2019-02-16 18:21:56 -080057#endif // __linux__
Austin Schuh793d6b92016-05-01 13:28:14 -070058
brians343bc112013-02-10 01:53:46 +000059namespace aos {
60namespace time {
61
Brian Silvermanc03a30c2019-02-16 18:21:56 -080062#ifdef __linux__
63
Austin Schuhd78ab542013-03-01 22:22:19 -080064// State required to enable and use mock time.
65namespace {
66// True if mock time is enabled.
67// This does not need to be checked with the mutex held because setting time to
68// be enabled or disabled is atomic, and all future operations are atomic
69// anyways. If there is a race condition setting or clearing whether time is
70// enabled or not, it will still be a race condition if current_mock_time is
71// also set atomically with enabled.
Brian Silverman0308f162016-01-02 13:32:49 -080072::std::atomic<bool> mock_time_enabled{false};
Austin Schuhd78ab542013-03-01 22:22:19 -080073// Mutex to make time reads and writes thread safe.
74Mutex time_mutex;
75// Current time when time is mocked.
Austin Schuh6a6f90c2016-11-25 21:36:42 -080076monotonic_clock::time_point current_mock_time = monotonic_clock::epoch();
Austin Schuhd78ab542013-03-01 22:22:19 -080077
Brian Silvermanb407c672014-04-09 11:58:37 -070078} // namespace
79
Austin Schuh6a6f90c2016-11-25 21:36:42 -080080void EnableMockTime(monotonic_clock::time_point now) {
Austin Schuhd78ab542013-03-01 22:22:19 -080081 MutexLocker time_mutex_locker(&time_mutex);
Brian Silvermanb407c672014-04-09 11:58:37 -070082 mock_time_enabled = true;
Austin Schuhd78ab542013-03-01 22:22:19 -080083 current_mock_time = now;
84}
85
Austin Schuh6a6f90c2016-11-25 21:36:42 -080086void UpdateMockTime() { SetMockTime(monotonic_clock::now()); }
Brian Silvermanb407c672014-04-09 11:58:37 -070087
Austin Schuh6a6f90c2016-11-25 21:36:42 -080088void DisableMockTime() {
Austin Schuhd78ab542013-03-01 22:22:19 -080089 MutexLocker time_mutex_locker(&time_mutex);
90 mock_time_enabled = false;
91}
92
Austin Schuh6a6f90c2016-11-25 21:36:42 -080093void SetMockTime(monotonic_clock::time_point now) {
Austin Schuhd78ab542013-03-01 22:22:19 -080094 MutexLocker time_mutex_locker(&time_mutex);
Austin Schuhf257f3c2019-10-27 21:00:43 -070095 CHECK(mock_time_enabled)
96 << ": Tried to set mock time and mock time is not enabled";
Austin Schuhd78ab542013-03-01 22:22:19 -080097 current_mock_time = now;
98}
99
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800100void IncrementMockTime(monotonic_clock::duration amount) {
Brian Silverman6659bc32013-10-16 10:31:32 -0700101 static ::aos::Mutex mutex;
102 ::aos::MutexLocker sync(&mutex);
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800103 SetMockTime(monotonic_clock::now() + amount);
Brian Silverman6659bc32013-10-16 10:31:32 -0700104}
105
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800106void OffsetToNow(monotonic_clock::time_point now) {
Brian Silverman0c715e62015-10-24 16:49:46 -0400107 CHECK_NOTNULL(&global_core);
Brian Silvermand0575692015-02-21 16:24:02 -0500108 CHECK_NOTNULL(global_core);
Brian Silverman0c715e62015-10-24 16:49:46 -0400109 CHECK_NOTNULL(global_core->mem_struct);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800110 const auto offset = now - monotonic_clock::now();
111 global_core->mem_struct->time_offset =
112 chrono::duration_cast<chrono::nanoseconds>(offset).count();
Brian Silvermand0575692015-02-21 16:24:02 -0500113}
114
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800115#endif // __linux__
116
Neil Balch229001a2018-01-07 18:22:52 -0800117struct timespec to_timespec(
118 const ::aos::monotonic_clock::duration duration) {
119 struct timespec time_timespec;
120 ::std::chrono::seconds sec =
121 ::std::chrono::duration_cast<::std::chrono::seconds>(duration);
122 ::std::chrono::nanoseconds nsec =
123 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(duration - sec);
124 time_timespec.tv_sec = sec.count();
125 time_timespec.tv_nsec = nsec.count();
126 return time_timespec;
127}
128
129struct timespec to_timespec(
130 const ::aos::monotonic_clock::time_point time) {
131 return to_timespec(time.time_since_epoch());
132}
brians343bc112013-02-10 01:53:46 +0000133} // namespace time
Austin Schuh858c0212016-11-25 17:23:30 -0800134
135constexpr monotonic_clock::time_point monotonic_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -0800136constexpr monotonic_clock::time_point monotonic_clock::max_time;
Brian Silverman2eb89762019-02-17 15:16:37 -0800137constexpr realtime_clock::time_point realtime_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -0800138constexpr realtime_clock::time_point realtime_clock::max_time;
Austin Schuh858c0212016-11-25 17:23:30 -0800139
140monotonic_clock::time_point monotonic_clock::now() noexcept {
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800141#ifdef __linux__
142
143 if (time::mock_time_enabled.load(::std::memory_order_relaxed)) {
144 MutexLocker time_mutex_locker(&time::time_mutex);
145 return time::current_mock_time;
Austin Schuh858c0212016-11-25 17:23:30 -0800146 }
147
148 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700149 PCHECK(clock_gettime(CLOCK_MONOTONIC, &current_time) == 0)
150 << ": clock_gettime(" << static_cast<uintmax_t>(CLOCK_MONOTONIC) << ", "
151 << &current_time << ") failed";
152
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800153 const chrono::nanoseconds offset =
154 (&global_core == nullptr || global_core == nullptr ||
155 global_core->mem_struct == nullptr)
156 ? chrono::nanoseconds(0)
157 : chrono::nanoseconds(global_core->mem_struct->time_offset);
158
Austin Schuh858c0212016-11-25 17:23:30 -0800159 return time_point(::std::chrono::seconds(current_time.tv_sec) +
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800160 ::std::chrono::nanoseconds(current_time.tv_nsec)) + offset;
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800161
162#else // __linux__
163
164 __disable_irq();
165 const uint32_t current_counter = SYST_CVR;
166 uint32_t ms_count = systick_millis_count;
167 const uint32_t istatus = SCB_ICSR;
168 __enable_irq();
169 // If the interrupt is pending and the timer has already wrapped from 0 back
170 // up to its max, then add another ms.
171 if ((istatus & SCB_ICSR_PENDSTSET) && current_counter > 50) {
172 ++ms_count;
173 }
174
175 // It counts down, but everything we care about counts up.
176 const uint32_t counter_up = ((F_CPU / 1000) - 1) - current_counter;
177
178 // "3.2.1.2 System Tick Timer" in the TRM says "The System Tick Timer's clock
179 // source is always the core clock, FCLK".
180 using systick_duration =
181 std::chrono::duration<uint32_t, std::ratio<1, F_CPU>>;
182
183 return time_point(aos::time::round<std::chrono::nanoseconds>(
184 std::chrono::milliseconds(ms_count) + systick_duration(counter_up)));
185
186#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800187}
188
Brian Silvermana3688802019-02-16 19:31:26 -0800189#ifdef __linux__
190realtime_clock::time_point realtime_clock::now() noexcept {
191 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700192 PCHECK(clock_gettime(CLOCK_REALTIME, &current_time) == 0)
193 << "clock_gettime(" << static_cast<uintmax_t>(CLOCK_REALTIME) << ", "
194 << &current_time << ") failed";
Brian Silvermana3688802019-02-16 19:31:26 -0800195
196 return time_point(::std::chrono::seconds(current_time.tv_sec) +
197 ::std::chrono::nanoseconds(current_time.tv_nsec));
198}
199#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800200
brians343bc112013-02-10 01:53:46 +0000201} // namespace aos