1 // Copyright 2020 The Pigweed Authors 2 // 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 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 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 13 // the License. 14 #pragma once 15 16 #include <stddef.h> 17 #include <stdint.h> 18 19 #include "pw_preprocessor/util.h" 20 21 // The backend implements this header to provide the following SystemClock 22 // parameters, for more detail on the parameters see the SystemClock usage of 23 // them below: 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" 30 31 #ifdef __cplusplus 32 33 #include <chrono> 34 #include <ratio> 35 36 namespace pw::chrono { 37 namespace backend { 38 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(); 44 45 } // namespace backend 46 47 // The SystemClock represents an unsteady, monotonic clock. 48 // 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 53 // PigweedClock. 54 // 55 // SystemClock is compatible with C++'s Clock & TrivialClock including: 56 // SystemClock::rep 57 // SystemClock::period 58 // SystemClock::duration 59 // SystemClock::time_point 60 // SystemClock::is_steady 61 // SystemClock::now() 62 // 63 // Example: 64 // 65 // SystemClock::time_point before = SystemClock::now(); 66 // TakesALongTime(); 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; 71 // } 72 // 73 // This code is thread & IRQ safe, it may be NMI safe depending on is_nmi_safe. 74 struct SystemClock { 75 using rep = int64_t; 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; 83 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; 89 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; 93 94 // The clock must stop while in halting debug mode. 95 static constexpr bool is_stopped_in_halting_debug_mode = true; 96 97 // The now() function can be invoked at any time. 98 static constexpr bool is_always_enabled = true; 99 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; 103 104 // This is thread and IRQ safe. This must be provided by the backend. nowSystemClock105 static time_point now() noexcept { 106 return time_point(duration(backend::GetSystemClockTickCount())); 107 } 108 109 // This is purely a helper, identical to directly using std::chrono::ceil, to 110 // convert a duration type which cannot be implicitly converted where the 111 // result is rounded up. 112 template <class Rep, class Period> for_at_leastSystemClock113 static constexpr duration for_at_least(std::chrono::duration<Rep, Period> d) { 114 return std::chrono::ceil<duration>(d); 115 }; 116 117 // Computes the nearest time_point after the specified duration has elapsed. 118 // 119 // This is useful for translating delay or timeout durations into deadlines. 120 // 121 // The time_point is computed based on now() plus the specified duration 122 // where a singular clock tick is added to handle partial ticks. This ensures 123 // that a duration of at least 1 tick does not result in [0,1] ticks and 124 // instead in [1,2] ticks. TimePointAfterAtLeastSystemClock125 static time_point TimePointAfterAtLeast(duration after_at_least) { 126 return now() + after_at_least + duration(1); 127 } 128 }; 129 130 // An abstract interface representing a SystemClock. 131 // 132 // This interface allows decoupling code that uses time from the code that 133 // creates a point in time. You can use this to your advantage by injecting 134 // Clocks into interfaces rather than having implementations call 135 // SystemClock::now() directly. However, this comes at a cost of a vtable per 136 // implementation and more importantly passing and maintaining references to the 137 // VirtualSystemCLock for all of the users. 138 // 139 // The VirtualSystemClock::RealClock() function returns a reference to the 140 // real global SystemClock. 141 // 142 // Example: 143 // 144 // void DoFoo(VirtualSystemClock& system_clock) { 145 // SystemClock::time_point now = clock.now(); 146 // // ... Code which consumes now. 147 // } 148 // 149 // // Production code: 150 // DoFoo(VirtualSystemCLock::RealClock); 151 // 152 // // Test code: 153 // MockClock test_clock(); 154 // DoFoo(test_clock); 155 // 156 // This interface is thread and IRQ safe. 157 class VirtualSystemClock { 158 public: 159 // Returns a reference to the real system clock to aid instantiation. 160 static VirtualSystemClock& RealClock(); 161 162 virtual ~VirtualSystemClock() = default; 163 virtual SystemClock::time_point now() = 0; 164 }; 165 166 } // namespace pw::chrono 167 168 // The backend can opt to include an inlined implementation of the following: 169 // int64_t GetSystemClockTickCount(); 170 #if __has_include("pw_chrono_backend/system_clock_inline.h") 171 #include "pw_chrono_backend/system_clock_inline.h" 172 #endif // __has_include("pw_chrono_backend/system_clock_inline.h") 173 174 #endif // __cplusplus 175 176 PW_EXTERN_C_START 177 178 // C API Users should not create pw_chrono_SystemClock_Duration's directly, 179 // instead it is strongly recommended to use macros which express the duration 180 // in time units, instead of non-portable ticks. 181 // 182 // The following macros round up just like std::chrono::ceil, this is the 183 // recommended rounding to maintain the "at least" contract of timeouts and 184 // deadlines (note the *_CEIL macros are the same only more explicit): 185 // PW_SYSTEM_CLOCK_MS(milliseconds) 186 // PW_SYSTEM_CLOCK_S(seconds) 187 // PW_SYSTEM_CLOCK_MIN(minutes) 188 // PW_SYSTEM_CLOCK_H(hours) 189 // PW_SYSTEM_CLOCK_MS_CEIL(milliseconds) 190 // PW_SYSTEM_CLOCK_S_CEIL(seconds) 191 // PW_SYSTEM_CLOCK_MIN_CEIL(minutes) 192 // PW_SYSTEM_CLOCK_H_CEIL(hours) 193 // 194 // The following macros round down like std::chrono::{floor,duration_cast}, 195 // these are discouraged but sometimes necessary: 196 // PW_SYSTEM_CLOCK_MS_FLOOR(milliseconds) 197 // PW_SYSTEM_CLOCK_S_FLOOR(seconds) 198 // PW_SYSTEM_CLOCK_MIN_FLOOR(minutes) 199 // PW_SYSTEM_CLOCK_H_FLOOR(hours) 200 #include "pw_chrono/internal/system_clock_macros.h" 201 202 typedef struct { 203 int64_t ticks; 204 } pw_chrono_SystemClock_Duration; 205 206 typedef struct { 207 pw_chrono_SystemClock_Duration duration_since_epoch; 208 } pw_chrono_SystemClock_TimePoint; 209 typedef int64_t pw_chrono_SystemClock_Nanoseconds; 210 211 // Returns the current time, see SystemClock::now() for more detail. 212 pw_chrono_SystemClock_TimePoint pw_chrono_SystemClock_Now(void); 213 214 // Returns the change in time between the current_time - last_time. 215 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_TimeElapsed( 216 pw_chrono_SystemClock_TimePoint last_time, 217 pw_chrono_SystemClock_TimePoint current_time); 218 219 // For lossless time unit conversion, the seconds per tick ratio that is 220 // numerator/denominator should be used: 221 // PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR 222 // PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR 223 224 // Warning, this may be lossy due to the use of std::chrono::floor, 225 // rounding towards zero. 226 pw_chrono_SystemClock_Nanoseconds pw_chrono_SystemClock_DurationToNsFloor( 227 pw_chrono_SystemClock_Duration duration); 228 229 PW_EXTERN_C_END 230