1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
19 #include "pw_preprocessor/util.h"
21 // The backend implements this header to provide the following SystemClock
22 // parameters, for more detail on the parameters see the SystemClock usage of
24 // PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR
25 // PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR
26 // constexpr pw::chrono::Epoch pw::chrono::backend::kSystemClockEpoch;
27 // constexpr bool pw::chrono::backend::kSystemClockFreeRunning;
28 // constexpr bool pw::chrono::backend::kSystemClockNmiSafe;
29 #include "pw_chrono_backend/system_clock_config.h"
36 namespace pw::chrono {
39 // The ARM AEBI does not permit the opaque 'time_point' to be passed via
40 // registers, ergo the underlying fundamental type is forward declared.
41 // A SystemCLock tick has the units of one SystemClock::period duration.
42 // This must be thread and IRQ safe and provided by the backend.
43 int64_t GetSystemClockTickCount();
45 } // namespace backend
47 // The SystemClock represents an unsteady, monotonic clock.
49 // The epoch of this clock is unspecified and may not be related to wall time
50 // (for example, it can be time since boot). The time between ticks of this
51 // clock may vary due to sleep modes and potential interrupt handling.
52 // SystemClock meets the requirements of C++'s TrivialClock and Pigweed's
55 // SystemClock is compatible with C++'s Clock & TrivialClock including:
57 // SystemClock::period
58 // SystemClock::duration
59 // SystemClock::time_point
60 // SystemClock::is_steady
65 // SystemClock::time_point before = SystemClock::now();
67 // SystemClock::duration time_taken = SystemClock::now() - before;
68 // bool took_way_too_long = false;
69 // if (time_taken > std::chrono::seconds(42)) {
70 // took_way_too_long = true;
73 // This code is thread & IRQ safe, it may be NMI safe depending on is_nmi_safe.
76 // The period must be provided by the backend.
77 using period = std::ratio<PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR,
78 PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR>;
79 using duration = std::chrono::duration<rep, period>;
80 using time_point = std::chrono::time_point<SystemClock>;
81 // The epoch must be provided by the backend.
82 static constexpr Epoch epoch = backend::kSystemClockEpoch;
84 // The time points of this clock cannot decrease, however the time between
85 // ticks of this clock may slightly vary due to sleep modes. The duration
86 // during sleep may be ignored or backfilled with another clock.
87 static constexpr bool is_monotonic = true;
88 static constexpr bool is_steady = false;
90 // The now() function may not move forward while in a critical section or
91 // interrupt. This must be provided by the backend.
92 static constexpr bool is_free_running = backend::kSystemClockFreeRunning;
94 // The clock must stop while in halting debug mode.
95 static constexpr bool is_stopped_in_halting_debug_mode = true;
97 // The now() function can be invoked at any time.
98 static constexpr bool is_always_enabled = true;
100 // The now() function may work in non-masking interrupts, depending on the
101 // backend. This must be provided by the backend.
102 static constexpr bool is_nmi_safe = backend::kSystemClockNmiSafe;
104 // This is thread and IRQ safe. This must be provided by the backend.
105 static time_point now() noexcept {
106 return time_point(duration(backend::GetSystemClockTickCount()));
110 // An abstract interface representing a SystemClock.
112 // This interface allows decoupling code that uses time from the code that
113 // creates a point in time. You can use this to your advantage by injecting
114 // Clocks into interfaces rather than having implementations call
115 // SystemClock::now() directly. However, this comes at a cost of a vtable per
116 // implementation and more importantly passing and maintaining references to the
117 // VirtualSystemCLock for all of the users.
119 // The VirtualSystemClock::RealClock() function returns a reference to the
120 // real global SystemClock.
124 // void DoFoo(VirtualSystemClock& system_clock) {
125 // SystemClock::time_point now = clock.now();
126 // // ... Code which consumes now.
129 // // Production code:
130 // DoFoo(VirtualSystemCLock::RealClock);
133 // MockClock test_clock();
134 // DoFoo(test_clock);
136 // This interface is thread and IRQ safe.
137 class VirtualSystemClock {
139 // Returns a reference to the real system clock to aid instantiation.
140 static VirtualSystemClock& RealClock();
142 virtual ~VirtualSystemClock() = default;
143 virtual SystemClock::time_point now() = 0;
146 } // namespace pw::chrono
148 // The backend can opt to include an inlined implementation of the following:
149 // int64_t GetSystemClockTickCount();
150 #if __has_include("pw_chrono_backend/system_clock_inline.h")
151 #include "pw_chrono_backend/system_clock_inline.h"
152 #endif // __has_include("pw_chrono_backend/system_clock_inline.h")
154 #endif // __cplusplus
158 // C API Users should not create pw_chrono_SystemClock_Duration's directly,
159 // instead it is strongly recommended to use macros which express the duration
160 // in time units, instead of non-portable ticks.
162 // The following macros round up just like std::chrono::ceil, this is the
163 // recommended rounding to maintain the "at least" contract of timeouts and
164 // deadlines (note the *_CEIL macros are the same only more explicit):
165 // PW_SYSTEM_CLOCK_MS(milliseconds)
166 // PW_SYSTEM_CLOCK_S(seconds)
167 // PW_SYSTEM_CLOCK_MIN(minutes)
168 // PW_SYSTEM_CLOCK_H(hours)
169 // PW_SYSTEM_CLOCK_MS_CEIL(milliseconds)
170 // PW_SYSTEM_CLOCK_S_CEIL(seconds)
171 // PW_SYSTEM_CLOCK_MIN_CEIL(minutes)
172 // PW_SYSTEM_CLOCK_H_CEIL(hours)
174 // The following macros round down like std::chrono::{floor,duration_cast},
175 // these are discouraged but sometimes necessary:
176 // PW_SYSTEM_CLOCK_MS_FLOOR(milliseconds)
177 // PW_SYSTEM_CLOCK_S_FLOOR(seconds)
178 // PW_SYSTEM_CLOCK_MIN_FLOOR(minutes)
179 // PW_SYSTEM_CLOCK_H_FLOOR(hours)
180 #include "pw_chrono/internal/system_clock_macros.h"
184 } pw_chrono_SystemClock_Duration;
187 pw_chrono_SystemClock_Duration duration_since_epoch;
188 } pw_chrono_SystemClock_TimePoint;
189 typedef int64_t pw_chrono_SystemClock_Nanoseconds;
191 // Returns the current time, see SystemClock::now() for more detail.
192 pw_chrono_SystemClock_TimePoint pw_chrono_SystemClock_Now();
194 // Returns the change in time between the current_time - last_time.
195 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_TimeElapsed(
196 pw_chrono_SystemClock_TimePoint last_time,
197 pw_chrono_SystemClock_TimePoint current_time);
199 // For lossless time unit conversion, the seconds per tick ratio that is
200 // numerator/denominator should be used:
201 // PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR
202 // PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR
204 // Warning, this may be lossy due to the use of std::chrono::floor,
205 // rounding towards zero.
206 pw_chrono_SystemClock_Nanoseconds pw_chrono_SystemClock_DurationToNsFloor(
207 pw_chrono_SystemClock_Duration duration);