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

Reply via email to