From: Martin Ling Date: Sat, 4 Jan 2020 00:43:41 +0000 (+0000) Subject: Move timing routines to separate file. X-Git-Url: https://sigrok.org/gitweb/?p=libserialport.git;a=commitdiff_plain;h=39acdc47db65e64e43d52bea2e425751a96f9780 Move timing routines to separate file. --- diff --git a/Makefile.am b/Makefile.am index a3bc0d1..a9aca6c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,7 +27,7 @@ AM_CFLAGS = -std=c99 -Wall -Wextra -pedantic -Wmissing-prototypes -Wshadow lib_LTLIBRARIES = libserialport.la -libserialport_la_SOURCES = serialport.c libserialport_internal.h +libserialport_la_SOURCES = serialport.c timing.c libserialport_internal.h if LINUX libserialport_la_SOURCES += linux.c linux_termios.c linux_termios.h endif diff --git a/libserialport_internal.h b/libserialport_internal.h index 77c31a5..fde4883 100644 --- a/libserialport_internal.h +++ b/libserialport_internal.h @@ -251,4 +251,35 @@ SP_PRIV struct sp_port **list_append(struct sp_port **list, const char *portname SP_PRIV enum sp_return get_port_details(struct sp_port *port); SP_PRIV enum sp_return list_ports(struct sp_port ***list); +/* Timing abstraction */ + +struct time { +#ifdef _WIN32 + int64_t ticks; +#else + struct timeval tv; +#endif +}; + +struct timeout { + unsigned int ms, limit_ms; + struct time start, now, end, delta, delta_max; + struct timeval delta_tv; + bool calls_started, overflow; +}; + +SP_PRIV void time_get(struct time *time); +SP_PRIV void time_set_ms(struct time *time, unsigned int ms); +SP_PRIV void time_add(const struct time *a, const struct time *b, struct time *result); +SP_PRIV void time_sub(const struct time *a, const struct time *b, struct time *result); +SP_PRIV bool time_greater(const struct time *a, const struct time *b); +SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv); +SP_PRIV unsigned int time_as_ms(const struct time *time); +SP_PRIV void timeout_start(struct timeout *timeout, unsigned int timeout_ms); +SP_PRIV void timeout_limit(struct timeout *timeout, unsigned int limit_ms); +SP_PRIV bool timeout_check(struct timeout *timeout); +SP_PRIV void timeout_update(struct timeout *timeout); +SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout); +SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout); + #endif diff --git a/serialport.c b/serialport.c index d7164b8..dc62da9 100644 --- a/serialport.c +++ b/serialport.c @@ -55,177 +55,6 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data, static enum sp_return set_config(struct sp_port *port, struct port_data *data, const struct sp_port_config *config); -/* Timing abstraction */ - -struct time { -#ifdef _WIN32 - int64_t ticks; -#else - struct timeval tv; -#endif -}; - -struct timeout { - unsigned int ms, limit_ms; - struct time start, now, end, delta, delta_max; - struct timeval delta_tv; - bool calls_started, overflow; -}; - -static void time_get(struct time *time) -{ -#ifdef _WIN32 - LARGE_INTEGER count; - QueryPerformanceCounter(&count); - time->ticks = count.QuadPart; -#elif defined(HAVE_CLOCK_GETTIME) - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) - clock_gettime(CLOCK_REALTIME, &ts); - time->tv.tv_sec = ts.tv_sec; - time->tv.tv_usec = ts.tv_nsec / 1000; -#elif defined(__APPLE__) - mach_timebase_info_data_t info; - mach_timebase_info(&info); - uint64_t ticks = mach_absolute_time(); - uint64_t ns = (ticks * info.numer) / info.denom; - time->tv.tv_sec = ns / 1000000000; - time->tv.tv_usec = (ns % 1000000000) / 1000; -#else - gettimeofday(&time->tv, NULL); -#endif -} - -static void time_set_ms(struct time *time, unsigned int ms) -{ -#ifdef _WIN32 - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - time->ticks = ms * (frequency.QuadPart / 1000); -#else - time->tv.tv_sec = ms / 1000; - time->tv.tv_usec = (ms % 1000) * 1000; -#endif -} - -static void time_add(const struct time *a, - const struct time *b, struct time *result) -{ -#ifdef _WIN32 - result->ticks = a->ticks + b->ticks; -#else - timeradd(&a->tv, &b->tv, &result->tv); -#endif -} - -static void time_sub(const struct time *a, - const struct time *b, struct time *result) -{ -#ifdef _WIN32 - result->ticks = a->ticks - b->ticks; -#else - timersub(&a->tv, &b->tv, &result->tv); -#endif -} - -static bool time_greater(const struct time *a, const struct time *b) -{ -#ifdef _WIN32 - return (a->ticks > b->ticks); -#else - return timercmp(&a->tv, &b->tv, >); -#endif -} - -static void time_as_timeval(const struct time *time, struct timeval *tv) -{ -#ifdef _WIN32 - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - tv->tv_sec = time->ticks / frequency.QuadPart; - tv->tv_usec = (time->ticks % frequency.QuadPart) / - (frequency.QuadPart / 1000000); -#else - *tv = time->tv; -#endif -} - -static unsigned int time_as_ms(const struct time *time) -{ -#ifdef _WIN32 - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - return time->ticks / (frequency.QuadPart / 1000); -#else - return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000; -#endif -} - -static void timeout_start(struct timeout *timeout, unsigned int timeout_ms) -{ - timeout->ms = timeout_ms; - - /* Get time at start of operation. */ - time_get(&timeout->start); - /* Define duration of timeout. */ - time_set_ms(&timeout->delta, timeout_ms); - /* Calculate time at which we should give up. */ - time_add(&timeout->start, &timeout->delta, &timeout->end); - /* Disable limit unless timeout_limit() called. */ - timeout->limit_ms = 0; - /* First blocking call has not yet been made. */ - timeout->calls_started = false; -} - -static void timeout_limit(struct timeout *timeout, unsigned int limit_ms) -{ - timeout->limit_ms = limit_ms; - timeout->overflow = (timeout->ms > timeout->limit_ms); - time_set_ms(&timeout->delta_max, timeout->limit_ms); -} - -static bool timeout_check(struct timeout *timeout) -{ - if (!timeout->calls_started) - return false; - - if (timeout->ms == 0) - return false; - - time_get(&timeout->now); - time_sub(&timeout->end, &timeout->now, &timeout->delta); - if (timeout->limit_ms) - if ((timeout->overflow = time_greater(&timeout->delta, &timeout->delta_max))) - timeout->delta = timeout->delta_max; - - return time_greater(&timeout->now, &timeout->end); -} - -static void timeout_update(struct timeout *timeout) -{ - timeout->calls_started = true; -} - -#ifndef _WIN32 -static struct timeval *timeout_timeval(struct timeout *timeout) -{ - if (timeout->ms == 0) - return NULL; - - time_as_timeval(&timeout->delta, &timeout->delta_tv); - - return &timeout->delta_tv; -} -#endif - -static unsigned int timeout_remaining_ms(struct timeout *timeout) -{ - if (timeout->limit_ms && timeout->overflow) - return timeout->limit_ms; - else - return time_as_ms(&timeout->delta); -} - SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) { struct sp_port *port; diff --git a/timing.c b/timing.c new file mode 100644 index 0000000..957f676 --- /dev/null +++ b/timing.c @@ -0,0 +1,176 @@ +/* + * This file is part of the libserialport project. + * + * Copyright (C) 2019 Martin Ling + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include "libserialport.h" +#include "libserialport_internal.h" + +SP_PRIV void time_get(struct time *time) +{ +#ifdef _WIN32 + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + time->ticks = count.QuadPart; +#elif defined(HAVE_CLOCK_GETTIME) + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) + clock_gettime(CLOCK_REALTIME, &ts); + time->tv.tv_sec = ts.tv_sec; + time->tv.tv_usec = ts.tv_nsec / 1000; +#elif defined(__APPLE__) + mach_timebase_info_data_t info; + mach_timebase_info(&info); + uint64_t ticks = mach_absolute_time(); + uint64_t ns = (ticks * info.numer) / info.denom; + time->tv.tv_sec = ns / 1000000000; + time->tv.tv_usec = (ns % 1000000000) / 1000; +#else + gettimeofday(&time->tv, NULL); +#endif +} + +SP_PRIV void time_set_ms(struct time *time, unsigned int ms) +{ +#ifdef _WIN32 + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + time->ticks = ms * (frequency.QuadPart / 1000); +#else + time->tv.tv_sec = ms / 1000; + time->tv.tv_usec = (ms % 1000) * 1000; +#endif +} + +SP_PRIV void time_add(const struct time *a, + const struct time *b, struct time *result) +{ +#ifdef _WIN32 + result->ticks = a->ticks + b->ticks; +#else + timeradd(&a->tv, &b->tv, &result->tv); +#endif +} + +SP_PRIV void time_sub(const struct time *a, + const struct time *b, struct time *result) +{ +#ifdef _WIN32 + result->ticks = a->ticks - b->ticks; +#else + timersub(&a->tv, &b->tv, &result->tv); +#endif +} + +SP_PRIV bool time_greater(const struct time *a, const struct time *b) +{ +#ifdef _WIN32 + return (a->ticks > b->ticks); +#else + return timercmp(&a->tv, &b->tv, >); +#endif +} + +SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv) +{ +#ifdef _WIN32 + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + tv->tv_sec = time->ticks / frequency.QuadPart; + tv->tv_usec = (time->ticks % frequency.QuadPart) / + (frequency.QuadPart / 1000000); +#else + *tv = time->tv; +#endif +} + +SP_PRIV unsigned int time_as_ms(const struct time *time) +{ +#ifdef _WIN32 + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + return time->ticks / (frequency.QuadPart / 1000); +#else + return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000; +#endif +} + +SP_PRIV void timeout_start(struct timeout *timeout, unsigned int timeout_ms) +{ + timeout->ms = timeout_ms; + + /* Get time at start of operation. */ + time_get(&timeout->start); + /* Define duration of timeout. */ + time_set_ms(&timeout->delta, timeout_ms); + /* Calculate time at which we should give up. */ + time_add(&timeout->start, &timeout->delta, &timeout->end); + /* Disable limit unless timeout_limit() called. */ + timeout->limit_ms = 0; + /* First blocking call has not yet been made. */ + timeout->calls_started = false; +} + +SP_PRIV void timeout_limit(struct timeout *timeout, unsigned int limit_ms) +{ + timeout->limit_ms = limit_ms; + timeout->overflow = (timeout->ms > timeout->limit_ms); + time_set_ms(&timeout->delta_max, timeout->limit_ms); +} + +SP_PRIV bool timeout_check(struct timeout *timeout) +{ + if (!timeout->calls_started) + return false; + + if (timeout->ms == 0) + return false; + + time_get(&timeout->now); + time_sub(&timeout->end, &timeout->now, &timeout->delta); + if (timeout->limit_ms) + if ((timeout->overflow = time_greater(&timeout->delta, &timeout->delta_max))) + timeout->delta = timeout->delta_max; + + return time_greater(&timeout->now, &timeout->end); +} + +SP_PRIV void timeout_update(struct timeout *timeout) +{ + timeout->calls_started = true; +} + +#ifndef _WIN32 +SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout) +{ + if (timeout->ms == 0) + return NULL; + + time_as_timeval(&timeout->delta, &timeout->delta_tv); + + return &timeout->delta_tv; +} +#endif + +SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout) +{ + if (timeout->limit_ms && timeout->overflow) + return timeout->limit_ms; + else + return time_as_ms(&timeout->delta); +}