1 /* $NetBSD: ntp_refclock.c,v 1.3 2004/10/10 22:13:04 christos Exp $ */
4 * ntp_refclock - processing support for reference clocks
12 #include "ntp_unixtime.h"
14 #include "ntp_refclock.h"
15 #include "ntp_stdlib.h"
19 #ifdef HAVE_SYS_IOCTL_H
20 # include <sys/ioctl.h>
21 #endif /* HAVE_SYS_IOCTL_H */
26 # ifdef HAVE_SYS_CLKDEFS_H
27 # include <sys/clkdefs.h>
30 # ifdef HAVE_SYS_SIO_H
36 #include "ntp_syscall.h"
37 #endif /* KERNEL_PLL */
40 * Reference clock support is provided here by maintaining the fiction
41 * that the clock is actually a peer. As no packets are exchanged with a
42 * reference clock, however, we replace the transmit, receive and packet
43 * procedures with separate code to simulate them. Routines
44 * refclock_transmit() and refclock_receive() maintain the peer
45 * variables in a state analogous to an actual peer and pass reference
46 * clock data on through the filters. Routines refclock_peer() and
47 * refclock_unpeer() are called to initialize and terminate reference
48 * clock associations. A set of utility routines is included to open
49 * serial devices, process sample data, edit input lines to extract
50 * embedded timestamps and to peform various debugging functions.
52 * The main interface used by these routines is the refclockproc
53 * structure, which contains for most drivers the decimal equivalants of
54 * the year, day, month, hour, second and millisecond/microsecond
55 * decoded from the ASCII timecode. Additional information includes the
56 * receive timestamp, exception report, statistics tallies, etc. In
57 * addition, there may be a driver-specific unit structure used for
58 * local control of the device.
60 * The support routines are passed a pointer to the peer structure,
61 * which is used for all peer-specific processing and contains a pointer
62 * to the refclockproc structure, which in turn containes a pointer to
63 * the unit structure, if used. The peer structure is identified by an
64 * interface address in the dotted quad form 127.127.t.u (for now only
65 * IPv4 addresses are used, so we need to be sure the address is it),
66 * where t is the clock type and u the unit. Some legacy drivers derive
67 * the refclockproc structure pointer from the table
68 * typeunit[type][unit]. This interface is strongly discouraged and may
69 * be abandoned in future.
71 #define MAXUNIT 8 /* max units */
72 #define FUDGEFAC .1 /* fudge correction factor */
73 #define LF 0x0a /* ASCII LF */
76 int fdpps
; /* ppsclock legacy */
78 int cal_enable
; /* enable refclock calibrate */
81 * Type/unit peer index. Used to find the peer structure for control and
82 * debugging. When all clock drivers have been converted to new style,
85 static struct peer
*typeunit
[REFCLK_MAX
+ 1][MAXUNIT
];
88 * Forward declarations
90 #ifdef QSORT_USES_VOID_P
91 static int refclock_cmpl_fp
P((const void *, const void *));
93 static int refclock_cmpl_fp
P((const double *, const double *));
94 #endif /* QSORT_USES_VOID_P */
95 static int refclock_sample
P((struct refclockproc
*));
99 * refclock_report - note the occurance of an event
101 * This routine presently just remembers the report and logs it, but
102 * does nothing heroic for the trap handler. It tries to be a good
103 * citizen and bothers the system log only if things change.
111 struct refclockproc
*pp
;
141 /* shouldn't happen */
145 if (pp
->currentstatus
!= code
) {
146 pp
->currentstatus
= (u_char
)code
;
148 /* RFC1305: copy only iff not CEVNT_NOMINAL */
149 if (code
!= CEVNT_NOMINAL
)
150 pp
->lastevent
= (u_char
)code
;
152 if (code
== CEVNT_FAULT
)
154 "clock %s event '%s' (0x%02x)",
155 refnumtoa(&peer
->srcadr
),
156 ceventstr(code
), code
);
158 NLOG(NLOG_CLOCKEVENT
)
160 "clock %s event '%s' (0x%02x)",
161 refnumtoa(&peer
->srcadr
),
162 ceventstr(code
), code
);
165 /* RFC1305: post peer clock event */
166 report_event(EVNT_PEERCLOCK
, peer
);
171 * init_refclock - initialize the reference clock drivers
173 * This routine calls each of the drivers in turn to initialize internal
174 * variables, if necessary. Most drivers have nothing to say at this
182 for (i
= 0; i
< (int)num_refclock_conf
; i
++) {
183 if (refclock_conf
[i
]->clock_init
!= noentry
)
184 (refclock_conf
[i
]->clock_init
)();
185 for (j
= 0; j
< MAXUNIT
; j
++)
192 * refclock_newpeer - initialize and start a reference clock
194 * This routine allocates and initializes the interface structure which
195 * supports a reference clock in the form of an ordinary NTP peer. A
196 * driver-specific support routine completes the initialization, if
197 * used. Default peer variables which identify the clock and establish
198 * its reference ID and stratum are set here. It returns one if success
199 * and zero if the clock address is invalid or already running,
200 * insufficient resources are available or the driver declares a bum
205 struct peer
*peer
/* peer structure pointer */
208 struct refclockproc
*pp
;
213 * Check for valid clock address. If already running, shut it
216 if (peer
->srcadr
.ss_family
!= AF_INET
) {
218 "refclock_newpeer: clock address %s invalid, address family not implemented for refclock",
219 stoa(&peer
->srcadr
));
222 if (!ISREFCLOCKADR(&peer
->srcadr
)) {
224 "refclock_newpeer: clock address %s invalid",
225 stoa(&peer
->srcadr
));
228 clktype
= (u_char
)REFCLOCKTYPE(&peer
->srcadr
);
229 unit
= REFCLOCKUNIT(&peer
->srcadr
);
230 if (clktype
>= num_refclock_conf
|| unit
>= MAXUNIT
||
231 refclock_conf
[clktype
]->clock_start
== noentry
) {
233 "refclock_newpeer: clock type %d invalid\n",
239 * Allocate and initialize interface structure
241 pp
= (struct refclockproc
*)emalloc(sizeof(struct refclockproc
));
245 memset((char *)pp
, 0, sizeof(struct refclockproc
));
246 typeunit
[clktype
][unit
] = peer
;
250 * Initialize structures
252 peer
->refclktype
= clktype
;
253 peer
->refclkunit
= (u_char
)unit
;
254 peer
->flags
|= FLAG_REFCLOCK
| FLAG_FIXPOLL
;
255 peer
->leap
= LEAP_NOTINSYNC
;
256 peer
->stratum
= STRATUM_REFCLOCK
;
257 peer
->ppoll
= peer
->maxpoll
;
259 pp
->timestarted
= current_time
;
262 * Set peer.pmode based on the hmode. For appearances only.
264 switch (peer
->hmode
) {
266 peer
->pmode
= MODE_PASSIVE
;
270 peer
->pmode
= MODE_SERVER
;
275 * Do driver dependent initialization. The above defaults
276 * can be wiggled, then finish up for consistency.
278 if (!((refclock_conf
[clktype
]->clock_start
)(unit
, peer
))) {
279 refclock_unpeer(peer
);
282 peer
->refid
= pp
->refid
;
288 * refclock_unpeer - shut down a clock
292 struct peer
*peer
/* peer structure pointer */
299 * Wiggle the driver to release its resources, then give back
300 * the interface structure.
305 clktype
= peer
->refclktype
;
306 unit
= peer
->refclkunit
;
307 if (refclock_conf
[clktype
]->clock_shutdown
!= noentry
)
308 (refclock_conf
[clktype
]->clock_shutdown
)(unit
, peer
);
315 * refclock_timer - called once per second for housekeeping.
319 struct peer
*peer
/* peer structure pointer */
325 clktype
= peer
->refclktype
;
326 unit
= peer
->refclkunit
;
327 if (refclock_conf
[clktype
]->clock_timer
!= noentry
)
328 (refclock_conf
[clktype
]->clock_timer
)(unit
, peer
);
333 * refclock_transmit - simulate the transmit procedure
335 * This routine implements the NTP transmit procedure for a reference
336 * clock. This provides a mechanism to call the driver at the NTP poll
337 * interval, as well as provides a reachability mechanism to detect a
338 * broken radio or other madness.
342 struct peer
*peer
/* peer structure pointer */
348 clktype
= peer
->refclktype
;
349 unit
= peer
->refclkunit
;
351 get_systime(&peer
->xmt
);
354 * This is a ripoff of the peer transmit routine, but
355 * specialized for reference clocks. We do a little less
356 * protocol here and call the driver-specific transmit routine.
358 if (peer
->burst
== 0) {
362 printf("refclock_transmit: at %ld %s\n",
363 current_time
, stoa(&(peer
->srcadr
)));
367 * Update reachability and poll variables like the
370 oreach
= peer
->reach
;
372 peer
->outdate
= current_time
;
375 report_event(EVNT_UNREACH
, peer
);
376 peer
->timereachable
= current_time
;
379 if (!(oreach
& 0x07)) {
380 clock_filter(peer
, 0., 0., MAXDISPERSE
);
383 if (peer
->flags
& FLAG_BURST
)
384 peer
->burst
= NSTAGE
;
389 if (refclock_conf
[clktype
]->clock_poll
!= noentry
)
390 (refclock_conf
[clktype
]->clock_poll
)(unit
, peer
);
391 poll_update(peer
, peer
->hpoll
);
396 * Compare two doubles - used with qsort()
398 #ifdef QSORT_USES_VOID_P
405 const double *dp1
= (const double *)p1
;
406 const double *dp2
= (const double *)p2
;
432 #endif /* QSORT_USES_VOID_P */
436 * refclock_process_offset - update median filter
438 * This routine uses the given offset and timestamps to construct a new
439 * entry in the median filter circular buffer. Samples that overflow the
440 * filter are quietly discarded.
443 refclock_process_offset(
444 struct refclockproc
*pp
, /* refclock structure pointer */
445 l_fp lasttim
, /* last timecode timestamp */
446 l_fp lastrec
, /* last receive timestamp */
453 pp
->lastrec
= lastrec
;
455 L_SUB(&lftemp
, &lastrec
);
456 LFPTOD(&lftemp
, doffset
);
457 SAMPLE(doffset
+ fudge
);
462 * refclock_process - process a sample from the clock
464 * This routine converts the timecode in the form days, hours, minutes,
465 * seconds and milliseconds/microseconds to internal timestamp format,
466 * then constructs a new entry in the median filter circular buffer.
467 * Return success (1) if the data are correct and consistent with the
468 * converntional calendar.
470 * Important for PPS users: Normally, the pp->lastrec is set to the
471 * system time when the on-time character is received and the pp->year,
472 * ..., pp->second decoded and the seconds fraction pp->nsec in
473 * nanoseconds). When a PPS offset is available, pp->nsec is forced to
474 * zero and the fraction for pp->lastrec is set to the PPS offset.
478 struct refclockproc
*pp
/* refclock structure pointer */
484 * Compute the timecode timestamp from the days, hours, minutes,
485 * seconds and milliseconds/microseconds of the timecode. Use
486 * clocktime() for the aggregate seconds and the msec/usec for
487 * the fraction, when present. Note that this code relies on the
488 * filesystem time for the years and does not use the years of
491 if (!clocktime(pp
->day
, pp
->hour
, pp
->minute
, pp
->second
, GMT
,
492 pp
->lastrec
.l_ui
, &pp
->yearstart
, &offset
.l_ui
))
496 DTOLFP(pp
->nsec
/ 1e9
, <emp
);
497 L_ADD(&offset
, <emp
);
498 refclock_process_offset(pp
, offset
, pp
->lastrec
,
505 * refclock_sample - process a pile of samples from the clock
507 * This routine implements a recursive median filter to suppress spikes
508 * in the data, as well as determine a performance statistic. It
509 * calculates the mean offset and RMS jitter. A time adjustment
510 * fudgetime1 can be added to the final offset to compensate for various
511 * systematic errors. The routine returns the number of samples
512 * processed, which could be zero.
516 struct refclockproc
*pp
/* refclock structure pointer */
520 double off
[MAXSTAGE
];
524 * Copy the raw offsets and sort into ascending order. Don't do
525 * anything if the buffer is empty.
528 while (pp
->codeproc
!= pp
->coderecv
) {
529 pp
->codeproc
= (pp
->codeproc
+ 1) % MAXSTAGE
;
530 off
[n
] = pp
->filter
[pp
->codeproc
];
538 #ifdef QSORT_USES_VOID_P
543 off
, (size_t)n
, sizeof(double), refclock_cmpl_fp
);
546 * Reject the furthest from the median of the samples until
547 * approximately 60 percent of the samples remain.
550 m
= n
- (n
* 4) / 10;
551 while ((j
- i
) > m
) {
552 offset
= off
[(j
+ i
) / 2];
553 if (off
[j
- 1] - offset
< offset
- off
[i
])
554 i
++; /* reject low end */
556 j
--; /* reject high end */
560 * Determine the offset and jitter.
564 for (k
= i
; k
< j
; k
++) {
565 pp
->offset
+= off
[k
];
567 pp
->jitter
+= SQUARE(off
[k
] - off
[k
- 1]);
570 pp
->jitter
= max(SQRT(pp
->jitter
/ m
), LOGTOD(sys_precision
));
574 "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n",
575 n
, pp
->offset
, pp
->disp
, pp
->jitter
);
582 * refclock_receive - simulate the receive and packet procedures
584 * This routine simulates the NTP receive and packet procedures for a
585 * reference clock. This provides a mechanism in which the ordinary NTP
586 * filter, selection and combining algorithms can be used to suppress
587 * misbehaving radios and to mitigate between them when more than one is
588 * available for backup.
592 struct peer
*peer
/* peer structure pointer */
595 struct refclockproc
*pp
;
599 printf("refclock_receive: at %lu %s\n",
600 current_time
, stoa(&peer
->srcadr
));
604 * Do a little sanity dance and update the peer structure. Groom
605 * the median filter samples and give the data to the clock
609 peer
->leap
= pp
->leap
;
610 if (peer
->leap
== LEAP_NOTINSYNC
)
614 peer
->timereceived
= current_time
;
616 report_event(EVNT_REACH
, peer
);
617 peer
->timereachable
= current_time
;
620 peer
->reftime
= pp
->lastref
;
621 peer
->org
= pp
->lastrec
;
622 peer
->rootdispersion
= pp
->disp
;
623 get_systime(&peer
->rec
);
624 if (!refclock_sample(pp
))
627 clock_filter(peer
, pp
->offset
, 0., pp
->jitter
);
628 record_peer_stats(&peer
->srcadr
, ctlpeerstatus(peer
),
629 peer
->offset
, peer
->delay
, clock_phi
* (current_time
-
630 peer
->epoch
), peer
->jitter
);
631 if (cal_enable
&& last_offset
< MINDISPERSE
) {
633 if (peer
!= sys_peer
|| pll_status
& STA_PPSTIME
)
635 if (peer
!= sys_peer
)
636 #endif /* KERNEL_PLL */
637 pp
->fudgetime1
-= pp
->offset
* FUDGEFAC
;
639 pp
->fudgetime1
-= pp
->fudgetime1
* FUDGEFAC
;
645 * refclock_gtlin - groom next input line and extract timestamp
647 * This routine processes the timecode received from the clock and
648 * strips the parity bit and control characters. It returns the number
649 * of characters in the line followed by a NULL character ('\0'), which
650 * is not included in the count. In case of an empty line, the previous
655 struct recvbuf
*rbufp
, /* receive buffer pointer */
656 char *lineptr
, /* current line pointer */
657 int bmax
, /* remaining characters in line */
658 l_fp
*tsptr
/* pointer to timestamp returned */
662 char *dpt
, *dpend
, *dp
;
665 dpend
= s
+ refclock_gtraw(rbufp
, s
, BMAX
- 1, tsptr
);
666 if (dpend
- dpt
> bmax
- 1)
667 dpend
= dpt
+ bmax
- 1;
668 for (dp
= lineptr
; dpt
< dpend
; dpt
++) {
672 if (c
>= 0x20 && c
< 0x7f)
679 return (dp
- lineptr
);
684 * refclock_gtraw - get next line/chunk of data
686 * This routine returns the raw data received from the clock in both
687 * canonical or raw modes. The terminal interface routines map CR to LF.
688 * In canonical mode this results in two lines, one containing data
689 * followed by LF and another containing only LF. In raw mode the
690 * interface routines can deliver arbitraty chunks of data from one
691 * character to a maximum specified by the calling routine. In either
692 * mode the routine returns the number of characters in the line
693 * followed by a NULL character ('\0'), which is not included in the
696 * If a timestamp is present in the timecode, as produced by the tty_clk
697 * STREAMS module, it returns that as the timestamp; otherwise, it
698 * returns the buffer timestamp.
702 struct recvbuf
*rbufp
, /* receive buffer pointer */
703 char *lineptr
, /* current line pointer */
704 int bmax
, /* remaining characters in line */
705 l_fp
*tsptr
/* pointer to timestamp returned */
708 char *dpt
, *dpend
, *dp
;
713 * Check for the presence of a timestamp left by the tty_clock
714 * module and, if present, use that instead of the buffer
715 * timestamp captured by the I/O routines. We recognize a
716 * timestamp by noting its value is earlier than the buffer
717 * timestamp, but not more than one second earlier.
719 dpt
= (char *)rbufp
->recv_buffer
;
720 dpend
= dpt
+ rbufp
->recv_length
;
721 trtmp
= rbufp
->recv_time
;
722 if (dpend
>= dpt
+ 8) {
723 if (buftvtots(dpend
- 8, &tstmp
)) {
724 L_SUB(&trtmp
, &tstmp
);
725 if (trtmp
.l_ui
== 0) {
729 "refclock_gtlin: fd %d ldisc %s",
730 rbufp
->fd
, lfptoa(&trtmp
,
733 L_SUB(&trtmp
, &tstmp
);
734 printf(" sigio %s\n",
741 trtmp
= rbufp
->recv_time
;
746 * Copy the raw buffer to the user string. The string is padded
747 * with a NULL, which is not included in the character count.
749 if (dpend
- dpt
> bmax
- 1)
750 dpend
= dpt
+ bmax
- 1;
751 for (dp
= lineptr
; dpt
< dpend
; dpt
++)
757 printf("refclock_gtraw: fd %d time %s timecode %d %s\n",
758 rbufp
->fd
, ulfptoa(&trtmp
, 6), i
, lineptr
);
766 * The following code does not apply to WINNT & VMS ...
768 #if !defined SYS_VXWORKS && !defined SYS_WINNT
769 #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
772 * refclock_open - open serial port for reference clock
774 * This routine opens a serial port for I/O and sets default options. It
775 * returns the file descriptor if success and zero if failure.
779 char *dev
, /* device name pointer */
780 u_int speed
, /* serial port speed (code) */
781 u_int lflags
/* line discipline flags */
788 * Open serial port and set default options
798 fd
= open(dev
, omode
, 0777);
800 msyslog(LOG_ERR
, "refclock_open %s: %m", dev
);
803 if (!refclock_setup(fd
, speed
, lflags
)) {
807 if (!refclock_ioctl(fd
, lflags
)) {
815 * refclock_setup - initialize terminal interface structure
819 int fd
, /* file descriptor */
820 u_int speed
, /* serial port speed (code) */
821 u_int lflags
/* line discipline flags */
827 fdpps
= fd
; /* ppsclock legacy */
831 * By default, the serial line port is initialized in canonical
832 * (line-oriented) mode at specified line speed, 8 bits and no
833 * parity. LF ends the line and CR is mapped to LF. The break,
834 * erase and kill functions are disabled. There is a different
835 * section for each terminal interface, as selected at compile
836 * time. The flag bits can be used to set raw mode and echo.
842 * POSIX serial line parameters (termios interface)
844 if (tcgetattr(fd
, ttyp
) < 0) {
846 "refclock_setup fd %d tcgetattr: %m", fd
);
851 * Set canonical mode and local connection; set specified speed,
852 * 8 bits and no parity; map CR to NL; ignore break.
857 ttyp
->c_iflag
= IGNBRK
| IGNPAR
| ICRNL
;
859 ttyp
->c_cflag
= CS8
| CLOCAL
| CREAD
;
860 if (lflags
& LDISC_7O1
) {
861 /* HP Z3801A needs 7-bit, odd parity */
862 ttyp
->c_cflag
= CS7
| PARENB
| PARODD
| CLOCAL
| CREAD
;
864 cfsetispeed(&ttyb
, speed
);
865 cfsetospeed(&ttyb
, speed
);
866 for (i
= 0; i
< NCCS
; ++i
)
867 ttyp
->c_cc
[i
] = '\0';
869 #if defined(TIOCMGET) && !defined(SCO5_CLOCK)
872 * If we have modem control, check to see if modem leads
873 * are active; if so, set remote connection. This is
874 * necessary for the kernel pps mods to work.
876 if (ioctl(fd
, TIOCMGET
, (char *)<emp
) < 0)
878 "refclock_setup fd %d TIOCMGET: %m", fd
);
881 printf("refclock_setup fd %d modem status: 0x%x\n",
884 if (ltemp
& TIOCM_DSR
&& lflags
& LDISC_REMOTE
)
885 ttyp
->c_cflag
&= ~CLOCAL
;
886 #endif /* TIOCMGET */
890 * Set raw and echo modes. These can be changed on-fly.
892 ttyp
->c_lflag
= ICANON
;
893 if (lflags
& LDISC_RAW
) {
896 ttyp
->c_cc
[VMIN
] = 1;
898 if (lflags
& LDISC_ECHO
)
899 ttyp
->c_lflag
|= ECHO
;
900 if (tcsetattr(fd
, TCSANOW
, ttyp
) < 0) {
902 "refclock_setup fd %d TCSANOW: %m", fd
);
905 #endif /* HAVE_TERMIOS */
907 #ifdef HAVE_SYSV_TTYS
910 * System V serial line parameters (termio interface)
913 if (ioctl(fd
, TCGETA
, ttyp
) < 0) {
915 "refclock_setup fd %d TCGETA: %m", fd
);
920 * Set canonical mode and local connection; set specified speed,
921 * 8 bits and no parity; map CR to NL; ignore break.
926 ttyp
->c_iflag
= IGNBRK
| IGNPAR
| ICRNL
;
928 ttyp
->c_cflag
= speed
| CS8
| CLOCAL
| CREAD
;
929 for (i
= 0; i
< NCCS
; ++i
)
930 ttyp
->c_cc
[i
] = '\0';
932 #if defined(TIOCMGET) && !defined(SCO5_CLOCK)
935 * If we have modem control, check to see if modem leads
936 * are active; if so, set remote connection. This is
937 * necessary for the kernel pps mods to work.
939 if (ioctl(fd
, TIOCMGET
, (char *)<emp
) < 0)
941 "refclock_setup fd %d TIOCMGET: %m", fd
);
944 printf("refclock_setup fd %d modem status: %x\n",
947 if (ltemp
& TIOCM_DSR
)
948 ttyp
->c_cflag
&= ~CLOCAL
;
949 #endif /* TIOCMGET */
953 * Set raw and echo modes. These can be changed on-fly.
955 ttyp
->c_lflag
= ICANON
;
956 if (lflags
& LDISC_RAW
) {
959 ttyp
->c_cc
[VMIN
] = 1;
961 if (ioctl(fd
, TCSETA
, ttyp
) < 0) {
963 "refclock_setup fd %d TCSETA: %m", fd
);
966 #endif /* HAVE_SYSV_TTYS */
971 * 4.3bsd serial line parameters (sgttyb interface)
973 if (ioctl(fd
, TIOCGETP
, (char *)ttyp
) < 0) {
975 "refclock_setup fd %d TIOCGETP: %m", fd
);
979 ttyp
->sg_ispeed
= ttyp
->sg_ospeed
= speed
;
980 ttyp
->sg_flags
= EVENP
| ODDP
| CRMOD
;
981 if (ioctl(fd
, TIOCSETP
, (char *)ttyp
) < 0) {
983 "refclock_setup TIOCSETP: %m");
986 #endif /* HAVE_BSD_TTYS */
989 #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
990 #endif /* SYS_VXWORKS SYS_WINNT */
994 * refclock_ioctl - set serial port control functions
996 * This routine attempts to hide the internal, system-specific details
997 * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
998 * (sgtty) interfaces with varying degrees of success. The routine sets
999 * up optional features such as tty_clk. The routine returns 1 if
1000 * success and 0 if failure.
1004 int fd
, /* file descriptor */
1005 u_int lflags
/* line discipline flags */
1009 * simply return 1 if no UNIX line discipline is supported
1011 #if !defined SYS_VXWORKS && !defined SYS_WINNT
1012 #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
1016 printf("refclock_ioctl: fd %d flags 0x%x\n", fd
,
1022 * The TTYCLK option provides timestamping at the driver level.
1023 * It requires the tty_clk streams module and System V STREAMS
1024 * support. If not available, don't complain.
1026 if (lflags
& (LDISC_CLK
| LDISC_CLKPPS
| LDISC_ACTS
)) {
1029 if (ioctl(fd
, I_PUSH
, "clk") < 0) {
1031 "refclock_ioctl fd %d I_PUSH: %m", fd
);
1037 if (lflags
& LDISC_CLKPPS
)
1039 else if (lflags
& LDISC_ACTS
)
1043 if (ioctl(fd
, CLK_SETSTR
, str
) < 0) {
1045 "refclock_ioctl fd %d CLK_SETSTR: %m", fd
);
1048 #endif /*CLK_SETSTR */
1052 #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
1053 #endif /* SYS_VXWORKS SYS_WINNT */
1059 * refclock_control - set and/or return clock values
1061 * This routine is used mainly for debugging. It returns designated
1062 * values from the interface structure that can be displayed using
1063 * ntpdc and the clockstat command. It can also be used to initialize
1064 * configuration variables, such as fudgetimes, fudgevalues, reference
1069 struct sockaddr_storage
*srcadr
,
1070 struct refclockstat
*in
,
1071 struct refclockstat
*out
1075 struct refclockproc
*pp
;
1080 * Check for valid address and running peer
1082 if (srcadr
->ss_family
!= AF_INET
)
1085 if (!ISREFCLOCKADR(srcadr
))
1088 clktype
= (u_char
)REFCLOCKTYPE(srcadr
);
1089 unit
= REFCLOCKUNIT(srcadr
);
1090 if (clktype
>= num_refclock_conf
|| unit
>= MAXUNIT
)
1093 peer
= typeunit
[clktype
][unit
];
1097 if (peer
->procptr
== NULL
)
1103 * Initialize requested data
1106 if (in
->haveflags
& CLK_HAVETIME1
)
1107 pp
->fudgetime1
= in
->fudgetime1
;
1108 if (in
->haveflags
& CLK_HAVETIME2
)
1109 pp
->fudgetime2
= in
->fudgetime2
;
1110 if (in
->haveflags
& CLK_HAVEVAL1
)
1111 peer
->stratum
= pp
->stratum
= (u_char
)in
->fudgeval1
;
1112 if (in
->haveflags
& CLK_HAVEVAL2
)
1113 peer
->refid
= pp
->refid
= in
->fudgeval2
;
1114 if (in
->haveflags
& CLK_HAVEFLAG1
) {
1115 pp
->sloppyclockflag
&= ~CLK_FLAG1
;
1116 pp
->sloppyclockflag
|= in
->flags
& CLK_FLAG1
;
1118 if (in
->haveflags
& CLK_HAVEFLAG2
) {
1119 pp
->sloppyclockflag
&= ~CLK_FLAG2
;
1120 pp
->sloppyclockflag
|= in
->flags
& CLK_FLAG2
;
1122 if (in
->haveflags
& CLK_HAVEFLAG3
) {
1123 pp
->sloppyclockflag
&= ~CLK_FLAG3
;
1124 pp
->sloppyclockflag
|= in
->flags
& CLK_FLAG3
;
1126 if (in
->haveflags
& CLK_HAVEFLAG4
) {
1127 pp
->sloppyclockflag
&= ~CLK_FLAG4
;
1128 pp
->sloppyclockflag
|= in
->flags
& CLK_FLAG4
;
1133 * Readback requested data
1136 out
->haveflags
= CLK_HAVETIME1
| CLK_HAVEVAL1
|
1137 CLK_HAVEVAL2
| CLK_HAVEFLAG4
;
1138 out
->fudgetime1
= pp
->fudgetime1
;
1139 out
->fudgetime2
= pp
->fudgetime2
;
1140 out
->fudgeval1
= pp
->stratum
;
1141 out
->fudgeval2
= pp
->refid
;
1142 out
->flags
= (u_char
) pp
->sloppyclockflag
;
1144 out
->timereset
= current_time
- pp
->timestarted
;
1145 out
->polls
= pp
->polls
;
1146 out
->noresponse
= pp
->noreply
;
1147 out
->badformat
= pp
->badformat
;
1148 out
->baddata
= pp
->baddata
;
1150 out
->lastevent
= pp
->lastevent
;
1151 out
->currentstatus
= pp
->currentstatus
;
1152 out
->type
= pp
->type
;
1153 out
->clockdesc
= pp
->clockdesc
;
1154 out
->lencode
= pp
->lencode
;
1155 out
->p_lastcode
= pp
->a_lastcode
;
1159 * Give the stuff to the clock
1161 if (refclock_conf
[clktype
]->clock_control
!= noentry
)
1162 (refclock_conf
[clktype
]->clock_control
)(unit
, in
, out
, peer
);
1167 * refclock_buginfo - return debugging info
1169 * This routine is used mainly for debugging. It returns designated
1170 * values from the interface structure that can be displayed using
1171 * ntpdc and the clkbug command.
1175 struct sockaddr_storage
*srcadr
, /* clock address */
1176 struct refclockbug
*bug
/* output structure */
1180 struct refclockproc
*pp
;
1186 * Check for valid address and peer structure
1188 if (srcadr
->ss_family
!= AF_INET
)
1191 if (!ISREFCLOCKADR(srcadr
))
1194 clktype
= (u_char
) REFCLOCKTYPE(srcadr
);
1195 unit
= REFCLOCKUNIT(srcadr
);
1196 if (clktype
>= num_refclock_conf
|| unit
>= MAXUNIT
)
1199 peer
= typeunit
[clktype
][unit
];
1206 * Copy structure values
1209 bug
->svalues
= 0x0000003f;
1210 bug
->values
[0] = pp
->year
;
1211 bug
->values
[1] = pp
->day
;
1212 bug
->values
[2] = pp
->hour
;
1213 bug
->values
[3] = pp
->minute
;
1214 bug
->values
[4] = pp
->second
;
1215 bug
->values
[5] = pp
->nsec
;
1216 bug
->values
[6] = pp
->yearstart
;
1217 bug
->values
[7] = pp
->coderecv
;
1218 bug
->stimes
= 0xfffffffc;
1219 bug
->times
[0] = pp
->lastref
;
1220 bug
->times
[1] = pp
->lastrec
;
1221 for (i
= 2; i
< (int)bug
->ntimes
; i
++)
1222 DTOLFP(pp
->filter
[i
- 2], &bug
->times
[i
]);
1225 * Give the stuff to the clock
1227 if (refclock_conf
[clktype
]->clock_buginfo
!= noentry
)
1228 (refclock_conf
[clktype
]->clock_buginfo
)(unit
, bug
, peer
);
1231 #endif /* REFCLOCK */