]> git.ipfire.org Git - thirdparty/chrony.git/blob - refclock_pps.c
conf: rework allow/deny parser
[thirdparty/chrony.git] / refclock_pps.c
1 /*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
5 * Copyright (C) Miroslav Lichvar 2009
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 **********************************************************************
21
22 =======================================================================
23
24 PPSAPI refclock driver.
25
26 */
27
28 #include "config.h"
29
30 #include "refclock.h"
31
32 #if FEAT_PPS
33
34 #if defined(HAVE_SYS_TIMEPPS_H)
35 #include <sys/timepps.h>
36 #elif defined(HAVE_TIMEPPS_H)
37 #include <timepps.h>
38 #endif
39
40 #include "logging.h"
41 #include "memory.h"
42 #include "util.h"
43
44 struct pps_instance {
45 pps_handle_t handle;
46 pps_seq_t last_seq;
47 int edge_clear;
48 };
49
50 static int pps_initialise(RCL_Instance instance) {
51 const char *options[] = {"clear", NULL};
52 pps_handle_t handle;
53 pps_params_t params;
54 struct pps_instance *pps;
55 int fd, edge_clear, mode;
56 char *path;
57
58 RCL_CheckDriverOptions(instance, options);
59
60 path = RCL_GetDriverParameter(instance);
61 edge_clear = RCL_GetDriverOption(instance, "clear") ? 1 : 0;
62
63 fd = open(path, O_RDWR);
64 if (fd < 0)
65 LOG_FATAL("Could not open %s : %s", path, strerror(errno));
66
67 UTI_FdSetCloexec(fd);
68
69 if (time_pps_create(fd, &handle) < 0)
70 LOG_FATAL("time_pps_create() failed on %s : %s", path, strerror(errno));
71
72 if (time_pps_getcap(handle, &mode) < 0)
73 LOG_FATAL("time_pps_getcap() failed on %s : %s", path, strerror(errno));
74
75 if (time_pps_getparams(handle, &params) < 0)
76 LOG_FATAL("time_pps_getparams() failed on %s : %s", path, strerror(errno));
77
78 if (!edge_clear) {
79 if (!(mode & PPS_CAPTUREASSERT))
80 LOG_FATAL("CAPTUREASSERT not supported on %s", path);
81
82 params.mode |= PPS_CAPTUREASSERT;
83 params.mode &= ~PPS_CAPTURECLEAR;
84 } else {
85 if (!(mode & PPS_CAPTURECLEAR))
86 LOG_FATAL("CAPTURECLEAR not supported on %s", path);
87
88 params.mode |= PPS_CAPTURECLEAR;
89 params.mode &= ~PPS_CAPTUREASSERT;
90 }
91
92 if (time_pps_setparams(handle, &params) < 0)
93 LOG_FATAL("time_pps_setparams() failed on %s : %s", path, strerror(errno));
94
95 pps = MallocNew(struct pps_instance);
96 pps->handle = handle;
97 pps->last_seq = 0;
98 pps->edge_clear = edge_clear;
99
100 RCL_SetDriverData(instance, pps);
101 return 1;
102 }
103
104 static void pps_finalise(RCL_Instance instance)
105 {
106 struct pps_instance *pps;
107
108 pps = (struct pps_instance *)RCL_GetDriverData(instance);
109 time_pps_destroy(pps->handle);
110 Free(pps);
111 }
112
113 static int pps_poll(RCL_Instance instance)
114 {
115 struct pps_instance *pps;
116 struct timespec ts;
117 pps_info_t pps_info;
118 pps_seq_t seq;
119
120 pps = (struct pps_instance *)RCL_GetDriverData(instance);
121
122 ts.tv_sec = 0;
123 ts.tv_nsec = 0;
124
125 if (time_pps_fetch(pps->handle, PPS_TSFMT_TSPEC, &pps_info, &ts) < 0) {
126 LOG(LOGS_ERR, "time_pps_fetch() failed : %s", strerror(errno));
127 return 0;
128 }
129
130 if (!pps->edge_clear) {
131 seq = pps_info.assert_sequence;
132 ts = pps_info.assert_timestamp;
133 } else {
134 seq = pps_info.clear_sequence;
135 ts = pps_info.clear_timestamp;
136 }
137
138 if (seq == pps->last_seq || UTI_IsZeroTimespec(&ts)) {
139 DEBUG_LOG("PPS sample ignored seq=%lu ts=%s",
140 (unsigned long)seq, UTI_TimespecToString(&ts));
141 return 0;
142 }
143
144 pps->last_seq = seq;
145
146 return RCL_AddPulse(instance, &ts, 1.0e-9 * ts.tv_nsec);
147 }
148
149 RefclockDriver RCL_PPS_driver = {
150 pps_initialise,
151 pps_finalise,
152 pps_poll
153 };
154
155 #else
156
157 RefclockDriver RCL_PPS_driver = { NULL, NULL, NULL };
158
159 #endif