About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog

Documentation / ptp / testptp.c




Custom Search

Based on kernel version 3.9. Page generated on 2013-05-02 23:12 EST.

1	/*
2	 * PTP 1588 clock support - User space test program
3	 *
4	 * Copyright (C) 2010 OMICRON electronics GmbH
5	 *
6	 *  This program is free software; you can redistribute it and/or modify
7	 *  it under the terms of the GNU General Public License as published by
8	 *  the Free Software Foundation; either version 2 of the License, or
9	 *  (at your option) any later version.
10	 *
11	 *  This program is distributed in the hope that it will be useful,
12	 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13	 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14	 *  GNU General Public License for more details.
15	 *
16	 *  You should have received a copy of the GNU General Public License
17	 *  along with this program; if not, write to the Free Software
18	 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19	 */
20	#include <errno.h>
21	#include <fcntl.h>
22	#include <math.h>
23	#include <signal.h>
24	#include <stdio.h>
25	#include <stdlib.h>
26	#include <string.h>
27	#include <sys/ioctl.h>
28	#include <sys/mman.h>
29	#include <sys/stat.h>
30	#include <sys/time.h>
31	#include <sys/timex.h>
32	#include <sys/types.h>
33	#include <time.h>
34	#include <unistd.h>
35	
36	#include <linux/ptp_clock.h>
37	
38	#define DEVICE "/dev/ptp0"
39	
40	#ifndef ADJ_SETOFFSET
41	#define ADJ_SETOFFSET 0x0100
42	#endif
43	
44	#ifndef CLOCK_INVALID
45	#define CLOCK_INVALID -1
46	#endif
47	
48	/* When glibc offers the syscall, this will go away. */
49	#include <sys/syscall.h>
50	static int clock_adjtime(clockid_t id, struct timex *tx)
51	{
52		return syscall(__NR_clock_adjtime, id, tx);
53	}
54	
55	static clockid_t get_clockid(int fd)
56	{
57	#define CLOCKFD 3
58	#define FD_TO_CLOCKID(fd)	((~(clockid_t) (fd) << 3) | CLOCKFD)
59	
60		return FD_TO_CLOCKID(fd);
61	}
62	
63	static void handle_alarm(int s)
64	{
65		printf("received signal %d\n", s);
66	}
67	
68	static int install_handler(int signum, void (*handler)(int))
69	{
70		struct sigaction action;
71		sigset_t mask;
72	
73		/* Unblock the signal. */
74		sigemptyset(&mask);
75		sigaddset(&mask, signum);
76		sigprocmask(SIG_UNBLOCK, &mask, NULL);
77	
78		/* Install the signal handler. */
79		action.sa_handler = handler;
80		action.sa_flags = 0;
81		sigemptyset(&action.sa_mask);
82		sigaction(signum, &action, NULL);
83	
84		return 0;
85	}
86	
87	static long ppb_to_scaled_ppm(int ppb)
88	{
89		/*
90		 * The 'freq' field in the 'struct timex' is in parts per
91		 * million, but with a 16 bit binary fractional field.
92		 * Instead of calculating either one of
93		 *
94		 *    scaled_ppm = (ppb / 1000) << 16  [1]
95		 *    scaled_ppm = (ppb << 16) / 1000  [2]
96		 *
97		 * we simply use double precision math, in order to avoid the
98		 * truncation in [1] and the possible overflow in [2].
99		 */
100		return (long) (ppb * 65.536);
101	}
102	
103	static void usage(char *progname)
104	{
105		fprintf(stderr,
106			"usage: %s [options]\n"
107			" -a val     request a one-shot alarm after 'val' seconds\n"
108			" -A val     request a periodic alarm every 'val' seconds\n"
109			" -c         query the ptp clock's capabilities\n"
110			" -d name    device to open\n"
111			" -e val     read 'val' external time stamp events\n"
112			" -f val     adjust the ptp clock frequency by 'val' ppb\n"
113			" -g         get the ptp clock time\n"
114			" -h         prints this message\n"
115			" -p val     enable output with a period of 'val' nanoseconds\n"
116			" -P val     enable or disable (val=1|0) the system clock PPS\n"
117			" -s         set the ptp clock time from the system time\n"
118			" -S         set the system time from the ptp clock time\n"
119			" -t val     shift the ptp clock time by 'val' seconds\n",
120			progname);
121	}
122	
123	int main(int argc, char *argv[])
124	{
125		struct ptp_clock_caps caps;
126		struct ptp_extts_event event;
127		struct ptp_extts_request extts_request;
128		struct ptp_perout_request perout_request;
129		struct timespec ts;
130		struct timex tx;
131	
132		static timer_t timerid;
133		struct itimerspec timeout;
134		struct sigevent sigevent;
135	
136		char *progname;
137		int c, cnt, fd;
138	
139		char *device = DEVICE;
140		clockid_t clkid;
141		int adjfreq = 0x7fffffff;
142		int adjtime = 0;
143		int capabilities = 0;
144		int extts = 0;
145		int gettime = 0;
146		int oneshot = 0;
147		int periodic = 0;
148		int perout = -1;
149		int pps = -1;
150		int settime = 0;
151	
152		progname = strrchr(argv[0], '/');
153		progname = progname ? 1+progname : argv[0];
154		while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghp:P:sSt:v"))) {
155			switch (c) {
156			case 'a':
157				oneshot = atoi(optarg);
158				break;
159			case 'A':
160				periodic = atoi(optarg);
161				break;
162			case 'c':
163				capabilities = 1;
164				break;
165			case 'd':
166				device = optarg;
167				break;
168			case 'e':
169				extts = atoi(optarg);
170				break;
171			case 'f':
172				adjfreq = atoi(optarg);
173				break;
174			case 'g':
175				gettime = 1;
176				break;
177			case 'p':
178				perout = atoi(optarg);
179				break;
180			case 'P':
181				pps = atoi(optarg);
182				break;
183			case 's':
184				settime = 1;
185				break;
186			case 'S':
187				settime = 2;
188				break;
189			case 't':
190				adjtime = atoi(optarg);
191				break;
192			case 'h':
193				usage(progname);
194				return 0;
195			case '?':
196			default:
197				usage(progname);
198				return -1;
199			}
200		}
201	
202		fd = open(device, O_RDWR);
203		if (fd < 0) {
204			fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
205			return -1;
206		}
207	
208		clkid = get_clockid(fd);
209		if (CLOCK_INVALID == clkid) {
210			fprintf(stderr, "failed to read clock id\n");
211			return -1;
212		}
213	
214		if (capabilities) {
215			if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
216				perror("PTP_CLOCK_GETCAPS");
217			} else {
218				printf("capabilities:\n"
219				       "  %d maximum frequency adjustment (ppb)\n"
220				       "  %d programmable alarms\n"
221				       "  %d external time stamp channels\n"
222				       "  %d programmable periodic signals\n"
223				       "  %d pulse per second\n",
224				       caps.max_adj,
225				       caps.n_alarm,
226				       caps.n_ext_ts,
227				       caps.n_per_out,
228				       caps.pps);
229			}
230		}
231	
232		if (0x7fffffff != adjfreq) {
233			memset(&tx, 0, sizeof(tx));
234			tx.modes = ADJ_FREQUENCY;
235			tx.freq = ppb_to_scaled_ppm(adjfreq);
236			if (clock_adjtime(clkid, &tx)) {
237				perror("clock_adjtime");
238			} else {
239				puts("frequency adjustment okay");
240			}
241		}
242	
243		if (adjtime) {
244			memset(&tx, 0, sizeof(tx));
245			tx.modes = ADJ_SETOFFSET;
246			tx.time.tv_sec = adjtime;
247			tx.time.tv_usec = 0;
248			if (clock_adjtime(clkid, &tx) < 0) {
249				perror("clock_adjtime");
250			} else {
251				puts("time shift okay");
252			}
253		}
254	
255		if (gettime) {
256			if (clock_gettime(clkid, &ts)) {
257				perror("clock_gettime");
258			} else {
259				printf("clock time: %ld.%09ld or %s",
260				       ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
261			}
262		}
263	
264		if (settime == 1) {
265			clock_gettime(CLOCK_REALTIME, &ts);
266			if (clock_settime(clkid, &ts)) {
267				perror("clock_settime");
268			} else {
269				puts("set time okay");
270			}
271		}
272	
273		if (settime == 2) {
274			clock_gettime(clkid, &ts);
275			if (clock_settime(CLOCK_REALTIME, &ts)) {
276				perror("clock_settime");
277			} else {
278				puts("set time okay");
279			}
280		}
281	
282		if (extts) {
283			memset(&extts_request, 0, sizeof(extts_request));
284			extts_request.index = 0;
285			extts_request.flags = PTP_ENABLE_FEATURE;
286			if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
287				perror("PTP_EXTTS_REQUEST");
288				extts = 0;
289			} else {
290				puts("external time stamp request okay");
291			}
292			for (; extts; extts--) {
293				cnt = read(fd, &event, sizeof(event));
294				if (cnt != sizeof(event)) {
295					perror("read");
296					break;
297				}
298				printf("event index %u at %lld.%09u\n", event.index,
299				       event.t.sec, event.t.nsec);
300				fflush(stdout);
301			}
302			/* Disable the feature again. */
303			extts_request.flags = 0;
304			if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
305				perror("PTP_EXTTS_REQUEST");
306			}
307		}
308	
309		if (oneshot) {
310			install_handler(SIGALRM, handle_alarm);
311			/* Create a timer. */
312			sigevent.sigev_notify = SIGEV_SIGNAL;
313			sigevent.sigev_signo = SIGALRM;
314			if (timer_create(clkid, &sigevent, &timerid)) {
315				perror("timer_create");
316				return -1;
317			}
318			/* Start the timer. */
319			memset(&timeout, 0, sizeof(timeout));
320			timeout.it_value.tv_sec = oneshot;
321			if (timer_settime(timerid, 0, &timeout, NULL)) {
322				perror("timer_settime");
323				return -1;
324			}
325			pause();
326			timer_delete(timerid);
327		}
328	
329		if (periodic) {
330			install_handler(SIGALRM, handle_alarm);
331			/* Create a timer. */
332			sigevent.sigev_notify = SIGEV_SIGNAL;
333			sigevent.sigev_signo = SIGALRM;
334			if (timer_create(clkid, &sigevent, &timerid)) {
335				perror("timer_create");
336				return -1;
337			}
338			/* Start the timer. */
339			memset(&timeout, 0, sizeof(timeout));
340			timeout.it_interval.tv_sec = periodic;
341			timeout.it_value.tv_sec = periodic;
342			if (timer_settime(timerid, 0, &timeout, NULL)) {
343				perror("timer_settime");
344				return -1;
345			}
346			while (1) {
347				pause();
348			}
349			timer_delete(timerid);
350		}
351	
352		if (perout >= 0) {
353			if (clock_gettime(clkid, &ts)) {
354				perror("clock_gettime");
355				return -1;
356			}
357			memset(&perout_request, 0, sizeof(perout_request));
358			perout_request.index = 0;
359			perout_request.start.sec = ts.tv_sec + 2;
360			perout_request.start.nsec = 0;
361			perout_request.period.sec = 0;
362			perout_request.period.nsec = perout;
363			if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
364				perror("PTP_PEROUT_REQUEST");
365			} else {
366				puts("periodic output request okay");
367			}
368		}
369	
370		if (pps != -1) {
371			int enable = pps ? 1 : 0;
372			if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
373				perror("PTP_ENABLE_PPS");
374			} else {
375				puts("pps for system time request okay");
376			}
377		}
378	
379		close(fd);
380		return 0;
381	}
Hide Line Numbers
About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog

Information is copyright its respective author. All material is available from the Linux Kernel Source distributed under a GPL License. This page is provided as a free service by mjmwired.net.