2 * ntp_refclock - processing support for reference clocks
10 #include "ntp_unixtime.h"
12 #include "ntp_refclock.h"
13 #include "ntp_stdlib.h"
17 #ifdef HAVE_SYS_IOCTL_H
18 # include <sys/ioctl.h>
19 #endif /* HAVE_SYS_IOCTL_H */
24 # ifdef HAVE_SYS_CLKDEFS_H
25 # include <sys/clkdefs.h>
28 # ifdef HAVE_SYS_SIO_H
33 #ifdef HAVE_PPSCLOCK_H
34 #include <sys/ppsclock.h>
35 #endif /* HAVE_PPSCLOCK_H */
38 #include "ntp_syscall.h"
39 #endif /* KERNEL_PLL */
42 * Reference clock support is provided here by maintaining the fiction
43 * that the clock is actually a peer. As no packets are exchanged with a
44 * reference clock, however, we replace the transmit, receive and packet
45 * procedures with separate code to simulate them. Routines
46 * refclock_transmit() and refclock_receive() maintain the peer
47 * variables in a state analogous to an actual peer and pass reference
48 * clock data on through the filters. Routines refclock_peer() and
49 * refclock_unpeer() are called to initialize and terminate reference
50 * clock associations. A set of utility routines is included to open
51 * serial devices, process sample data, edit input lines to extract
52 * embedded timestamps and to peform various debugging functions.
54 * The main interface used by these routines is the refclockproc
55 * structure, which contains for most drivers the decimal equivalants of
56 * the year, day, month, hour, second and millisecond/microsecond
57 * decoded from the ASCII timecode. Additional information includes the
58 * receive timestamp, exception report, statistics tallies, etc. In
59 * addition, there may be a driver-specific unit structure used for
60 * local control of the device.
62 * The support routines are passed a pointer to the peer structure,
63 * which is used for all peer-specific processing and contains a pointer
64 * to the refclockproc structure, which in turn containes a pointer to
65 * the unit structure, if used. The peer structure is identified by an
66 * interface address in the dotted quad form 127.127.t.u, where t is the
67 * clock type and u the unit. Some legacy drivers derive the
68 * refclockproc structure pointer from the table typeunit[type][unit].
69 * This interface is strongly discouraged and may be abandoned in
72 #define MAXUNIT 4 /* max units */
73 #define FUDGEFAC .1 /* fudge correction factor */
75 int fdpps; /* pps file descriptor */
76 int cal_enable; /* enable refclock calibrate */
79 * Type/unit peer index. Used to find the peer structure for control and
80 * debugging. When all clock drivers have been converted to new style,
83 static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT];
86 * Forward declarations
88 #ifdef QSORT_USES_VOID_P
89 static int refclock_cmpl_fp P((const void *, const void *));
91 static int refclock_cmpl_fp P((const double *, const double *));
92 #endif /* QSORT_USES_VOID_P */
93 static int refclock_sample P((struct refclockproc *));
96 * refclock_report - note the occurance of an event
98 * This routine presently just remembers the report and logs it, but
99 * does nothing heroic for the trap handler. It tries to be a good
100 * citizen and bothers the system log only if things change.
108 struct refclockproc *pp;
110 if (!(pp = peer->procptr))
112 if (code == CEVNT_BADREPLY)
114 if (code == CEVNT_BADTIME)
116 if (code == CEVNT_TIMEOUT)
118 if (pp->currentstatus != code) {
119 pp->currentstatus = code;
120 pp->lastevent = code;
121 if (code == CEVNT_FAULT)
123 "clock %s event '%s' (0x%02x)",
124 refnumtoa(peer->srcadr.sin_addr.s_addr),
125 ceventstr(code), code);
127 NLOG(NLOG_CLOCKEVENT)
129 "clock %s event '%s' (0x%02x)",
130 refnumtoa(peer->srcadr.sin_addr.s_addr),
131 ceventstr(code), code);
136 printf("clock %s event '%s' (0x%02x)\n",
137 refnumtoa(peer->srcadr.sin_addr.s_addr),
138 ceventstr(code), code);
144 * init_refclock - initialize the reference clock drivers
146 * This routine calls each of the drivers in turn to initialize internal
147 * variables, if necessary. Most drivers have nothing to say at this
155 for (i = 0; i < (int)num_refclock_conf; i++) {
156 if (refclock_conf[i]->clock_init != noentry)
157 (refclock_conf[i]->clock_init)();
158 for (j = 0; j < MAXUNIT; j++)
165 * refclock_newpeer - initialize and start a reference clock
167 * This routine allocates and initializes the interface structure which
168 * supports a reference clock in the form of an ordinary NTP peer. A
169 * driver-specific support routine completes the initialization, if
170 * used. Default peer variables which identify the clock and establish
171 * its reference ID and stratum are set here. It returns one if success
172 * and zero if the clock address is invalid or already running,
173 * insufficient resources are available or the driver declares a bum
178 struct peer *peer /* peer structure pointer */
181 struct refclockproc *pp;
186 * Check for valid clock address. If already running, shut it
189 if (!ISREFCLOCKADR(&peer->srcadr)) {
191 "refclock_newpeer: clock address %s invalid",
192 ntoa(&peer->srcadr));
195 clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
196 unit = REFCLOCKUNIT(&peer->srcadr);
197 if (clktype >= num_refclock_conf || unit >= MAXUNIT ||
198 refclock_conf[clktype]->clock_start == noentry) {
200 "refclock_newpeer: clock type %d invalid\n",
206 * Allocate and initialize interface structure
208 if (!(pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc))))
210 memset((char *)pp, 0, sizeof(struct refclockproc));
211 typeunit[clktype][unit] = peer;
215 * Initialize structures
217 peer->refclktype = clktype;
218 peer->refclkunit = unit;
219 peer->flags |= FLAG_REFCLOCK;
220 peer->stratum = STRATUM_REFCLOCK;
221 peer->refid = peer->srcadr.sin_addr.s_addr;
222 peer->maxpoll = peer->minpoll;
225 pp->timestarted = current_time;
228 * Set peer.pmode based on the hmode. For appearances only.
230 switch (peer->hmode) {
233 peer->pmode = MODE_PASSIVE;
237 peer->pmode = MODE_SERVER;
242 * Do driver dependent initialization. The above defaults
243 * can be wiggled, then finish up for consistency.
245 if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {
246 refclock_unpeer(peer);
249 peer->hpoll = peer->minpoll;
250 peer->ppoll = peer->maxpoll;
251 if (peer->stratum <= 1)
252 peer->refid = pp->refid;
254 peer->refid = peer->srcadr.sin_addr.s_addr;
260 * refclock_unpeer - shut down a clock
264 struct peer *peer /* peer structure pointer */
271 * Wiggle the driver to release its resources, then give back
272 * the interface structure.
276 clktype = peer->refclktype;
277 unit = peer->refclkunit;
278 if (refclock_conf[clktype]->clock_shutdown != noentry)
279 (refclock_conf[clktype]->clock_shutdown)(unit, peer);
286 * refclock_transmit - simulate the transmit procedure
288 * This routine implements the NTP transmit procedure for a reference
289 * clock. This provides a mechanism to call the driver at the NTP poll
290 * interval, as well as provides a reachability mechanism to detect a
291 * broken radio or other madness.
295 struct peer *peer /* peer structure pointer */
303 clktype = peer->refclktype;
304 unit = peer->refclkunit;
308 * This is a ripoff of the peer transmit routine, but
309 * specialized for reference clocks. We do a little less
310 * protocol here and call the driver-specific transmit routine.
313 next = peer->outdate;
314 if (peer->burst == 0) {
318 printf("refclock_transmit: at %ld %s\n",
319 current_time, ntoa(&(peer->srcadr)));
323 * Update reachability and poll variables like the
326 oreach = peer->reach;
330 report_event(EVNT_UNREACH, peer);
331 peer->timereachable = current_time;
335 if (!(oreach & 0x03)) {
336 clock_filter(peer, 0., 0., MAXDISPERSE);
339 if (!(oreach & 0x0f)) {
341 } else if ((oreach & 0x0f) == 0x0f)
343 if (peer->flags & FLAG_BURST)
344 peer->burst = NSTAGE;
348 get_systime(&peer->xmt);
349 if (refclock_conf[clktype]->clock_poll != noentry)
350 (refclock_conf[clktype]->clock_poll)(unit, peer);
351 peer->outdate = next;
354 poll_update(peer, hpoll);
359 * Compare two doubles - used with qsort()
361 #ifdef QSORT_USES_VOID_P
368 const double *dp1 = (const double *)p1;
369 const double *dp2 = (const double *)p2;
390 #endif /* QSORT_USES_VOID_P */
394 * refclock_process_offset - update median filter
396 * This routine uses the given offset and timestamps to construct a new
397 * entry in the median filter circular buffer. Samples that overflow the
398 * filter are quietly discarded.
401 refclock_process_offset(
402 struct refclockproc *pp,
410 pp->lastref = offset;
411 pp->lastrec = lastrec;
412 L_SUB(&offset, &lastrec);
413 LFPTOD(&offset, doffset);
414 SAMPLE(doffset + fudge);
418 * refclock_process - process a sample from the clock
420 * This routine converts the timecode in the form days, hours, minutes,
421 * seconds and milliseconds/microseconds to internal timestamp format,
422 * then constructs a new entry in the median filter circular buffer.
423 * Return success (1) if the data are correct and consistent with the
424 * converntional calendar.
428 struct refclockproc *pp
434 * Compute the timecode timestamp from the days, hours, minutes,
435 * seconds and milliseconds/microseconds of the timecode. Use
436 * clocktime() for the aggregate seconds and the msec/usec for
437 * the fraction, when present. Note that this code relies on the
438 * filesystem time for the years and does not use the years of
441 if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
442 pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui))
445 TVUTOTSF(pp->usec, offset.l_uf);
447 MSUTOTSF(pp->msec, offset.l_uf);
449 refclock_process_offset(pp, offset, pp->lastrec,
455 * refclock_sample - process a pile of samples from the clock
457 * This routine implements a recursive median filter to suppress spikes
458 * in the data, as well as determine a performance statistic. It
459 * calculates the mean offset and jitter (squares). A time adjustment
460 * fudgetime1 can be added to the final offset to compensate for various
461 * systematic errors. The routine returns the number of samples
462 * processed, which could be zero.
466 struct refclockproc *pp
471 double off[MAXSTAGE];
474 * Copy the raw offsets and sort into ascending order. Don't do
475 * anything if the buffer is empty.
477 if (pp->codeproc == pp->coderecv)
480 while (pp->codeproc != pp->coderecv)
481 off[n++] = pp->filter[pp->codeproc++ % MAXSTAGE];
483 qsort((char *)off, (size_t)n, sizeof(double), refclock_cmpl_fp);
486 * Reject the furthest from the median of the samples until
487 * approximately 60 percent of the samples remain.
490 m = n - (n * 2) / NSTAGE;
491 while ((j - i) > m) {
492 offset = off[(j + i) / 2];
493 if (off[j - 1] - offset < offset - off[i])
494 i++; /* reject low end */
496 j--; /* reject high end */
500 * Determine the offset and jitter.
503 for (k = i; k < j; k++)
505 pp->offset = offset / m;
507 pp->jitter = SQUARE(off[i] - off[j - 1]);
513 "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n",
514 n, pp->offset, pp->disp, SQRT(pp->jitter));
521 * refclock_receive - simulate the receive and packet procedures
523 * This routine simulates the NTP receive and packet procedures for a
524 * reference clock. This provides a mechanism in which the ordinary NTP
525 * filter, selection and combining algorithms can be used to suppress
526 * misbehaving radios and to mitigate between them when more than one is
527 * available for backup.
531 struct peer *peer /* peer structure pointer */
534 struct refclockproc *pp;
538 printf("refclock_receive: at %lu %s\n",
539 current_time, ntoa(&peer->srcadr));
543 * Do a little sanity dance and update the peer structure. Groom
544 * the median filter samples and give the data to the clock
550 peer->timereceived = current_time;
551 peer->leap = pp->leap;
552 if (peer->leap == LEAP_NOTINSYNC) {
553 refclock_report(peer, CEVNT_FAULT);
557 report_event(EVNT_REACH, peer);
559 peer->reftime = peer->org = pp->lastrec;
560 peer->rootdispersion = pp->disp + SQRT(pp->jitter);
561 get_systime(&peer->rec);
562 if (!refclock_sample(pp))
564 clock_filter(peer, pp->offset, 0., pp->jitter);
566 record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
567 peer->offset, peer->delay, clock_phi * (current_time -
568 peer->epoch), SQRT(peer->jitter));
569 if (cal_enable && last_offset < MINDISPERSE) {
571 if (peer != sys_peer || pll_status & STA_PPSTIME)
573 if (peer != sys_peer)
574 #endif /* KERNEL_PLL */
575 pp->fudgetime1 -= pp->offset * FUDGEFAC;
577 pp->fudgetime1 -= pp->fudgetime1 * FUDGEFAC;
582 * refclock_gtlin - groom next input line and extract timestamp
584 * This routine processes the timecode received from the clock and
585 * removes the parity bit and control characters. If a timestamp is
586 * present in the timecode, as produced by the tty_clk STREAMS module,
587 * it returns that as the timestamp; otherwise, it returns the buffer
588 * timestamp. The routine return code is the number of characters in
593 struct recvbuf *rbufp, /* receive buffer pointer */
594 char *lineptr, /* current line pointer */
595 int bmax, /* remaining characters in line */
596 l_fp *tsptr /* pointer to timestamp returned */
599 char *dpt, *dpend, *dp;
605 * Check for the presence of a timestamp left by the tty_clock
606 * module and, if present, use that instead of the buffer
607 * timestamp captured by the I/O routines. We recognize a
608 * timestamp by noting its value is earlier than the buffer
609 * timestamp, but not more than one second earlier.
611 dpt = (char *)&rbufp->recv_space;
612 dpend = dpt + rbufp->recv_length;
613 trtmp = rbufp->recv_time;
615 if (dpend >= dpt + 8) {
616 if (buftvtots(dpend - 8, &tstmp)) {
617 L_SUB(&trtmp, &tstmp);
618 if (trtmp.l_ui == 0) {
622 "refclock_gtlin: fd %d ldisc %s",
623 rbufp->fd, lfptoa(&trtmp, 6));
625 L_SUB(&trtmp, &tstmp);
626 printf(" sigio %s\n", lfptoa(&trtmp, 6));
632 trtmp = rbufp->recv_time;
637 * Edit timecode to remove control chars. Don't monkey with the
638 * line buffer if the input buffer contains no ASCII printing
641 if (dpend - dpt > bmax - 1)
642 dpend = dpt + bmax - 1;
643 for (dp = lineptr; dpt < dpend; dpt++) {
652 if (debug > 1 && i > 0)
653 printf("refclock_gtlin: fd %d time %s timecode %d %s\n",
654 rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr);
661 * The following code does not apply to WINNT & VMS ...
663 #if !defined SYS_VXWORKS && !defined SYS_WINNT
664 #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
667 * refclock_open - open serial port for reference clock
669 * This routine opens a serial port for I/O and sets default options. It
670 * returns the file descriptor if success and zero if failure.
674 char *dev, /* device name pointer */
675 int speed, /* serial port speed (code) */
676 int lflags /* line discipline flags */
684 #endif /* TIOCMGET */
688 * Open serial port and set default options
700 fd = open(dev, omode, 0777);
703 msyslog(LOG_ERR, "refclock_open: %s: %m", dev);
708 * This little jewel lights up the PPS file descriptor if the
709 * device name matches the name in the pps line in the
710 * configuration file. This is so the atom driver can glom onto
711 * the right device. Very silly.
713 if (strcmp(dev, pps_device) == 0)
717 * The following sections initialize the serial line port in
718 * canonical (line-oriented) mode and set the specified line
719 * speed, 8 bits and no parity. The modem control, break, erase
720 * and kill functions are normally disabled. There is a
721 * different section for each terminal interface, as selected at
728 * POSIX serial line parameters (termios interface)
730 if (tcgetattr(fd, ttyp) < 0) {
732 "refclock_open: fd %d tcgetattr: %m", fd);
737 * Set canonical mode and local connection; set specified speed,
738 * 8 bits and no parity; map CR to NL; ignore break.
740 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
742 ttyp->c_cflag = CS8 | CLOCAL | CREAD;
743 (void)cfsetispeed(&ttyb, (u_int)speed);
744 (void)cfsetospeed(&ttyb, (u_int)speed);
745 ttyp->c_lflag = ICANON;
746 for (i = 0; i < NCCS; ++i)
748 ttyp->c_cc[i] = '\0';
754 if (flags & LDISC_RAW) {
757 ttyp->c_cc[VMIN] = 1;
759 #if defined(TIOCMGET) && !defined(SCO5_CLOCK)
761 * If we have modem control, check to see if modem leads are
762 * active; if so, set remote connection. This is necessary for
763 * the kernel pps mods to work.
766 if (ioctl(fd, TIOCMGET, (char *)<emp) < 0)
768 "refclock_open: fd %d TIOCMGET failed: %m", fd);
771 printf("refclock_open: fd %d modem status 0x%lx\n",
774 if (ltemp & TIOCM_DSR)
775 ttyp->c_cflag &= ~CLOCAL;
776 #endif /* TIOCMGET */
777 if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
779 "refclock_open: fd %d TCSANOW failed: %m", fd);
782 if (tcflush(fd, TCIOFLUSH) < 0) {
784 "refclock_open: fd %d TCIOFLUSH failed: %m", fd);
787 #endif /* HAVE_TERMIOS */
789 #ifdef HAVE_SYSV_TTYS
792 * System V serial line parameters (termio interface)
795 if (ioctl(fd, TCGETA, ttyp) < 0) {
797 "refclock_open: fd %d TCGETA failed: %m", fd);
802 * Set canonical mode and local connection; set specified speed,
803 * 8 bits and no parity; map CR to NL; ignore break.
805 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
807 ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD;
808 ttyp->c_lflag = ICANON;
809 ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
814 if (flags & LDISC_RAW) {
820 * If we have modem control, check to see if modem leads are
821 * active; if so, set remote connection. This is necessary for
822 * the kernel pps mods to work.
825 if (ioctl(fd, TIOCMGET, (char *)<emp) < 0)
827 "refclock_open: fd %d TIOCMGET failed: %m", fd);
830 printf("refclock_open: fd %d modem status %lx\n",
833 if (ltemp & TIOCM_DSR)
834 ttyp->c_cflag &= ~CLOCAL;
835 #endif /* TIOCMGET */
836 if (ioctl(fd, TCSETA, ttyp) < 0) {
838 "refclock_open: fd %d TCSETA failed: %m", fd);
841 #endif /* HAVE_SYSV_TTYS */
846 * 4.3bsd serial line parameters (sgttyb interface)
848 if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
850 "refclock_open: fd %d TIOCGETP %m", fd);
853 ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
854 ttyp->sg_flags = EVENP | ODDP | CRMOD;
855 if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
857 "refclock_open: TIOCSETP failed: %m");
860 #endif /* HAVE_BSD_TTYS */
861 if (!refclock_ioctl(fd, flags)) {
864 "refclock_open: fd %d ioctl failed: %m", fd);
869 #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
870 #endif /* SYS_VXWORKS SYS_WINNT */
873 * refclock_ioctl - set serial port control functions
875 * This routine attempts to hide the internal, system-specific details
876 * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
877 * (sgtty) interfaces with varying degrees of success. The routine sets
878 * up optional features such as tty_clk. The routine returns 1 if
879 * success and 0 if failure.
883 int fd, /* file descriptor */
884 int flags /* line discipline flags */
887 /* simply return 1 if no UNIX line discipline is supported */
888 #if !defined SYS_VXWORKS && !defined SYS_WINNT
889 #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
897 printf("refclock_ioctl: fd %d flags 0x%x\n", fd, flags);
901 #if !(defined(HAVE_TERMIOS) || defined(HAVE_BSD_TTYS))
902 if (flags & (LDISC_CLK | LDISC_PPS | LDISC_ACTS)) {
904 "refclock_ioctl: unsupported terminal interface");
907 #endif /* HAVE_TERMIOS HAVE_BSD_TTYS */
913 * The following features may or may not require System V
914 * STREAMS support, depending on the particular implementation.
918 * The TTYCLK option provides timestamping at the driver level.
919 * It requires the tty_clk streams module and System V STREAMS
920 * support. If not available, don't complain.
922 if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
925 if (ioctl(fd, I_PUSH, "clk") < 0) {
927 "refclock_ioctl: I_PUSH clk failed: %m");
931 if (flags & LDISC_CLKPPS)
933 else if (flags & LDISC_ACTS)
938 if ((rval = ioctl(fd, CLK_SETSTR, str)) < 0)
940 "refclock_ioctl: CLK_SETSTR failed: %m");
942 printf("refclock_ioctl: fd %d CLK_SETSTR %d str %s\n",
948 #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
949 #endif /* SYS_VXWORKS SYS_WINNT */
954 * refclock_control - set and/or return clock values
956 * This routine is used mainly for debugging. It returns designated
957 * values from the interface structure that can be displayed using
958 * ntpdc and the clockstat command. It can also be used to initialize
959 * configuration variables, such as fudgetimes, fudgevalues, reference
964 struct sockaddr_in *srcadr,
965 struct refclockstat *in,
966 struct refclockstat *out
970 struct refclockproc *pp;
975 * Check for valid address and running peer
977 if (!ISREFCLOCKADR(srcadr))
979 clktype = (u_char)REFCLOCKTYPE(srcadr);
980 unit = REFCLOCKUNIT(srcadr);
981 if (clktype >= num_refclock_conf || unit >= MAXUNIT)
983 if (!(peer = typeunit[clktype][unit]))
985 if (peer->procptr == NULL)
990 * Initialize requested data
993 if (in->haveflags & CLK_HAVETIME1)
994 pp->fudgetime1 = in->fudgetime1;
995 if (in->haveflags & CLK_HAVETIME2)
996 pp->fudgetime2 = in->fudgetime2;
997 if (in->haveflags & CLK_HAVEVAL1)
998 peer->stratum = (u_char) in->fudgeval1;
999 if (in->haveflags & CLK_HAVEVAL2)
1000 pp->refid = in->fudgeval2;
1001 if (peer->stratum <= 1)
1002 peer->refid = pp->refid;
1004 peer->refid = peer->srcadr.sin_addr.s_addr;
1005 if (in->haveflags & CLK_HAVEFLAG1) {
1006 pp->sloppyclockflag &= ~CLK_FLAG1;
1007 pp->sloppyclockflag |= in->flags & CLK_FLAG1;
1009 if (in->haveflags & CLK_HAVEFLAG2) {
1010 pp->sloppyclockflag &= ~CLK_FLAG2;
1011 pp->sloppyclockflag |= in->flags & CLK_FLAG2;
1013 if (in->haveflags & CLK_HAVEFLAG3) {
1014 pp->sloppyclockflag &= ~CLK_FLAG3;
1015 pp->sloppyclockflag |= in->flags & CLK_FLAG3;
1017 if (in->haveflags & CLK_HAVEFLAG4) {
1018 pp->sloppyclockflag &= ~CLK_FLAG4;
1019 pp->sloppyclockflag |= in->flags & CLK_FLAG4;
1024 * Readback requested data
1027 out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 |
1028 CLK_HAVEVAL2 | CLK_HAVEFLAG4;
1029 out->fudgetime1 = pp->fudgetime1;
1030 out->fudgetime2 = pp->fudgetime2;
1031 out->fudgeval1 = peer->stratum;
1032 out->fudgeval2 = pp->refid;
1033 out->flags = (u_char) pp->sloppyclockflag;
1035 out->timereset = current_time - pp->timestarted;
1036 out->polls = pp->polls;
1037 out->noresponse = pp->noreply;
1038 out->badformat = pp->badformat;
1039 out->baddata = pp->baddata;
1041 out->lastevent = pp->lastevent;
1042 out->currentstatus = pp->currentstatus;
1043 out->type = pp->type;
1044 out->clockdesc = pp->clockdesc;
1045 out->lencode = pp->lencode;
1046 out->p_lastcode = pp->a_lastcode;
1050 * Give the stuff to the clock
1052 if (refclock_conf[clktype]->clock_control != noentry)
1053 (refclock_conf[clktype]->clock_control)(unit, in, out, peer);
1058 * refclock_buginfo - return debugging info
1060 * This routine is used mainly for debugging. It returns designated
1061 * values from the interface structure that can be displayed using
1062 * ntpdc and the clkbug command.
1066 struct sockaddr_in *srcadr, /* clock address */
1067 struct refclockbug *bug /* output structure */
1071 struct refclockproc *pp;
1077 * Check for valid address and peer structure
1079 if (!ISREFCLOCKADR(srcadr))
1081 clktype = (u_char) REFCLOCKTYPE(srcadr);
1082 unit = REFCLOCKUNIT(srcadr);
1083 if (clktype >= num_refclock_conf || unit >= MAXUNIT)
1085 if (!(peer = typeunit[clktype][unit]))
1090 * Copy structure values
1093 bug->svalues = 0x0000003f;
1094 bug->values[0] = pp->year;
1095 bug->values[1] = pp->day;
1096 bug->values[2] = pp->hour;
1097 bug->values[3] = pp->minute;
1098 bug->values[4] = pp->second;
1099 bug->values[5] = pp->msec;
1100 bug->values[6] = pp->yearstart;
1101 bug->values[7] = pp->coderecv;
1102 bug->stimes = 0xfffffffc;
1103 bug->times[0] = pp->lastref;
1104 bug->times[1] = pp->lastrec;
1105 for (i = 2; i < (int)bug->ntimes; i++)
1106 DTOLFP(pp->filter[i - 2], &bug->times[i]);
1109 * Give the stuff to the clock
1111 if (refclock_conf[clktype]->clock_buginfo != noentry)
1112 (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);
1115 #endif /* REFCLOCK */