Add example of sending and receiving data.
[libserialport/gsi.git] / timing.c
blob25876d622c9a17edd37f54fc8d498c5e01e42b16
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 "libserialport_internal.h"
22 SP_PRIV void time_get(struct time *time)
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
46 SP_PRIV void time_set_ms(struct time *time, unsigned int ms)
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
58 SP_PRIV void time_add(const struct time *a,
59 const struct time *b, struct time *result)
61 #ifdef _WIN32
62 result->ticks = a->ticks + b->ticks;
63 #else
64 timeradd(&a->tv, &b->tv, &result->tv);
65 #endif
68 SP_PRIV void time_sub(const struct time *a,
69 const struct time *b, struct time *result)
71 #ifdef _WIN32
72 result->ticks = a->ticks - b->ticks;
73 #else
74 timersub(&a->tv, &b->tv, &result->tv);
75 #endif
78 SP_PRIV bool time_greater(const struct time *a, const struct time *b)
80 #ifdef _WIN32
81 return (a->ticks > b->ticks);
82 #else
83 return timercmp(&a->tv, &b->tv, >);
84 #endif
87 SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv)
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
100 SP_PRIV unsigned int time_as_ms(const struct time *time)
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
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)
137 return false;
139 if (timeout->ms == 0)
140 return false;
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;
156 #ifndef _WIN32
157 SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout)
159 if (timeout->ms == 0)
160 return NULL;
162 time_as_timeval(&timeout->delta, &timeout->delta_tv);
164 return &timeout->delta_tv;
166 #endif
168 SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout)
170 if (timeout->limit_ms && timeout->overflow)
171 return timeout->limit_ms;
172 else
173 return time_as_ms(&timeout->delta);