]> sigrok.org Git - libserialport.git/blame - timing.c
change type of result variables to ssize_t
[libserialport.git] / timing.c
CommitLineData
39acdc47
ML
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
39acdc47
ML
20#include "libserialport_internal.h"
21
22SP_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
46SP_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
58SP_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
68SP_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
78SP_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
87SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv)
88{
89#ifdef _WIN32
90 LARGE_INTEGER frequency;
91 QueryPerformanceFrequency(&frequency);
528e8c00
ML
92 tv->tv_sec = (long) (time->ticks / frequency.QuadPart);
93 tv->tv_usec = (long) ((time->ticks % frequency.QuadPart) /
94 (frequency.QuadPart / 1000000));
39acdc47
ML
95#else
96 *tv = time->tv;
97#endif
98}
99
100SP_PRIV unsigned int time_as_ms(const struct time *time)
101{
102#ifdef _WIN32
103 LARGE_INTEGER frequency;
104 QueryPerformanceFrequency(&frequency);
41fc921c 105 return (unsigned int) (time->ticks / (frequency.QuadPart / 1000));
39acdc47
ML
106#else
107 return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
108#endif
109}
110
111SP_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
127SP_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
134SP_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
151SP_PRIV void timeout_update(struct timeout *timeout)
152{
153 timeout->calls_started = true;
154}
155
156#ifndef _WIN32
157SP_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
168SP_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}