From 7a61d4545b6c5d5c622e7ee1d413133b97f889e5 Mon Sep 17 00:00:00 2001 From: Mike Purvis Date: Sun, 6 Oct 2013 10:35:00 -0400 Subject: [PATCH] Create key operator/manipulation functions for timespecs, add them to new unix-timespec.h helper header. --- include/serial/impl/unix-timespec.h | 122 ++++++++++++++++++++++++++++ include/serial/impl/unix.h | 10 ++- src/impl/unix.cc | 72 +--------------- 3 files changed, 132 insertions(+), 72 deletions(-) create mode 100644 include/serial/impl/unix-timespec.h diff --git a/include/serial/impl/unix-timespec.h b/include/serial/impl/unix-timespec.h new file mode 100644 index 0000000..79c1d8c --- /dev/null +++ b/include/serial/impl/unix-timespec.h @@ -0,0 +1,122 @@ +/*! + * \file serial/impl/unit-timespec.h + * \author Mike Purvis + * \version 0.1 + * + * \section LICENSE + * + * The MIT License + * + * Copyright (c) 2013 William Woodall + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * \section DESCRIPTION + * + * Provides helper and operator functions for concisely and reliably handling + * timespec instances on unix platforms. + */ + +#ifndef SERIAL_IMPL_UNIX_TIMESPEC_H +#define SERIAL_IMPL_UNIX_TIMESPEC_H + +/*! Smooth over platform variances in getting an accurate timespec + * representing the present moment. */ +static inline void +get_time_now (struct timespec &time) +{ +# ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + time.tv_sec = mts.tv_sec; + time.tv_nsec = mts.tv_nsec; +# else + clock_gettime(CLOCK_REALTIME, &time); +# endif +} + +/*! Simple function to normalize the tv_nsec field to [0..1e9), carrying + * the remainder into the tv_sec field. This will not protect against the + * possibility of an overflow in the nsec field--proceed with caution. */ +static inline void +normalize(struct timespec* ts) { + while (ts->tv_nsec < 0) { + ts->tv_nsec += 1e9; + ts->tv_sec -= 1; + } + while (ts->tv_nsec >= 1e9) { + ts->tv_nsec -= 1e9; + ts->tv_sec += 1; + } +} + +/*! Return a timespec which is the sum of two other timespecs. */ +static inline struct timespec +operator+ (const struct timespec &a, const struct timespec &b) { + struct timespec result = { a.tv_sec + b.tv_sec, + a.tv_nsec + b.tv_nsec }; + normalize(&result); + return result; +} + +/*! Return a timespec which is the difference of two other timespecs. */ +static inline struct timespec +operator- (const struct timespec &a, const struct timespec &b) { + struct timespec result = { a.tv_sec - b.tv_sec, + a.tv_nsec - b.tv_nsec }; + normalize(&result); + return result; +} + +/*! Return a timespec which is a multiplication of a timespec and a positive + * integer. No overflow protection-- not suitable for multiplications with + * large carries, eg a <1s timespec multiplied by a large enough integer + * that the result is muliple seconds. */ +static inline struct timespec +operator* (const struct timespec &ts, const size_t mul) { + struct timespec result = { ts.tv_sec * mul, + ts.tv_nsec * mul }; + normalize(&result); + return result; +} + +/*! Return whichever of two timespecs represents the shortest or most + * negative duration. */ +static inline struct timespec +min (const struct timespec &a, const struct timespec &b) { + if (a.tv_sec < b.tv_sec + || (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec)) { + return a; + } else { + return b; + } +} + +/*! Return a timespec set from a provided number of milliseconds. */ +static struct timespec +timespec_from_millis(const size_t millis) { + struct timespec result = { 0, millis * 1000000 }; + normalize(&result); + return result; +} + +#endif diff --git a/include/serial/impl/unix.h b/include/serial/impl/unix.h index 3e45ec4..c3add0b 100644 --- a/include/serial/impl/unix.h +++ b/include/serial/impl/unix.h @@ -122,7 +122,7 @@ public: getPort () const; void - setTimeout (Timeout &timeout); + setTimeout (const Timeout &timeout); Timeout getTimeout () const; @@ -180,7 +180,13 @@ private: bool xonxoff_; bool rtscts_; - Timeout timeout_; // Timeout for read operations + Timeout timeout_; // Timeouts for read/write operations + struct timespec inter_byte_timeout_; + struct timespec read_timeout_constant_; + struct timespec read_timeout_multiplier_; + struct timespec write_timeout_constant_; + struct timespec write_timeout_multiplier_; + unsigned long baudrate_; // Baudrate parity_t parity_; // Parity diff --git a/src/impl/unix.cc b/src/impl/unix.cc index 1b5143c..115f94f 100755 --- a/src/impl/unix.cc +++ b/src/impl/unix.cc @@ -27,6 +27,7 @@ #endif #include "serial/impl/unix.h" +#include "serial/impl/unix-timespec.h" #ifndef TIOCINQ #ifdef FIONREAD @@ -396,74 +397,6 @@ Serial::SerialImpl::available () } } -inline void -get_time_now (struct timespec &time) -{ -# ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - time.tv_sec = mts.tv_sec; - time.tv_nsec = mts.tv_nsec; -# else - clock_gettime(CLOCK_REALTIME, &time); -# endif -} - -inline void -diff_timespec (timespec &start, timespec &end, timespec &result) { - if (start.tv_sec > end.tv_sec) { - throw SerialException ("Timetravel, start time later than end time."); - } - result.tv_sec = end.tv_sec - start.tv_sec; - result.tv_nsec = end.tv_nsec - start.tv_nsec; - if (result.tv_nsec < 0) { - result.tv_nsec = 1e9 - result.tv_nsec; - result.tv_sec -= 1; - } -} - -/*! Simple function to normalize the tv_nsec field to [0..1e9), carrying - * the remainder into the tv_sec field. */ -void normalize(timespec* ts) { - while (ts->tv_nsec < 0) { - ts->tv_nsec += 1e9; - ts->tv_sec -= 1; - } - while (ts->tv_nsec >= 1e9) { - ts->tv_nsec -= 1e9; - ts->tv_sec += 1; - } -} - -inline struct timespec -operator+ (const struct timespec &a, const struct timespec &b) { - struct timespec result = { a.tv_sec + b.tv_sec, - a.tv_nsec + b.tv_nsec }; - normalize(&result); - return result; -} - -inline struct timespec -operator- (const struct timespec &a, const struct timespec &b) { - struct timespec result = { a.tv_sec - b.tv_sec, - a.tv_nsec - b.tv_nsec }; - normalize(&result); - return result; -} - -inline struct timespec -min (const struct timespec &a, const struct timespec &b) { - if (a.tv_sec < b.tv_sec - || (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec)) { - return a; - } else { - return b; - } -} - size_t Serial::SerialImpl::read (uint8_t *buf, size_t size) { @@ -611,8 +544,7 @@ Serial::SerialImpl::write (const uint8_t *data, size_t length) // Calculate difference and update the structure get_time_now(end); // Calculate the time select took - struct timespec diff; - diff_timespec(start, end, diff); + struct timespec diff(end - start); // Update the timeout if (timeout.tv_sec <= diff.tv_sec) { timeout.tv_sec = 0;