blob: 6daae7ee8a6d1683519be809eb07aab0a7dbae8d [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>
James Kuszmaul38735e82019-12-07 16:42:06 -08008#include <ctime>
Brian Silvermand0575692015-02-21 16:24:02 -05009
Brian Silvermanc03a30c2019-02-16 18:21:56 -080010#ifdef __linux__
11
John Park33858a32018-09-28 23:05:48 -070012#include "aos/mutex/mutex.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
Brian Silvermanc03a30c2019-02-16 18:21:56 -080026#ifdef __linux__
27
Austin Schuh793d6b92016-05-01 13:28:14 -070028namespace std {
29namespace this_thread {
30template <>
31void sleep_until(const ::aos::monotonic_clock::time_point &end_time) {
32 struct timespec end_time_timespec;
33 ::std::chrono::seconds sec =
34 ::std::chrono::duration_cast<::std::chrono::seconds>(
35 end_time.time_since_epoch());
36 ::std::chrono::nanoseconds nsec =
37 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
38 end_time.time_since_epoch() - sec);
39 end_time_timespec.tv_sec = sec.count();
40 end_time_timespec.tv_nsec = nsec.count();
41 int returnval;
42 do {
43 returnval = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
44 &end_time_timespec, nullptr);
Austin Schuhf257f3c2019-10-27 21:00:43 -070045 PCHECK(returnval == 0 || returnval == EINTR)
46 << ": clock_nanosleep(" << static_cast<uintmax_t>(CLOCK_MONOTONIC)
47 << ", TIMER_ABSTIME, " << &end_time_timespec << ", nullptr) failed";
Austin Schuh793d6b92016-05-01 13:28:14 -070048 } while (returnval != 0);
49}
50
51} // namespace this_thread
52} // namespace std
53
Brian Silvermanc03a30c2019-02-16 18:21:56 -080054#endif // __linux__
Austin Schuh793d6b92016-05-01 13:28:14 -070055
brians343bc112013-02-10 01:53:46 +000056namespace aos {
Austin Schuhde8a8ff2019-11-30 15:25:36 -080057
James Kuszmaul38735e82019-12-07 16:42:06 -080058std::ostream &operator<<(std::ostream &stream,
59 const aos::monotonic_clock::time_point &now) {
60 auto seconds =
61 std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
62 stream << seconds.count() << "."
63 << std::chrono::duration_cast<std::chrono::nanoseconds>(
64 now.time_since_epoch() - seconds)
65 .count()
66 << "sec";
67 return stream;
Austin Schuhde8a8ff2019-11-30 15:25:36 -080068}
69
brians343bc112013-02-10 01:53:46 +000070namespace time {
71
Neil Balch229001a2018-01-07 18:22:52 -080072struct timespec to_timespec(
73 const ::aos::monotonic_clock::duration duration) {
74 struct timespec time_timespec;
75 ::std::chrono::seconds sec =
76 ::std::chrono::duration_cast<::std::chrono::seconds>(duration);
77 ::std::chrono::nanoseconds nsec =
78 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(duration - sec);
79 time_timespec.tv_sec = sec.count();
80 time_timespec.tv_nsec = nsec.count();
81 return time_timespec;
82}
83
84struct timespec to_timespec(
85 const ::aos::monotonic_clock::time_point time) {
86 return to_timespec(time.time_since_epoch());
87}
brians343bc112013-02-10 01:53:46 +000088} // namespace time
Austin Schuh858c0212016-11-25 17:23:30 -080089
90constexpr monotonic_clock::time_point monotonic_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -080091constexpr monotonic_clock::time_point monotonic_clock::max_time;
Brian Silverman2eb89762019-02-17 15:16:37 -080092constexpr realtime_clock::time_point realtime_clock::min_time;
Brian Silverman94357272019-02-23 21:00:54 -080093constexpr realtime_clock::time_point realtime_clock::max_time;
Austin Schuh858c0212016-11-25 17:23:30 -080094
95monotonic_clock::time_point monotonic_clock::now() noexcept {
Brian Silvermanc03a30c2019-02-16 18:21:56 -080096#ifdef __linux__
Austin Schuh858c0212016-11-25 17:23:30 -080097 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -070098 PCHECK(clock_gettime(CLOCK_MONOTONIC, &current_time) == 0)
99 << ": clock_gettime(" << static_cast<uintmax_t>(CLOCK_MONOTONIC) << ", "
100 << &current_time << ") failed";
101
Austin Schuh858c0212016-11-25 17:23:30 -0800102 return time_point(::std::chrono::seconds(current_time.tv_sec) +
Alex Perrycb7da4b2019-08-28 19:35:56 -0700103 ::std::chrono::nanoseconds(current_time.tv_nsec));
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800104
105#else // __linux__
106
107 __disable_irq();
108 const uint32_t current_counter = SYST_CVR;
109 uint32_t ms_count = systick_millis_count;
110 const uint32_t istatus = SCB_ICSR;
111 __enable_irq();
112 // If the interrupt is pending and the timer has already wrapped from 0 back
113 // up to its max, then add another ms.
114 if ((istatus & SCB_ICSR_PENDSTSET) && current_counter > 50) {
115 ++ms_count;
116 }
117
118 // It counts down, but everything we care about counts up.
119 const uint32_t counter_up = ((F_CPU / 1000) - 1) - current_counter;
120
121 // "3.2.1.2 System Tick Timer" in the TRM says "The System Tick Timer's clock
122 // source is always the core clock, FCLK".
123 using systick_duration =
124 std::chrono::duration<uint32_t, std::ratio<1, F_CPU>>;
125
126 return time_point(aos::time::round<std::chrono::nanoseconds>(
127 std::chrono::milliseconds(ms_count) + systick_duration(counter_up)));
128
129#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800130}
131
Brian Silvermana3688802019-02-16 19:31:26 -0800132#ifdef __linux__
133realtime_clock::time_point realtime_clock::now() noexcept {
134 struct timespec current_time;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700135 PCHECK(clock_gettime(CLOCK_REALTIME, &current_time) == 0)
136 << "clock_gettime(" << static_cast<uintmax_t>(CLOCK_REALTIME) << ", "
137 << &current_time << ") failed";
Brian Silvermana3688802019-02-16 19:31:26 -0800138
139 return time_point(::std::chrono::seconds(current_time.tv_sec) +
140 ::std::chrono::nanoseconds(current_time.tv_nsec));
141}
142#endif // __linux__
Austin Schuh858c0212016-11-25 17:23:30 -0800143
brians343bc112013-02-10 01:53:46 +0000144} // namespace aos