/src/ntp-dev/ntpd/ntp_refclock.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * ntp_refclock - processing support for reference clocks |
3 | | */ |
4 | | #ifdef HAVE_CONFIG_H |
5 | | # include <config.h> |
6 | | #endif |
7 | | |
8 | | #include "ntpd.h" |
9 | | #include "ntp_io.h" |
10 | | #include "ntp_unixtime.h" |
11 | | #include "ntp_tty.h" |
12 | | #include "ntp_refclock.h" |
13 | | #include "ntp_stdlib.h" |
14 | | #include "ntp_assert.h" |
15 | | |
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 | | |
24 | | #ifdef KERNEL_PLL |
25 | | #include "ntp_syscall.h" |
26 | | #endif /* KERNEL_PLL */ |
27 | | |
28 | | #ifdef HAVE_PPSAPI |
29 | | #include "ppsapi_timepps.h" |
30 | | #include "refclock_atom.h" |
31 | | #endif /* HAVE_PPSAPI */ |
32 | | |
33 | | /* |
34 | | * 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 |
38 | | * refclock_transmit() and refclock_receive() maintain the peer |
39 | | * variables in a state analogous to an actual peer and pass reference |
40 | | * clock data on through the filters. Routines refclock_peer() and |
41 | | * 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. |
45 | | * |
46 | | * 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 | | * local control of the device. |
53 | | * |
54 | | * 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 | | */ |
61 | 0 | #define FUDGEFAC .1 /* fudge correction factor */ |
62 | | #define LF 0x0a /* ASCII LF */ |
63 | | |
64 | | int cal_enable; /* enable refclock calibrate */ |
65 | | |
66 | | /* |
67 | | * Forward declarations |
68 | | */ |
69 | | static int refclock_cmpl_fp (const void *, const void *); |
70 | | static int refclock_sample (struct refclockproc *); |
71 | | static int refclock_ioctl(int, u_int); |
72 | | |
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 | | */ |
81 | | void |
82 | | refclock_report( |
83 | | struct peer *peer, |
84 | | int code |
85 | | ) |
86 | 0 | { |
87 | 0 | struct refclockproc *pp; |
88 | |
|
89 | 0 | pp = peer->procptr; |
90 | 0 | if (pp == NULL) |
91 | 0 | return; |
92 | | |
93 | 0 | switch (code) { |
94 | | |
95 | 0 | case CEVNT_TIMEOUT: |
96 | 0 | pp->noreply++; |
97 | 0 | break; |
98 | | |
99 | 0 | case CEVNT_BADREPLY: |
100 | 0 | pp->badformat++; |
101 | 0 | break; |
102 | | |
103 | 0 | case CEVNT_FAULT: |
104 | 0 | break; |
105 | | |
106 | 0 | case CEVNT_BADDATE: |
107 | 0 | case CEVNT_BADTIME: |
108 | 0 | pp->baddata++; |
109 | 0 | break; |
110 | | |
111 | 0 | default: |
112 | | /* ignore others */ |
113 | 0 | break; |
114 | 0 | } |
115 | 0 | if ((code != CEVNT_NOMINAL) && (pp->lastevent < 15)) |
116 | 0 | pp->lastevent++; |
117 | 0 | if (pp->currentstatus != code) { |
118 | 0 | pp->currentstatus = (u_char)code; |
119 | 0 | report_event(PEVNT_CLOCK, peer, ceventstr(code)); |
120 | 0 | } |
121 | 0 | } |
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 | | */ |
131 | | void |
132 | | init_refclock(void) |
133 | 0 | { |
134 | 0 | int i; |
135 | |
|
136 | 0 | for (i = 0; i < (int)num_refclock_conf; i++) |
137 | 0 | if (refclock_conf[i]->clock_init != noentry) |
138 | 0 | (refclock_conf[i]->clock_init)(); |
139 | 0 | } |
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 |
147 | | * driver-specific support routine completes the initialization, if |
148 | | * used. Default peer variables which identify the clock and establish |
149 | | * its reference ID and stratum are set here. It returns one if success |
150 | | * and zero if the clock address is invalid or already running, |
151 | | * insufficient resources are available or the driver declares a bum |
152 | | * rap. |
153 | | */ |
154 | | int |
155 | | refclock_newpeer( |
156 | | struct peer *peer /* peer structure pointer */ |
157 | | ) |
158 | 0 | { |
159 | 0 | struct refclockproc *pp; |
160 | 0 | u_char clktype; |
161 | 0 | int unit; |
162 | | |
163 | | /* |
164 | | * Check for valid clock address. If already running, shut it |
165 | | * down first. |
166 | | */ |
167 | 0 | if (!ISREFCLOCKADR(&peer->srcadr)) { |
168 | 0 | msyslog(LOG_ERR, |
169 | 0 | "refclock_newpeer: clock address %s invalid", |
170 | 0 | stoa(&peer->srcadr)); |
171 | 0 | return (0); |
172 | 0 | } |
173 | 0 | clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); |
174 | 0 | unit = REFCLOCKUNIT(&peer->srcadr); |
175 | 0 | if (clktype >= num_refclock_conf || |
176 | 0 | refclock_conf[clktype]->clock_start == noentry) { |
177 | 0 | msyslog(LOG_ERR, |
178 | 0 | "refclock_newpeer: clock type %d invalid\n", |
179 | 0 | clktype); |
180 | 0 | return (0); |
181 | 0 | } |
182 | | |
183 | | /* |
184 | | * Allocate and initialize interface structure |
185 | | */ |
186 | 0 | pp = emalloc_zero(sizeof(*pp)); |
187 | 0 | peer->procptr = pp; |
188 | | |
189 | | /* |
190 | | * Initialize structures |
191 | | */ |
192 | 0 | peer->refclktype = clktype; |
193 | 0 | peer->refclkunit = (u_char)unit; |
194 | 0 | peer->flags |= FLAG_REFCLOCK; |
195 | 0 | peer->leap = LEAP_NOTINSYNC; |
196 | 0 | peer->stratum = STRATUM_REFCLOCK; |
197 | 0 | peer->ppoll = peer->maxpoll; |
198 | 0 | pp->type = clktype; |
199 | 0 | pp->conf = refclock_conf[clktype]; |
200 | 0 | pp->timestarted = current_time; |
201 | 0 | pp->io.fd = -1; |
202 | | |
203 | | /* |
204 | | * Set peer.pmode based on the hmode. For appearances only. |
205 | | */ |
206 | 0 | switch (peer->hmode) { |
207 | 0 | case MODE_ACTIVE: |
208 | 0 | peer->pmode = MODE_PASSIVE; |
209 | 0 | break; |
210 | | |
211 | 0 | default: |
212 | 0 | peer->pmode = MODE_SERVER; |
213 | 0 | break; |
214 | 0 | } |
215 | | |
216 | | /* |
217 | | * Do driver dependent initialization. The above defaults |
218 | | * can be wiggled, then finish up for consistency. |
219 | | */ |
220 | 0 | if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { |
221 | 0 | refclock_unpeer(peer); |
222 | 0 | return (0); |
223 | 0 | } |
224 | 0 | peer->refid = pp->refid; |
225 | 0 | return (1); |
226 | 0 | } |
227 | | |
228 | | |
229 | | /* |
230 | | * refclock_unpeer - shut down a clock |
231 | | */ |
232 | | void |
233 | | refclock_unpeer( |
234 | | struct peer *peer /* peer structure pointer */ |
235 | | ) |
236 | 0 | { |
237 | 0 | u_char clktype; |
238 | 0 | int unit; |
239 | | |
240 | | /* |
241 | | * Wiggle the driver to release its resources, then give back |
242 | | * the interface structure. |
243 | | */ |
244 | 0 | if (NULL == peer->procptr) |
245 | 0 | return; |
246 | | |
247 | 0 | clktype = peer->refclktype; |
248 | 0 | unit = peer->refclkunit; |
249 | 0 | if (refclock_conf[clktype]->clock_shutdown != noentry) |
250 | 0 | (refclock_conf[clktype]->clock_shutdown)(unit, peer); |
251 | 0 | free(peer->procptr); |
252 | 0 | peer->procptr = NULL; |
253 | 0 | } |
254 | | |
255 | | |
256 | | /* |
257 | | * refclock_timer - called once per second for housekeeping. |
258 | | */ |
259 | | void |
260 | | refclock_timer( |
261 | | struct peer *p |
262 | | ) |
263 | 0 | { |
264 | 0 | struct refclockproc * pp; |
265 | 0 | int unit; |
266 | |
|
267 | 0 | unit = p->refclkunit; |
268 | 0 | pp = p->procptr; |
269 | 0 | if (pp->conf->clock_timer != noentry) |
270 | 0 | (*pp->conf->clock_timer)(unit, p); |
271 | 0 | if (pp->action != NULL && pp->nextaction <= current_time) |
272 | 0 | (*pp->action)(p); |
273 | 0 | } |
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 | | */ |
284 | | void |
285 | | refclock_transmit( |
286 | | struct peer *peer /* peer structure pointer */ |
287 | | ) |
288 | 0 | { |
289 | 0 | u_char clktype; |
290 | 0 | int unit; |
291 | |
|
292 | 0 | clktype = peer->refclktype; |
293 | 0 | unit = peer->refclkunit; |
294 | 0 | peer->sent++; |
295 | 0 | 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 | | */ |
302 | 0 | if (peer->burst == 0) { |
303 | 0 | u_char oreach; |
304 | 0 | #ifdef DEBUG |
305 | 0 | if (debug) |
306 | 0 | printf("refclock_transmit: at %ld %s\n", |
307 | 0 | current_time, stoa(&(peer->srcadr))); |
308 | 0 | #endif |
309 | | |
310 | | /* |
311 | | * Update reachability and poll variables like the |
312 | | * network code. |
313 | | */ |
314 | 0 | oreach = peer->reach & 0xfe; |
315 | 0 | peer->reach <<= 1; |
316 | 0 | if (!(peer->reach & 0x0f)) |
317 | 0 | clock_filter(peer, 0., 0., MAXDISPERSE); |
318 | 0 | peer->outdate = current_time; |
319 | 0 | if (!peer->reach) { |
320 | 0 | if (oreach) { |
321 | 0 | report_event(PEVNT_UNREACH, peer, NULL); |
322 | 0 | peer->timereachable = current_time; |
323 | 0 | } |
324 | 0 | } else { |
325 | 0 | if (peer->flags & FLAG_BURST) |
326 | 0 | peer->burst = NSTAGE; |
327 | 0 | } |
328 | 0 | } else { |
329 | 0 | peer->burst--; |
330 | 0 | } |
331 | 0 | if (refclock_conf[clktype]->clock_poll != noentry) |
332 | 0 | (refclock_conf[clktype]->clock_poll)(unit, peer); |
333 | 0 | poll_update(peer, peer->hpoll); |
334 | 0 | } |
335 | | |
336 | | |
337 | | /* |
338 | | * Compare two doubles - used with qsort() |
339 | | */ |
340 | | static int |
341 | | refclock_cmpl_fp( |
342 | | const void *p1, |
343 | | const void *p2 |
344 | | ) |
345 | 0 | { |
346 | 0 | const double *dp1 = (const double *)p1; |
347 | 0 | const double *dp2 = (const double *)p2; |
348 | |
|
349 | 0 | if (*dp1 < *dp2) |
350 | 0 | return -1; |
351 | 0 | if (*dp1 > *dp2) |
352 | 0 | return 1; |
353 | 0 | return 0; |
354 | 0 | } |
355 | | |
356 | | |
357 | | /* |
358 | | * refclock_process_offset - update median filter |
359 | | * |
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. |
363 | | */ |
364 | | void |
365 | | refclock_process_offset( |
366 | | struct refclockproc *pp, /* refclock structure pointer */ |
367 | | l_fp lasttim, /* last timecode timestamp */ |
368 | | l_fp lastrec, /* last receive timestamp */ |
369 | | double fudge |
370 | | ) |
371 | 0 | { |
372 | 0 | l_fp lftemp; |
373 | 0 | double doffset; |
374 | |
|
375 | 0 | pp->lastrec = lastrec; |
376 | 0 | lftemp = lasttim; |
377 | 0 | L_SUB(&lftemp, &lastrec); |
378 | 0 | LFPTOD(&lftemp, doffset); |
379 | 0 | SAMPLE(doffset + fudge); |
380 | 0 | } |
381 | | |
382 | | |
383 | | /* |
384 | | * 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. |
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 | | */ |
399 | | int |
400 | | refclock_process_f( |
401 | | struct refclockproc *pp, /* refclock structure pointer */ |
402 | | double fudge |
403 | | ) |
404 | 0 | { |
405 | 0 | l_fp offset, ltemp; |
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 | 0 | if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, |
416 | 0 | pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) |
417 | 0 | return (0); |
418 | | |
419 | 0 | offset.l_uf = 0; |
420 | 0 | DTOLFP(pp->nsec / 1e9, <emp); |
421 | 0 | L_ADD(&offset, <emp); |
422 | 0 | refclock_process_offset(pp, offset, pp->lastrec, fudge); |
423 | 0 | return (1); |
424 | 0 | } |
425 | | |
426 | | |
427 | | int |
428 | | refclock_process( |
429 | | struct refclockproc *pp /* refclock structure pointer */ |
430 | | ) |
431 | 0 | { |
432 | 0 | return refclock_process_f(pp, pp->fudgetime1); |
433 | 0 | } |
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 |
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. |
445 | | */ |
446 | | static int |
447 | | refclock_sample( |
448 | | struct refclockproc *pp /* refclock structure pointer */ |
449 | | ) |
450 | 0 | { |
451 | 0 | size_t i, j, k, m, n; |
452 | 0 | double off[MAXSTAGE]; |
453 | 0 | double offset; |
454 | | |
455 | | /* |
456 | | * Copy the raw offsets and sort into ascending order. Don't do |
457 | | * anything if the buffer is empty. |
458 | | */ |
459 | 0 | n = 0; |
460 | 0 | while (pp->codeproc != pp->coderecv) { |
461 | 0 | pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; |
462 | 0 | off[n] = pp->filter[pp->codeproc]; |
463 | 0 | n++; |
464 | 0 | } |
465 | 0 | if (n == 0) |
466 | 0 | return (0); |
467 | | |
468 | 0 | if (n > 1) |
469 | 0 | qsort(off, n, sizeof(off[0]), 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 | 0 | i = 0; j = n; |
476 | 0 | m = n - (n * 4) / 10; |
477 | 0 | while ((j - i) > m) { |
478 | 0 | offset = off[(j + i) / 2]; |
479 | 0 | if (off[j - 1] - offset < offset - off[i]) |
480 | 0 | i++; /* reject low end */ |
481 | 0 | else |
482 | 0 | j--; /* reject high end */ |
483 | 0 | } |
484 | | |
485 | | /* |
486 | | * Determine the offset and jitter. |
487 | | */ |
488 | 0 | pp->offset = 0; |
489 | 0 | pp->jitter = 0; |
490 | 0 | for (k = i; k < j; k++) { |
491 | 0 | pp->offset += off[k]; |
492 | 0 | if (k > i) |
493 | 0 | pp->jitter += SQUARE(off[k] - off[k - 1]); |
494 | 0 | } |
495 | 0 | pp->offset /= m; |
496 | 0 | pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision)); |
497 | 0 | #ifdef DEBUG |
498 | 0 | if (debug) |
499 | 0 | printf( |
500 | 0 | "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n", |
501 | 0 | (int)n, pp->offset, pp->disp, pp->jitter); |
502 | 0 | #endif |
503 | 0 | return (int)n; |
504 | 0 | } |
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 |
512 | | * filter, selection and combining algorithms can be used to suppress |
513 | | * misbehaving radios and to mitigate between them when more than one is |
514 | | * available for backup. |
515 | | */ |
516 | | void |
517 | | refclock_receive( |
518 | | struct peer *peer /* peer structure pointer */ |
519 | | ) |
520 | 0 | { |
521 | 0 | struct refclockproc *pp; |
522 | |
|
523 | 0 | #ifdef DEBUG |
524 | 0 | if (debug) |
525 | 0 | printf("refclock_receive: at %lu %s\n", |
526 | 0 | current_time, stoa(&peer->srcadr)); |
527 | 0 | #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 | | */ |
534 | 0 | pp = peer->procptr; |
535 | 0 | peer->leap = pp->leap; |
536 | 0 | if (peer->leap == LEAP_NOTINSYNC) |
537 | 0 | return; |
538 | | |
539 | 0 | peer->received++; |
540 | 0 | peer->timereceived = current_time; |
541 | 0 | if (!peer->reach) { |
542 | 0 | report_event(PEVNT_REACH, peer, NULL); |
543 | 0 | peer->timereachable = current_time; |
544 | 0 | } |
545 | 0 | peer->reach |= 1; |
546 | 0 | peer->reftime = pp->lastref; |
547 | 0 | peer->aorg = pp->lastrec; |
548 | 0 | peer->rootdisp = pp->disp; |
549 | 0 | get_systime(&peer->dst); |
550 | 0 | if (!refclock_sample(pp)) |
551 | 0 | return; |
552 | | |
553 | 0 | clock_filter(peer, pp->offset, 0., pp->jitter); |
554 | 0 | if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer != |
555 | 0 | NULL) { |
556 | 0 | if (sys_peer->refclktype == REFCLK_ATOM_PPS && |
557 | 0 | peer->refclktype != REFCLK_ATOM_PPS) |
558 | 0 | pp->fudgetime1 -= pp->offset * FUDGEFAC; |
559 | 0 | } |
560 | 0 | } |
561 | | |
562 | | |
563 | | /* |
564 | | * refclock_gtlin - groom next input line and extract timestamp |
565 | | * |
566 | | * 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. |
571 | | */ |
572 | | int |
573 | | refclock_gtlin( |
574 | | 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 */ |
578 | | ) |
579 | 0 | { |
580 | 0 | const char *sp, *spend; |
581 | 0 | char *dp, *dpend; |
582 | 0 | int dlen; |
583 | |
|
584 | 0 | if (bmax <= 0) |
585 | 0 | return (0); |
586 | | |
587 | 0 | dp = lineptr; |
588 | 0 | dpend = dp + bmax - 1; /* leave room for NUL pad */ |
589 | 0 | sp = (const char *)rbufp->recv_buffer; |
590 | 0 | spend = sp + rbufp->recv_length; |
591 | |
|
592 | 0 | while (sp != spend && dp != dpend) { |
593 | 0 | char c; |
594 | | |
595 | 0 | c = *sp++ & 0x7f; |
596 | 0 | if (c >= 0x20 && c < 0x7f) |
597 | 0 | *dp++ = c; |
598 | 0 | } |
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. |
602 | | */ |
603 | 0 | dlen = dp - lineptr; |
604 | 0 | if (dlen) |
605 | 0 | *dp = '\0'; |
606 | 0 | *tsptr = rbufp->recv_time; |
607 | 0 | DPRINTF(2, ("refclock_gtlin: fd %d time %s timecode %d %s\n", |
608 | 0 | rbufp->fd, ulfptoa(&rbufp->recv_time, 6), dlen, |
609 | 0 | (dlen != 0) |
610 | 0 | ? lineptr |
611 | 0 | : "")); |
612 | 0 | return (dlen); |
613 | 0 | } |
614 | | |
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 | | */ |
631 | | int |
632 | | refclock_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 | 0 | { |
639 | 0 | if (bmax <= 0) |
640 | 0 | return (0); |
641 | 0 | bmax -= 1; /* leave room for trailing NUL */ |
642 | 0 | if (bmax > rbufp->recv_length) |
643 | 0 | bmax = rbufp->recv_length; |
644 | 0 | memcpy(lineptr, rbufp->recv_buffer, bmax); |
645 | 0 | lineptr[bmax] = '\0'; |
646 | |
|
647 | 0 | *tsptr = rbufp->recv_time; |
648 | 0 | DPRINTF(2, ("refclock_gtraw: fd %d time %s timecode %d %s\n", |
649 | 0 | rbufp->fd, ulfptoa(&rbufp->recv_time, 6), bmax, |
650 | 0 | lineptr)); |
651 | 0 | return (bmax); |
652 | 0 | } |
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 | | */ |
666 | | int |
667 | | indicate_refclock_packet( |
668 | | struct refclockio * rio, |
669 | | struct recvbuf * rb |
670 | | ) |
671 | 0 | { |
672 | | /* Does this refclock use direct input routine? */ |
673 | 0 | 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 | 0 | freerecvbuf(rb); |
679 | |
|
680 | 0 | return TRUE; |
681 | 0 | } |
682 | 0 | add_full_recv_buffer(rb); |
683 | |
|
684 | 0 | return FALSE; |
685 | 0 | } |
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 |
696 | | void |
697 | | process_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. |
709 | | */ |
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); |
715 | | } |
716 | | } |
717 | | #endif /* HAVE_IO_COMPLETION_PORT */ |
718 | | |
719 | | |
720 | | /* |
721 | | * The following code does not apply to WINNT & VMS ... |
722 | | */ |
723 | | #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 |
730 | | * returns the file descriptor if successful, or logs an error and |
731 | | * returns -1. |
732 | | */ |
733 | | int |
734 | | refclock_open( |
735 | | const char *dev, /* device name pointer */ |
736 | | u_int speed, /* serial port speed (code) */ |
737 | | u_int lflags /* line discipline flags */ |
738 | | ) |
739 | 0 | { |
740 | 0 | int fd; |
741 | 0 | int omode; |
742 | 0 | #ifdef O_NONBLOCK |
743 | 0 | char trash[128]; /* litter bin for old input data */ |
744 | 0 | #endif |
745 | | |
746 | | /* |
747 | | * Open serial port and set default options |
748 | | */ |
749 | 0 | omode = O_RDWR; |
750 | 0 | #ifdef O_NONBLOCK |
751 | 0 | omode |= O_NONBLOCK; |
752 | 0 | #endif |
753 | 0 | #ifdef O_NOCTTY |
754 | 0 | omode |= O_NOCTTY; |
755 | 0 | #endif |
756 | |
|
757 | 0 | fd = open(dev, omode, 0777); |
758 | | /* refclock_open() long returned 0 on failure, avoid it. */ |
759 | 0 | if (0 == fd) { |
760 | 0 | fd = dup(0); |
761 | 0 | SAVE_ERRNO( |
762 | 0 | close(0); |
763 | 0 | ) |
764 | 0 | } |
765 | 0 | if (fd < 0) { |
766 | 0 | SAVE_ERRNO( |
767 | 0 | msyslog(LOG_ERR, "refclock_open %s: %m", dev); |
768 | 0 | ) |
769 | 0 | return -1; |
770 | 0 | } |
771 | 0 | if (!refclock_setup(fd, speed, lflags)) { |
772 | 0 | close(fd); |
773 | 0 | return -1; |
774 | 0 | } |
775 | 0 | if (!refclock_ioctl(fd, lflags)) { |
776 | 0 | close(fd); |
777 | 0 | return -1; |
778 | 0 | } |
779 | 0 | #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 | 0 | while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR) |
787 | 0 | /*NOP*/; |
788 | 0 | #endif |
789 | 0 | return fd; |
790 | 0 | } |
791 | | |
792 | | |
793 | | /* |
794 | | * refclock_setup - initialize terminal interface structure |
795 | | */ |
796 | | int |
797 | | refclock_setup( |
798 | | int fd, /* file descriptor */ |
799 | | u_int speed, /* serial port speed (code) */ |
800 | | u_int lflags /* line discipline flags */ |
801 | | ) |
802 | 0 | { |
803 | 0 | int i; |
804 | 0 | TTY ttyb, *ttyp; |
805 | | |
806 | | /* |
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. |
813 | | */ |
814 | 0 | ttyp = &ttyb; |
815 | 0 | #ifdef HAVE_TERMIOS |
816 | | |
817 | | /* |
818 | | * POSIX serial line parameters (termios interface) |
819 | | */ |
820 | 0 | if (tcgetattr(fd, ttyp) < 0) { |
821 | 0 | SAVE_ERRNO( |
822 | 0 | msyslog(LOG_ERR, |
823 | 0 | "refclock_setup fd %d tcgetattr: %m", |
824 | 0 | fd); |
825 | 0 | ) |
826 | 0 | return FALSE; |
827 | 0 | } |
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 | | */ |
833 | 0 | if (speed) { |
834 | 0 | u_int ltemp = 0; |
835 | |
|
836 | 0 | ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; |
837 | 0 | ttyp->c_oflag = 0; |
838 | 0 | ttyp->c_cflag = CS8 | CLOCAL | CREAD; |
839 | 0 | if (lflags & LDISC_7O1) { |
840 | | /* HP Z3801A needs 7-bit, odd parity */ |
841 | 0 | ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD; |
842 | 0 | } |
843 | 0 | cfsetispeed(&ttyb, speed); |
844 | 0 | cfsetospeed(&ttyb, speed); |
845 | 0 | for (i = 0; i < NCCS; ++i) |
846 | 0 | ttyp->c_cc[i] = '\0'; |
847 | |
|
848 | 0 | #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 | 0 | if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) |
856 | 0 | msyslog(LOG_ERR, |
857 | 0 | "refclock_setup fd %d TIOCMGET: %m", fd); |
858 | 0 | #ifdef DEBUG |
859 | 0 | if (debug) |
860 | 0 | printf("refclock_setup fd %d modem status: 0x%x\n", |
861 | 0 | fd, ltemp); |
862 | 0 | #endif |
863 | 0 | if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE) |
864 | 0 | ttyp->c_cflag &= ~CLOCAL; |
865 | 0 | #endif /* TIOCMGET */ |
866 | 0 | } |
867 | | |
868 | | /* |
869 | | * Set raw and echo modes. These can be changed on-fly. |
870 | | */ |
871 | 0 | ttyp->c_lflag = ICANON; |
872 | 0 | if (lflags & LDISC_RAW) { |
873 | 0 | ttyp->c_lflag = 0; |
874 | 0 | ttyp->c_iflag = 0; |
875 | 0 | ttyp->c_cc[VMIN] = 1; |
876 | 0 | } |
877 | 0 | if (lflags & LDISC_ECHO) |
878 | 0 | ttyp->c_lflag |= ECHO; |
879 | 0 | if (tcsetattr(fd, TCSANOW, ttyp) < 0) { |
880 | 0 | SAVE_ERRNO( |
881 | 0 | msyslog(LOG_ERR, |
882 | 0 | "refclock_setup fd %d TCSANOW: %m", |
883 | 0 | fd); |
884 | 0 | ) |
885 | 0 | return FALSE; |
886 | 0 | } |
887 | | |
888 | | /* |
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. |
892 | | */ |
893 | 0 | if (tcflush(fd, TCIOFLUSH) < 0) |
894 | 0 | msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m", |
895 | 0 | fd); |
896 | 0 | #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) { |
905 | | SAVE_ERRNO( |
906 | | msyslog(LOG_ERR, |
907 | | "refclock_setup fd %d TCGETA: %m", |
908 | | fd); |
909 | | ) |
910 | | return FALSE; |
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 | | */ |
917 | | if (speed) { |
918 | | u_int ltemp = 0; |
919 | | |
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 *)<emp) < 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 | | /* |
947 | | * Set raw and echo modes. These can be changed on-fly. |
948 | | */ |
949 | | ttyp->c_lflag = ICANON; |
950 | | if (lflags & LDISC_RAW) { |
951 | | ttyp->c_lflag = 0; |
952 | | ttyp->c_iflag = 0; |
953 | | ttyp->c_cc[VMIN] = 1; |
954 | | } |
955 | | 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; |
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) { |
970 | | SAVE_ERRNO( |
971 | | msyslog(LOG_ERR, |
972 | | "refclock_setup fd %d TIOCGETP: %m", |
973 | | fd); |
974 | | ) |
975 | | return FALSE; |
976 | | } |
977 | | if (speed) |
978 | | ttyp->sg_ispeed = ttyp->sg_ospeed = speed; |
979 | | ttyp->sg_flags = EVENP | ODDP | CRMOD; |
980 | | if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { |
981 | | SAVE_ERRNO( |
982 | | msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m"); |
983 | | ) |
984 | | return FALSE; |
985 | | } |
986 | | #endif /* HAVE_BSD_TTYS */ |
987 | 0 | return(1); |
988 | 0 | } |
989 | | #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ |
990 | | |
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 |
998 | | * up optional features such as tty_clk. The routine returns TRUE if |
999 | | * successful. |
1000 | | */ |
1001 | | int |
1002 | | refclock_ioctl( |
1003 | | int fd, /* file descriptor */ |
1004 | | u_int lflags /* line discipline flags */ |
1005 | | ) |
1006 | 0 | { |
1007 | | /* |
1008 | | * simply return TRUE if no UNIX line discipline is supported |
1009 | | */ |
1010 | 0 | DPRINTF(1, ("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags)); |
1011 | |
|
1012 | 0 | return TRUE; |
1013 | 0 | } |
1014 | | #endif /* !defined(SYS_VXWORKS) && !defined(SYS_WINNT) */ |
1015 | | |
1016 | | |
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 | | */ |
1026 | | void |
1027 | | refclock_control( |
1028 | | sockaddr_u *srcadr, |
1029 | | const struct refclockstat *in, |
1030 | | struct refclockstat *out |
1031 | | ) |
1032 | 0 | { |
1033 | 0 | struct peer *peer; |
1034 | 0 | struct refclockproc *pp; |
1035 | 0 | u_char clktype; |
1036 | 0 | int unit; |
1037 | | |
1038 | | /* |
1039 | | * Check for valid address and running peer |
1040 | | */ |
1041 | 0 | if (!ISREFCLOCKADR(srcadr)) |
1042 | 0 | return; |
1043 | | |
1044 | 0 | clktype = (u_char)REFCLOCKTYPE(srcadr); |
1045 | 0 | unit = REFCLOCKUNIT(srcadr); |
1046 | |
|
1047 | 0 | peer = findexistingpeer(srcadr, NULL, NULL, -1, 0, NULL); |
1048 | |
|
1049 | 0 | if (NULL == peer) |
1050 | 0 | return; |
1051 | | |
1052 | 0 | INSIST(peer->procptr != NULL); |
1053 | 0 | pp = peer->procptr; |
1054 | | |
1055 | | /* |
1056 | | * Initialize requested data |
1057 | | */ |
1058 | 0 | if (in != NULL) { |
1059 | 0 | if (in->haveflags & CLK_HAVETIME1) |
1060 | 0 | pp->fudgetime1 = in->fudgetime1; |
1061 | 0 | if (in->haveflags & CLK_HAVETIME2) |
1062 | 0 | pp->fudgetime2 = in->fudgetime2; |
1063 | 0 | if (in->haveflags & CLK_HAVEVAL1) |
1064 | 0 | peer->stratum = pp->stratum = (u_char)in->fudgeval1; |
1065 | 0 | if (in->haveflags & CLK_HAVEVAL2) |
1066 | 0 | peer->refid = pp->refid = in->fudgeval2; |
1067 | 0 | if (in->haveflags & CLK_HAVEFLAG1) { |
1068 | 0 | pp->sloppyclockflag &= ~CLK_FLAG1; |
1069 | 0 | pp->sloppyclockflag |= in->flags & CLK_FLAG1; |
1070 | 0 | } |
1071 | 0 | if (in->haveflags & CLK_HAVEFLAG2) { |
1072 | 0 | pp->sloppyclockflag &= ~CLK_FLAG2; |
1073 | 0 | pp->sloppyclockflag |= in->flags & CLK_FLAG2; |
1074 | 0 | } |
1075 | 0 | if (in->haveflags & CLK_HAVEFLAG3) { |
1076 | 0 | pp->sloppyclockflag &= ~CLK_FLAG3; |
1077 | 0 | pp->sloppyclockflag |= in->flags & CLK_FLAG3; |
1078 | 0 | } |
1079 | 0 | if (in->haveflags & CLK_HAVEFLAG4) { |
1080 | 0 | pp->sloppyclockflag &= ~CLK_FLAG4; |
1081 | 0 | pp->sloppyclockflag |= in->flags & CLK_FLAG4; |
1082 | 0 | } |
1083 | 0 | } |
1084 | | |
1085 | | /* |
1086 | | * Readback requested data |
1087 | | */ |
1088 | 0 | if (out != NULL) { |
1089 | 0 | out->fudgeval1 = pp->stratum; |
1090 | 0 | out->fudgeval2 = pp->refid; |
1091 | 0 | out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2; |
1092 | 0 | out->fudgetime1 = pp->fudgetime1; |
1093 | 0 | if (0.0 != out->fudgetime1) |
1094 | 0 | out->haveflags |= CLK_HAVETIME1; |
1095 | 0 | out->fudgetime2 = pp->fudgetime2; |
1096 | 0 | if (0.0 != out->fudgetime2) |
1097 | 0 | out->haveflags |= CLK_HAVETIME2; |
1098 | 0 | out->flags = (u_char) pp->sloppyclockflag; |
1099 | 0 | if (CLK_FLAG1 & out->flags) |
1100 | 0 | out->haveflags |= CLK_HAVEFLAG1; |
1101 | 0 | if (CLK_FLAG2 & out->flags) |
1102 | 0 | out->haveflags |= CLK_HAVEFLAG2; |
1103 | 0 | if (CLK_FLAG3 & out->flags) |
1104 | 0 | out->haveflags |= CLK_HAVEFLAG3; |
1105 | 0 | if (CLK_FLAG4 & out->flags) |
1106 | 0 | out->haveflags |= CLK_HAVEFLAG4; |
1107 | |
|
1108 | 0 | out->timereset = current_time - pp->timestarted; |
1109 | 0 | out->polls = pp->polls; |
1110 | 0 | out->noresponse = pp->noreply; |
1111 | 0 | out->badformat = pp->badformat; |
1112 | 0 | out->baddata = pp->baddata; |
1113 | |
|
1114 | 0 | out->lastevent = pp->lastevent; |
1115 | 0 | out->currentstatus = pp->currentstatus; |
1116 | 0 | out->type = pp->type; |
1117 | 0 | out->clockdesc = pp->clockdesc; |
1118 | 0 | out->lencode = (u_short)pp->lencode; |
1119 | 0 | out->p_lastcode = pp->a_lastcode; |
1120 | 0 | } |
1121 | | |
1122 | | /* |
1123 | | * Give the stuff to the clock |
1124 | | */ |
1125 | 0 | if (refclock_conf[clktype]->clock_control != noentry) |
1126 | 0 | (refclock_conf[clktype]->clock_control)(unit, in, out, peer); |
1127 | 0 | } |
1128 | | |
1129 | | |
1130 | | /* |
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 | | */ |
1137 | | void |
1138 | | refclock_buginfo( |
1139 | | sockaddr_u *srcadr, /* clock address */ |
1140 | | struct refclockbug *bug /* output structure */ |
1141 | | ) |
1142 | 0 | { |
1143 | 0 | struct peer *peer; |
1144 | 0 | struct refclockproc *pp; |
1145 | 0 | int clktype; |
1146 | 0 | int unit; |
1147 | 0 | unsigned u; |
1148 | | |
1149 | | /* |
1150 | | * Check for valid address and peer structure |
1151 | | */ |
1152 | 0 | if (!ISREFCLOCKADR(srcadr)) |
1153 | 0 | return; |
1154 | | |
1155 | 0 | clktype = (u_char) REFCLOCKTYPE(srcadr); |
1156 | 0 | unit = REFCLOCKUNIT(srcadr); |
1157 | |
|
1158 | 0 | peer = findexistingpeer(srcadr, NULL, NULL, -1, 0, NULL); |
1159 | |
|
1160 | 0 | if (NULL == peer || NULL == peer->procptr) |
1161 | 0 | return; |
1162 | | |
1163 | 0 | pp = peer->procptr; |
1164 | | |
1165 | | /* |
1166 | | * Copy structure values |
1167 | | */ |
1168 | 0 | bug->nvalues = 8; |
1169 | 0 | bug->svalues = 0x0000003f; |
1170 | 0 | bug->values[0] = pp->year; |
1171 | 0 | bug->values[1] = pp->day; |
1172 | 0 | bug->values[2] = pp->hour; |
1173 | 0 | bug->values[3] = pp->minute; |
1174 | 0 | bug->values[4] = pp->second; |
1175 | 0 | bug->values[5] = pp->nsec; |
1176 | 0 | bug->values[6] = pp->yearstart; |
1177 | 0 | bug->values[7] = pp->coderecv; |
1178 | 0 | bug->stimes = 0xfffffffc; |
1179 | 0 | bug->times[0] = pp->lastref; |
1180 | 0 | bug->times[1] = pp->lastrec; |
1181 | 0 | for (u = 2; u < bug->ntimes; u++) |
1182 | 0 | DTOLFP(pp->filter[u - 2], &bug->times[u]); |
1183 | | |
1184 | | /* |
1185 | | * Give the stuff to the clock |
1186 | | */ |
1187 | 0 | if (refclock_conf[clktype]->clock_buginfo != noentry) |
1188 | 0 | (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); |
1189 | 0 | } |
1190 | | |
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 | | */ |
1199 | | int |
1200 | | refclock_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 | | ZERO(ap->ts); /* [Bug 2689] defined INIT state */ |
1212 | | } |
1213 | | return (1); |
1214 | | } |
1215 | | |
1216 | | |
1217 | | /* |
1218 | | * refclock_params - set ppsapi parameters |
1219 | | * |
1220 | | * This routine is called to set the PPSAPI parameters after the fudge |
1221 | | * command. |
1222 | | */ |
1223 | | int |
1224 | | refclock_params( |
1225 | | int mode, /* mode bits */ |
1226 | | struct refclock_atom *ap /* atom structure pointer */ |
1227 | | ) |
1228 | | { |
1229 | | ZERO(ap->pps_params); |
1230 | | ap->pps_params.api_version = PPS_API_VERS_1; |
1231 | | |
1232 | | /* |
1233 | | * Solaris serial ports provide PPS pulse capture only on the |
1234 | | * assert edge. FreeBSD serial ports provide capture on the |
1235 | | * clear edge, while FreeBSD parallel ports provide capture |
1236 | | * on the assert edge. Your mileage may vary. |
1237 | | */ |
1238 | | if (mode & CLK_FLAG2) |
1239 | | ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR; |
1240 | | else |
1241 | | ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT; |
1242 | | if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) { |
1243 | | msyslog(LOG_ERR, |
1244 | | "refclock_params: time_pps_setparams: %m"); |
1245 | | return (0); |
1246 | | } |
1247 | | |
1248 | | /* |
1249 | | * If flag3 is lit, select the kernel PPS if we can. |
1250 | | * |
1251 | | * Note: EOPNOTSUPP is the only 'legal' error code we deal with; |
1252 | | * it is part of the 'if we can' strategy. Any other error |
1253 | | * indicates something more sinister and makes this function fail. |
1254 | | */ |
1255 | | if (mode & CLK_FLAG3) { |
1256 | | if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS, |
1257 | | ap->pps_params.mode & ~PPS_TSFMT_TSPEC, |
1258 | | PPS_TSFMT_TSPEC) < 0) |
1259 | | { |
1260 | | if (errno != EOPNOTSUPP) { |
1261 | | msyslog(LOG_ERR, |
1262 | | "refclock_params: time_pps_kcbind: %m"); |
1263 | | return (0); |
1264 | | } |
1265 | | } else { |
1266 | | hardpps_enable = 1; |
1267 | | } |
1268 | | } |
1269 | | return (1); |
1270 | | } |
1271 | | |
1272 | | |
1273 | | /* |
1274 | | * refclock_pps - called once per second |
1275 | | * |
1276 | | * This routine is called once per second. It snatches the PPS |
1277 | | * timestamp from the kernel and saves the sign-extended fraction in |
1278 | | * a circular buffer for processing at the next poll event. |
1279 | | */ |
1280 | | int |
1281 | | refclock_pps( |
1282 | | struct peer *peer, /* peer structure pointer */ |
1283 | | struct refclock_atom *ap, /* atom structure pointer */ |
1284 | | int mode /* mode bits */ |
1285 | | ) |
1286 | | { |
1287 | | struct refclockproc *pp; |
1288 | | pps_info_t pps_info; |
1289 | | struct timespec timeout; |
1290 | | double dtemp, dcorr, trash; |
1291 | | |
1292 | | /* |
1293 | | * We require the clock to be synchronized before setting the |
1294 | | * parameters. When the parameters have been set, fetch the |
1295 | | * most recent PPS timestamp. |
1296 | | */ |
1297 | | pp = peer->procptr; |
1298 | | if (ap->handle == 0) |
1299 | | return (0); |
1300 | | |
1301 | | if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) { |
1302 | | if (refclock_params(pp->sloppyclockflag, ap) < 1) |
1303 | | return (0); |
1304 | | } |
1305 | | ZERO(timeout); |
1306 | | ZERO(pps_info); |
1307 | | if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info, |
1308 | | &timeout) < 0) { |
1309 | | refclock_report(peer, CEVNT_FAULT); |
1310 | | return (0); |
1311 | | } |
1312 | | timeout = ap->ts; /* save old timestamp for check */ |
1313 | | if (ap->pps_params.mode & PPS_CAPTUREASSERT) |
1314 | | ap->ts = pps_info.assert_timestamp; |
1315 | | else if (ap->pps_params.mode & PPS_CAPTURECLEAR) |
1316 | | ap->ts = pps_info.clear_timestamp; |
1317 | | else |
1318 | | return (0); |
1319 | | |
1320 | | /* [Bug 2689] Discard the first sample we read -- if the PPS |
1321 | | * source is currently down / disconnected, we have read a |
1322 | | * potentially *very* stale value here. So if our old TS value |
1323 | | * is all-zero, we consider this sample unrealiable and drop it. |
1324 | | * |
1325 | | * Note 1: a better check would compare the PPS time stamp to |
1326 | | * the current system time and drop it if it's more than say 3s |
1327 | | * away. |
1328 | | * |
1329 | | * Note 2: If we ever again get an all-zero PPS sample, the next |
1330 | | * one will be discarded. This can happen every 136yrs and is |
1331 | | * unlikely to be ever observed. |
1332 | | */ |
1333 | | if (0 == (timeout.tv_sec | timeout.tv_nsec)) |
1334 | | return (0); |
1335 | | |
1336 | | /* If the PPS source fails to deliver a new sample between |
1337 | | * polls, it regurgitates the last sample. We do not want to |
1338 | | * process the same sample multiple times. |
1339 | | */ |
1340 | | if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout))) |
1341 | | return (0); |
1342 | | |
1343 | | /* |
1344 | | * Convert to signed fraction offset, apply fudge and properly |
1345 | | * fold the correction into the [-0.5s,0.5s] range. Handle |
1346 | | * excessive fudge times, too. |
1347 | | */ |
1348 | | dtemp = ap->ts.tv_nsec / 1e9; |
1349 | | dcorr = modf((pp->fudgetime1 - dtemp), &trash); |
1350 | | if (dcorr > 0.5) |
1351 | | dcorr -= 1.0; |
1352 | | else if (dcorr < -0.5) |
1353 | | dcorr += 1.0; |
1354 | | |
1355 | | /* phase gate check: avoid wobbling by +/-1s when too close to |
1356 | | * the switch-over point. We allow +/-400ms max phase deviation. |
1357 | | * The trade-off is clear: The smaller the limit, the less |
1358 | | * sensitive to sampling noise the clock becomes. OTOH the |
1359 | | * system must get into phase gate range by other means for the |
1360 | | * PPS clock to lock in. |
1361 | | */ |
1362 | | if (fabs(dcorr) > 0.4) |
1363 | | return (0); |
1364 | | |
1365 | | /* |
1366 | | * record this time stamp and stuff in median filter |
1367 | | */ |
1368 | | pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970; |
1369 | | pp->lastrec.l_uf = (u_int32)(dtemp * FRAC); |
1370 | | SAMPLE(dcorr); |
1371 | | |
1372 | | #ifdef DEBUG |
1373 | | if (debug > 1) |
1374 | | printf("refclock_pps: %lu %f %f\n", current_time, |
1375 | | dcorr, pp->fudgetime1); |
1376 | | #endif |
1377 | | return (1); |
1378 | | } |
1379 | | #endif /* HAVE_PPSAPI */ |
1380 | | #endif /* REFCLOCK */ |