2 * This file is part of the libserialport project.
4 * Copyright (C) 2019 Martin Ling <martin-libserialport@earth.li>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "libserialport_internal.h"
22 SP_PRIV
void time_get(struct time
*time
)
26 QueryPerformanceCounter(&count
);
27 time
->ticks
= count
.QuadPart
;
28 #elif defined(HAVE_CLOCK_GETTIME)
30 if (clock_gettime(CLOCK_MONOTONIC
, &ts
) == -1)
31 clock_gettime(CLOCK_REALTIME
, &ts
);
32 time
->tv
.tv_sec
= ts
.tv_sec
;
33 time
->tv
.tv_usec
= ts
.tv_nsec
/ 1000;
34 #elif defined(__APPLE__)
35 mach_timebase_info_data_t info
;
36 mach_timebase_info(&info
);
37 uint64_t ticks
= mach_absolute_time();
38 uint64_t ns
= (ticks
* info
.numer
) / info
.denom
;
39 time
->tv
.tv_sec
= ns
/ 1000000000;
40 time
->tv
.tv_usec
= (ns
% 1000000000) / 1000;
42 gettimeofday(&time
->tv
, NULL
);
46 SP_PRIV
void time_set_ms(struct time
*time
, unsigned int ms
)
49 LARGE_INTEGER frequency
;
50 QueryPerformanceFrequency(&frequency
);
51 time
->ticks
= ms
* (frequency
.QuadPart
/ 1000);
53 time
->tv
.tv_sec
= ms
/ 1000;
54 time
->tv
.tv_usec
= (ms
% 1000) * 1000;
58 SP_PRIV
void time_add(const struct time
*a
,
59 const struct time
*b
, struct time
*result
)
62 result
->ticks
= a
->ticks
+ b
->ticks
;
64 timeradd(&a
->tv
, &b
->tv
, &result
->tv
);
68 SP_PRIV
void time_sub(const struct time
*a
,
69 const struct time
*b
, struct time
*result
)
72 result
->ticks
= a
->ticks
- b
->ticks
;
74 timersub(&a
->tv
, &b
->tv
, &result
->tv
);
78 SP_PRIV
bool time_greater(const struct time
*a
, const struct time
*b
)
81 return (a
->ticks
> b
->ticks
);
83 return timercmp(&a
->tv
, &b
->tv
, >);
87 SP_PRIV
void time_as_timeval(const struct time
*time
, struct timeval
*tv
)
90 LARGE_INTEGER frequency
;
91 QueryPerformanceFrequency(&frequency
);
92 tv
->tv_sec
= (long) (time
->ticks
/ frequency
.QuadPart
);
93 tv
->tv_usec
= (long) ((time
->ticks
% frequency
.QuadPart
) /
94 (frequency
.QuadPart
/ 1000000));
100 SP_PRIV
unsigned int time_as_ms(const struct time
*time
)
103 LARGE_INTEGER frequency
;
104 QueryPerformanceFrequency(&frequency
);
105 return (unsigned int) (time
->ticks
/ (frequency
.QuadPart
/ 1000));
107 return time
->tv
.tv_sec
* 1000 + time
->tv
.tv_usec
/ 1000;
111 SP_PRIV
void timeout_start(struct timeout
*timeout
, unsigned int timeout_ms
)
113 timeout
->ms
= timeout_ms
;
115 /* Get time at start of operation. */
116 time_get(&timeout
->start
);
117 /* Define duration of timeout. */
118 time_set_ms(&timeout
->delta
, timeout_ms
);
119 /* Calculate time at which we should give up. */
120 time_add(&timeout
->start
, &timeout
->delta
, &timeout
->end
);
121 /* Disable limit unless timeout_limit() called. */
122 timeout
->limit_ms
= 0;
123 /* First blocking call has not yet been made. */
124 timeout
->calls_started
= false;
127 SP_PRIV
void timeout_limit(struct timeout
*timeout
, unsigned int limit_ms
)
129 timeout
->limit_ms
= limit_ms
;
130 timeout
->overflow
= (timeout
->ms
> timeout
->limit_ms
);
131 time_set_ms(&timeout
->delta_max
, timeout
->limit_ms
);
134 SP_PRIV
bool timeout_check(struct timeout
*timeout
)
136 if (!timeout
->calls_started
)
139 if (timeout
->ms
== 0)
142 time_get(&timeout
->now
);
143 time_sub(&timeout
->end
, &timeout
->now
, &timeout
->delta
);
144 if (timeout
->limit_ms
)
145 if ((timeout
->overflow
= time_greater(&timeout
->delta
, &timeout
->delta_max
)))
146 timeout
->delta
= timeout
->delta_max
;
148 return time_greater(&timeout
->now
, &timeout
->end
);
151 SP_PRIV
void timeout_update(struct timeout
*timeout
)
153 timeout
->calls_started
= true;
157 SP_PRIV
struct timeval
*timeout_timeval(struct timeout
*timeout
)
159 if (timeout
->ms
== 0)
162 time_as_timeval(&timeout
->delta
, &timeout
->delta_tv
);
164 return &timeout
->delta_tv
;
168 SP_PRIV
unsigned int timeout_remaining_ms(struct timeout
*timeout
)
170 if (timeout
->limit_ms
&& timeout
->overflow
)
171 return timeout
->limit_ms
;
173 return time_as_ms(&timeout
->delta
);