This patch contains a package with two PPS-tools and a header file,
authorFelix Fietkau <nbd@openwrt.org>
Wed, 19 Mar 2008 08:03:21 +0000 (08:03 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Wed, 19 Mar 2008 08:03:21 +0000 (08:03 +0000)
i extracted from http://wiki.enneenne.com/index.php/LinuxPPS_support.

Signed-off-by: Frithjof Hammer <openwrt@frithjof-hammer.de>
SVN-Revision: 10620

utils/pps-tools/Makefile [new file with mode: 0644]
utils/pps-tools/patches/001-source.patch [new file with mode: 0644]

diff --git a/utils/pps-tools/Makefile b/utils/pps-tools/Makefile
new file mode 100644 (file)
index 0000000..3176776
--- /dev/null
@@ -0,0 +1,49 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=pps-tools
+PKG_VERSION:=2.6.23
+PKG_RELEASE:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/pps-tools
+  SUBMENU:=Time Synchronization
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=@LINUX_2_6_23
+  TITLE:=PPS (Pulse Per Second) Userland tools
+  URL:=http://wiki.enneenne.com/index.php/LinuxPPS_support
+endef
+
+
+define Package/pps-tools/description
+  Userland tools for GPS and DCF-77 Clock syncronization. PPS support in Kernel must be enabled.
+endef
+
+define Build/InstallDev
+       $(CP) $(PKG_BUILD_DIR)/timepps.h $(1)/usr/include/
+endef
+
+define Build/Compile
+       $(MAKE) -C $(PKG_BUILD_DIR) \
+               $(TARGET_CONFIGURE_OPTS) \
+               CFLAGS="$(TARGET_CFLAGS) -DHAVE_ISC_READER=1 -I ." \
+               BINDIR="/usr/sbin" MANDIR="/usr/man" 
+endef
+
+define Package/pps-tools/install
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/ppstest $(1)/usr/sbin/
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/ppsctl $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,pps-tools))
diff --git a/utils/pps-tools/patches/001-source.patch b/utils/pps-tools/patches/001-source.patch
new file mode 100644 (file)
index 0000000..6707478
--- /dev/null
@@ -0,0 +1,480 @@
+diff --git a/Makefile b/Makefile
+new file mode 100644
+index 0000000..a2660a2
+--- /dev/null
++++ b/Makefile
+@@ -0,0 +1,27 @@
++TARGETS = ppstest ppsctl
++
++CFLAGS += -Wall -O2 -D_GNU_SOURCE
++CFLAGS += -I .
++CFLAGS += -ggdb
++
++# -- Actions section ----------------------------------------------------------
++
++.PHONY : all depend dep
++
++all : .depend $(TARGETS)
++
++.depend depend dep :
++      $(CC) $(CFLAGS) -M $(TARGETS:=.c) > .depend
++
++ifeq (.depend,$(wildcard .depend))
++include .depend
++endif
++
++
++# -- Clean section ------------------------------------------------------------
++
++.PHONY : clean
++
++clean :
++      rm -f *.o *~ core .depend
++      rm -f ${TARGETS}
+diff --git a/ppsctl.c b/ppsctl.c
+new file mode 100644
+index 0000000..83fd08a
+--- /dev/null
++++ b/ppsctl.c
+@@ -0,0 +1,62 @@
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <sys/ioctl.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <string.h>
++#include <linux/serial.h>
++
++void usage(char *name)
++{
++      fprintf(stderr, "usage: %s <ttyS> [enable|disable]\n", name);
++
++      exit(EXIT_FAILURE);
++}
++
++int main(int argc, char *argv[])
++{
++      int fd;
++      int ret;
++      struct serial_struct ss;
++
++      if (argc < 2)
++              usage(argv[0]);
++
++      fd = open(argv[1], O_RDWR);
++      if (fd < 0) {
++              perror("open");
++              exit(EXIT_FAILURE);
++      }
++
++      ret = ioctl(fd, TIOCGSERIAL, &ss);
++      if (ret < 0) {
++              perror("ioctl(TIOCGSERIAL)");
++              exit(EXIT_FAILURE);
++      }
++
++      if (argc < 3) {         /* just read PPS status */
++              printf("PPS is %sabled\n",
++                     ss.flags & ASYNC_HARDPPS_CD ? "en" : "dis");
++              exit(EXIT_SUCCESS);
++      }
++
++      if (argv[2][0] == 'e' || argv[2][0] == '1')
++              ss.flags |= ASYNC_HARDPPS_CD;
++      else if (argv[2][0] == 'd' || argv[2][0] == '0')
++              ss.flags &= ~ASYNC_HARDPPS_CD;
++      else {
++              fprintf(stderr, "invalid state argument \"%s\"\n", argv[2]);
++              exit(EXIT_FAILURE);
++      }
++
++      ret = ioctl(fd, TIOCSSERIAL, &ss);
++      if (ret < 0) {
++              perror("ioctl(TIOCSSERIAL)");
++              exit(EXIT_FAILURE);
++      }
++
++      return 0;
++}
+diff --git a/ppsfind b/ppsfind
+new file mode 100755
+index 0000000..93c0e17
+--- /dev/null
++++ b/ppsfind
+@@ -0,0 +1,17 @@
++#!/bin/sh
++
++SYS="/sys/class/pps/"
++
++if [ $# -lt 1 ] ; then
++      echo "usage: ppsfind <name>" >&2
++      exit 1
++fi
++
++for d in $(ls $SYS) ; do
++      if grep $1 $SYS/$d/name >& /dev/null || \
++         grep $1 $SYS/$d/path >& /dev/null ; then
++              echo "$d: name=$(cat $SYS/$d/name) path=$(cat $SYS/$d/path)"
++      fi
++done
++
++exit 0
+diff --git a/ppstest.c b/ppstest.c
+new file mode 100644
+index 0000000..d125ffa
+--- /dev/null
++++ b/ppstest.c
+@@ -0,0 +1,151 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <timepps.h>
++
++int find_source(char *path, pps_handle_t *handle, int *avail_mode)
++{
++      pps_params_t params;
++      int ret;
++
++      printf("trying PPS source \"%s\"\n", path);
++
++      /* Try to find the source by using the supplied "path" name */
++      ret = open(path, O_RDWR);
++      if (ret < 0) {
++              fprintf(stderr, "unable to open device \"%s\" (%m)\n", path);
++              return ret;
++      }
++
++      /* Open the PPS source (and check the file descriptor) */
++      ret = time_pps_create(ret, handle);
++      if (ret < 0) {
++              fprintf(stderr, "cannot create a PPS source from device "
++                              "\"%s\" (%m)\n", path);
++              return -1;
++      }
++      printf("found PPS source \"%s\"\n", path);
++
++      /* Find out what features are supported */
++      ret = time_pps_getcap(*handle, avail_mode);
++      if (ret < 0) {
++              fprintf(stderr, "cannot get capabilities (%m)\n");
++              return -1;
++      }
++      if ((*avail_mode & PPS_CAPTUREASSERT) == 0) {
++              fprintf(stderr, "cannot CAPTUREASSERT\n");
++              return -1;
++      }
++      if ((*avail_mode & PPS_OFFSETASSERT) == 0) {
++              fprintf(stderr, "cannot OFFSETASSERT\n");
++              return -1;
++      }
++
++      /* Capture assert timestamps, and compensate for a 675 nsec
++       * propagation delay */
++      ret = time_pps_getparams(*handle, &params);
++      if (ret < 0) {
++              fprintf(stderr, "cannot get parameters (%m)\n");
++              return -1;
++      }
++      params.assert_offset.tv_sec = 0;
++      params.assert_offset.tv_nsec = 675;
++      params.mode |= PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
++      ret = time_pps_setparams(*handle, &params);
++      if (ret < 0) {
++              fprintf(stderr, "cannot set parameters (%m)\n");
++              return -1;
++      }
++
++      return 0;
++}
++
++int fetch_source(int i, pps_handle_t *handle, int *avail_mode)
++{
++      struct timespec timeout;
++      pps_info_t infobuf;
++      int ret;
++
++      /* create a zero-valued timeout */
++      timeout.tv_sec = 3;
++      timeout.tv_nsec = 0;
++
++retry:
++      if (*avail_mode & PPS_CANWAIT) /* waits for the next event */
++              ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf,
++                                 &timeout);
++      else {
++              sleep(1);
++              ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf,
++                                 &timeout);
++      }
++      if (ret < 0) {
++              if (ret == -EINTR) {
++                      fprintf(stderr, "time_pps_fetch() got a signal!\n");
++                      goto retry;
++              }
++
++              fprintf(stderr, "time_pps_fetch() error %d (%m)\n", ret);
++              return -1;
++      }
++
++      printf("source %d - "
++             "assert %ld.%09ld, sequence: %ld - "
++             "clear  %ld.%09ld, sequence: %ld\n",
++             i,
++             infobuf.assert_timestamp.tv_sec,
++             infobuf.assert_timestamp.tv_nsec,
++             infobuf.assert_sequence,
++             infobuf.clear_timestamp.tv_sec,
++             infobuf.clear_timestamp.tv_nsec, infobuf.clear_sequence);
++
++      return 0;
++}
++
++void usage(char *name)
++{
++      fprintf(stderr, "usage: %s <ppsdev> [<ppsdev> ...]\n", name);
++      exit(EXIT_FAILURE);
++}
++
++int main(int argc, char *argv[])
++{
++      int num;
++      pps_handle_t handle[4];
++      int avail_mode[4];
++      int i = 0;
++      int ret;
++
++      /* Check the command line */
++      if (argc < 2)
++              usage(argv[0]);
++
++      for (i = 1; i < argc && i <= 4; i++) {
++              ret = find_source(argv[i], &handle[i - 1], &avail_mode[i - 1]);
++              if (ret < 0)
++                      exit(EXIT_FAILURE);
++      }
++
++      num = i - 1;
++      printf("ok, found %d source(s), now start fetching data...\n", num);
++
++      /* loop, printing the most recent timestamp every second or so */
++      while (1) {
++              for (i = 0; i < num; i++) {
++                      ret = fetch_source(i, &handle[i], &avail_mode[i]);
++                      if (ret < 0 && errno != ETIMEDOUT)
++                              exit(EXIT_FAILURE);
++              }
++      }
++
++      for (; i >= 0; i--)
++              time_pps_destroy(handle[i]);
++
++      return 0;
++}
+diff --git a/timepps.h b/timepps.h
+new file mode 100644
+index 0000000..28ebf4c
+--- /dev/null
++++ b/timepps.h
+@@ -0,0 +1,193 @@
++/*
++ * timepps.h -- PPS API main header
++ *
++ * Copyright (C) 2005-2007   Rodolfo Giometti <giometti@linux.it>
++ *
++ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef _SYS_TIMEPPS_H_
++#define _SYS_TIMEPPS_H_
++
++#include <sys/syscall.h>
++#include <unistd.h>
++#include <errno.h>
++#include <linux/pps.h>
++
++/*
++ * New data structures
++ */
++
++struct ntp_fp {
++      unsigned int integral;
++      unsigned int fractional;
++};
++
++union pps_timeu {
++      struct timespec tspec;
++      struct ntp_fp ntpfp;
++      unsigned long longpad[3];
++};
++
++struct pps_info {
++      unsigned long assert_sequence;  /* seq. num. of assert event */
++      unsigned long clear_sequence;   /* seq. num. of clear event */
++      union pps_timeu assert_tu;      /* time of assert event */
++      union pps_timeu clear_tu;       /* time of clear event */
++      int current_mode;               /* current mode bits */
++};
++
++struct pps_params {
++      int api_version;                /* API version # */
++      int mode;                       /* mode bits */
++      union pps_timeu assert_off_tu;  /* offset compensation for assert */
++      union pps_timeu clear_off_tu;   /* offset compensation for clear */
++};
++
++typedef int pps_handle_t;             /* represents a PPS source */
++typedef unsigned long pps_seq_t;      /* sequence number */
++typedef struct ntp_fp ntp_fp_t;               /* NTP-compatible time stamp */
++typedef union pps_timeu pps_timeu_t;  /* generic data type for time stamps */
++typedef struct pps_info pps_info_t;
++typedef struct pps_params pps_params_t;
++
++#define assert_timestamp        assert_tu.tspec
++#define clear_timestamp         clear_tu.tspec
++
++#define assert_timestamp_ntpfp  assert_tu.ntpfp
++#define clear_timestamp_ntpfp   clear_tu.ntpfp
++
++#define assert_offset         assert_off_tu.tspec
++#define clear_offset          clear_off_tu.tspec
++
++#define assert_offset_ntpfp     assert_off_tu.ntpfp
++#define clear_offset_ntpfp      clear_off_tu.ntpfp
++
++/*
++ * The PPS API
++ */
++
++static __inline int time_pps_create(int source, pps_handle_t *handle)
++{
++      int ret;
++
++      if (!handle) {
++              errno = EINVAL;
++              return -1;
++      }
++
++      /* First we check if current device is a PPS valid PPS one...
++       */
++      ret = ioctl(source, PPS_CHECK);
++      if (ret) {
++              errno = EOPNOTSUPP;
++              return -1;
++      }
++
++      /* ... then since in LinuxPPS there are no differences between a
++       * "PPS source" and a "PPS handle", we simply return the same value.
++       */
++      *handle = source;
++
++      return 0;
++}
++
++static __inline int time_pps_destroy(pps_handle_t handle)
++{
++      return close(handle);
++}
++
++static __inline int time_pps_getparams(pps_handle_t handle,
++                                      pps_params_t *ppsparams)
++{
++      int ret;
++      struct pps_kparams __ppsparams;
++
++      ret = ioctl(handle, PPS_GETPARAMS, &__ppsparams);
++
++      ppsparams->api_version = __ppsparams.api_version;
++      ppsparams->mode = __ppsparams.mode;
++      ppsparams->assert_off_tu.tspec.tv_sec = __ppsparams.assert_off_tu.sec;
++      ppsparams->assert_off_tu.tspec.tv_nsec = __ppsparams.assert_off_tu.nsec;
++      ppsparams->clear_off_tu.tspec.tv_sec = __ppsparams.clear_off_tu.sec;
++      ppsparams->clear_off_tu.tspec.tv_nsec = __ppsparams.clear_off_tu.nsec;
++
++      return ret;
++}
++
++static __inline int time_pps_setparams(pps_handle_t handle,
++                                      const pps_params_t *ppsparams)
++{
++      struct pps_kparams __ppsparams;
++
++      __ppsparams.api_version = ppsparams->api_version;
++      __ppsparams.mode = ppsparams->mode;
++      __ppsparams.assert_off_tu.sec = ppsparams->assert_off_tu.tspec.tv_sec;
++      __ppsparams.assert_off_tu.nsec = ppsparams->assert_off_tu.tspec.tv_nsec;
++      __ppsparams.clear_off_tu.sec = ppsparams->clear_off_tu.tspec.tv_sec;
++      __ppsparams.clear_off_tu.nsec = ppsparams->clear_off_tu.tspec.tv_nsec;
++
++      return ioctl(handle, PPS_SETPARAMS, &__ppsparams);
++}
++
++/* Get capabilities for handle */
++static __inline int time_pps_getcap(pps_handle_t handle, int *mode)
++{
++      return ioctl(handle, PPS_GETCAP, mode);
++}
++
++static __inline int time_pps_fetch(pps_handle_t handle, const int tsformat,
++                                      pps_info_t *ppsinfobuf,
++                                      const struct timespec *timeout)
++{
++      struct pps_fdata __fdata;
++      int ret;
++
++      /* Sanity checks */
++      if (tsformat != PPS_TSFMT_TSPEC) {
++              errno = EINVAL;
++              return -1;
++      }
++
++      if (timeout) {
++              __fdata.timeout.sec = timeout->tv_sec;
++              __fdata.timeout.nsec = timeout->tv_nsec;
++              __fdata.timeout.flags = ~PPS_TIME_INVALID;
++      } else
++              __fdata.timeout.flags = PPS_TIME_INVALID;
++
++      ret = ioctl(handle, PPS_FETCH, &__fdata);
++
++      ppsinfobuf->assert_sequence = __fdata.info.assert_sequence;
++      ppsinfobuf->clear_sequence = __fdata.info.clear_sequence;
++      ppsinfobuf->assert_tu.tspec.tv_sec = __fdata.info.assert_tu.sec;
++      ppsinfobuf->assert_tu.tspec.tv_nsec = __fdata.info.assert_tu.nsec;
++      ppsinfobuf->clear_tu.tspec.tv_sec = __fdata.info.clear_tu.sec;
++      ppsinfobuf->clear_tu.tspec.tv_nsec = __fdata.info.clear_tu.nsec;
++      ppsinfobuf->current_mode = __fdata.info.current_mode;
++
++      return ret;
++}
++
++static __inline int time_pps_kcbind(pps_handle_t handle,
++                                      const int kernel_consumer,
++                                      const int edge, const int tsformat)
++{
++      /* LinuxPPS doesn't implement kernel consumer feature */
++      errno = EOPNOTSUPP;
++      return -1;
++}
++
++#endif                                /* _SYS_TIMEPPS_H_ */