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