windows: Don't try to include <unistd.h>.
[libserialport/gsi.git] / timing.c
blob957f676e160f551f62c9051fc344f76abe33b52e
1 /*
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 <config.h>
21 #include "libserialport.h"
22 #include "libserialport_internal.h"
24 SP_PRIV void time_get(struct time *time)
26 #ifdef _WIN32
27 LARGE_INTEGER count;
28 QueryPerformanceCounter(&count);
29 time->ticks = count.QuadPart;
30 #elif defined(HAVE_CLOCK_GETTIME)
31 struct timespec ts;
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;
43 #else
44 gettimeofday(&time->tv, NULL);
45 #endif
48 SP_PRIV void time_set_ms(struct time *time, unsigned int ms)
50 #ifdef _WIN32
51 LARGE_INTEGER frequency;
52 QueryPerformanceFrequency(&frequency);
53 time->ticks = ms * (frequency.QuadPart / 1000);
54 #else
55 time->tv.tv_sec = ms / 1000;
56 time->tv.tv_usec = (ms % 1000) * 1000;
57 #endif
60 SP_PRIV void time_add(const struct time *a,
61 const struct time *b, struct time *result)
63 #ifdef _WIN32
64 result->ticks = a->ticks + b->ticks;
65 #else
66 timeradd(&a->tv, &b->tv, &result->tv);
67 #endif
70 SP_PRIV void time_sub(const struct time *a,
71 const struct time *b, struct time *result)
73 #ifdef _WIN32
74 result->ticks = a->ticks - b->ticks;
75 #else
76 timersub(&a->tv, &b->tv, &result->tv);
77 #endif
80 SP_PRIV bool time_greater(const struct time *a, const struct time *b)
82 #ifdef _WIN32
83 return (a->ticks > b->ticks);
84 #else
85 return timercmp(&a->tv, &b->tv, >);
86 #endif
89 SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv)
91 #ifdef _WIN32
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);
97 #else
98 *tv = time->tv;
99 #endif
102 SP_PRIV unsigned int time_as_ms(const struct time *time)
104 #ifdef _WIN32
105 LARGE_INTEGER frequency;
106 QueryPerformanceFrequency(&frequency);
107 return time->ticks / (frequency.QuadPart / 1000);
108 #else
109 return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
110 #endif
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)
139 return false;
141 if (timeout->ms == 0)
142 return false;
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;
158 #ifndef _WIN32
159 SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout)
161 if (timeout->ms == 0)
162 return NULL;
164 time_as_timeval(&timeout->delta, &timeout->delta_tv);
166 return &timeout->delta_tv;
168 #endif
170 SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout)
172 if (timeout->limit_ms && timeout->overflow)
173 return timeout->limit_ms;
174 else
175 return time_as_ms(&timeout->delta);