Deleted Added
full compact
ntp_refclock.c (302408) ntp_refclock.c (54359)
1/*
2 * ntp_refclock - processing support for reference clocks
3 */
4#ifdef HAVE_CONFIG_H
5# include <config.h>
6#endif
7
1/*
2 * ntp_refclock - processing support for reference clocks
3 */
4#ifdef HAVE_CONFIG_H
5# include <config.h>
6#endif
7
8#include <stdio.h>
9#include <sys/types.h>
10#ifdef HAVE_SYS_IOCTL_H
11# include <sys/ioctl.h>
12#endif /* HAVE_SYS_IOCTL_H */
13
8#include "ntpd.h"
9#include "ntp_io.h"
10#include "ntp_unixtime.h"
14#include "ntpd.h"
15#include "ntp_io.h"
16#include "ntp_unixtime.h"
11#include "ntp_tty.h"
12#include "ntp_refclock.h"
13#include "ntp_stdlib.h"
17#include "ntp_refclock.h"
18#include "ntp_stdlib.h"
14#include "ntp_assert.h"
15
19
16#include <stdio.h>
17
18#ifdef HAVE_SYS_IOCTL_H
19# include <sys/ioctl.h>
20#endif /* HAVE_SYS_IOCTL_H */
21
22#ifdef REFCLOCK
23
20#ifdef REFCLOCK
21
24#ifdef KERNEL_PLL
25#include "ntp_syscall.h"
26#endif /* KERNEL_PLL */
22#ifdef TTYCLK
23# ifdef SCO5_CLOCK
24# include <sys/sio.h>
25# else
26# include <sys/clkdefs.h>
27# endif
28#endif /* TTYCLK */
27
29
30#ifdef HAVE_PPSCLOCK_H
31#include <sys/ppsclock.h>
32#endif /* HAVE_PPSCLOCK_H */
33
28#ifdef HAVE_PPSAPI
34#ifdef HAVE_PPSAPI
29#include "ppsapi_timepps.h"
30#include "refclock_atom.h"
35#include <sys/timepps.h>
31#endif /* HAVE_PPSAPI */
32
33/*
34 * Reference clock support is provided here by maintaining the fiction
36#endif /* HAVE_PPSAPI */
37
38/*
39 * Reference clock support is provided here by maintaining the fiction
35 * that the clock is actually a peer. As no packets are exchanged with
36 * a reference clock, however, we replace the transmit, receive and
37 * packet procedures with separate code to simulate them. Routines
40 * that the clock is actually a peer. As no packets are exchanged with a
41 * reference clock, however, we replace the transmit, receive and packet
42 * procedures with separate code to simulate them. Routines
38 * refclock_transmit() and refclock_receive() maintain the peer
39 * variables in a state analogous to an actual peer and pass reference
43 * refclock_transmit() and refclock_receive() maintain the peer
44 * variables in a state analogous to an actual peer and pass reference
40 * clock data on through the filters. Routines refclock_peer() and
45 * clock data on through the filters. Routines refclock_peer() and
41 * refclock_unpeer() are called to initialize and terminate reference
46 * refclock_unpeer() are called to initialize and terminate reference
42 * clock associations. A set of utility routines is included to open
43 * serial devices, process sample data, and to perform various debugging
44 * functions.
47 * clock associations. A set of utility routines is included to open
48 * serial devices, process sample data, edit input lines to extract
49 * embedded timestamps and to peform various debugging functions.
45 *
46 * The main interface used by these routines is the refclockproc
50 *
51 * The main interface used by these routines is the refclockproc
47 * structure, which contains for most drivers the decimal equivalants
48 * of the year, day, month, hour, second and millisecond/microsecond
49 * decoded from the ASCII timecode. Additional information includes
50 * the receive timestamp, exception report, statistics tallies, etc.
51 * In addition, there may be a driver-specific unit structure used for
52 * structure, which contains for most drivers the decimal equivalants of
53 * the year, day, month, hour, second and millisecond/microsecond
54 * decoded from the ASCII timecode. Additional information includes the
55 * receive timestamp, exception report, statistics tallies, etc. In
56 * addition, there may be a driver-specific unit structure used for
52 * local control of the device.
53 *
54 * The support routines are passed a pointer to the peer structure,
57 * local control of the device.
58 *
59 * The support routines are passed a pointer to the peer structure,
55 * which is used for all peer-specific processing and contains a
56 * pointer to the refclockproc structure, which in turn contains a
57 * pointer to the unit structure, if used. The peer structure is
58 * identified by an interface address in the dotted quad form
59 * 127.127.t.u, where t is the clock type and u the unit.
60 * which is used for all peer-specific processing and contains a pointer
61 * to the refclockproc structure, which in turn containes a pointer to
62 * the unit structure, if used. The peer structure is identified by an
63 * interface address in the dotted quad form 127.127.t.u, where t is the
64 * clock type and u the unit. Some legacy drivers derive the
65 * refclockproc structure pointer from the table typeunit[type][unit].
66 * This interface is strongly discouraged and may be abandoned in
67 * future.
68 *
69 * The routines include support for the 1-pps signal provided by some
70 * radios and connected via a level converted described in the gadget
71 * directory. The signal is captured using a serial port and one of
72 * three STREAMS modules described in the refclock_atom.c file. For the
73 * highest precision, the signal is captured using the carrier-detect
74 * line of a serial port and either the ppsclock or ppsapi streams
75 * module or some devilish ioctl() folks keep slipping in as a patch. Be
76 * advised ALL support for other than the duly standardized ppsapi
77 * interface will eventually be withdrawn.
60 */
78 */
79#define MAXUNIT 4 /* max units */
80
81#if defined(PPS) || defined(HAVE_PPSAPI)
82int fdpps; /* pps file descriptor */
83#endif /* PPS HAVE_PPSAPI */
84
61#define FUDGEFAC .1 /* fudge correction factor */
85#define FUDGEFAC .1 /* fudge correction factor */
62#define LF 0x0a /* ASCII LF */
63
86
64int cal_enable; /* enable refclock calibrate */
87/*
88 * Type/unit peer index. Used to find the peer structure for control and
89 * debugging. When all clock drivers have been converted to new style,
90 * this dissapears.
91 */
92static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT];
65
66/*
67 * Forward declarations
68 */
93
94/*
95 * Forward declarations
96 */
69static int refclock_cmpl_fp (const void *, const void *);
70static int refclock_sample (struct refclockproc *);
71static int refclock_ioctl(int, u_int);
97#ifdef QSORT_USES_VOID_P
98static int refclock_cmpl_fp P((const void *, const void *));
99#else
100static int refclock_cmpl_fp P((const double *, const double *));
101#endif /* QSORT_USES_VOID_P */
102static int refclock_sample P((struct refclockproc *));
72
103
104#ifdef HAVE_PPSAPI
105extern int pps_assert; /* capture edge 1:assert, 0:clear */
106extern int pps_hardpps; /* PPS kernel 1:on, 0:off */
107#endif /* HAVE_PPSAPI */
73
74/*
75 * refclock_report - note the occurance of an event
76 *
77 * This routine presently just remembers the report and logs it, but
78 * does nothing heroic for the trap handler. It tries to be a good
79 * citizen and bothers the system log only if things change.
80 */
81void
82refclock_report(
83 struct peer *peer,
84 int code
85 )
86{
87 struct refclockproc *pp;
88
108
109/*
110 * refclock_report - note the occurance of an event
111 *
112 * This routine presently just remembers the report and logs it, but
113 * does nothing heroic for the trap handler. It tries to be a good
114 * citizen and bothers the system log only if things change.
115 */
116void
117refclock_report(
118 struct peer *peer,
119 int code
120 )
121{
122 struct refclockproc *pp;
123
89 pp = peer->procptr;
90 if (pp == NULL)
124 if (!(pp = peer->procptr))
91 return;
125 return;
92
93 switch (code) {
94
95 case CEVNT_TIMEOUT:
96 pp->noreply++;
97 break;
98
99 case CEVNT_BADREPLY:
126 if (code == CEVNT_BADREPLY)
100 pp->badformat++;
127 pp->badformat++;
101 break;
102
103 case CEVNT_FAULT:
104 break;
105
106 case CEVNT_BADDATE:
107 case CEVNT_BADTIME:
128 if (code == CEVNT_BADTIME)
108 pp->baddata++;
129 pp->baddata++;
109 break;
110
111 default:
112 /* ignore others */
113 break;
114 }
115 if (pp->lastevent < 15)
116 pp->lastevent++;
130 if (code == CEVNT_TIMEOUT)
131 pp->noreply++;
117 if (pp->currentstatus != code) {
132 if (pp->currentstatus != code) {
118 pp->currentstatus = (u_char)code;
119 report_event(PEVNT_CLOCK, peer, ceventstr(code));
133 pp->currentstatus = code;
134 pp->lastevent = code;
135 if (code == CEVNT_FAULT)
136 msyslog(LOG_ERR,
137 "clock %s event '%s' (0x%02x)",
138 refnumtoa(peer->srcadr.sin_addr.s_addr),
139 ceventstr(code), code);
140 else {
141 NLOG(NLOG_CLOCKEVENT)
142 msyslog(LOG_INFO,
143 "clock %s event '%s' (0x%02x)",
144 refnumtoa(peer->srcadr.sin_addr.s_addr),
145 ceventstr(code), code);
146 }
120 }
147 }
148#ifdef DEBUG
149 if (debug)
150 printf("clock %s event '%s' (0x%02x)\n",
151 refnumtoa(peer->srcadr.sin_addr.s_addr),
152 ceventstr(code), code);
153#endif
121}
122
123
124/*
125 * init_refclock - initialize the reference clock drivers
126 *
127 * This routine calls each of the drivers in turn to initialize internal
128 * variables, if necessary. Most drivers have nothing to say at this
129 * point.
130 */
131void
132init_refclock(void)
133{
154}
155
156
157/*
158 * init_refclock - initialize the reference clock drivers
159 *
160 * This routine calls each of the drivers in turn to initialize internal
161 * variables, if necessary. Most drivers have nothing to say at this
162 * point.
163 */
164void
165init_refclock(void)
166{
134 int i;
167 int i, j;
135
168
136 for (i = 0; i < (int)num_refclock_conf; i++)
169 for (i = 0; i < (int)num_refclock_conf; i++) {
137 if (refclock_conf[i]->clock_init != noentry)
138 (refclock_conf[i]->clock_init)();
170 if (refclock_conf[i]->clock_init != noentry)
171 (refclock_conf[i]->clock_init)();
172 for (j = 0; j < MAXUNIT; j++)
173 typeunit[i][j] = 0;
174 }
139}
140
141
142/*
143 * refclock_newpeer - initialize and start a reference clock
144 *
145 * This routine allocates and initializes the interface structure which
146 * supports a reference clock in the form of an ordinary NTP peer. A

--- 15 unchanged lines hidden (view full) ---

162
163 /*
164 * Check for valid clock address. If already running, shut it
165 * down first.
166 */
167 if (!ISREFCLOCKADR(&peer->srcadr)) {
168 msyslog(LOG_ERR,
169 "refclock_newpeer: clock address %s invalid",
175}
176
177
178/*
179 * refclock_newpeer - initialize and start a reference clock
180 *
181 * This routine allocates and initializes the interface structure which
182 * supports a reference clock in the form of an ordinary NTP peer. A

--- 15 unchanged lines hidden (view full) ---

198
199 /*
200 * Check for valid clock address. If already running, shut it
201 * down first.
202 */
203 if (!ISREFCLOCKADR(&peer->srcadr)) {
204 msyslog(LOG_ERR,
205 "refclock_newpeer: clock address %s invalid",
170 stoa(&peer->srcadr));
206 ntoa(&peer->srcadr));
171 return (0);
172 }
173 clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
174 unit = REFCLOCKUNIT(&peer->srcadr);
207 return (0);
208 }
209 clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
210 unit = REFCLOCKUNIT(&peer->srcadr);
175 if (clktype >= num_refclock_conf ||
211 if (clktype >= num_refclock_conf || unit >= MAXUNIT ||
176 refclock_conf[clktype]->clock_start == noentry) {
177 msyslog(LOG_ERR,
178 "refclock_newpeer: clock type %d invalid\n",
179 clktype);
180 return (0);
181 }
212 refclock_conf[clktype]->clock_start == noentry) {
213 msyslog(LOG_ERR,
214 "refclock_newpeer: clock type %d invalid\n",
215 clktype);
216 return (0);
217 }
218 refclock_unpeer(peer);
182
183 /*
184 * Allocate and initialize interface structure
185 */
219
220 /*
221 * Allocate and initialize interface structure
222 */
186 pp = emalloc_zero(sizeof(*pp));
223 if (!(pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc))))
224 return (0);
225 memset((char *)pp, 0, sizeof(struct refclockproc));
226 typeunit[clktype][unit] = peer;
187 peer->procptr = pp;
188
189 /*
190 * Initialize structures
191 */
192 peer->refclktype = clktype;
227 peer->procptr = pp;
228
229 /*
230 * Initialize structures
231 */
232 peer->refclktype = clktype;
193 peer->refclkunit = (u_char)unit;
233 peer->refclkunit = unit;
194 peer->flags |= FLAG_REFCLOCK;
234 peer->flags |= FLAG_REFCLOCK;
195 peer->leap = LEAP_NOTINSYNC;
196 peer->stratum = STRATUM_REFCLOCK;
235 peer->stratum = STRATUM_REFCLOCK;
197 peer->ppoll = peer->maxpoll;
236 peer->refid = peer->srcadr.sin_addr.s_addr;
237 peer->maxpoll = peer->minpoll;
238
198 pp->type = clktype;
239 pp->type = clktype;
199 pp->conf = refclock_conf[clktype];
200 pp->timestarted = current_time;
240 pp->timestarted = current_time;
201 pp->io.fd = -1;
202
203 /*
241
242 /*
243 * If the interface has been set to any_interface, set it to the
244 * loopback address if we have one. This is so that peers which
245 * are unreachable are easy to see in the peer display.
246 */
247 if (peer->dstadr == any_interface && loopback_interface != 0)
248 peer->dstadr = loopback_interface;
249
250 /*
204 * Set peer.pmode based on the hmode. For appearances only.
205 */
206 switch (peer->hmode) {
251 * Set peer.pmode based on the hmode. For appearances only.
252 */
253 switch (peer->hmode) {
207 case MODE_ACTIVE:
254
255 case MODE_ACTIVE:
208 peer->pmode = MODE_PASSIVE;
209 break;
210
256 peer->pmode = MODE_PASSIVE;
257 break;
258
211 default:
259 default:
212 peer->pmode = MODE_SERVER;
213 break;
214 }
215
216 /*
217 * Do driver dependent initialization. The above defaults
218 * can be wiggled, then finish up for consistency.
219 */
220 if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {
260 peer->pmode = MODE_SERVER;
261 break;
262 }
263
264 /*
265 * Do driver dependent initialization. The above defaults
266 * can be wiggled, then finish up for consistency.
267 */
268 if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {
221 refclock_unpeer(peer);
269 free(pp);
222 return (0);
223 }
270 return (0);
271 }
224 peer->refid = pp->refid;
272 peer->hpoll = peer->minpoll;
273 peer->ppoll = peer->maxpoll;
274 if (peer->stratum <= 1)
275 peer->refid = pp->refid;
276 else
277 peer->refid = peer->srcadr.sin_addr.s_addr;
225 return (1);
226}
227
228
229/*
230 * refclock_unpeer - shut down a clock
231 */
232void
233refclock_unpeer(
234 struct peer *peer /* peer structure pointer */
235 )
236{
237 u_char clktype;
238 int unit;
239
240 /*
241 * Wiggle the driver to release its resources, then give back
242 * the interface structure.
243 */
278 return (1);
279}
280
281
282/*
283 * refclock_unpeer - shut down a clock
284 */
285void
286refclock_unpeer(
287 struct peer *peer /* peer structure pointer */
288 )
289{
290 u_char clktype;
291 int unit;
292
293 /*
294 * Wiggle the driver to release its resources, then give back
295 * the interface structure.
296 */
244 if (NULL == peer->procptr)
297 if (!peer->procptr)
245 return;
298 return;
246
247 clktype = peer->refclktype;
248 unit = peer->refclkunit;
249 if (refclock_conf[clktype]->clock_shutdown != noentry)
250 (refclock_conf[clktype]->clock_shutdown)(unit, peer);
251 free(peer->procptr);
299 clktype = peer->refclktype;
300 unit = peer->refclkunit;
301 if (refclock_conf[clktype]->clock_shutdown != noentry)
302 (refclock_conf[clktype]->clock_shutdown)(unit, peer);
303 free(peer->procptr);
252 peer->procptr = NULL;
304 peer->procptr = 0;
253}
254
255
256/*
305}
306
307
308/*
257 * refclock_timer - called once per second for housekeeping.
258 */
259void
260refclock_timer(
261 struct peer *p
262 )
263{
264 struct refclockproc * pp;
265 int unit;
266
267 unit = p->refclkunit;
268 pp = p->procptr;
269 if (pp->conf->clock_timer != noentry)
270 (*pp->conf->clock_timer)(unit, p);
271 if (pp->action != NULL && pp->nextaction <= current_time)
272 (*pp->action)(p);
273}
274
275
276/*
277 * refclock_transmit - simulate the transmit procedure
278 *
279 * This routine implements the NTP transmit procedure for a reference
280 * clock. This provides a mechanism to call the driver at the NTP poll
281 * interval, as well as provides a reachability mechanism to detect a
282 * broken radio or other madness.
283 */
284void
285refclock_transmit(
286 struct peer *peer /* peer structure pointer */
287 )
288{
289 u_char clktype;
290 int unit;
309 * refclock_transmit - simulate the transmit procedure
310 *
311 * This routine implements the NTP transmit procedure for a reference
312 * clock. This provides a mechanism to call the driver at the NTP poll
313 * interval, as well as provides a reachability mechanism to detect a
314 * broken radio or other madness.
315 */
316void
317refclock_transmit(
318 struct peer *peer /* peer structure pointer */
319 )
320{
321 u_char clktype;
322 int unit;
323 int hpoll;
324 u_long next;
291
292 clktype = peer->refclktype;
293 unit = peer->refclkunit;
294 peer->sent++;
325
326 clktype = peer->refclktype;
327 unit = peer->refclkunit;
328 peer->sent++;
295 get_systime(&peer->xmt);
296
297 /*
298 * This is a ripoff of the peer transmit routine, but
299 * specialized for reference clocks. We do a little less
300 * protocol here and call the driver-specific transmit routine.
301 */
329
330 /*
331 * This is a ripoff of the peer transmit routine, but
332 * specialized for reference clocks. We do a little less
333 * protocol here and call the driver-specific transmit routine.
334 */
335 hpoll = peer->hpoll;
336 next = peer->outdate;
302 if (peer->burst == 0) {
303 u_char oreach;
304#ifdef DEBUG
305 if (debug)
306 printf("refclock_transmit: at %ld %s\n",
337 if (peer->burst == 0) {
338 u_char oreach;
339#ifdef DEBUG
340 if (debug)
341 printf("refclock_transmit: at %ld %s\n",
307 current_time, stoa(&(peer->srcadr)));
342 current_time, ntoa(&(peer->srcadr)));
308#endif
309
310 /*
311 * Update reachability and poll variables like the
312 * network code.
313 */
343#endif
344
345 /*
346 * Update reachability and poll variables like the
347 * network code.
348 */
314 oreach = peer->reach & 0xfe;
315 peer->reach <<= 1;
316 if (!(peer->reach & 0x0f))
317 clock_filter(peer, 0., 0., MAXDISPERSE);
318 peer->outdate = current_time;
319 if (!peer->reach) {
320 if (oreach) {
321 report_event(PEVNT_UNREACH, peer, NULL);
349 oreach = peer->reach;
350 if (oreach & 0x01)
351 peer->valid++;
352 if (oreach & 0x80)
353 peer->valid--;
354 peer->reach <<= 1;
355 if (peer->reach == 0) {
356 if (oreach != 0) {
357 report_event(EVNT_UNREACH, peer);
322 peer->timereachable = current_time;
358 peer->timereachable = current_time;
359 peer_clear(peer);
323 }
324 } else {
360 }
361 } else {
362 if ((oreach & 0x03) == 0) {
363 clock_filter(peer, 0., 0., MAXDISPERSE);
364 clock_select();
365 }
366 if (peer->valid <= 2) {
367 hpoll--;
368 } else if (peer->valid > NTP_SHIFT - 2)
369 hpoll++;
325 if (peer->flags & FLAG_BURST)
326 peer->burst = NSTAGE;
327 }
370 if (peer->flags & FLAG_BURST)
371 peer->burst = NSTAGE;
372 }
328 } else {
329 peer->burst--;
373 next = current_time;
330 }
374 }
375 get_systime(&peer->xmt);
331 if (refclock_conf[clktype]->clock_poll != noentry)
332 (refclock_conf[clktype]->clock_poll)(unit, peer);
376 if (refclock_conf[clktype]->clock_poll != noentry)
377 (refclock_conf[clktype]->clock_poll)(unit, peer);
333 poll_update(peer, peer->hpoll);
378 peer->outdate = next;
379 poll_update(peer, hpoll);
380 if (peer->burst > 0)
381 peer->burst--;
382 poll_update(peer, hpoll);
334}
335
336
337/*
338 * Compare two doubles - used with qsort()
339 */
383}
384
385
386/*
387 * Compare two doubles - used with qsort()
388 */
389#ifdef QSORT_USES_VOID_P
340static int
341refclock_cmpl_fp(
342 const void *p1,
343 const void *p2
344 )
345{
346 const double *dp1 = (const double *)p1;
347 const double *dp2 = (const double *)p2;
348
349 if (*dp1 < *dp2)
390static int
391refclock_cmpl_fp(
392 const void *p1,
393 const void *p2
394 )
395{
396 const double *dp1 = (const double *)p1;
397 const double *dp2 = (const double *)p2;
398
399 if (*dp1 < *dp2)
350 return -1;
400 return (-1);
351 if (*dp1 > *dp2)
401 if (*dp1 > *dp2)
352 return 1;
353 return 0;
402 return (1);
403 return (0);
354}
404}
405#else
406static int
407refclock_cmpl_fp(
408 const double *dp1,
409 const double *dp2
410 )
411{
412 if (*dp1 < *dp2)
413 return (-1);
414 if (*dp1 > *dp2)
415 return (1);
416 return (0);
417}
418#endif /* QSORT_USES_VOID_P */
355
356
357/*
358 * refclock_process_offset - update median filter
359 *
419
420
421/*
422 * refclock_process_offset - update median filter
423 *
360 * This routine uses the given offset and timestamps to construct a new
361 * entry in the median filter circular buffer. Samples that overflow the
362 * filter are quietly discarded.
424 * This routine uses the given offset and timestamps to construct a new entry in the median filter circular buffer. Samples that overflow the filter are quietly discarded.
363 */
364void
365refclock_process_offset(
425 */
426void
427refclock_process_offset(
366 struct refclockproc *pp, /* refclock structure pointer */
367 l_fp lasttim, /* last timecode timestamp */
368 l_fp lastrec, /* last receive timestamp */
428 struct refclockproc *pp,
429 l_fp offset,
430 l_fp lastrec,
369 double fudge
370 )
371{
431 double fudge
432 )
433{
372 l_fp lftemp;
373 double doffset;
374
434 double doffset;
435
436 pp->lastref = offset;
375 pp->lastrec = lastrec;
437 pp->lastrec = lastrec;
376 lftemp = lasttim;
377 L_SUB(&lftemp, &lastrec);
378 LFPTOD(&lftemp, doffset);
438 pp->variance = 0;
439 L_SUB(&offset, &lastrec);
440 LFPTOD(&offset, doffset);
379 SAMPLE(doffset + fudge);
380}
381
441 SAMPLE(doffset + fudge);
442}
443
382
383/*
384 * refclock_process - process a sample from the clock
444/*
445 * refclock_process - process a sample from the clock
385 * refclock_process_f - refclock_process with other than time1 fudge
386 *
387 * This routine converts the timecode in the form days, hours, minutes,
388 * seconds and milliseconds/microseconds to internal timestamp format,
389 * then constructs a new entry in the median filter circular buffer.
390 * Return success (1) if the data are correct and consistent with the
391 * converntional calendar.
446 *
447 * This routine converts the timecode in the form days, hours, minutes,
448 * seconds and milliseconds/microseconds to internal timestamp format,
449 * then constructs a new entry in the median filter circular buffer.
450 * Return success (1) if the data are correct and consistent with the
451 * converntional calendar.
392 *
393 * Important for PPS users: Normally, the pp->lastrec is set to the
394 * system time when the on-time character is received and the pp->year,
395 * ..., pp->second decoded and the seconds fraction pp->nsec in
396 * nanoseconds). When a PPS offset is available, pp->nsec is forced to
397 * zero and the fraction for pp->lastrec is set to the PPS offset.
398 */
452*/
399int
453int
400refclock_process_f(
401 struct refclockproc *pp, /* refclock structure pointer */
402 double fudge
454refclock_process(
455 struct refclockproc *pp
403 )
404{
456 )
457{
405 l_fp offset, ltemp;
458 l_fp offset;
406
407 /*
408 * Compute the timecode timestamp from the days, hours, minutes,
409 * seconds and milliseconds/microseconds of the timecode. Use
410 * clocktime() for the aggregate seconds and the msec/usec for
411 * the fraction, when present. Note that this code relies on the
412 * filesystem time for the years and does not use the years of
413 * the timecode.
414 */
415 if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
416 pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui))
417 return (0);
459
460 /*
461 * Compute the timecode timestamp from the days, hours, minutes,
462 * seconds and milliseconds/microseconds of the timecode. Use
463 * clocktime() for the aggregate seconds and the msec/usec for
464 * the fraction, when present. Note that this code relies on the
465 * filesystem time for the years and does not use the years of
466 * the timecode.
467 */
468 if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
469 pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui))
470 return (0);
418
419 offset.l_uf = 0;
420 DTOLFP(pp->nsec / 1e9, &ltemp);
421 L_ADD(&offset, &ltemp);
422 refclock_process_offset(pp, offset, pp->lastrec, fudge);
471 if (pp->usec) {
472 TVUTOTSF(pp->usec, offset.l_uf);
473 } else {
474 MSUTOTSF(pp->msec, offset.l_uf);
475 }
476 refclock_process_offset(pp, offset, pp->lastrec,
477 pp->fudgetime1);
423 return (1);
424}
425
478 return (1);
479}
480
426
427int
428refclock_process(
429 struct refclockproc *pp /* refclock structure pointer */
430)
431{
432 return refclock_process_f(pp, pp->fudgetime1);
433}
434
435
436/*
437 * refclock_sample - process a pile of samples from the clock
438 *
439 * This routine implements a recursive median filter to suppress spikes
440 * in the data, as well as determine a performance statistic. It
481/*
482 * refclock_sample - process a pile of samples from the clock
483 *
484 * This routine implements a recursive median filter to suppress spikes
485 * in the data, as well as determine a performance statistic. It
441 * calculates the mean offset and RMS jitter. A time adjustment
442 * fudgetime1 can be added to the final offset to compensate for various
443 * systematic errors. The routine returns the number of samples
444 * processed, which could be zero.
486 * calculates the mean offset and mean-square variance. A time
487 * adjustment fudgetime1 can be added to the final offset to compensate
488 * for various systematic errors. The routine returns the number of
489 * samples processed, which could be 0.
445 */
446static int
447refclock_sample(
490 */
491static int
492refclock_sample(
448 struct refclockproc *pp /* refclock structure pointer */
493 struct refclockproc *pp
449 )
450{
494 )
495{
451 size_t i, j, k, m, n;
452 double off[MAXSTAGE];
453 double offset;
496 int i, j, k, n;
497 double offset, disp;
498 double off[MAXSTAGE];
454
455 /*
456 * Copy the raw offsets and sort into ascending order. Don't do
457 * anything if the buffer is empty.
458 */
499
500 /*
501 * Copy the raw offsets and sort into ascending order. Don't do
502 * anything if the buffer is empty.
503 */
459 n = 0;
460 while (pp->codeproc != pp->coderecv) {
461 pp->codeproc = (pp->codeproc + 1) % MAXSTAGE;
462 off[n] = pp->filter[pp->codeproc];
463 n++;
464 }
465 if (n == 0)
504 if (pp->codeproc == pp->coderecv)
466 return (0);
505 return (0);
467
506 n = 0;
507 while (pp->codeproc != pp->coderecv)
508 off[n++] = pp->filter[pp->codeproc++ % MAXSTAGE];
468 if (n > 1)
509 if (n > 1)
469 qsort(off, n, sizeof(off[0]), refclock_cmpl_fp);
510 qsort((char *)off, n, sizeof(double), refclock_cmpl_fp);
470
471 /*
472 * Reject the furthest from the median of the samples until
473 * approximately 60 percent of the samples remain.
474 */
475 i = 0; j = n;
511
512 /*
513 * Reject the furthest from the median of the samples until
514 * approximately 60 percent of the samples remain.
515 */
516 i = 0; j = n;
476 m = n - (n * 4) / 10;
477 while ((j - i) > m) {
517 k = n - (n * 2) / NSTAGE;
518 while ((j - i) > k) {
478 offset = off[(j + i) / 2];
479 if (off[j - 1] - offset < offset - off[i])
480 i++; /* reject low end */
481 else
482 j--; /* reject high end */
483 }
484
485 /*
519 offset = off[(j + i) / 2];
520 if (off[j - 1] - offset < offset - off[i])
521 i++; /* reject low end */
522 else
523 j--; /* reject high end */
524 }
525
526 /*
486 * Determine the offset and jitter.
527 * Determine the offset and variance.
487 */
528 */
488 pp->offset = 0;
489 pp->jitter = 0;
490 for (k = i; k < j; k++) {
491 pp->offset += off[k];
492 if (k > i)
493 pp->jitter += SQUARE(off[k] - off[k - 1]);
529 offset = disp = 0;
530 for (; i < j; i++) {
531 offset += off[i];
532 disp += SQUARE(off[i]);
494 }
533 }
495 pp->offset /= m;
496 pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision));
534 offset /= k;
535 pp->offset = offset;
536 pp->variance += disp / k - SQUARE(offset);
497#ifdef DEBUG
498 if (debug)
499 printf(
537#ifdef DEBUG
538 if (debug)
539 printf(
500 "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n",
501 (int)n, pp->offset, pp->disp, pp->jitter);
540 "refclock_sample: n %d offset %.6f disp %.6f std %.6f\n",
541 n, pp->offset, pp->disp, SQRT(pp->variance));
502#endif
542#endif
503 return (int)n;
543 return (n);
504}
505
506
507/*
508 * refclock_receive - simulate the receive and packet procedures
509 *
510 * This routine simulates the NTP receive and packet procedures for a
511 * reference clock. This provides a mechanism in which the ordinary NTP

--- 6 unchanged lines hidden (view full) ---

518 struct peer *peer /* peer structure pointer */
519 )
520{
521 struct refclockproc *pp;
522
523#ifdef DEBUG
524 if (debug)
525 printf("refclock_receive: at %lu %s\n",
544}
545
546
547/*
548 * refclock_receive - simulate the receive and packet procedures
549 *
550 * This routine simulates the NTP receive and packet procedures for a
551 * reference clock. This provides a mechanism in which the ordinary NTP

--- 6 unchanged lines hidden (view full) ---

558 struct peer *peer /* peer structure pointer */
559 )
560{
561 struct refclockproc *pp;
562
563#ifdef DEBUG
564 if (debug)
565 printf("refclock_receive: at %lu %s\n",
526 current_time, stoa(&peer->srcadr));
566 current_time, ntoa(&peer->srcadr));
527#endif
528
529 /*
530 * Do a little sanity dance and update the peer structure. Groom
531 * the median filter samples and give the data to the clock
532 * filter.
533 */
567#endif
568
569 /*
570 * Do a little sanity dance and update the peer structure. Groom
571 * the median filter samples and give the data to the clock
572 * filter.
573 */
574 peer->received++;
534 pp = peer->procptr;
575 pp = peer->procptr;
576 peer->processed++;
577 peer->timereceived = current_time;
535 peer->leap = pp->leap;
578 peer->leap = pp->leap;
536 if (peer->leap == LEAP_NOTINSYNC)
579 if (peer->leap == LEAP_NOTINSYNC) {
580 refclock_report(peer, CEVNT_FAULT);
537 return;
581 return;
538
539 peer->received++;
540 peer->timereceived = current_time;
541 if (!peer->reach) {
542 report_event(PEVNT_REACH, peer, NULL);
543 peer->timereachable = current_time;
544 }
582 }
583 if (peer->reach == 0)
584 report_event(EVNT_REACH, peer);
545 peer->reach |= 1;
585 peer->reach |= 1;
546 peer->reftime = pp->lastref;
547 peer->aorg = pp->lastrec;
548 peer->rootdisp = pp->disp;
549 get_systime(&peer->dst);
586 peer->reftime = peer->org = pp->lastrec;
587 peer->rootdispersion = pp->disp + SQRT(pp->variance);
588 get_systime(&peer->rec);
550 if (!refclock_sample(pp))
551 return;
589 if (!refclock_sample(pp))
590 return;
552
553 clock_filter(peer, pp->offset, 0., pp->jitter);
554 if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer !=
555 NULL) {
556 if (sys_peer->refclktype == REFCLK_ATOM_PPS &&
557 peer->refclktype != REFCLK_ATOM_PPS)
558 pp->fudgetime1 -= pp->offset * FUDGEFAC;
559 }
591 clock_filter(peer, pp->offset, 0., 0.);
592 clock_select();
593 record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
594 peer->offset, peer->delay, CLOCK_PHI * (current_time -
595 peer->epoch), SQRT(peer->variance));
596 if (pps_control && pp->sloppyclockflag & CLK_FLAG1)
597 pp->fudgetime1 -= pp->offset * FUDGEFAC;
560}
561
598}
599
562
563/*
564 * refclock_gtlin - groom next input line and extract timestamp
565 *
566 * This routine processes the timecode received from the clock and
600/*
601 * refclock_gtlin - groom next input line and extract timestamp
602 *
603 * This routine processes the timecode received from the clock and
567 * strips the parity bit and control characters. It returns the number
568 * of characters in the line followed by a NULL character ('\0'), which
569 * is not included in the count. In case of an empty line, the previous
570 * line is preserved.
604 * removes the parity bit and control characters. If a timestamp is
605 * present in the timecode, as produced by the tty_clk STREAMS module,
606 * it returns that as the timestamp; otherwise, it returns the buffer
607 * timestamp. The routine return code is the number of characters in
608 * the line.
571 */
572int
573refclock_gtlin(
574 struct recvbuf *rbufp, /* receive buffer pointer */
609 */
610int
611refclock_gtlin(
612 struct recvbuf *rbufp, /* receive buffer pointer */
575 char *lineptr, /* current line pointer */
576 int bmax, /* remaining characters in line */
577 l_fp *tsptr /* pointer to timestamp returned */
613 char *lineptr, /* current line pointer */
614 int bmax, /* remaining characters in line */
615 l_fp *tsptr /* pointer to timestamp returned */
578 )
579{
616 )
617{
580 const char *sp, *spend;
581 char *dp, *dpend;
582 int dlen;
618 char *dpt, *dpend, *dp;
619 int i;
620 l_fp trtmp, tstmp;
621 char c;
622#ifdef TIOCDCDTIMESTAMP
623 struct timeval dcd_time;
624#endif /* TIOCDCDTIMESTAMP */
625#ifdef HAVE_PPSAPI
626 pps_info_t pi;
627 struct timespec timeout, *tsp;
628 double a;
629#endif /* HAVE_PPSAPI */
583
630
584 if (bmax <= 0)
585 return (0);
586
587 dp = lineptr;
588 dpend = dp + bmax - 1; /* leave room for NUL pad */
589 sp = (const char *)rbufp->recv_buffer;
590 spend = sp + rbufp->recv_length;
591
592 while (sp != spend && dp != dpend) {
593 char c;
594
595 c = *sp++ & 0x7f;
596 if (c >= 0x20 && c < 0x7f)
597 *dp++ = c;
598 }
599 /* Get length of data written to the destination buffer. If
600 * zero, do *not* place a NUL byte to preserve the previous
601 * buffer content.
631 /*
632 * Check for the presence of a timestamp left by the tty_clock
633 * module and, if present, use that instead of the buffer
634 * timestamp captured by the I/O routines. We recognize a
635 * timestamp by noting its value is earlier than the buffer
636 * timestamp, but not more than one second earlier.
602 */
637 */
603 dlen = dp - lineptr;
604 if (dlen)
605 *dp = '\0';
606 *tsptr = rbufp->recv_time;
607 DPRINTF(2, ("refclock_gtlin: fd %d time %s timecode %d %s\n",
608 rbufp->fd, ulfptoa(&rbufp->recv_time, 6), dlen,
609 (dlen != 0)
610 ? lineptr
611 : ""));
612 return (dlen);
613}
638 dpt = (char *)&rbufp->recv_space;
639 dpend = dpt + rbufp->recv_length;
640 trtmp = rbufp->recv_time;
614
641
615
616/*
617 * refclock_gtraw - get next line/chunk of data
618 *
619 * This routine returns the raw data received from the clock in both
620 * canonical or raw modes. The terminal interface routines map CR to LF.
621 * In canonical mode this results in two lines, one containing data
622 * followed by LF and another containing only LF. In raw mode the
623 * interface routines can deliver arbitraty chunks of data from one
624 * character to a maximum specified by the calling routine. In either
625 * mode the routine returns the number of characters in the line
626 * followed by a NULL character ('\0'), which is not included in the
627 * count.
628 *
629 * *tsptr receives a copy of the buffer timestamp.
630 */
631int
632refclock_gtraw(
633 struct recvbuf *rbufp, /* receive buffer pointer */
634 char *lineptr, /* current line pointer */
635 int bmax, /* remaining characters in line */
636 l_fp *tsptr /* pointer to timestamp returned */
637 )
638{
639 if (bmax <= 0)
640 return (0);
641 bmax -= 1; /* leave room for trailing NUL */
642 if (bmax > rbufp->recv_length)
643 bmax = rbufp->recv_length;
644 memcpy(lineptr, rbufp->recv_buffer, bmax);
645 lineptr[bmax] = '\0';
646
647 *tsptr = rbufp->recv_time;
648 DPRINTF(2, ("refclock_gtraw: fd %d time %s timecode %d %s\n",
649 rbufp->fd, ulfptoa(&rbufp->recv_time, 6), bmax,
650 lineptr));
651 return (bmax);
652}
653
654
655/*
656 * indicate_refclock_packet()
657 *
658 * Passes a fragment of refclock input read from the device to the
659 * driver direct input routine, which may consume it (batch it for
660 * queuing once a logical unit is assembled). If it is not so
661 * consumed, queue it for the driver's receive entrypoint.
662 *
663 * The return value is TRUE if the data has been consumed as a fragment
664 * and should not be counted as a received packet.
665 */
666int
667indicate_refclock_packet(
668 struct refclockio * rio,
669 struct recvbuf * rb
670 )
671{
672 /* Does this refclock use direct input routine? */
673 if (rio->io_input != NULL && (*rio->io_input)(rb) == 0) {
674 /*
675 * data was consumed - nothing to pass up
676 * into block input machine
677 */
678 freerecvbuf(rb);
679
680 return TRUE;
642#ifdef HAVE_PPSAPI
643 timeout.tv_sec = 0;
644 timeout.tv_nsec = 0;
645 if ((rbufp->fd == fdpps) &&
646 (time_pps_fetch(fdpps, PPS_TSFMT_TSPEC, &pi, &timeout) >= 0)) {
647 if(pps_assert)
648 tsp = &pi.assert_timestamp;
649 else
650 tsp = &pi.clear_timestamp;
651 a = tsp->tv_nsec;
652 a /= 1e9;
653 tstmp.l_uf = a * 4294967296.0;
654 tstmp.l_ui = tsp->tv_sec;
655 tstmp.l_ui += JAN_1970;
656 L_SUB(&trtmp, &tstmp);
657 if (trtmp.l_ui == 0) {
658#ifdef DEBUG
659 if (debug > 1) {
660 printf(
661 "refclock_gtlin: fd %d time_pps_fetch %s",
662 fdpps, lfptoa(&tstmp, 6));
663 printf(" sigio %s\n", lfptoa(&trtmp, 6));
664 }
665#endif
666 trtmp = tstmp;
667 goto gotit;
668 } else
669 trtmp = rbufp->recv_time;
681 }
670 }
682 add_full_recv_buffer(rb);
671#endif /* HAVE_PPSAPI */
672#ifdef TIOCDCDTIMESTAMP
673 if(ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) {
674 TVTOTS(&dcd_time, &tstmp);
675 tstmp.l_ui += JAN_1970;
676 L_SUB(&trtmp, &tstmp);
677 if (trtmp.l_ui == 0) {
678#ifdef DEBUG
679 if (debug > 1) {
680 printf(
681 "refclock_gtlin: fd %d DCDTIMESTAMP %s",
682 rbufp->fd, lfptoa(&tstmp, 6));
683 printf(" sigio %s\n", lfptoa(&trtmp, 6));
684 }
685#endif
686 trtmp = tstmp;
687 goto gotit;
688 } else
689 trtmp = rbufp->recv_time;
690 }
691 else
692 /* XXX fallback to old method if kernel refuses TIOCDCDTIMESTAMP */
693#endif /* TIOCDCDTIMESTAMP */
694 if (dpend >= dpt + 8) {
695 if (buftvtots(dpend - 8, &tstmp)) {
696 L_SUB(&trtmp, &tstmp);
697 if (trtmp.l_ui == 0) {
698#ifdef DEBUG
699 if (debug > 1) {
700 printf(
701 "refclock_gtlin: fd %d ldisc %s",
702 rbufp->fd, lfptoa(&trtmp, 6));
703 get_systime(&trtmp);
704 L_SUB(&trtmp, &tstmp);
705 printf(" sigio %s\n", lfptoa(&trtmp, 6));
706 }
707#endif
708 dpend -= 8;
709 trtmp = tstmp;
710 } else
711 trtmp = rbufp->recv_time;
712 }
713 }
683
714
684 return FALSE;
685}
686
687
688/*
689 * process_refclock_packet()
690 *
691 * Used for deferred processing of 'io_input' on systems where threading
692 * is used (notably Windows). This is acting as a trampoline to make the
693 * real calls to the refclock functions.
694 */
695#ifdef HAVE_IO_COMPLETION_PORT
696void
697process_refclock_packet(
698 struct recvbuf * rb
699 )
700{
701 struct refclockio * rio;
702
703 /* get the refclockio structure from the receive buffer */
704 rio = &rb->recv_peer->procptr->io;
705
706 /* call 'clock_recv' if either there is no input function or the
707 * raw input function tells us to feed the packet to the
708 * receiver.
715#if defined(HAVE_PPSAPI) || defined(TIOCDCDTIMESTAMP)
716gotit:
717#endif
718 /*
719 * Edit timecode to remove control chars. Don't monkey with the
720 * line buffer if the input buffer contains no ASCII printing
721 * characters.
709 */
722 */
710 if (rio->io_input == NULL || (*rio->io_input)(rb) != 0) {
711 rio->recvcount++;
712 packets_received++;
713 handler_pkts++;
714 (*rio->clock_recv)(rb);
723 if (dpend - dpt > bmax - 1)
724 dpend = dpt + bmax - 1;
725 for (dp = lineptr; dpt < dpend; dpt++) {
726 c = *dpt & 0x7f;
727 if (c >= ' ')
728 *dp++ = c;
715 }
729 }
730 i = dp - lineptr;
731 if (i > 0)
732 *dp = '\0';
733#ifdef DEBUG
734 if (debug > 1 && i > 0)
735 printf("refclock_gtlin: fd %d time %s timecode %d %s\n",
736 rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr);
737#endif
738 *tsptr = trtmp;
739 return (i);
716}
740}
717#endif /* HAVE_IO_COMPLETION_PORT */
718
741
719
720/*
721 * The following code does not apply to WINNT & VMS ...
722 */
742/*
743 * The following code does not apply to WINNT & VMS ...
744 */
723#if !defined(SYS_VXWORKS) && !defined(SYS_WINNT)
745#if !defined SYS_VXWORKS && !defined SYS_WINNT
724#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
725
726/*
727 * refclock_open - open serial port for reference clock
728 *
729 * This routine opens a serial port for I/O and sets default options. It
746#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
747
748/*
749 * refclock_open - open serial port for reference clock
750 *
751 * This routine opens a serial port for I/O and sets default options. It
730 * returns the file descriptor if successful, or logs an error and
731 * returns -1.
752 * returns the file descriptor if success and zero if failure.
732 */
733int
734refclock_open(
753 */
754int
755refclock_open(
735 const char *dev, /* device name pointer */
736 u_int speed, /* serial port speed (code) */
737 u_int lflags /* line discipline flags */
756 char *dev, /* device name pointer */
757 int speed, /* serial port speed (code) */
758 int flags /* line discipline flags */
738 )
739{
759 )
760{
740 int fd;
741 int omode;
742#ifdef O_NONBLOCK
743 char trash[128]; /* litter bin for old input data */
744#endif
761 int fd, i;
762#ifdef HAVE_TERMIOS
763 struct termios ttyb, *ttyp;
764#endif /* HAVE_TERMIOS */
765#ifdef HAVE_SYSV_TTYS
766 struct termio ttyb, *ttyp;
767#endif /* HAVE_SYSV_TTYS */
768#ifdef HAVE_BSD_TTYS
769 struct sgttyb ttyb, *ttyp;
770#endif /* HAVE_BSD_TTYS */
771#ifdef TIOCMGET
772 u_long ltemp;
773#endif /* TIOCMGET */
745
746 /*
747 * Open serial port and set default options
748 */
774
775 /*
776 * Open serial port and set default options
777 */
749 omode = O_RDWR;
750#ifdef O_NONBLOCK
778#ifdef O_NONBLOCK
751 omode |= O_NONBLOCK;
752#endif
753#ifdef O_NOCTTY
754 omode |= O_NOCTTY;
755#endif
756
757 fd = open(dev, omode, 0777);
758 /* refclock_open() long returned 0 on failure, avoid it. */
759 if (0 == fd) {
760 fd = dup(0);
761 SAVE_ERRNO(
762 close(0);
763 )
779 fd = open(dev, O_RDWR | O_NONBLOCK, 0777);
780#else
781 fd = open(dev, O_RDWR, 0777);
782#endif /* O_NONBLOCK */
783 if (fd == -1) {
784 msyslog(LOG_ERR, "refclock_open: %s: %m", dev);
785 return (0);
764 }
786 }
765 if (fd < 0) {
766 SAVE_ERRNO(
767 msyslog(LOG_ERR, "refclock_open %s: %m", dev);
768 )
769 return -1;
770 }
771 if (!refclock_setup(fd, speed, lflags)) {
772 close(fd);
773 return -1;
774 }
775 if (!refclock_ioctl(fd, lflags)) {
776 close(fd);
777 return -1;
778 }
779#ifdef O_NONBLOCK
780 /*
781 * We want to make sure there is no pending trash in the input
782 * buffer. Since we have non-blocking IO available, this is a
783 * good moment to read and dump all available outdated stuff
784 * that might have become toxic for the driver.
785 */
786 while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR)
787 /*NOP*/;
788#endif
789 return fd;
790}
791
787
792
793/*
794 * refclock_setup - initialize terminal interface structure
795 */
796int
797refclock_setup(
798 int fd, /* file descriptor */
799 u_int speed, /* serial port speed (code) */
800 u_int lflags /* line discipline flags */
801 )
802{
803 int i;
804 TTY ttyb, *ttyp;
805
806 /*
788 /*
807 * By default, the serial line port is initialized in canonical
808 * (line-oriented) mode at specified line speed, 8 bits and no
809 * parity. LF ends the line and CR is mapped to LF. The break,
810 * erase and kill functions are disabled. There is a different
811 * section for each terminal interface, as selected at compile
812 * time. The flag bits can be used to set raw mode and echo.
789 * The following sections initialize the serial line port in
790 * canonical (line-oriented) mode and set the specified line
791 * speed, 8 bits and no parity. The modem control, break, erase
792 * and kill functions are normally disabled. There is a
793 * different section for each terminal interface, as selected at
794 * compile time.
813 */
814 ttyp = &ttyb;
795 */
796 ttyp = &ttyb;
815#ifdef HAVE_TERMIOS
816
797
798#ifdef HAVE_TERMIOS
817 /*
818 * POSIX serial line parameters (termios interface)
819 */
820 if (tcgetattr(fd, ttyp) < 0) {
799 /*
800 * POSIX serial line parameters (termios interface)
801 */
802 if (tcgetattr(fd, ttyp) < 0) {
821 SAVE_ERRNO(
822 msyslog(LOG_ERR,
823 "refclock_setup fd %d tcgetattr: %m",
824 fd);
825 )
826 return FALSE;
803 msyslog(LOG_ERR,
804 "refclock_open: fd %d tcgetattr: %m", fd);
805 return (0);
827 }
828
829 /*
830 * Set canonical mode and local connection; set specified speed,
831 * 8 bits and no parity; map CR to NL; ignore break.
832 */
806 }
807
808 /*
809 * Set canonical mode and local connection; set specified speed,
810 * 8 bits and no parity; map CR to NL; ignore break.
811 */
833 if (speed) {
834 u_int ltemp = 0;
835
836 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
837 ttyp->c_oflag = 0;
838 ttyp->c_cflag = CS8 | CLOCAL | CREAD;
839 if (lflags & LDISC_7O1) {
840 /* HP Z3801A needs 7-bit, odd parity */
841 ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD;
842 }
843 cfsetispeed(&ttyb, speed);
844 cfsetospeed(&ttyb, speed);
845 for (i = 0; i < NCCS; ++i)
846 ttyp->c_cc[i] = '\0';
847
848#if defined(TIOCMGET) && !defined(SCO5_CLOCK)
849
850 /*
851 * If we have modem control, check to see if modem leads
852 * are active; if so, set remote connection. This is
853 * necessary for the kernel pps mods to work.
854 */
855 if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
856 msyslog(LOG_ERR,
857 "refclock_setup fd %d TIOCMGET: %m", fd);
858#ifdef DEBUG
859 if (debug)
860 printf("refclock_setup fd %d modem status: 0x%x\n",
861 fd, ltemp);
862#endif
863 if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE)
864 ttyp->c_cflag &= ~CLOCAL;
865#endif /* TIOCMGET */
812 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
813 ttyp->c_oflag = 0;
814 ttyp->c_cflag = CS8 | CLOCAL | CREAD;
815 (void)cfsetispeed(&ttyb, (u_int)speed);
816 (void)cfsetospeed(&ttyb, (u_int)speed);
817 ttyp->c_lflag = ICANON;
818 for (i = 0; i < NCCS; ++i)
819 {
820 ttyp->c_cc[i] = '\0';
866 }
867
868 /*
821 }
822
823 /*
869 * Set raw and echo modes. These can be changed on-fly.
824 * Some special cases
870 */
825 */
871 ttyp->c_lflag = ICANON;
872 if (lflags & LDISC_RAW) {
873 ttyp->c_lflag = 0;
826 if (flags & LDISC_RAW) {
874 ttyp->c_iflag = 0;
827 ttyp->c_iflag = 0;
828 ttyp->c_lflag = 0;
875 ttyp->c_cc[VMIN] = 1;
876 }
829 ttyp->c_cc[VMIN] = 1;
830 }
877 if (lflags & LDISC_ECHO)
878 ttyp->c_lflag |= ECHO;
879 if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
880 SAVE_ERRNO(
881 msyslog(LOG_ERR,
882 "refclock_setup fd %d TCSANOW: %m",
883 fd);
884 )
885 return FALSE;
886 }
887
831#if defined(TIOCMGET) && !defined(SCO5_CLOCK)
888 /*
832 /*
889 * flush input and output buffers to discard any outdated stuff
890 * that might have become toxic for the driver. Failing to do so
891 * is logged, but we keep our fingers crossed otherwise.
833 * If we have modem control, check to see if modem leads are
834 * active; if so, set remote connection. This is necessary for
835 * the kernel pps mods to work.
892 */
836 */
893 if (tcflush(fd, TCIOFLUSH) < 0)
894 msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m",
895 fd);
837 ltemp = 0;
838 if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
839 msyslog(LOG_ERR,
840 "refclock_open: fd %d TIOCMGET failed: %m", fd);
841#ifdef DEBUG
842 if (debug)
843 printf("refclock_open: fd %d modem status 0x%lx\n",
844 fd, ltemp);
845#endif
846 if (ltemp & TIOCM_DSR)
847 ttyp->c_cflag &= ~CLOCAL;
848#endif /* TIOCMGET */
849 if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
850 msyslog(LOG_ERR,
851 "refclock_open: fd %d TCSANOW failed: %m", fd);
852 return (0);
853 }
854 if (tcflush(fd, TCIOFLUSH) < 0) {
855 msyslog(LOG_ERR,
856 "refclock_open: fd %d TCIOFLUSH failed: %m", fd);
857 return (0);
858 }
896#endif /* HAVE_TERMIOS */
897
898#ifdef HAVE_SYSV_TTYS
899
900 /*
901 * System V serial line parameters (termio interface)
902 *
903 */
904 if (ioctl(fd, TCGETA, ttyp) < 0) {
859#endif /* HAVE_TERMIOS */
860
861#ifdef HAVE_SYSV_TTYS
862
863 /*
864 * System V serial line parameters (termio interface)
865 *
866 */
867 if (ioctl(fd, TCGETA, ttyp) < 0) {
905 SAVE_ERRNO(
906 msyslog(LOG_ERR,
907 "refclock_setup fd %d TCGETA: %m",
908 fd);
909 )
910 return FALSE;
868 msyslog(LOG_ERR,
869 "refclock_open: fd %d TCGETA failed: %m", fd);
870 return (0);
911 }
912
913 /*
914 * Set canonical mode and local connection; set specified speed,
915 * 8 bits and no parity; map CR to NL; ignore break.
916 */
871 }
872
873 /*
874 * Set canonical mode and local connection; set specified speed,
875 * 8 bits and no parity; map CR to NL; ignore break.
876 */
917 if (speed) {
918 u_int ltemp = 0;
877 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
878 ttyp->c_oflag = 0;
879 ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD;
880 ttyp->c_lflag = ICANON;
881 ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
919
882
920 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
921 ttyp->c_oflag = 0;
922 ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD;
923 for (i = 0; i < NCCS; ++i)
924 ttyp->c_cc[i] = '\0';
925
926#if defined(TIOCMGET) && !defined(SCO5_CLOCK)
927
928 /*
929 * If we have modem control, check to see if modem leads
930 * are active; if so, set remote connection. This is
931 * necessary for the kernel pps mods to work.
932 */
933 if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
934 msyslog(LOG_ERR,
935 "refclock_setup fd %d TIOCMGET: %m", fd);
936#ifdef DEBUG
937 if (debug)
938 printf("refclock_setup fd %d modem status: %x\n",
939 fd, ltemp);
940#endif
941 if (ltemp & TIOCM_DSR)
942 ttyp->c_cflag &= ~CLOCAL;
943#endif /* TIOCMGET */
944 }
945
946 /*
883 /*
947 * Set raw and echo modes. These can be changed on-fly.
884 * Some special cases
948 */
885 */
949 ttyp->c_lflag = ICANON;
950 if (lflags & LDISC_RAW) {
951 ttyp->c_lflag = 0;
886 if (flags & LDISC_RAW) {
952 ttyp->c_iflag = 0;
887 ttyp->c_iflag = 0;
953 ttyp->c_cc[VMIN] = 1;
888 ttyp->c_lflag = 0;
954 }
889 }
890#ifdef TIOCMGET
891 /*
892 * If we have modem control, check to see if modem leads are
893 * active; if so, set remote connection. This is necessary for
894 * the kernel pps mods to work.
895 */
896 ltemp = 0;
897 if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
898 msyslog(LOG_ERR,
899 "refclock_open: fd %d TIOCMGET failed: %m", fd);
900#ifdef DEBUG
901 if (debug)
902 printf("refclock_open: fd %d modem status %lx\n",
903 fd, ltemp);
904#endif
905 if (ltemp & TIOCM_DSR)
906 ttyp->c_cflag &= ~CLOCAL;
907#endif /* TIOCMGET */
955 if (ioctl(fd, TCSETA, ttyp) < 0) {
908 if (ioctl(fd, TCSETA, ttyp) < 0) {
956 SAVE_ERRNO(
957 msyslog(LOG_ERR,
958 "refclock_setup fd %d TCSETA: %m", fd);
959 )
960 return FALSE;
909 msyslog(LOG_ERR,
910 "refclock_open: fd %d TCSETA failed: %m", fd);
911 return (0);
961 }
962#endif /* HAVE_SYSV_TTYS */
963
964#ifdef HAVE_BSD_TTYS
965
966 /*
967 * 4.3bsd serial line parameters (sgttyb interface)
968 */
969 if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
912 }
913#endif /* HAVE_SYSV_TTYS */
914
915#ifdef HAVE_BSD_TTYS
916
917 /*
918 * 4.3bsd serial line parameters (sgttyb interface)
919 */
920 if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
970 SAVE_ERRNO(
971 msyslog(LOG_ERR,
972 "refclock_setup fd %d TIOCGETP: %m",
973 fd);
974 )
975 return FALSE;
921 msyslog(LOG_ERR,
922 "refclock_open: fd %d TIOCGETP %m", fd);
923 return (0);
976 }
924 }
977 if (speed)
978 ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
925 ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
979 ttyp->sg_flags = EVENP | ODDP | CRMOD;
980 if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
926 ttyp->sg_flags = EVENP | ODDP | CRMOD;
927 if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
981 SAVE_ERRNO(
982 msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m");
983 )
984 return FALSE;
928 msyslog(LOG_ERR,
929 "refclock_open: TIOCSETP failed: %m");
930 return (0);
985 }
986#endif /* HAVE_BSD_TTYS */
931 }
932#endif /* HAVE_BSD_TTYS */
987 return(1);
933 if (!refclock_ioctl(fd, flags)) {
934 (void)close(fd);
935 msyslog(LOG_ERR,
936 "refclock_open: fd %d ioctl failed: %m", fd);
937 return (0);
938 }
939
940 /*
941 * If this is the PPS device, so say and initialize the thing.
942 */
943 if (strcmp(dev, pps_device) == 0)
944 (void)refclock_ioctl(fd, LDISC_PPS);
945 return (fd);
988}
989#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
946}
947#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
948#endif /* SYS_VXWORKS SYS_WINNT */
990
949
991
992/*
993 * refclock_ioctl - set serial port control functions
994 *
995 * This routine attempts to hide the internal, system-specific details
996 * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
997 * (sgtty) interfaces with varying degrees of success. The routine sets
950/*
951 * refclock_ioctl - set serial port control functions
952 *
953 * This routine attempts to hide the internal, system-specific details
954 * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
955 * (sgtty) interfaces with varying degrees of success. The routine sets
998 * up optional features such as tty_clk. The routine returns TRUE if
999 * successful.
956 * up optional features such as tty_clk, ppsclock and ppsapi, as well as
957 * their many other variants. The routine returns 1 if success and 0 if
958 * failure.
1000 */
1001int
1002refclock_ioctl(
959 */
960int
961refclock_ioctl(
1003 int fd, /* file descriptor */
1004 u_int lflags /* line discipline flags */
962 int fd, /* file descriptor */
963 int flags /* line discipline flags */
1005 )
1006{
964 )
965{
966 /* simply return 1 if no UNIX line discipline is supported */
967#if !defined SYS_VXWORKS && !defined SYS_WINNT
968#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
969
970#ifdef TTYCLK
971#ifdef HAVE_TERMIOS
972 struct termios ttyb, *ttyp;
973#endif /* HAVE_TERMIOS */
974#ifdef HAVE_SYSV_TTYS
975 struct termio ttyb, *ttyp;
976#endif /* HAVE_SYSV_TTYS */
977#ifdef HAVE_BSD_TTYS
978 struct sgttyb ttyb, *ttyp;
979#endif /* HAVE_BSD_TTYS */
980#endif /* TTYCLK */
981
982#ifdef DEBUG
983 if (debug)
984 printf("refclock_ioctl: fd %d flags 0x%x\n", fd, flags);
985#endif
986
1007 /*
987 /*
1008 * simply return TRUE if no UNIX line discipline is supported
988 * The following sections select optional features, such as
989 * modem control, PPS capture and so forth. Some require
990 * specific operating system support in the form of STREAMS
991 * modules, which can be loaded and unloaded at run time without
992 * rebooting the kernel. The STREAMS modules require System
993 * V STREAMS support. The checking frenzy is attenuated here,
994 * since the device is already open.
995 *
996 * Note that the tty_clk and ppsclock modules are optional; if
997 * configured and unavailable, the dang thing still works, but
998 * the accuracy improvement using them will not be available.
999 * The only known implmentations of these moldules are specific
1000 * to SunOS 4.x. Use the ppsclock module ONLY with Sun baseboard
1001 * ttya or ttyb. Using it with the SPIF multipexor crashes the
1002 * kernel.
1003 *
1004 * The preferred way to capture PPS timestamps is using the
1005 * ppsapi interface, which is machine independent. The SunOS 4.x
1006 * and Digital Unix 4.x interfaces use STREAMS modules and
1007 * support both the ppsapi specification and ppsclock
1008 * functionality, but other systems may vary widely.
1009 */
1009 */
1010 DPRINTF(1, ("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags));
1010 if (flags == 0)
1011 return (1);
1012#if !(defined(HAVE_TERMIOS) || defined(HAVE_BSD_TTYS))
1013 if (flags & (LDISC_CLK | LDISC_PPS | LDISC_ACTS)) {
1014 msyslog(LOG_ERR,
1015 "refclock_ioctl: unsupported terminal interface");
1016 return (0);
1017 }
1018#endif /* HAVE_TERMIOS HAVE_BSD_TTYS */
1019#ifdef TTYCLK
1020 ttyp = &ttyb;
1021#endif /* TTYCLK */
1011
1022
1012 return TRUE;
1013}
1014#endif /* !defined(SYS_VXWORKS) && !defined(SYS_WINNT) */
1023 /*
1024 * The following features may or may not require System V
1025 * STREAMS support, depending on the particular implementation.
1026 */
1027#if defined(TTYCLK)
1028 /*
1029 * The TTYCLK option provides timestamping at the driver level.
1030 * It requires the tty_clk streams module and System V STREAMS
1031 * support. If not available, don't complain.
1032 */
1033 if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
1034 int rval = 0;
1015
1035
1036 if (ioctl(fd, I_PUSH, "clk") < 0) {
1037 msyslog(LOG_NOTICE,
1038 "refclock_ioctl: I_PUSH clk failed: %m");
1039 } else {
1040 char *str;
1016
1041
1042 if (flags & LDISC_CLKPPS)
1043 str = "\377";
1044 else if (flags & LDISC_ACTS)
1045 str = "*";
1046 else
1047 str = "\n";
1048#ifdef CLK_SETSTR
1049 if ((rval = ioctl(fd, CLK_SETSTR, str)) < 0)
1050 msyslog(LOG_ERR,
1051 "refclock_ioctl: CLK_SETSTR failed: %m");
1052 if (debug)
1053 printf("refclock_ioctl: fd %d CLK_SETSTR %d str %s\n",
1054 fd, rval, str);
1055#endif
1056 }
1057 }
1058#endif /* TTYCLK */
1059
1060#if defined(PPS) && !defined(HAVE_PPSAPI)
1061 /*
1062 * The PPS option provides timestamping at the driver level.
1063 * It uses a 1-pps signal and level converter (gadget box) and
1064 * requires the ppsclock streams module and System V STREAMS
1065 * support. This option has been superseded by the ppsapi
1066 * option and may be withdrawn in future.
1067 */
1068 if (flags & LDISC_PPS) {
1069 int rval = 0;
1070#ifdef HAVE_TIOCSPPS /* Solaris */
1071 int one = 1;
1072#endif /* HAVE_TIOCSPPS */
1073
1074 if (fdpps > 0) {
1075 msyslog(LOG_ERR,
1076 "refclock_ioctl: PPS already configured");
1077 return (0);
1078 }
1079#ifdef HAVE_TIOCSPPS /* Solaris */
1080 if (ioctl(fd, TIOCSPPS, &one) < 0) {
1081 msyslog(LOG_NOTICE,
1082 "refclock_ioctl: TIOCSPPS failed: %m");
1083 return (0);
1084 }
1085 if (debug)
1086 printf("refclock_ioctl: fd %d TIOCSPPS %d\n",
1087 fd, rval);
1088#else
1089 if (ioctl(fd, I_PUSH, "ppsclock") < 0) {
1090 msyslog(LOG_NOTICE,
1091 "refclock_ioctl: I_PUSH ppsclock failed: %m");
1092 return (0);
1093 }
1094 if (debug)
1095 printf("refclock_ioctl: fd %d ppsclock %d\n",
1096 fd, rval);
1097#endif /* not HAVE_TIOCSPPS */
1098 fdpps = fd;
1099 }
1100#endif /* PPS HAVE_PPSAPI */
1101
1102#ifdef HAVE_PPSAPI
1103 /*
1104 * The PPSAPI option provides timestamping at the driver level.
1105 * It uses a 1-pps signal and level converter (gadget box) and
1106 * requires ppsapi compiled into the kernel on non STREAMS
1107 * systems. This is the preferred way to capture PPS timestamps
1108 * and is expected to become an IETF cross-platform standard.
1109 */
1110 if (flags & (LDISC_PPS | LDISC_CLKPPS)) {
1111 pps_params_t pp;
1112 int mode, temp;
1113 pps_handle_t handle;
1114
1115 memset((char *)&pp, 0, sizeof(pp));
1116 if (fdpps > 0) {
1117 msyslog(LOG_ERR,
1118 "refclock_ioctl: ppsapi already configured");
1119 return (0);
1120 }
1121 if (time_pps_create(fd, &handle) < 0) {
1122 msyslog(LOG_ERR,
1123 "refclock_ioctl: time_pps_create failed: %m");
1124 return (0);
1125 }
1126 if (time_pps_getcap(handle, &mode) < 0) {
1127 msyslog(LOG_ERR,
1128 "refclock_ioctl: time_pps_getcap failed: %m");
1129 return (0);
1130 }
1131 pp.mode = mode & PPS_CAPTUREBOTH;
1132 if (time_pps_setparams(handle, &pp) < 0) {
1133 msyslog(LOG_ERR,
1134 "refclock_ioctl: time_pps_setparams failed: %m");
1135 return (0);
1136 }
1137 if (!pps_hardpps)
1138 temp = 0;
1139 else if (pps_assert)
1140 temp = mode & PPS_CAPTUREASSERT;
1141 else
1142 temp = mode & PPS_CAPTURECLEAR;
1143 if (time_pps_kcbind(handle, PPS_KC_HARDPPS, temp,
1144 PPS_TSFMT_TSPEC) < 0) {
1145 msyslog(LOG_ERR,
1146 "refclock_ioctl: time_pps_kcbind failed: %m");
1147 return (0);
1148 }
1149 (void)time_pps_getparams(handle, &pp);
1150 fdpps = (int)handle;
1151 if (debug)
1152 printf(
1153 "refclock_ioctl: fd %d ppsapi vers %d mode 0x%x cap 0x%x\n",
1154 fdpps, pp.api_version, pp.mode, mode);
1155 }
1156#endif /* HAVE_PPSAPI */
1157#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
1158#endif /* SYS_VXWORKS SYS_WINNT */
1159 return (1);
1160}
1161
1017/*
1018 * refclock_control - set and/or return clock values
1019 *
1020 * This routine is used mainly for debugging. It returns designated
1021 * values from the interface structure that can be displayed using
1022 * ntpdc and the clockstat command. It can also be used to initialize
1023 * configuration variables, such as fudgetimes, fudgevalues, reference
1024 * ID and stratum.
1025 */
1026void
1027refclock_control(
1162/*
1163 * refclock_control - set and/or return clock values
1164 *
1165 * This routine is used mainly for debugging. It returns designated
1166 * values from the interface structure that can be displayed using
1167 * ntpdc and the clockstat command. It can also be used to initialize
1168 * configuration variables, such as fudgetimes, fudgevalues, reference
1169 * ID and stratum.
1170 */
1171void
1172refclock_control(
1028 sockaddr_u *srcadr,
1029 const struct refclockstat *in,
1173 struct sockaddr_in *srcadr,
1174 struct refclockstat *in,
1030 struct refclockstat *out
1031 )
1032{
1033 struct peer *peer;
1034 struct refclockproc *pp;
1035 u_char clktype;
1036 int unit;
1037
1038 /*
1039 * Check for valid address and running peer
1040 */
1041 if (!ISREFCLOCKADR(srcadr))
1042 return;
1175 struct refclockstat *out
1176 )
1177{
1178 struct peer *peer;
1179 struct refclockproc *pp;
1180 u_char clktype;
1181 int unit;
1182
1183 /*
1184 * Check for valid address and running peer
1185 */
1186 if (!ISREFCLOCKADR(srcadr))
1187 return;
1043
1044 clktype = (u_char)REFCLOCKTYPE(srcadr);
1045 unit = REFCLOCKUNIT(srcadr);
1188 clktype = (u_char)REFCLOCKTYPE(srcadr);
1189 unit = REFCLOCKUNIT(srcadr);
1046
1047 peer = findexistingpeer(srcadr, NULL, NULL, -1, 0);
1048
1049 if (NULL == peer)
1190 if (clktype >= num_refclock_conf || unit >= MAXUNIT)
1050 return;
1191 return;
1051
1052 INSIST(peer->procptr != NULL);
1192 if (!(peer = typeunit[clktype][unit]))
1193 return;
1053 pp = peer->procptr;
1054
1055 /*
1056 * Initialize requested data
1057 */
1194 pp = peer->procptr;
1195
1196 /*
1197 * Initialize requested data
1198 */
1058 if (in != NULL) {
1199 if (in != 0) {
1059 if (in->haveflags & CLK_HAVETIME1)
1060 pp->fudgetime1 = in->fudgetime1;
1061 if (in->haveflags & CLK_HAVETIME2)
1062 pp->fudgetime2 = in->fudgetime2;
1063 if (in->haveflags & CLK_HAVEVAL1)
1200 if (in->haveflags & CLK_HAVETIME1)
1201 pp->fudgetime1 = in->fudgetime1;
1202 if (in->haveflags & CLK_HAVETIME2)
1203 pp->fudgetime2 = in->fudgetime2;
1204 if (in->haveflags & CLK_HAVEVAL1)
1064 peer->stratum = pp->stratum = (u_char)in->fudgeval1;
1205 peer->stratum = (u_char) in->fudgeval1;
1065 if (in->haveflags & CLK_HAVEVAL2)
1206 if (in->haveflags & CLK_HAVEVAL2)
1066 peer->refid = pp->refid = in->fudgeval2;
1207 pp->refid = in->fudgeval2;
1208 if (peer->stratum <= 1)
1209 peer->refid = pp->refid;
1210 else
1211 peer->refid = peer->srcadr.sin_addr.s_addr;
1067 if (in->haveflags & CLK_HAVEFLAG1) {
1068 pp->sloppyclockflag &= ~CLK_FLAG1;
1069 pp->sloppyclockflag |= in->flags & CLK_FLAG1;
1070 }
1071 if (in->haveflags & CLK_HAVEFLAG2) {
1072 pp->sloppyclockflag &= ~CLK_FLAG2;
1073 pp->sloppyclockflag |= in->flags & CLK_FLAG2;
1074 }

--- 5 unchanged lines hidden (view full) ---

1080 pp->sloppyclockflag &= ~CLK_FLAG4;
1081 pp->sloppyclockflag |= in->flags & CLK_FLAG4;
1082 }
1083 }
1084
1085 /*
1086 * Readback requested data
1087 */
1212 if (in->haveflags & CLK_HAVEFLAG1) {
1213 pp->sloppyclockflag &= ~CLK_FLAG1;
1214 pp->sloppyclockflag |= in->flags & CLK_FLAG1;
1215 }
1216 if (in->haveflags & CLK_HAVEFLAG2) {
1217 pp->sloppyclockflag &= ~CLK_FLAG2;
1218 pp->sloppyclockflag |= in->flags & CLK_FLAG2;
1219 }

--- 5 unchanged lines hidden (view full) ---

1225 pp->sloppyclockflag &= ~CLK_FLAG4;
1226 pp->sloppyclockflag |= in->flags & CLK_FLAG4;
1227 }
1228 }
1229
1230 /*
1231 * Readback requested data
1232 */
1088 if (out != NULL) {
1089 out->fudgeval1 = pp->stratum;
1090 out->fudgeval2 = pp->refid;
1091 out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;
1233 if (out != 0) {
1234 out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 |
1235 CLK_HAVEVAL2 | CLK_HAVEFLAG4;
1092 out->fudgetime1 = pp->fudgetime1;
1236 out->fudgetime1 = pp->fudgetime1;
1093 if (0.0 != out->fudgetime1)
1094 out->haveflags |= CLK_HAVETIME1;
1095 out->fudgetime2 = pp->fudgetime2;
1237 out->fudgetime2 = pp->fudgetime2;
1096 if (0.0 != out->fudgetime2)
1097 out->haveflags |= CLK_HAVETIME2;
1238 out->fudgeval1 = peer->stratum;
1239 out->fudgeval2 = pp->refid;
1098 out->flags = (u_char) pp->sloppyclockflag;
1240 out->flags = (u_char) pp->sloppyclockflag;
1099 if (CLK_FLAG1 & out->flags)
1100 out->haveflags |= CLK_HAVEFLAG1;
1101 if (CLK_FLAG2 & out->flags)
1102 out->haveflags |= CLK_HAVEFLAG2;
1103 if (CLK_FLAG3 & out->flags)
1104 out->haveflags |= CLK_HAVEFLAG3;
1105 if (CLK_FLAG4 & out->flags)
1106 out->haveflags |= CLK_HAVEFLAG4;
1107
1108 out->timereset = current_time - pp->timestarted;
1109 out->polls = pp->polls;
1110 out->noresponse = pp->noreply;
1111 out->badformat = pp->badformat;
1112 out->baddata = pp->baddata;
1113
1114 out->lastevent = pp->lastevent;
1115 out->currentstatus = pp->currentstatus;
1116 out->type = pp->type;
1117 out->clockdesc = pp->clockdesc;
1241
1242 out->timereset = current_time - pp->timestarted;
1243 out->polls = pp->polls;
1244 out->noresponse = pp->noreply;
1245 out->badformat = pp->badformat;
1246 out->baddata = pp->baddata;
1247
1248 out->lastevent = pp->lastevent;
1249 out->currentstatus = pp->currentstatus;
1250 out->type = pp->type;
1251 out->clockdesc = pp->clockdesc;
1118 out->lencode = (u_short)pp->lencode;
1252 out->lencode = pp->lencode;
1119 out->p_lastcode = pp->a_lastcode;
1120 }
1121
1122 /*
1123 * Give the stuff to the clock
1124 */
1125 if (refclock_conf[clktype]->clock_control != noentry)
1126 (refclock_conf[clktype]->clock_control)(unit, in, out, peer);

--- 4 unchanged lines hidden (view full) ---

1131 * refclock_buginfo - return debugging info
1132 *
1133 * This routine is used mainly for debugging. It returns designated
1134 * values from the interface structure that can be displayed using
1135 * ntpdc and the clkbug command.
1136 */
1137void
1138refclock_buginfo(
1253 out->p_lastcode = pp->a_lastcode;
1254 }
1255
1256 /*
1257 * Give the stuff to the clock
1258 */
1259 if (refclock_conf[clktype]->clock_control != noentry)
1260 (refclock_conf[clktype]->clock_control)(unit, in, out, peer);

--- 4 unchanged lines hidden (view full) ---

1265 * refclock_buginfo - return debugging info
1266 *
1267 * This routine is used mainly for debugging. It returns designated
1268 * values from the interface structure that can be displayed using
1269 * ntpdc and the clkbug command.
1270 */
1271void
1272refclock_buginfo(
1139 sockaddr_u *srcadr, /* clock address */
1273 struct sockaddr_in *srcadr, /* clock address */
1140 struct refclockbug *bug /* output structure */
1141 )
1142{
1143 struct peer *peer;
1144 struct refclockproc *pp;
1274 struct refclockbug *bug /* output structure */
1275 )
1276{
1277 struct peer *peer;
1278 struct refclockproc *pp;
1145 int clktype;
1279 u_char clktype;
1146 int unit;
1280 int unit;
1147 unsigned u;
1281 int i;
1148
1149 /*
1150 * Check for valid address and peer structure
1151 */
1152 if (!ISREFCLOCKADR(srcadr))
1153 return;
1282
1283 /*
1284 * Check for valid address and peer structure
1285 */
1286 if (!ISREFCLOCKADR(srcadr))
1287 return;
1154
1155 clktype = (u_char) REFCLOCKTYPE(srcadr);
1156 unit = REFCLOCKUNIT(srcadr);
1288 clktype = (u_char) REFCLOCKTYPE(srcadr);
1289 unit = REFCLOCKUNIT(srcadr);
1157
1158 peer = findexistingpeer(srcadr, NULL, NULL, -1, 0);
1159
1160 if (NULL == peer || NULL == peer->procptr)
1290 if (clktype >= num_refclock_conf || unit >= MAXUNIT)
1161 return;
1291 return;
1162
1292 if (!(peer = typeunit[clktype][unit]))
1293 return;
1163 pp = peer->procptr;
1164
1165 /*
1166 * Copy structure values
1167 */
1168 bug->nvalues = 8;
1169 bug->svalues = 0x0000003f;
1170 bug->values[0] = pp->year;
1171 bug->values[1] = pp->day;
1172 bug->values[2] = pp->hour;
1173 bug->values[3] = pp->minute;
1174 bug->values[4] = pp->second;
1294 pp = peer->procptr;
1295
1296 /*
1297 * Copy structure values
1298 */
1299 bug->nvalues = 8;
1300 bug->svalues = 0x0000003f;
1301 bug->values[0] = pp->year;
1302 bug->values[1] = pp->day;
1303 bug->values[2] = pp->hour;
1304 bug->values[3] = pp->minute;
1305 bug->values[4] = pp->second;
1175 bug->values[5] = pp->nsec;
1306 bug->values[5] = pp->msec;
1176 bug->values[6] = pp->yearstart;
1177 bug->values[7] = pp->coderecv;
1178 bug->stimes = 0xfffffffc;
1179 bug->times[0] = pp->lastref;
1180 bug->times[1] = pp->lastrec;
1307 bug->values[6] = pp->yearstart;
1308 bug->values[7] = pp->coderecv;
1309 bug->stimes = 0xfffffffc;
1310 bug->times[0] = pp->lastref;
1311 bug->times[1] = pp->lastrec;
1181 for (u = 2; u < bug->ntimes; u++)
1182 DTOLFP(pp->filter[u - 2], &bug->times[u]);
1312 for (i = 2; i < (int)bug->ntimes; i++)
1313 DTOLFP(pp->filter[i - 2], &bug->times[i]);
1183
1184 /*
1185 * Give the stuff to the clock
1186 */
1187 if (refclock_conf[clktype]->clock_buginfo != noentry)
1188 (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);
1189}
1190
1314
1315 /*
1316 * Give the stuff to the clock
1317 */
1318 if (refclock_conf[clktype]->clock_buginfo != noentry)
1319 (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);
1320}
1321
1191
1192#ifdef HAVE_PPSAPI
1193/*
1194 * refclock_ppsapi - initialize/update ppsapi
1195 *
1196 * This routine is called after the fudge command to open the PPSAPI
1197 * interface for later parameter setting after the fudge command.
1198 */
1199int
1200refclock_ppsapi(
1201 int fddev, /* fd device */
1202 struct refclock_atom *ap /* atom structure pointer */
1203 )
1204{
1205 if (ap->handle == 0) {
1206 if (time_pps_create(fddev, &ap->handle) < 0) {
1207 msyslog(LOG_ERR,
1208 "refclock_ppsapi: time_pps_create: %m");
1209 return (0);
1210 }
1211 }
1212 return (1);
1213}
1214
1215
1216/*
1217 * refclock_params - set ppsapi parameters
1218 *
1219 * This routine is called to set the PPSAPI parameters after the fudge
1220 * command.
1221 */
1222int
1223refclock_params(
1224 int mode, /* mode bits */
1225 struct refclock_atom *ap /* atom structure pointer */
1226 )
1227{
1228 ZERO(ap->pps_params);
1229 ap->pps_params.api_version = PPS_API_VERS_1;
1230
1231 /*
1232 * Solaris serial ports provide PPS pulse capture only on the
1233 * assert edge. FreeBSD serial ports provide capture on the
1234 * clear edge, while FreeBSD parallel ports provide capture
1235 * on the assert edge. Your mileage may vary.
1236 */
1237 if (mode & CLK_FLAG2)
1238 ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR;
1239 else
1240 ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT;
1241 if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) {
1242 msyslog(LOG_ERR,
1243 "refclock_params: time_pps_setparams: %m");
1244 return (0);
1245 }
1246
1247 /*
1248 * If flag3 is lit, select the kernel PPS if we can.
1249 */
1250 if (mode & CLK_FLAG3) {
1251 if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS,
1252 ap->pps_params.mode & ~PPS_TSFMT_TSPEC,
1253 PPS_TSFMT_TSPEC) < 0) {
1254 msyslog(LOG_ERR,
1255 "refclock_params: time_pps_kcbind: %m");
1256 return (0);
1257 }
1258 hardpps_enable = 1;
1259 }
1260 return (1);
1261}
1262
1263
1264/*
1265 * refclock_pps - called once per second
1266 *
1267 * This routine is called once per second. It snatches the PPS
1268 * timestamp from the kernel and saves the sign-extended fraction in
1269 * a circular buffer for processing at the next poll event.
1270 */
1271int
1272refclock_pps(
1273 struct peer *peer, /* peer structure pointer */
1274 struct refclock_atom *ap, /* atom structure pointer */
1275 int mode /* mode bits */
1276 )
1277{
1278 struct refclockproc *pp;
1279 pps_info_t pps_info;
1280 struct timespec timeout;
1281 double dtemp;
1282
1283 /*
1284 * We require the clock to be synchronized before setting the
1285 * parameters. When the parameters have been set, fetch the
1286 * most recent PPS timestamp.
1287 */
1288 pp = peer->procptr;
1289 if (ap->handle == 0)
1290 return (0);
1291
1292 if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) {
1293 if (refclock_params(pp->sloppyclockflag, ap) < 1)
1294 return (0);
1295 }
1296 timeout.tv_sec = 0;
1297 timeout.tv_nsec = 0;
1298 ZERO(pps_info);
1299 if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info,
1300 &timeout) < 0) {
1301 refclock_report(peer, CEVNT_FAULT);
1302 return (0);
1303 }
1304 timeout = ap->ts;
1305 if (ap->pps_params.mode & PPS_CAPTUREASSERT)
1306 ap->ts = pps_info.assert_timestamp;
1307 else if (ap->pps_params.mode & PPS_CAPTURECLEAR)
1308 ap->ts = pps_info.clear_timestamp;
1309 else
1310 return (0);
1311
1312 if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout)))
1313 return (0);
1314
1315 /*
1316 * Convert to signed fraction offset and stuff in median filter.
1317 */
1318 pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970;
1319 dtemp = ap->ts.tv_nsec / 1e9;
1320 pp->lastrec.l_uf = (u_int32)(dtemp * FRAC);
1321 if (dtemp > .5)
1322 dtemp -= 1.;
1323 SAMPLE(-dtemp + pp->fudgetime1);
1324#ifdef DEBUG
1325 if (debug > 1)
1326 printf("refclock_pps: %lu %f %f\n", current_time,
1327 dtemp, pp->fudgetime1);
1328#endif
1329 return (1);
1330}
1331#endif /* HAVE_PPSAPI */
1332#endif /* REFCLOCK */
1322#endif /* REFCLOCK */