1 diff --git a/Makefile b/Makefile
7 +TARGETS = ppstest ppsctl
9 +CFLAGS += -Wall -O2 -D_GNU_SOURCE
13 +# -- Actions section ----------------------------------------------------------
15 +.PHONY : all depend dep
17 +all : .depend $(TARGETS)
20 + $(CC) $(CFLAGS) -M $(TARGETS:=.c) > .depend
22 +ifeq (.depend,$(wildcard .depend))
27 +# -- Clean section ------------------------------------------------------------
32 + rm -f *.o *~ core .depend
34 diff --git a/ppsctl.c b/ppsctl.c
36 index 0000000..83fd08a
44 +#include <sys/ioctl.h>
45 +#include <sys/types.h>
46 +#include <sys/stat.h>
49 +#include <linux/serial.h>
51 +void usage(char *name)
53 + fprintf(stderr, "usage: %s <ttyS> [enable|disable]\n", name);
58 +int main(int argc, char *argv[])
62 + struct serial_struct ss;
67 + fd = open(argv[1], O_RDWR);
73 + ret = ioctl(fd, TIOCGSERIAL, &ss);
75 + perror("ioctl(TIOCGSERIAL)");
79 + if (argc < 3) { /* just read PPS status */
80 + printf("PPS is %sabled\n",
81 + ss.flags & ASYNC_HARDPPS_CD ? "en" : "dis");
85 + if (argv[2][0] == 'e' || argv[2][0] == '1')
86 + ss.flags |= ASYNC_HARDPPS_CD;
87 + else if (argv[2][0] == 'd' || argv[2][0] == '0')
88 + ss.flags &= ~ASYNC_HARDPPS_CD;
90 + fprintf(stderr, "invalid state argument \"%s\"\n", argv[2]);
94 + ret = ioctl(fd, TIOCSSERIAL, &ss);
96 + perror("ioctl(TIOCSSERIAL)");
102 diff --git a/ppsfind b/ppsfind
104 index 0000000..93c0e17
110 +SYS="/sys/class/pps/"
112 +if [ $# -lt 1 ] ; then
113 + echo "usage: ppsfind <name>" >&2
117 +for d in $(ls $SYS) ; do
118 + if grep $1 $SYS/$d/name >& /dev/null || \
119 + grep $1 $SYS/$d/path >& /dev/null ; then
120 + echo "$d: name=$(cat $SYS/$d/name) path=$(cat $SYS/$d/path)"
125 diff --git a/ppstest.c b/ppstest.c
127 index 0000000..d125ffa
136 +#include <sys/types.h>
137 +#include <sys/stat.h>
140 +#include <timepps.h>
142 +int find_source(char *path, pps_handle_t *handle, int *avail_mode)
144 + pps_params_t params;
147 + printf("trying PPS source \"%s\"\n", path);
149 + /* Try to find the source by using the supplied "path" name */
150 + ret = open(path, O_RDWR);
152 + fprintf(stderr, "unable to open device \"%s\" (%m)\n", path);
156 + /* Open the PPS source (and check the file descriptor) */
157 + ret = time_pps_create(ret, handle);
159 + fprintf(stderr, "cannot create a PPS source from device "
160 + "\"%s\" (%m)\n", path);
163 + printf("found PPS source \"%s\"\n", path);
165 + /* Find out what features are supported */
166 + ret = time_pps_getcap(*handle, avail_mode);
168 + fprintf(stderr, "cannot get capabilities (%m)\n");
171 + if ((*avail_mode & PPS_CAPTUREASSERT) == 0) {
172 + fprintf(stderr, "cannot CAPTUREASSERT\n");
175 + if ((*avail_mode & PPS_OFFSETASSERT) == 0) {
176 + fprintf(stderr, "cannot OFFSETASSERT\n");
180 + /* Capture assert timestamps, and compensate for a 675 nsec
181 + * propagation delay */
182 + ret = time_pps_getparams(*handle, ¶ms);
184 + fprintf(stderr, "cannot get parameters (%m)\n");
187 + params.assert_offset.tv_sec = 0;
188 + params.assert_offset.tv_nsec = 675;
189 + params.mode |= PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
190 + ret = time_pps_setparams(*handle, ¶ms);
192 + fprintf(stderr, "cannot set parameters (%m)\n");
199 +int fetch_source(int i, pps_handle_t *handle, int *avail_mode)
201 + struct timespec timeout;
202 + pps_info_t infobuf;
205 + /* create a zero-valued timeout */
206 + timeout.tv_sec = 3;
207 + timeout.tv_nsec = 0;
210 + if (*avail_mode & PPS_CANWAIT) /* waits for the next event */
211 + ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf,
215 + ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf,
219 + if (ret == -EINTR) {
220 + fprintf(stderr, "time_pps_fetch() got a signal!\n");
224 + fprintf(stderr, "time_pps_fetch() error %d (%m)\n", ret);
228 + printf("source %d - "
229 + "assert %ld.%09ld, sequence: %ld - "
230 + "clear %ld.%09ld, sequence: %ld\n",
232 + infobuf.assert_timestamp.tv_sec,
233 + infobuf.assert_timestamp.tv_nsec,
234 + infobuf.assert_sequence,
235 + infobuf.clear_timestamp.tv_sec,
236 + infobuf.clear_timestamp.tv_nsec, infobuf.clear_sequence);
241 +void usage(char *name)
243 + fprintf(stderr, "usage: %s <ppsdev> [<ppsdev> ...]\n", name);
244 + exit(EXIT_FAILURE);
247 +int main(int argc, char *argv[])
250 + pps_handle_t handle[4];
255 + /* Check the command line */
259 + for (i = 1; i < argc && i <= 4; i++) {
260 + ret = find_source(argv[i], &handle[i - 1], &avail_mode[i - 1]);
262 + exit(EXIT_FAILURE);
266 + printf("ok, found %d source(s), now start fetching data...\n", num);
268 + /* loop, printing the most recent timestamp every second or so */
270 + for (i = 0; i < num; i++) {
271 + ret = fetch_source(i, &handle[i], &avail_mode[i]);
272 + if (ret < 0 && errno != ETIMEDOUT)
273 + exit(EXIT_FAILURE);
277 + for (; i >= 0; i--)
278 + time_pps_destroy(handle[i]);
282 diff --git a/timepps.h b/timepps.h
284 index 0000000..28ebf4c
289 + * timepps.h -- PPS API main header
291 + * Copyright (C) 2005-2007 Rodolfo Giometti <giometti@linux.it>
293 + * This program is free software; you can redistribute it and/or modify
294 + * it under the terms of the GNU General Public License as published by
295 + * the Free Software Foundation; either version 2 of the License, or
296 + * (at your option) any later version.
298 + * This program is distributed in the hope that it will be useful,
299 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
300 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
301 + * GNU General Public License for more details.
303 + * You should have received a copy of the GNU General Public License
304 + * along with this program; if not, write to the Free Software
305 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
308 +#ifndef _SYS_TIMEPPS_H_
309 +#define _SYS_TIMEPPS_H_
311 +#include <sys/syscall.h>
314 +#include <linux/pps.h>
317 + * New data structures
321 + unsigned int integral;
322 + unsigned int fractional;
326 + struct timespec tspec;
327 + struct ntp_fp ntpfp;
328 + unsigned long longpad[3];
332 + unsigned long assert_sequence; /* seq. num. of assert event */
333 + unsigned long clear_sequence; /* seq. num. of clear event */
334 + union pps_timeu assert_tu; /* time of assert event */
335 + union pps_timeu clear_tu; /* time of clear event */
336 + int current_mode; /* current mode bits */
340 + int api_version; /* API version # */
341 + int mode; /* mode bits */
342 + union pps_timeu assert_off_tu; /* offset compensation for assert */
343 + union pps_timeu clear_off_tu; /* offset compensation for clear */
346 +typedef int pps_handle_t; /* represents a PPS source */
347 +typedef unsigned long pps_seq_t; /* sequence number */
348 +typedef struct ntp_fp ntp_fp_t; /* NTP-compatible time stamp */
349 +typedef union pps_timeu pps_timeu_t; /* generic data type for time stamps */
350 +typedef struct pps_info pps_info_t;
351 +typedef struct pps_params pps_params_t;
353 +#define assert_timestamp assert_tu.tspec
354 +#define clear_timestamp clear_tu.tspec
356 +#define assert_timestamp_ntpfp assert_tu.ntpfp
357 +#define clear_timestamp_ntpfp clear_tu.ntpfp
359 +#define assert_offset assert_off_tu.tspec
360 +#define clear_offset clear_off_tu.tspec
362 +#define assert_offset_ntpfp assert_off_tu.ntpfp
363 +#define clear_offset_ntpfp clear_off_tu.ntpfp
369 +static __inline int time_pps_create(int source, pps_handle_t *handle)
378 + /* First we check if current device is a PPS valid PPS one...
380 + ret = ioctl(source, PPS_CHECK);
382 + errno = EOPNOTSUPP;
386 + /* ... then since in LinuxPPS there are no differences between a
387 + * "PPS source" and a "PPS handle", we simply return the same value.
394 +static __inline int time_pps_destroy(pps_handle_t handle)
396 + return close(handle);
399 +static __inline int time_pps_getparams(pps_handle_t handle,
400 + pps_params_t *ppsparams)
403 + struct pps_kparams __ppsparams;
405 + ret = ioctl(handle, PPS_GETPARAMS, &__ppsparams);
407 + ppsparams->api_version = __ppsparams.api_version;
408 + ppsparams->mode = __ppsparams.mode;
409 + ppsparams->assert_off_tu.tspec.tv_sec = __ppsparams.assert_off_tu.sec;
410 + ppsparams->assert_off_tu.tspec.tv_nsec = __ppsparams.assert_off_tu.nsec;
411 + ppsparams->clear_off_tu.tspec.tv_sec = __ppsparams.clear_off_tu.sec;
412 + ppsparams->clear_off_tu.tspec.tv_nsec = __ppsparams.clear_off_tu.nsec;
417 +static __inline int time_pps_setparams(pps_handle_t handle,
418 + const pps_params_t *ppsparams)
420 + struct pps_kparams __ppsparams;
422 + __ppsparams.api_version = ppsparams->api_version;
423 + __ppsparams.mode = ppsparams->mode;
424 + __ppsparams.assert_off_tu.sec = ppsparams->assert_off_tu.tspec.tv_sec;
425 + __ppsparams.assert_off_tu.nsec = ppsparams->assert_off_tu.tspec.tv_nsec;
426 + __ppsparams.clear_off_tu.sec = ppsparams->clear_off_tu.tspec.tv_sec;
427 + __ppsparams.clear_off_tu.nsec = ppsparams->clear_off_tu.tspec.tv_nsec;
429 + return ioctl(handle, PPS_SETPARAMS, &__ppsparams);
432 +/* Get capabilities for handle */
433 +static __inline int time_pps_getcap(pps_handle_t handle, int *mode)
435 + return ioctl(handle, PPS_GETCAP, mode);
438 +static __inline int time_pps_fetch(pps_handle_t handle, const int tsformat,
439 + pps_info_t *ppsinfobuf,
440 + const struct timespec *timeout)
442 + struct pps_fdata __fdata;
445 + /* Sanity checks */
446 + if (tsformat != PPS_TSFMT_TSPEC) {
452 + __fdata.timeout.sec = timeout->tv_sec;
453 + __fdata.timeout.nsec = timeout->tv_nsec;
454 + __fdata.timeout.flags = ~PPS_TIME_INVALID;
456 + __fdata.timeout.flags = PPS_TIME_INVALID;
458 + ret = ioctl(handle, PPS_FETCH, &__fdata);
460 + ppsinfobuf->assert_sequence = __fdata.info.assert_sequence;
461 + ppsinfobuf->clear_sequence = __fdata.info.clear_sequence;
462 + ppsinfobuf->assert_tu.tspec.tv_sec = __fdata.info.assert_tu.sec;
463 + ppsinfobuf->assert_tu.tspec.tv_nsec = __fdata.info.assert_tu.nsec;
464 + ppsinfobuf->clear_tu.tspec.tv_sec = __fdata.info.clear_tu.sec;
465 + ppsinfobuf->clear_tu.tspec.tv_nsec = __fdata.info.clear_tu.nsec;
466 + ppsinfobuf->current_mode = __fdata.info.current_mode;
471 +static __inline int time_pps_kcbind(pps_handle_t handle,
472 + const int kernel_consumer,
473 + const int edge, const int tsformat)
475 + /* LinuxPPS doesn't implement kernel consumer feature */
476 + errno = EOPNOTSUPP;
480 +#endif /* _SYS_TIMEPPS_H_ */