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/>.
21 #include "libserialport.h"
22 #include "libserialport_internal.h"
24 SP_PRIV
void time_get(struct time
*time
)
28 QueryPerformanceCounter(&count
);
29 time
->ticks
= count
.QuadPart
;
30 #elif defined(HAVE_CLOCK_GETTIME)
32 if (clock_gettime(CLOCK_MONOTONIC
, &ts
) == -1)
33 clock_gettime(CLOCK_REALTIME
, &ts
);
34 time
->tv
.tv_sec
= ts
.tv_sec
;
35 time
->tv
.tv_usec
= ts
.tv_nsec
/ 1000;
36 #elif defined(__APPLE__)
37 mach_timebase_info_data_t info
;
38 mach_timebase_info(&info
);
39 uint64_t ticks
= mach_absolute_time();
40 uint64_t ns
= (ticks
* info
.numer
) / info
.denom
;
41 time
->tv
.tv_sec
= ns
/ 1000000000;
42 time
->tv
.tv_usec
= (ns
% 1000000000) / 1000;
44 gettimeofday(&time
->tv
, NULL
);
48 SP_PRIV
void time_set_ms(struct time
*time
, unsigned int ms
)
51 LARGE_INTEGER frequency
;
52 QueryPerformanceFrequency(&frequency
);
53 time
->ticks
= ms
* (frequency
.QuadPart
/ 1000);
55 time
->tv
.tv_sec
= ms
/ 1000;
56 time
->tv
.tv_usec
= (ms
% 1000) * 1000;
60 SP_PRIV
void time_add(const struct time
*a
,
61 const struct time
*b
, struct time
*result
)
64 result
->ticks
= a
->ticks
+ b
->ticks
;
66 timeradd(&a
->tv
, &b
->tv
, &result
->tv
);
70 SP_PRIV
void time_sub(const struct time
*a
,
71 const struct time
*b
, struct time
*result
)
74 result
->ticks
= a
->ticks
- b
->ticks
;
76 timersub(&a
->tv
, &b
->tv
, &result
->tv
);
80 SP_PRIV
bool time_greater(const struct time
*a
, const struct time
*b
)
83 return (a
->ticks
> b
->ticks
);
85 return timercmp(&a
->tv
, &b
->tv
, >);
89 SP_PRIV
void time_as_timeval(const struct time
*time
, struct timeval
*tv
)
92 LARGE_INTEGER frequency
;
93 QueryPerformanceFrequency(&frequency
);
94 tv
->tv_sec
= time
->ticks
/ frequency
.QuadPart
;
95 tv
->tv_usec
= (time
->ticks
% frequency
.QuadPart
) /
96 (frequency
.QuadPart
/ 1000000);
102 SP_PRIV
unsigned int time_as_ms(const struct time
*time
)
105 LARGE_INTEGER frequency
;
106 QueryPerformanceFrequency(&frequency
);
107 return time
->ticks
/ (frequency
.QuadPart
/ 1000);
109 return time
->tv
.tv_sec
* 1000 + time
->tv
.tv_usec
/ 1000;
113 SP_PRIV
void timeout_start(struct timeout
*timeout
, unsigned int timeout_ms
)
115 timeout
->ms
= timeout_ms
;
117 /* Get time at start of operation. */
118 time_get(&timeout
->start
);
119 /* Define duration of timeout. */
120 time_set_ms(&timeout
->delta
, timeout_ms
);
121 /* Calculate time at which we should give up. */
122 time_add(&timeout
->start
, &timeout
->delta
, &timeout
->end
);
123 /* Disable limit unless timeout_limit() called. */
124 timeout
->limit_ms
= 0;
125 /* First blocking call has not yet been made. */
126 timeout
->calls_started
= false;
129 SP_PRIV
void timeout_limit(struct timeout
*timeout
, unsigned int limit_ms
)
131 timeout
->limit_ms
= limit_ms
;
132 timeout
->overflow
= (timeout
->ms
> timeout
->limit_ms
);
133 time_set_ms(&timeout
->delta_max
, timeout
->limit_ms
);
136 SP_PRIV
bool timeout_check(struct timeout
*timeout
)
138 if (!timeout
->calls_started
)
141 if (timeout
->ms
== 0)
144 time_get(&timeout
->now
);
145 time_sub(&timeout
->end
, &timeout
->now
, &timeout
->delta
);
146 if (timeout
->limit_ms
)
147 if ((timeout
->overflow
= time_greater(&timeout
->delta
, &timeout
->delta_max
)))
148 timeout
->delta
= timeout
->delta_max
;
150 return time_greater(&timeout
->now
, &timeout
->end
);
153 SP_PRIV
void timeout_update(struct timeout
*timeout
)
155 timeout
->calls_started
= true;
159 SP_PRIV
struct timeval
*timeout_timeval(struct timeout
*timeout
)
161 if (timeout
->ms
== 0)
164 time_as_timeval(&timeout
->delta
, &timeout
->delta_tv
);
166 return &timeout
->delta_tv
;
170 SP_PRIV
unsigned int timeout_remaining_ms(struct timeout
*timeout
)
172 if (timeout
->limit_ms
&& timeout
->overflow
)
173 return timeout
->limit_ms
;
175 return time_as_ms(&timeout
->delta
);