Signed-off-by: Michael Brown <[email protected]> --- makefile | 2 +- tmv.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tmv.h | 112 +++++++++------------------------------------------- 3 files changed, 156 insertions(+), 94 deletions(-) create mode 100644 tmv.c
diff --git a/makefile b/makefile index f898336..8ccc322 100644 --- a/makefile +++ b/makefile @@ -25,7 +25,7 @@ LDLIBS = -lm -lrt $(EXTRA_LDFLAGS) PRG = ptp4l pmc phc2sys hwstamp_ctl phc_ctl timemaster OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o fault.o \ filter.o fsm.o hash.o linreg.o mave.o mmedian.o msg.o ntpshm.o nullf.o phc.o \ - pi.o port.o print.o ptp4l.o raw.o rtnl.o servo.o sk.o stats.o tlv.o \ + pi.o port.o print.o ptp4l.o raw.o rtnl.o servo.o sk.o stats.o tlv.o tmv.o \ transport.o tsproc.o udp.o udp6.o uds.o util.o version.o OBJECTS = $(OBJ) hwstamp_ctl.o phc2sys.o phc_ctl.o pmc.o pmc_common.o \ diff --git a/tmv.c b/tmv.c new file mode 100644 index 0000000..f2d36a3 --- /dev/null +++ b/tmv.c @@ -0,0 +1,136 @@ +/** + * @file tmv.c + * @brief Implements an abstract time value type. + * @note Copyright (C) 2018 Michael Brown <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <math.h> +#include <time.h> + +#include "ddt.h" +#include "pdt.h" +#include "tmv.h" + +#define NS_FRAC 0x10000 + +static tmv_t tmv_normalize(int64_t ns, int32_t frac) +{ + tmv_t t; + + while ((frac > NS_FRAC) || (frac > 0 && ns < 0)) { + frac -= NS_FRAC; + ns++; + } + while ((frac < -NS_FRAC) || (frac < 0 && ns > 0)) { + frac += NS_FRAC; + ns--; + } + t.ns = ns; + t.frac = frac; + return t; +} + +tmv_t tmv_add(tmv_t a, tmv_t b) +{ + return tmv_normalize(a.ns + b.ns, a.frac + b.frac); +} + +tmv_t tmv_div(tmv_t a, int divisor) +{ + int64_t q; + int64_t r; + q = a.ns / divisor; + r = a.ns % divisor; + return tmv_normalize(q, (r * NS_FRAC + a.frac) / divisor); +} + +int tmv_cmp(tmv_t a, tmv_t b) +{ + if (a.ns == b.ns) { + return a.frac == b.frac ? 0 : a.frac > b.frac ? +1 : -1; + } else { + return a.ns > b.ns ? +1 : -1; + } +} + +int tmv_sign(tmv_t x) +{ + if (x.ns == 0) { + return x.frac == 0 ? 0 : x.frac > 0 ? +1 : -1; + } else { + return x.ns > 0 ? +1 : -1; + } +} + +int tmv_is_zero(tmv_t x) +{ + return x.ns == 0 && x.frac == 0 ? 1 : 0; +} + +tmv_t tmv_sub(tmv_t a, tmv_t b) +{ + return tmv_normalize(a.ns - b.ns, a.frac - b.frac); +} + +tmv_t tmv_zero(void) +{ + tmv_t t = { 0, 0 }; + return t; +} + +tmv_t correction_to_tmv(Integer64 c) +{ + return tmv_normalize(c / NS_FRAC, c % NS_FRAC); +} + +double tmv_dbl(tmv_t x) +{ + return (double) x.ns + (double) x.frac / NS_FRAC; +} + +tmv_t dbl_tmv(double x) +{ + double ns; + double frac; + frac = modf(x, &ns); + return tmv_normalize(ns, frac * NS_FRAC); +} + +int64_t tmv_to_nanoseconds(tmv_t x) +{ + return x.ns; +} + +TimeInterval tmv_to_TimeInterval(tmv_t x) +{ + return x.ns * NS_FRAC + x.frac; +} + +tmv_t timespec_to_tmv(struct timespec ts) +{ + tmv_t t; + t.ns = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; + t.frac = 0; + return t; +} + +tmv_t timestamp_to_tmv(struct timestamp ts) +{ + tmv_t t; + t.ns = ts.sec * NS_PER_SEC + ts.nsec; + t.frac = 0; + return t; +} diff --git a/tmv.h b/tmv.h index 72f2d51..425a35e 100644 --- a/tmv.h +++ b/tmv.h @@ -29,103 +29,29 @@ /** * We implement the time value as a 64 bit signed integer containing - * nanoseconds. Using this representation, we could really spare the - * arithmetic functions such as @ref tmv_add() and the like, and just - * use plain old math operators in the code. - * - * However, we are going to be a bit pedantic here and enforce the - * use of the these functions, so that we can easily upgrade the code - * to a finer representation later on. In that way, we can make use of - * the fractional nanosecond parts of the correction fields, if and - * when people start asking for them. + * integer nanoseconds and a 32 bit signed integer containing + * fractional (2^-16) nanoseconds, where the fractional part is + * guaranteed to lie within the range [-0xffff,0xffff] and to have the + * same sign as the integer part. */ typedef struct { int64_t ns; + int32_t frac; } tmv_t; -static inline tmv_t tmv_add(tmv_t a, tmv_t b) -{ - tmv_t t; - t.ns = a.ns + b.ns; - return t; -} - -static inline tmv_t tmv_div(tmv_t a, int divisor) -{ - tmv_t t; - t.ns = a.ns / divisor; - return t; -} - -static inline int tmv_cmp(tmv_t a, tmv_t b) -{ - return a.ns == b.ns ? 0 : a.ns > b.ns ? +1 : -1; -} - -static inline int tmv_sign(tmv_t x) -{ - return x.ns == 0 ? 0 : x.ns > 0 ? +1 : -1; -} - -static inline int tmv_is_zero(tmv_t x) -{ - return x.ns == 0 ? 1 : 0; -} - -static inline tmv_t tmv_sub(tmv_t a, tmv_t b) -{ - tmv_t t; - t.ns = a.ns - b.ns; - return t; -} - -static inline tmv_t tmv_zero(void) -{ - tmv_t t = { 0 }; - return t; -} - -static inline tmv_t correction_to_tmv(Integer64 c) -{ - tmv_t t; - t.ns = (c >> 16); - return t; -} - -static inline double tmv_dbl(tmv_t x) -{ - return (double) x.ns; -} - -static inline tmv_t dbl_tmv(double x) -{ - tmv_t t; - t.ns = x; - return t; -} - -static inline int64_t tmv_to_nanoseconds(tmv_t x) -{ - return x.ns; -} - -static inline TimeInterval tmv_to_TimeInterval(tmv_t x) -{ - return x.ns << 16; -} - -static inline tmv_t timespec_to_tmv(struct timespec ts) -{ - tmv_t t; - t.ns = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; - return t; -} - -static inline tmv_t timestamp_to_tmv(struct timestamp ts) -{ - tmv_t t; - t.ns = ts.sec * NS_PER_SEC + ts.nsec; - return t; -} +extern tmv_t tmv_add(tmv_t a, tmv_t b); +extern tmv_t tmv_div(tmv_t a, int divisor); +extern int tmv_cmp(tmv_t a, tmv_t b); +extern int tmv_sign(tmv_t x); +extern int tmv_is_zero(tmv_t x); +extern tmv_t tmv_sub(tmv_t a, tmv_t b); +extern tmv_t tmv_zero(void); +extern tmv_t correction_to_tmv(Integer64 c); +extern double tmv_dbl(tmv_t x); +extern tmv_t dbl_tmv(double x); +extern int64_t tmv_to_nanoseconds(tmv_t x); +extern TimeInterval tmv_to_TimeInterval(tmv_t x); +extern tmv_t timespec_to_tmv(struct timespec ts); +extern tmv_t timestamp_to_tmv(struct timestamp ts); #endif -- 2.9.5 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Linuxptp-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
