1c87c5fbaSopenharmony_ci/* coap_time.c -- Clock Handling 2c87c5fbaSopenharmony_ci * 3c87c5fbaSopenharmony_ci * Copyright (C) 2015,2023 Olaf Bergmann <bergmann@tzi.org> 4c87c5fbaSopenharmony_ci * 5c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 6c87c5fbaSopenharmony_ci * 7c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see 8c87c5fbaSopenharmony_ci * README for terms of use. 9c87c5fbaSopenharmony_ci */ 10c87c5fbaSopenharmony_ci 11c87c5fbaSopenharmony_ci/** 12c87c5fbaSopenharmony_ci * @file coap_time.c 13c87c5fbaSopenharmony_ci * @brief Clock handling functions 14c87c5fbaSopenharmony_ci */ 15c87c5fbaSopenharmony_ci 16c87c5fbaSopenharmony_ci#include "coap3/coap_internal.h" 17c87c5fbaSopenharmony_ci 18c87c5fbaSopenharmony_ci#ifdef HAVE_TIME_H 19c87c5fbaSopenharmony_ci#include <time.h> 20c87c5fbaSopenharmony_ci#ifdef HAVE_SYS_TIME_H 21c87c5fbaSopenharmony_ci#include <sys/time.h> 22c87c5fbaSopenharmony_ci#endif 23c87c5fbaSopenharmony_ci#ifdef HAVE_UNISTD_H 24c87c5fbaSopenharmony_ci#include <unistd.h> /* _POSIX_TIMERS */ 25c87c5fbaSopenharmony_ci#endif 26c87c5fbaSopenharmony_ci#ifdef HAVE_WINSOCK2_H 27c87c5fbaSopenharmony_ci#include <winsock2.h> 28c87c5fbaSopenharmony_ci#include <stdint.h> 29c87c5fbaSopenharmony_ci#endif 30c87c5fbaSopenharmony_ci 31c87c5fbaSopenharmony_cistatic coap_tick_t coap_clock_offset = 0; 32c87c5fbaSopenharmony_ci 33c87c5fbaSopenharmony_ci#if _POSIX_TIMERS && !defined(__APPLE__) 34c87c5fbaSopenharmony_ci/* _POSIX_TIMERS is > 0 when clock_gettime() is available */ 35c87c5fbaSopenharmony_ci 36c87c5fbaSopenharmony_ci/* Use real-time clock for correct timestamps in coap_log(). */ 37c87c5fbaSopenharmony_ci#define COAP_CLOCK CLOCK_REALTIME 38c87c5fbaSopenharmony_ci#endif 39c87c5fbaSopenharmony_ci 40c87c5fbaSopenharmony_ci#if defined(HAVE_WINSOCK2_H) && !defined(__MINGW32__) 41c87c5fbaSopenharmony_cistatic int 42c87c5fbaSopenharmony_cigettimeofday(struct timeval *tp, TIME_ZONE_INFORMATION *tzp) { 43c87c5fbaSopenharmony_ci (void)tzp; 44c87c5fbaSopenharmony_ci static const uint64_t s_tUnixEpoch = 116444736000000000Ui64; 45c87c5fbaSopenharmony_ci 46c87c5fbaSopenharmony_ci FILETIME file_time; 47c87c5fbaSopenharmony_ci ULARGE_INTEGER time; 48c87c5fbaSopenharmony_ci uint64_t tUsSinceUnicEpoch; 49c87c5fbaSopenharmony_ci 50c87c5fbaSopenharmony_ci GetSystemTimeAsFileTime(&file_time); 51c87c5fbaSopenharmony_ci time.LowPart = file_time.dwLowDateTime; 52c87c5fbaSopenharmony_ci time.HighPart = file_time.dwHighDateTime; 53c87c5fbaSopenharmony_ci tUsSinceUnicEpoch = (time.QuadPart - s_tUnixEpoch) / 10; 54c87c5fbaSopenharmony_ci 55c87c5fbaSopenharmony_ci tp->tv_sec = (long)(tUsSinceUnicEpoch / 1000000); 56c87c5fbaSopenharmony_ci tp->tv_usec = (long)(tUsSinceUnicEpoch % 1000000); 57c87c5fbaSopenharmony_ci return 0; 58c87c5fbaSopenharmony_ci} 59c87c5fbaSopenharmony_ci#endif /* HAVE_WINSOCK2_H && !__MINGW32__ */ 60c87c5fbaSopenharmony_ci 61c87c5fbaSopenharmony_civoid 62c87c5fbaSopenharmony_cicoap_clock_init(void) { 63c87c5fbaSopenharmony_ci#ifdef COAP_CLOCK 64c87c5fbaSopenharmony_ci struct timespec tv; 65c87c5fbaSopenharmony_ci clock_gettime(COAP_CLOCK, &tv); 66c87c5fbaSopenharmony_ci#else /* _POSIX_TIMERS */ 67c87c5fbaSopenharmony_ci struct timeval tv; 68c87c5fbaSopenharmony_ci gettimeofday(&tv, NULL); 69c87c5fbaSopenharmony_ci#endif /* not _POSIX_TIMERS */ 70c87c5fbaSopenharmony_ci 71c87c5fbaSopenharmony_ci coap_clock_offset = tv.tv_sec; 72c87c5fbaSopenharmony_ci} 73c87c5fbaSopenharmony_ci 74c87c5fbaSopenharmony_ci/* creates a Qx.frac from fval */ 75c87c5fbaSopenharmony_ci#define Q(frac,fval) ((1 << (frac)) * (fval)) 76c87c5fbaSopenharmony_ci 77c87c5fbaSopenharmony_ci/* number of frac bits for sub-seconds */ 78c87c5fbaSopenharmony_ci#define FRAC 10 79c87c5fbaSopenharmony_ci 80c87c5fbaSopenharmony_ci/* rounds val up and right shifts by frac positions */ 81c87c5fbaSopenharmony_ci#define SHR_FP(val,frac) (((coap_tick_t)((val) + (1 << ((frac) - 1)))) >> (frac)) 82c87c5fbaSopenharmony_ci 83c87c5fbaSopenharmony_civoid 84c87c5fbaSopenharmony_cicoap_ticks(coap_tick_t *t) { 85c87c5fbaSopenharmony_ci coap_tick_t tmp; 86c87c5fbaSopenharmony_ci 87c87c5fbaSopenharmony_ci#ifdef COAP_CLOCK 88c87c5fbaSopenharmony_ci struct timespec tv; 89c87c5fbaSopenharmony_ci clock_gettime(COAP_CLOCK, &tv); 90c87c5fbaSopenharmony_ci /* Possible errors are (see clock_gettime(2)): 91c87c5fbaSopenharmony_ci * EFAULT tp points outside the accessible address space. 92c87c5fbaSopenharmony_ci * EINVAL The clk_id specified is not supported on this system. 93c87c5fbaSopenharmony_ci * Both cases should not be possible here. 94c87c5fbaSopenharmony_ci */ 95c87c5fbaSopenharmony_ci 96c87c5fbaSopenharmony_ci tmp = SHR_FP(tv.tv_nsec * Q(FRAC, (COAP_TICKS_PER_SECOND/1000000000.0)), FRAC); 97c87c5fbaSopenharmony_ci#else /* _POSIX_TIMERS */ 98c87c5fbaSopenharmony_ci /* Fall back to gettimeofday() */ 99c87c5fbaSopenharmony_ci 100c87c5fbaSopenharmony_ci struct timeval tv; 101c87c5fbaSopenharmony_ci gettimeofday(&tv, NULL); 102c87c5fbaSopenharmony_ci /* Possible errors are (see gettimeofday(2)): 103c87c5fbaSopenharmony_ci * EFAULT One of tv or tz pointed outside the accessible address space. 104c87c5fbaSopenharmony_ci * EINVAL Timezone (or something else) is invalid. 105c87c5fbaSopenharmony_ci * Both cases should not be possible here. 106c87c5fbaSopenharmony_ci */ 107c87c5fbaSopenharmony_ci 108c87c5fbaSopenharmony_ci tmp = SHR_FP(tv.tv_usec * Q(FRAC, (COAP_TICKS_PER_SECOND/1000000.0)), FRAC); 109c87c5fbaSopenharmony_ci#endif /* not _POSIX_TIMERS */ 110c87c5fbaSopenharmony_ci 111c87c5fbaSopenharmony_ci /* Finally, convert temporary FP representation to multiple of 112c87c5fbaSopenharmony_ci * COAP_TICKS_PER_SECOND */ 113c87c5fbaSopenharmony_ci *t = tmp + (tv.tv_sec - coap_clock_offset) * COAP_TICKS_PER_SECOND; 114c87c5fbaSopenharmony_ci} 115c87c5fbaSopenharmony_ci 116c87c5fbaSopenharmony_cicoap_time_t 117c87c5fbaSopenharmony_cicoap_ticks_to_rt(coap_tick_t t) { 118c87c5fbaSopenharmony_ci return coap_clock_offset + (t / COAP_TICKS_PER_SECOND); 119c87c5fbaSopenharmony_ci} 120c87c5fbaSopenharmony_ci 121c87c5fbaSopenharmony_ciuint64_t 122c87c5fbaSopenharmony_cicoap_ticks_to_rt_us(coap_tick_t t) { 123c87c5fbaSopenharmony_ci return (uint64_t)coap_clock_offset * 1000000 + (uint64_t)t * 1000000 / COAP_TICKS_PER_SECOND; 124c87c5fbaSopenharmony_ci} 125c87c5fbaSopenharmony_ci 126c87c5fbaSopenharmony_cicoap_tick_t 127c87c5fbaSopenharmony_cicoap_ticks_from_rt_us(uint64_t t) { 128c87c5fbaSopenharmony_ci return (coap_tick_t)((t - (uint64_t)coap_clock_offset * 1000000) * COAP_TICKS_PER_SECOND / 1000000); 129c87c5fbaSopenharmony_ci} 130c87c5fbaSopenharmony_ci 131c87c5fbaSopenharmony_ci#undef Q 132c87c5fbaSopenharmony_ci#undef FRAC 133c87c5fbaSopenharmony_ci#undef SHR_FP 134c87c5fbaSopenharmony_ci 135c87c5fbaSopenharmony_ci#else /* HAVE_TIME_H */ 136c87c5fbaSopenharmony_ci 137c87c5fbaSopenharmony_ci#ifdef __clang__ 138c87c5fbaSopenharmony_ci/* Make compilers happy that do not like empty modules. As this function is 139c87c5fbaSopenharmony_ci * never used, we ignore -Wunused-function at the end of compiling this file 140c87c5fbaSopenharmony_ci */ 141c87c5fbaSopenharmony_ci#pragma GCC diagnostic ignored "-Wunused-function" 142c87c5fbaSopenharmony_ci#endif 143c87c5fbaSopenharmony_ciCOAP_STATIC_INLINE void 144c87c5fbaSopenharmony_cidummy(void) { 145c87c5fbaSopenharmony_ci} 146c87c5fbaSopenharmony_ci 147c87c5fbaSopenharmony_ci#endif /* not HAVE_TIME_H */ 148