]> sigrok.org Git - libserialport.git/blob - timing.c
windows: Fix a warning on conversion to unsigned int.
[libserialport.git] / timing.c
1 /*
2  * This file is part of the libserialport project.
3  *
4  * Copyright (C) 2019 Martin Ling <martin-libserialport@earth.li>
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include "libserialport_internal.h"
21
22 SP_PRIV void time_get(struct time *time)
23 {
24 #ifdef _WIN32
25         LARGE_INTEGER count;
26         QueryPerformanceCounter(&count);
27         time->ticks = count.QuadPart;
28 #elif defined(HAVE_CLOCK_GETTIME)
29         struct timespec ts;
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;
41 #else
42         gettimeofday(&time->tv, NULL);
43 #endif
44 }
45
46 SP_PRIV void time_set_ms(struct time *time, unsigned int ms)
47 {
48 #ifdef _WIN32
49         LARGE_INTEGER frequency;
50         QueryPerformanceFrequency(&frequency);
51         time->ticks = ms * (frequency.QuadPart / 1000);
52 #else
53         time->tv.tv_sec = ms / 1000;
54         time->tv.tv_usec = (ms % 1000) * 1000;
55 #endif
56 }
57
58 SP_PRIV void time_add(const struct time *a,
59                 const struct time *b, struct time *result)
60 {
61 #ifdef _WIN32
62         result->ticks = a->ticks + b->ticks;
63 #else
64         timeradd(&a->tv, &b->tv, &result->tv);
65 #endif
66 }
67
68 SP_PRIV void time_sub(const struct time *a,
69                 const struct time *b, struct time *result)
70 {
71 #ifdef _WIN32
72         result->ticks = a->ticks - b->ticks;
73 #else
74         timersub(&a->tv, &b->tv, &result->tv);
75 #endif
76 }
77
78 SP_PRIV bool time_greater(const struct time *a, const struct time *b)
79 {
80 #ifdef _WIN32
81         return (a->ticks > b->ticks);
82 #else
83         return timercmp(&a->tv, &b->tv, >);
84 #endif
85 }
86
87 SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv)
88 {
89 #ifdef _WIN32
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));
95 #else
96         *tv = time->tv;
97 #endif
98 }
99
100 SP_PRIV unsigned int time_as_ms(const struct time *time)
101 {
102 #ifdef _WIN32
103         LARGE_INTEGER frequency;
104         QueryPerformanceFrequency(&frequency);
105         return (unsigned int) (time->ticks / (frequency.QuadPart / 1000));
106 #else
107         return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
108 #endif
109 }
110
111 SP_PRIV void timeout_start(struct timeout *timeout, unsigned int timeout_ms)
112 {
113         timeout->ms = timeout_ms;
114
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;
125 }
126
127 SP_PRIV void timeout_limit(struct timeout *timeout, unsigned int limit_ms)
128 {
129         timeout->limit_ms = limit_ms;
130         timeout->overflow = (timeout->ms > timeout->limit_ms);
131         time_set_ms(&timeout->delta_max, timeout->limit_ms);
132 }
133
134 SP_PRIV bool timeout_check(struct timeout *timeout)
135 {
136         if (!timeout->calls_started)
137                 return false;
138
139         if (timeout->ms == 0)
140                 return false;
141
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;
147
148         return time_greater(&timeout->now, &timeout->end);
149 }
150
151 SP_PRIV void timeout_update(struct timeout *timeout)
152 {
153         timeout->calls_started = true;
154 }
155
156 #ifndef _WIN32
157 SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout)
158 {
159         if (timeout->ms == 0)
160                 return NULL;
161
162         time_as_timeval(&timeout->delta, &timeout->delta_tv);
163
164         return &timeout->delta_tv;
165 }
166 #endif
167
168 SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout)
169 {
170         if (timeout->limit_ms && timeout->overflow)
171                 return timeout->limit_ms;
172         else
173                 return time_as_ms(&timeout->delta);
174 }