/src/gpsd/gpsd-3.26.2~dev/include/timespec.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * This file is Copyright by the GPSD project |
3 | | * SPDX-License-Identifier: BSD-2-clause |
4 | | */ |
5 | | |
6 | | #ifndef GPSD_TIMESPEC_H |
7 | | #define GPSD_TIMESPEC_H |
8 | | |
9 | | #include <math.h> // for modf() |
10 | | #include <stdbool.h> // for bool |
11 | | |
12 | 0 | #define NS_IN_SEC 1000000000LL // nanoseconds in a second |
13 | 0 | #define NS_IN_MS 1000000LL // nanoseconds in a millisecond |
14 | | #define US_IN_SEC 1000000LL // microseconds in a second |
15 | 0 | #define MS_IN_SEC 1000LL // milliseconds in a second |
16 | | |
17 | | // convert a timespec_t to an int64_t of milliseconds |
18 | 0 | #define TSTOMS(ts) ((int64_t)((ts)->tv_sec) * MS_IN_SEC + \ |
19 | 0 | (int64_t)((ts)->tv_nsec / NS_IN_MS)) |
20 | | |
21 | | /* normalize a timespec |
22 | | * |
23 | | * three cases to note |
24 | | * if tv_sec is positive, then tv_nsec must be positive |
25 | | * if tv_sec is negative, then tv_nsec must be negative |
26 | | * if tv_sec is zero, then tv_nsec may be positive or negative. |
27 | | * |
28 | | * this only handles the case where two normalized timespecs |
29 | | * are added or subtracted. (e.g. only a one needs to be borrowed/carried |
30 | | * |
31 | | * NOTE: this normalization is not the same as ntpd uses |
32 | | */ |
33 | | |
34 | | /* return the difference between timespecs in nanoseconds |
35 | | * int may be too small, 32 bit long is too small, floats are too imprecise, |
36 | | * doubles are not quite precise enough |
37 | | * MUST be at least int64_t to maintain precision on 32 bit code */ |
38 | | #define timespec_diff_ns(x, y) \ |
39 | 0 | (int64_t)((((x).tv_sec-(y).tv_sec)*NS_IN_SEC)+(x).tv_nsec-(y).tv_nsec) |
40 | | |
41 | | static inline void TS_NORM( struct timespec *ts) |
42 | 0 | { |
43 | 0 | if ((1 <= ts->tv_sec) || |
44 | 0 | ((0 == ts->tv_sec) && |
45 | 0 | (0 <= ts->tv_nsec))) { |
46 | | // result is positive |
47 | 0 | if (NS_IN_SEC <= ts->tv_nsec) { |
48 | | // borrow from tv_sec |
49 | 0 | ts->tv_nsec -= NS_IN_SEC; |
50 | 0 | ts->tv_sec++; |
51 | 0 | } else if (0 > (ts)->tv_nsec) { |
52 | | // carry to tv_sec |
53 | 0 | ts->tv_nsec += NS_IN_SEC; |
54 | 0 | ts->tv_sec--; |
55 | 0 | } |
56 | 0 | } else { |
57 | | // result is negative |
58 | 0 | if (-NS_IN_SEC >= ts->tv_nsec) { |
59 | | // carry to tv_sec |
60 | 0 | ts->tv_nsec += NS_IN_SEC; |
61 | 0 | ts->tv_sec--; |
62 | 0 | } else if (0 < ts->tv_nsec) { |
63 | | // borrow from tv_sec |
64 | 0 | ts->tv_nsec -= NS_IN_SEC; |
65 | 0 | ts->tv_sec++; |
66 | 0 | } |
67 | 0 | } |
68 | 0 | } Unexecuted instantiation: FuzzJson.c:TS_NORM Unexecuted instantiation: libgps_json.c:TS_NORM Unexecuted instantiation: rtcm2_json.c:TS_NORM Unexecuted instantiation: rtcm3_json.c:TS_NORM Unexecuted instantiation: shared_json.c:TS_NORM Unexecuted instantiation: hex.c:TS_NORM Unexecuted instantiation: json.c:TS_NORM Unexecuted instantiation: gpsutils.c:TS_NORM Unexecuted instantiation: FuzzPacket.c:TS_NORM Unexecuted instantiation: packet.c:TS_NORM Unexecuted instantiation: driver_rtcm2.c:TS_NORM Unexecuted instantiation: isgps.c:TS_NORM Unexecuted instantiation: libgpsd_core.c:TS_NORM Unexecuted instantiation: net_gnss_dispatch.c:TS_NORM Unexecuted instantiation: net_ntrip.c:TS_NORM Unexecuted instantiation: ppsthread.c:TS_NORM Unexecuted instantiation: pseudonmea.c:TS_NORM Unexecuted instantiation: serial.c:TS_NORM Unexecuted instantiation: timebase.c:TS_NORM Unexecuted instantiation: bsd_base64.c:TS_NORM Unexecuted instantiation: driver_nmea0183.c:TS_NORM Unexecuted instantiation: driver_nmea2000.c:TS_NORM Unexecuted instantiation: drivers.c:TS_NORM Unexecuted instantiation: driver_sirf.c:TS_NORM Unexecuted instantiation: driver_skytraq.c:TS_NORM Unexecuted instantiation: driver_superstar2.c:TS_NORM Unexecuted instantiation: driver_tsip.c:TS_NORM Unexecuted instantiation: driver_ubx.c:TS_NORM Unexecuted instantiation: driver_zodiac.c:TS_NORM Unexecuted instantiation: geoid.c:TS_NORM Unexecuted instantiation: net_dgpsip.c:TS_NORM Unexecuted instantiation: pseudoais.c:TS_NORM Unexecuted instantiation: subframe.c:TS_NORM Unexecuted instantiation: driver_ais.c:TS_NORM Unexecuted instantiation: driver_allystar.c:TS_NORM Unexecuted instantiation: driver_casic.c:TS_NORM Unexecuted instantiation: driver_evermore.c:TS_NORM Unexecuted instantiation: driver_garmin.c:TS_NORM Unexecuted instantiation: driver_garmin_txt.c:TS_NORM Unexecuted instantiation: driver_geostar.c:TS_NORM Unexecuted instantiation: driver_greis.c:TS_NORM Unexecuted instantiation: driver_italk.c:TS_NORM Unexecuted instantiation: driver_navcom.c:TS_NORM Unexecuted instantiation: driver_oncore.c:TS_NORM Unexecuted instantiation: driver_rtcm3.c:TS_NORM Unexecuted instantiation: gps_maskdump.c:TS_NORM Unexecuted instantiation: libgps_core.c:TS_NORM Unexecuted instantiation: libgps_shm.c:TS_NORM Unexecuted instantiation: libgps_sock.c:TS_NORM Unexecuted instantiation: netlib.c:TS_NORM Unexecuted instantiation: timespec_str.c:TS_NORM |
69 | | |
70 | | // normalize a timeval |
71 | | #define TV_NORM(tv) \ |
72 | | do { \ |
73 | | if (US_IN_SEC <= (tv)->tv_usec) { \ |
74 | | (tv)->tv_usec -= US_IN_SEC; \ |
75 | | (tv)->tv_sec++; \ |
76 | | } else if (0 > (tv)->tv_usec) { \ |
77 | | (tv)->tv_usec += US_IN_SEC; \ |
78 | | (tv)->tv_sec--; \ |
79 | | } \ |
80 | | } while (0) |
81 | | |
82 | | // convert timespec to timeval, with rounding |
83 | | #define TSTOTV(tv, ts) \ |
84 | | do { \ |
85 | | (tv)->tv_sec = (ts)->tv_sec; \ |
86 | | (tv)->tv_usec = ((ts)->tv_nsec + 500)/1000; \ |
87 | | TV_NORM(tv); \ |
88 | | } while (0) |
89 | | |
90 | | // convert timeval to timespec |
91 | | #define TVTOTS(ts, tv) \ |
92 | | do { \ |
93 | | (ts)->tv_sec = (tv)->tv_sec; \ |
94 | | (ts)->tv_nsec = (tv)->tv_usec*1000; \ |
95 | | TS_NORM(ts); \ |
96 | | } while (0) |
97 | | |
98 | | // subtract two timespec |
99 | | #define TS_SUB(r, ts1, ts2) \ |
100 | 0 | do { \ |
101 | 0 | (r)->tv_sec = (ts1)->tv_sec - (ts2)->tv_sec; \ |
102 | 0 | (r)->tv_nsec = (ts1)->tv_nsec - (ts2)->tv_nsec; \ |
103 | 0 | TS_NORM(r); \ |
104 | 0 | } while (0) |
105 | | |
106 | | // subtract two timespec, return a double |
107 | | #define TS_SUB_D(ts1, ts2) \ |
108 | 0 | ((double)((ts1)->tv_sec - (ts2)->tv_sec) + \ |
109 | 0 | ((double)((ts1)->tv_nsec - (ts2)->tv_nsec) * 1e-9)) |
110 | | |
111 | | // true if normalized timespec is non zero |
112 | | #define TS_NZ(ts) (0 != (ts)->tv_sec || 0 != (ts)->tv_nsec) |
113 | | |
114 | | // true if normalized timespec equal or greater than zero |
115 | 0 | #define TS_GEZ(ts) (0 <= (ts)->tv_sec && 0 <= (ts)->tv_nsec) |
116 | | |
117 | | // true if normalized timespec greater than zero |
118 | | #define TS_GZ(ts) (0 < (ts)->tv_sec || 0 < (ts)->tv_nsec) |
119 | | |
120 | | // true if normalized timespec1 greater than timespec2 |
121 | 0 | #define TS_GT(ts1, ts2) ((ts1)->tv_sec > (ts2)->tv_sec || \ |
122 | 0 | ((ts1)->tv_sec == (ts2)->tv_sec && \ |
123 | 0 | (ts1)->tv_nsec > (ts2)->tv_nsec)) |
124 | | |
125 | | // true if normalized timespec1 greater or equal to timespec2 |
126 | | #define TS_GE(ts1, ts2) ((ts1)->tv_sec > (ts2)->tv_sec || \ |
127 | | ((ts1)->tv_sec == (ts2)->tv_sec && \ |
128 | | (ts1)->tv_nsec >= (ts2)->tv_nsec)) |
129 | | |
130 | | // true if normalized timespec1 equal to timespec2 |
131 | 0 | #define TS_EQ(ts1, ts2) ((ts1)->tv_sec == (ts2)->tv_sec && \ |
132 | 0 | (ts1)->tv_nsec == (ts2)->tv_nsec) |
133 | | |
134 | | /* convert a timespec to a double. |
135 | | * if tv_sec > 2, then inevitable loss of precision in tv_nsec |
136 | | * so best to NEVER use TSTONS() |
137 | | * WARNING replacing 1e9 with NS_IN_SEC causes loss of precision */ |
138 | 0 | #define TSTONS(ts) ((double)((ts)->tv_sec + ((ts)->tv_nsec / 1e9))) |
139 | | |
140 | | /* convert a double to a timespec_t |
141 | | * if D > 2, then inevitable loss of precision in nanoseconds |
142 | | */ |
143 | | #define DTOTS(ts, d) \ |
144 | 198 | do { \ |
145 | 198 | double int_part; \ |
146 | 198 | (ts)->tv_nsec = (long)(modf(d, &int_part) * 1e9); \ |
147 | 198 | (ts)->tv_sec = (time_t)int_part; \ |
148 | 198 | } while (0) |
149 | | |
150 | | // convert integer (64 bit for full range) ms to a timespec_t |
151 | | #define MSTOTS(ts, ms) \ |
152 | 0 | do { \ |
153 | 0 | (ts)->tv_sec = (time_t)(ms / 1000); \ |
154 | 0 | (ts)->tv_nsec = (long)((ms % 1000) * 1000000L); \ |
155 | 0 | } while (0) |
156 | | |
157 | | // convert integer (64 bit for full range) us to a timespec_t |
158 | | #define USTOTS(ts, ms) \ |
159 | 0 | do { \ |
160 | 0 | (ts)->tv_sec = (time_t)(ms / 1000000); \ |
161 | 0 | (ts)->tv_nsec = (long)((ms % 1000000) * 1000L); \ |
162 | 0 | } while (0) |
163 | | |
164 | | #define TIMESPEC_LEN 42 // required length of a timespec buffer |
165 | | |
166 | | extern const char *timespec_str(const struct timespec *, char *, size_t); |
167 | | |
168 | | bool nanowait(int, struct timespec *); |
169 | | |
170 | | #endif // GPSD_TIMESPEC_H |
171 | | |
172 | | // vim: set expandtab shiftwidth=4 |