From 64d164befc03a7277ee6df5010d649fdecc7182e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 19 Mar 2008 08:03:21 +0000 Subject: [PATCH] This patch contains a package with two PPS-tools and a header file, i extracted from http://wiki.enneenne.com/index.php/LinuxPPS_support. Signed-off-by: Frithjof Hammer SVN-Revision: 10620 --- utils/pps-tools/Makefile | 49 +++ utils/pps-tools/patches/001-source.patch | 480 +++++++++++++++++++++++ 2 files changed, 529 insertions(+) create mode 100644 utils/pps-tools/Makefile create mode 100644 utils/pps-tools/patches/001-source.patch diff --git a/utils/pps-tools/Makefile b/utils/pps-tools/Makefile new file mode 100644 index 0000000000..3176776963 --- /dev/null +++ b/utils/pps-tools/Makefile @@ -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 index 0000000000..67074789e7 --- /dev/null +++ b/utils/pps-tools/patches/001-source.patch @@ -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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void usage(char *name) ++{ ++ fprintf(stderr, "usage: %s [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 " >&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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++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, ¶ms); ++ 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, ¶ms); ++ 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 [ ...]\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 ++ * ++ * 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 ++#include ++#include ++#include ++ ++/* ++ * 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_ */ -- 2.30.2