1/*-
2 * Copyright (c) 1998-2003 Poul-Henning Kamp
3 *
4 * Please see src/share/examples/etc/bsd-style-copyright.
5 *
6 */
7
8#include <sys/cdefs.h>
9__FBSDID("$FreeBSD: stable/11/tools/test/ppsapi/ppsapitest.c 323406 2017-09-11 00:19:09Z ian $");
10
11#include <stdio.h>
12#include <stdint.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <err.h>
17#include <sys/timepps.h>
18
19static int aflag, Aflag, cflag, Cflag, eflag, uflag, vflag;
20
21static void
22Chew(struct timespec *tsa, struct timespec *tsc, unsigned sa, unsigned sc)
23{
24	printf("%jd .%09ld %u", (intmax_t)tsa->tv_sec, tsa->tv_nsec, sa);
25	printf(" %jd .%09ld %u\n", (intmax_t)tsc->tv_sec, tsc->tv_nsec, sc);
26	if (uflag)
27		fflush(stdout);
28}
29
30int
31main(int argc, char **argv)
32{
33	int fd;
34	FILE *fdo;
35	pps_info_t pi;
36	pps_params_t pp;
37	pps_handle_t ph;
38	int i, mode;
39	u_int olda, oldc;
40	struct timespec to;
41	char const *ofn;
42
43	ofn = NULL;
44	while ((i = getopt(argc, argv, "aAbBcCeo:uv")) != -1) {
45		switch (i) {
46		case 'a': aflag = 1; break;
47		case 'A': Aflag = 1; break;
48		case 'b': aflag = 1; cflag = 1; break;
49		case 'B': Aflag = 1; Cflag = 1; break;
50		case 'c': cflag = 1; break;
51		case 'C': Cflag = 1; break;
52		case 'e': eflag = 1; break;
53		case 'o': ofn = optarg; break;
54		case 'u': uflag = 1; break;
55		case 'v': vflag = 1; break;
56		case '?':
57		default:
58			fprintf(stderr,
59			    "Usage: ppsapitest [-aAcC] device\n");
60			exit (1);
61		}
62	}
63	if (ofn != NULL) {
64		fdo = fopen(ofn, "w");
65		if (fdo == NULL)
66			err(1, "Cannot open %s", ofn);
67	} else {
68		fdo = NULL;
69	}
70	argc -= optind;
71	argv += optind;
72	if (argc > 0) {
73		fd = open(argv[0], O_RDONLY);
74		if (fd < 0)
75			err(1, "%s", argv[0]);
76	} else {
77		fd = 0;
78	}
79	i = time_pps_create(fd, &ph);
80	if (i < 0)
81		err(1, "time_pps_create");
82
83	i = time_pps_getcap(ph, &mode);
84	if (i < 0)
85		err(1, "time_pps_getcap");
86	if (vflag) {
87		fprintf(stderr, "Supported modebits:");
88		if (mode & PPS_CAPTUREASSERT)
89			fprintf(stderr, " CAPTUREASSERT");
90		if (mode & PPS_CAPTURECLEAR)
91			fprintf(stderr, " CAPTURECLEAR");
92		if (mode & PPS_OFFSETASSERT)
93			fprintf(stderr, " OFFSETASSERT");
94		if (mode & PPS_OFFSETCLEAR)
95			fprintf(stderr, " OFFSETCLEAR");
96		if (mode & PPS_ECHOASSERT)
97			fprintf(stderr, " ECHOASSERT");
98		if (mode & PPS_ECHOCLEAR)
99			fprintf(stderr, " ECHOCLEAR");
100		if (mode & PPS_CANWAIT)
101			fprintf(stderr, " CANWAIT");
102		if (mode & PPS_CANPOLL)
103			fprintf(stderr, " CANPOLL");
104		if (mode & PPS_TSFMT_TSPEC)
105			fprintf(stderr, " TSPEC");
106		if (mode & PPS_TSFMT_NTPFP)
107			fprintf(stderr, " NTPFP");
108		fprintf(stderr, "\n");
109	}
110
111	if (!aflag && !cflag) {
112		if (mode & PPS_CAPTUREASSERT)
113			aflag = 1;
114		if (mode & PPS_CAPTURECLEAR)
115			cflag = 1;
116	}
117	if (!Aflag && !Cflag) {
118		Aflag = aflag;
119		Cflag = cflag;
120	}
121
122	if (Cflag && !(mode & PPS_CAPTURECLEAR))
123		errx(1, "-C but cannot capture on clear flank");
124
125	if (Aflag && !(mode & PPS_CAPTUREASSERT))
126		errx(1, "-A but cannot capture on assert flank");
127
128	i = time_pps_getparams(ph, &pp);
129	if (i < 0)
130		err(1, "time_pps_getparams():");
131
132	if (aflag)
133		pp.mode |= PPS_CAPTUREASSERT;
134	if (cflag)
135		pp.mode |= PPS_CAPTURECLEAR;
136
137	if (eflag & aflag)
138		pp.mode |= PPS_ECHOASSERT;
139
140	if (eflag & cflag)
141		pp.mode |= PPS_ECHOCLEAR;
142
143	if (!(pp.mode & PPS_TSFMT_TSPEC))
144		pp.mode |= PPS_TSFMT_TSPEC;
145
146	i = time_pps_setparams(ph, &pp);
147	if (i < 0) {
148		err(1, "time_pps_setparams(mode %x):", pp.mode);
149	}
150
151	/*
152	 * Pick up first event outside the loop in order to not
153	 * get something ancient into the outfile.
154	 */
155	to.tv_nsec = 0;
156	to.tv_sec = 0;
157	i = time_pps_fetch(ph, PPS_TSFMT_TSPEC, &pi, &to);
158	if (i < 0)
159		err(1, "time_pps_fetch()");
160	olda = pi.assert_sequence;
161	oldc = pi.clear_sequence;
162
163	while (1) {
164		to.tv_nsec = 0;
165		to.tv_sec = 0;
166		i = time_pps_fetch(ph, PPS_TSFMT_TSPEC, &pi, &to);
167		if (i < 0)
168			err(1, "time_pps_fetch()");
169		if (oldc != pi.clear_sequence && Cflag)
170			;
171		else if (olda != pi.assert_sequence && Aflag)
172			;
173		else {
174			usleep(10000);
175			continue;
176		}
177		if (fdo != NULL) {
178			if (fwrite(&pi, sizeof pi, 1, fdo) != 1)
179				err(1, "Write error on %s", ofn);
180			if (uflag)
181				fflush(fdo);
182		}
183		Chew(&pi.assert_timestamp, &pi.clear_timestamp,
184			pi.assert_sequence, pi.clear_sequence);
185		olda = pi.assert_sequence;
186		oldc = pi.clear_sequence;
187	}
188	return(0);
189}
190