• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
118 // An abstract interface representing a SystemClock.
119 //
120 // This interface allows decoupling code that uses time from the code that
121 // creates a point in time. You can use this to your advantage by injecting
122 // Clocks into interfaces rather than having implementations call
123 // SystemClock::now() directly. However, this comes at a cost of a vtable per
124 // implementation and more importantly passing and maintaining references to the
125 // VirtualSystemCLock for all of the users.
126 //
127 // The VirtualSystemClock::RealClock() function returns a reference to the
128 // real global SystemClock.
129 //
130 // Example:
131 //
132 //  void DoFoo(VirtualSystemClock& system_clock) {
133 //    SystemClock::time_point now = clock.now();
134 //    // ... Code which consumes now.
135 //  }
136 //
137 //  // Production code:
138 //  DoFoo(VirtualSystemCLock::RealClock);
139 //
140 //  // Test code:
141 //  MockClock test_clock();
142 //  DoFoo(test_clock);
143 //
144 // This interface is thread and IRQ safe.
145 class VirtualSystemClock {
146  public:
147   // Returns a reference to the real system clock to aid instantiation.
148   static VirtualSystemClock& RealClock();
149 
150   virtual ~VirtualSystemClock() = default;
151   virtual SystemClock::time_point now() = 0;
152 };
153 
154 }  // namespace pw::chrono
155 
156 // The backend can opt to include an inlined implementation of the following:
157 //   int64_t GetSystemClockTickCount();
158 #if __has_include("pw_chrono_backend/system_clock_inline.h")
159 #include "pw_chrono_backend/system_clock_inline.h"
160 #endif  // __has_include("pw_chrono_backend/system_clock_inline.h")
161 
162 #endif  // __cplusplus
163 
164 PW_EXTERN_C_START
165 
166 // C API Users should not create pw_chrono_SystemClock_Duration's directly,
167 // instead it is strongly recommended to use macros which express the duration
168 // in time units, instead of non-portable ticks.
169 //
170 // The following macros round up just like std::chrono::ceil, this is the
171 // recommended rounding to maintain the "at least" contract of timeouts and
172 // deadlines (note the *_CEIL macros are the same only more explicit):
173 //   PW_SYSTEM_CLOCK_MS(milliseconds)
174 //   PW_SYSTEM_CLOCK_S(seconds)
175 //   PW_SYSTEM_CLOCK_MIN(minutes)
176 //   PW_SYSTEM_CLOCK_H(hours)
177 //   PW_SYSTEM_CLOCK_MS_CEIL(milliseconds)
178 //   PW_SYSTEM_CLOCK_S_CEIL(seconds)
179 //   PW_SYSTEM_CLOCK_MIN_CEIL(minutes)
180 //   PW_SYSTEM_CLOCK_H_CEIL(hours)
181 //
182 // The following macros round down like std::chrono::{floor,duration_cast},
183 // these are discouraged but sometimes necessary:
184 //   PW_SYSTEM_CLOCK_MS_FLOOR(milliseconds)
185 //   PW_SYSTEM_CLOCK_S_FLOOR(seconds)
186 //   PW_SYSTEM_CLOCK_MIN_FLOOR(minutes)
187 //   PW_SYSTEM_CLOCK_H_FLOOR(hours)
188 #include "pw_chrono/internal/system_clock_macros.h"
189 
190 typedef struct {
191   int64_t ticks;
192 } pw_chrono_SystemClock_Duration;
193 
194 typedef struct {
195   pw_chrono_SystemClock_Duration duration_since_epoch;
196 } pw_chrono_SystemClock_TimePoint;
197 typedef int64_t pw_chrono_SystemClock_Nanoseconds;
198 
199 // Returns the current time, see SystemClock::now() for more detail.
200 pw_chrono_SystemClock_TimePoint pw_chrono_SystemClock_Now(void);
201 
202 // Returns the change in time between the current_time - last_time.
203 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_TimeElapsed(
204     pw_chrono_SystemClock_TimePoint last_time,
205     pw_chrono_SystemClock_TimePoint current_time);
206 
207 // For lossless time unit conversion, the seconds per tick ratio that is
208 // numerator/denominator should be used:
209 //   PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR
210 //   PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR
211 
212 // Warning, this may be lossy due to the use of std::chrono::floor,
213 // rounding towards zero.
214 pw_chrono_SystemClock_Nanoseconds pw_chrono_SystemClock_DurationToNsFloor(
215     pw_chrono_SystemClock_Duration duration);
216 
217 PW_EXTERN_C_END
218