3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2018 Nest Labs, Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * Provides default implementations for the platform Get/SetClock_ functions
22 * for POSIX and LwIP platforms.
25 // __STDC_LIMIT_MACROS must be defined for UINT8_MAX to be defined for pre-C++11 clib
26 #ifndef __STDC_LIMIT_MACROS
27 #define __STDC_LIMIT_MACROS
28 #endif // __STDC_LIMIT_MACROS
30 // __STDC_CONSTANT_MACROS must be defined for INT64_C and UINT64_C to be defined for pre-C++11 clib
31 #ifndef __STDC_CONSTANT_MACROS
32 #define __STDC_CONSTANT_MACROS
33 #endif // __STDC_CONSTANT_MACROS
36 #include <system/SystemConfig.h>
38 #if !CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
41 #include <system/SystemClock.h>
43 #include "SystemLayerPrivate.h"
45 #include <support/CodeUtils.h>
46 #include <system/SystemError.h>
48 #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
50 #if !(HAVE_CLOCK_GETTIME)
54 #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
56 #if CHIP_SYSTEM_CONFIG_USE_LWIP
58 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
68 // -------------------- Default Get/SetClock Functions for POSIX Systems --------------------
70 #if CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
72 #if !HAVE_CLOCK_GETTIME && !HAVE_GETTIMEOFDAY
73 #error "CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS requires either clock_gettime() or gettimeofday()"
76 #if HAVE_CLOCK_GETTIME
77 #if HAVE_DECL_CLOCK_BOOTTIME
78 // CLOCK_BOOTTIME is a Linux-specific option to clock_gettime for a clock which compensates for system sleep.
79 #define MONOTONIC_CLOCK_ID CLOCK_BOOTTIME
80 #define MONOTONIC_RAW_CLOCK_ID CLOCK_MONOTONIC_RAW
81 #else // HAVE_DECL_CLOCK_BOOTTIME
82 // CLOCK_MONOTONIC is defined in POSIX and hence is the default choice
83 #define MONOTONIC_CLOCK_ID CLOCK_MONOTONIC
85 #endif // HAVE_CLOCK_GETTIME
87 uint64_t GetClock_Monotonic()
89 #if HAVE_CLOCK_GETTIME
91 int res = clock_gettime(MONOTONIC_CLOCK_ID, &ts);
92 VerifyOrDie(res == 0);
93 return (static_cast<uint64_t>(ts.tv_sec) * UINT64_C(1000000)) + (static_cast<uint64_t>(ts.tv_nsec) / 1000);
94 #else // HAVE_CLOCK_GETTIME
96 int res = gettimeofday(&tv, NULL);
97 VerifyOrDie(res == 0);
98 return (tv.tv_sec * UINT64_C(1000000)) + tv.tv_usec;
99 #endif // HAVE_CLOCK_GETTIME
102 uint64_t GetClock_MonotonicMS()
104 return GetClock_Monotonic() / 1000;
107 uint64_t GetClock_MonotonicHiRes()
109 #if HAVE_CLOCK_GETTIME && defined(MONOTONIC_RAW_CLOCK_ID)
111 int res = clock_gettime(MONOTONIC_RAW_CLOCK_ID, &ts);
112 VerifyOrDie(res == 0);
113 return (ts.tv_sec * UINT64_C(1000000)) + (ts.tv_nsec / 1000);
114 #else // HAVE_CLOCK_GETTIME
115 return GetClock_Monotonic();
116 #endif // HAVE_CLOCK_GETTIME
119 Error GetClock_RealTime(uint64_t & curTime)
121 #if HAVE_CLOCK_GETTIME
123 int res = clock_gettime(CLOCK_REALTIME, &ts);
126 return MapErrorPOSIX(errno);
128 if (ts.tv_sec < CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD)
130 return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED;
132 curTime = (static_cast<uint64_t>(ts.tv_sec) * UINT64_C(1000000)) + (static_cast<uint64_t>(ts.tv_nsec) / 1000);
133 return CHIP_SYSTEM_NO_ERROR;
134 #else // HAVE_CLOCK_GETTIME
136 int res = gettimeofday(&tv, NULL);
139 return MapErrorPOSIX(errno);
141 if (tv.tv_sec < CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD)
143 return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED;
145 curTime = (tv.tv_sec * UINT64_C(1000000)) + tv.tv_usec;
146 return CHIP_SYSTEM_NO_ERROR;
147 #endif // HAVE_CLOCK_GETTIME
150 Error GetClock_RealTimeMS(uint64_t & curTime)
152 Error err = GetClock_RealTime(curTime);
153 curTime = curTime / 1000;
157 #if HAVE_CLOCK_SETTIME || HAVE_SETTIMEOFDAY
159 Error SetClock_RealTime(uint64_t newCurTime)
161 #if HAVE_CLOCK_SETTIME
163 ts.tv_sec = static_cast<time_t>(newCurTime / UINT64_C(1000000));
164 ts.tv_nsec = static_cast<long>(newCurTime % UINT64_C(1000000)) * 1000;
165 int res = clock_settime(CLOCK_REALTIME, &ts);
168 return (errno == EPERM) ? CHIP_SYSTEM_ERROR_ACCESS_DENIED : MapErrorPOSIX(errno);
170 return CHIP_SYSTEM_NO_ERROR;
171 #else // HAVE_CLOCK_SETTIME
173 tv.tv_sec = static_cast<time_t>(newCurTime / UINT64_C(1000000));
174 tv.tv_usec = static_cast<long>(newCurTime % UINT64_C(1000000));
175 int res = settimeofday(&tv, NULL);
178 return (errno == EPERM) ? CHIP_SYSTEM_ERROR_ACCESS_DENIED : MapErrorPOSIX(errno);
180 return CHIP_SYSTEM_NO_ERROR;
181 #endif // HAVE_CLOCK_SETTIME
184 #else // !HAVE_CLOCK_SETTTIME
186 Error SetClock_RealTime(uint64_t newCurTime)
188 return CHIP_SYSTEM_ERROR_NOT_SUPPORTED;
191 #endif // HAVE_CLOCK_SETTIME || HAVE_SETTIMEOFDAY
193 #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS
195 // -------------------- Default Get/SetClock Functions for LwIP Systems --------------------
197 #if CHIP_SYSTEM_CONFIG_USE_LWIP_MONOTONIC_TIME
199 uint64_t GetClock_Monotonic(void)
201 return GetClock_MonotonicMS();
204 uint64_t GetClock_MonotonicMS(void)
206 static volatile uint64_t overflow = 0;
207 static volatile u32_t lastSample = 0;
208 static volatile uint8_t lock = 0;
209 static const uint64_t kOverflowIncrement = static_cast<uint64_t>(0x100000000);
211 uint64_t overflowSample;
214 // Tracking timer wrap assumes that this function gets called with
215 // a period that is less than 1/2 the timer range.
216 if (__sync_bool_compare_and_swap(&lock, 0, 1))
220 if (lastSample > sample)
222 overflow += kOverflowIncrement;
226 overflowSample = overflow;
228 __sync_bool_compare_and_swap(&lock, 1, 0);
232 // a lower priority task is in the block above. Depending where that
233 // lower task is blocked can spell trouble in a timer wrap condition.
234 // the question here is what this task should use as an overflow value.
235 // To fix this race requires a platform api that can be used to
236 // protect critical sections.
237 overflowSample = overflow;
241 return static_cast<uint64_t>(overflowSample | static_cast<uint64_t>(sample));
244 uint64_t GetClock_MonotonicHiRes(void)
246 return GetClock_MonotonicMS();
249 Error GetClock_RealTime(uint64_t & curTime)
251 return CHIP_SYSTEM_ERROR_NOT_SUPPORTED;
254 Error GetClock_RealTimeMS(uint64_t & curTime)
256 return CHIP_SYSTEM_ERROR_NOT_SUPPORTED;
259 Error SetClock_RealTime(uint64_t newCurTime)
261 return CHIP_SYSTEM_ERROR_NOT_SUPPORTED;
264 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP_MONOTONIC_TIME
267 } // namespace Platform
268 } // namespace System
271 #endif // CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME