📄 ntp_refclock.c
字号:
peer->timereachable = current_time; } peer->reach |= 1; peer->reftime = pp->lastref; peer->org = pp->lastrec; peer->rootdispersion = pp->disp; get_systime(&peer->rec); if (!refclock_sample(pp)) return; clock_filter(peer, pp->offset, 0., pp->jitter); record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), peer->offset, peer->delay, clock_phi * (current_time - peer->epoch), peer->jitter); if (cal_enable && last_offset < MINDISPERSE) {#ifdef KERNEL_PLL if (peer != sys_peer || pll_status & STA_PPSTIME)#else if (peer != sys_peer)#endif /* KERNEL_PLL */ pp->fudgetime1 -= pp->offset * FUDGEFAC; else pp->fudgetime1 -= pp->fudgetime1 * FUDGEFAC; }}/* * refclock_gtlin - groom next input line and extract timestamp * * This routine processes the timecode received from the clock and * strips the parity bit and control characters. It returns the number * of characters in the line followed by a NULL character ('\0'), which * is not included in the count. In case of an empty line, the previous * line is preserved. */intrefclock_gtlin( struct recvbuf *rbufp, /* receive buffer pointer */ char *lineptr, /* current line pointer */ int bmax, /* remaining characters in line */ l_fp *tsptr /* pointer to timestamp returned */ ){ char s[BMAX]; char *dpt, *dpend, *dp; dpt = s; dpend = s + refclock_gtraw(rbufp, s, BMAX - 1, tsptr); if (dpend - dpt > bmax - 1) dpend = dpt + bmax - 1; for (dp = lineptr; dpt < dpend; dpt++) { char c; c = *dpt & 0x7f; if (c >= 0x20 && c < 0x7f) *dp++ = c; } if (dp == lineptr) return (0); *dp = '\0'; return (dp - lineptr);}/* * refclock_gtraw - get next line/chunk of data * * This routine returns the raw data received from the clock in both * canonical or raw modes. The terminal interface routines map CR to LF. * In canonical mode this results in two lines, one containing data * followed by LF and another containing only LF. In raw mode the * interface routines can deliver arbitraty chunks of data from one * character to a maximum specified by the calling routine. In either * mode the routine returns the number of characters in the line * followed by a NULL character ('\0'), which is not included in the * count. * * If a timestamp is present in the timecode, as produced by the tty_clk * STREAMS module, it returns that as the timestamp; otherwise, it * returns the buffer timestamp. */intrefclock_gtraw( struct recvbuf *rbufp, /* receive buffer pointer */ char *lineptr, /* current line pointer */ int bmax, /* remaining characters in line */ l_fp *tsptr /* pointer to timestamp returned */ ){ char *dpt, *dpend, *dp; l_fp trtmp, tstmp; int i; /* * Check for the presence of a timestamp left by the tty_clock * module and, if present, use that instead of the buffer * timestamp captured by the I/O routines. We recognize a * timestamp by noting its value is earlier than the buffer * timestamp, but not more than one second earlier. */ dpt = (char *)rbufp->recv_buffer; dpend = dpt + rbufp->recv_length; trtmp = rbufp->recv_time; if (dpend >= dpt + 8) { if (buftvtots(dpend - 8, &tstmp)) { L_SUB(&trtmp, &tstmp); if (trtmp.l_ui == 0) {#ifdef DEBUG if (debug > 1) { printf( "refclock_gtlin: fd %d ldisc %s", rbufp->fd, lfptoa(&trtmp, 6)); get_systime(&trtmp); L_SUB(&trtmp, &tstmp); printf(" sigio %s\n", lfptoa(&trtmp, 6)); }#endif dpend -= 8; trtmp = tstmp; } else trtmp = rbufp->recv_time; } } /* * Copy the raw buffer to the user string. The string is padded * with a NULL, which is not included in the character count. */ if (dpend - dpt > bmax - 1) dpend = dpt + bmax - 1; for (dp = lineptr; dpt < dpend; dpt++) *dp++ = *dpt; *dp = '\0'; i = dp - lineptr;#ifdef DEBUG if (debug > 1) printf("refclock_gtraw: fd %d time %s timecode %d %s\n", rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr);#endif *tsptr = trtmp; return (i);}/* * The following code does not apply to WINNT & VMS ... */#if !defined SYS_VXWORKS && !defined SYS_WINNT#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)/* * refclock_open - open serial port for reference clock * * This routine opens a serial port for I/O and sets default options. It * returns the file descriptor if success and zero if failure. */intrefclock_open( char *dev, /* device name pointer */ u_int speed, /* serial port speed (code) */ u_int lflags /* line discipline flags */ ){ int fd; int omode; /* * Open serial port and set default options */ omode = O_RDWR;#ifdef O_NONBLOCK omode |= O_NONBLOCK;#endif#ifdef O_NOCTTY omode |= O_NOCTTY;#endif fd = open(dev, omode, 0777); if (fd < 0) { msyslog(LOG_ERR, "refclock_open %s: %m", dev); return (0); } if (!refclock_setup(fd, speed, lflags)) { close(fd); return (0); } if (!refclock_ioctl(fd, lflags)) { close(fd); return (0); } return (fd);}/* * refclock_setup - initialize terminal interface structure */intrefclock_setup( int fd, /* file descriptor */ u_int speed, /* serial port speed (code) */ u_int lflags /* line discipline flags */ ){ int i; TTY ttyb, *ttyp;#ifdef PPS fdpps = fd; /* ppsclock legacy */#endif /* PPS */ /* * By default, the serial line port is initialized in canonical * (line-oriented) mode at specified line speed, 8 bits and no * parity. LF ends the line and CR is mapped to LF. The break, * erase and kill functions are disabled. There is a different * section for each terminal interface, as selected at compile * time. The flag bits can be used to set raw mode and echo. */ ttyp = &ttyb;#ifdef HAVE_TERMIOS /* * POSIX serial line parameters (termios interface) */ if (tcgetattr(fd, ttyp) < 0) { msyslog(LOG_ERR, "refclock_setup fd %d tcgetattr: %m", fd); return (0); } /* * Set canonical mode and local connection; set specified speed, * 8 bits and no parity; map CR to NL; ignore break. */ if (speed) { u_int ltemp = 0; ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; ttyp->c_oflag = 0; ttyp->c_cflag = CS8 | CLOCAL | CREAD; if (lflags & LDISC_7O1) { /* HP Z3801A needs 7-bit, odd parity */ ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD; } cfsetispeed(&ttyb, speed); cfsetospeed(&ttyb, speed); for (i = 0; i < NCCS; ++i) ttyp->c_cc[i] = '\0';#if defined(TIOCMGET) && !defined(SCO5_CLOCK) /* * If we have modem control, check to see if modem leads * are active; if so, set remote connection. This is * necessary for the kernel pps mods to work. */ if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) msyslog(LOG_ERR, "refclock_setup fd %d TIOCMGET: %m", fd);#ifdef DEBUG if (debug) printf("refclock_setup fd %d modem status: 0x%x\n", fd, ltemp);#endif if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE) ttyp->c_cflag &= ~CLOCAL;#endif /* TIOCMGET */ } /* * Set raw and echo modes. These can be changed on-fly. */ ttyp->c_lflag = ICANON; if (lflags & LDISC_RAW) { ttyp->c_lflag = 0; ttyp->c_cc[VMIN] = 1; } if (lflags & LDISC_ECHO) ttyp->c_lflag |= ECHO; if (tcsetattr(fd, TCSANOW, ttyp) < 0) { msyslog(LOG_ERR, "refclock_setup fd %d TCSANOW: %m", fd); return (0); }#endif /* HAVE_TERMIOS */#ifdef HAVE_SYSV_TTYS /* * System V serial line parameters (termio interface) * */ if (ioctl(fd, TCGETA, ttyp) < 0) { msyslog(LOG_ERR, "refclock_setup fd %d TCGETA: %m", fd); return (0); } /* * Set canonical mode and local connection; set specified speed, * 8 bits and no parity; map CR to NL; ignore break. */ if (speed) { u_int ltemp = 0; ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; ttyp->c_oflag = 0; ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; for (i = 0; i < NCCS; ++i) ttyp->c_cc[i] = '\0';#if defined(TIOCMGET) && !defined(SCO5_CLOCK) /* * If we have modem control, check to see if modem leads * are active; if so, set remote connection. This is * necessary for the kernel pps mods to work. */ if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) msyslog(LOG_ERR, "refclock_setup fd %d TIOCMGET: %m", fd);#ifdef DEBUG if (debug) printf("refclock_setup fd %d modem status: %x\n", fd, ltemp);#endif if (ltemp & TIOCM_DSR) ttyp->c_cflag &= ~CLOCAL;#endif /* TIOCMGET */ } /* * Set raw and echo modes. These can be changed on-fly. */ ttyp->c_lflag = ICANON; if (lflags & LDISC_RAW) { ttyp->c_lflag = 0; ttyp->c_cc[VMIN] = 1; } if (ioctl(fd, TCSETA, ttyp) < 0) { msyslog(LOG_ERR, "refclock_setup fd %d TCSETA: %m", fd); return (0); }#endif /* HAVE_SYSV_TTYS */#ifdef HAVE_BSD_TTYS /* * 4.3bsd serial line parameters (sgttyb interface) */ if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { msyslog(LOG_ERR, "refclock_setup fd %d TIOCGETP: %m", fd); return (0); } if (speed) ttyp->sg_ispeed = ttyp->sg_ospeed = speed; ttyp->sg_flags = EVENP | ODDP | CRMOD; if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m"); return (0); }#endif /* HAVE_BSD_TTYS */ return(1);}#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */#endif /* SYS_VXWORKS SYS_WINNT *//* * refclock_ioctl - set serial port control functions * * This routine attempts to hide the internal, system-specific details * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD * (sgtty) interfaces with varying degrees of success. The routine sets * up optional features such as tty_clk. The routine returns 1 if * success and 0 if failure. */intrefclock_ioctl( int fd, /* file descriptor */ u_int lflags /* line discipline flags */ ){ /* * simply return 1 if no UNIX line discipline is supported */#if !defined SYS_VXWORKS && !defined SYS_WINNT#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)#ifdef DEBUG if (debug) printf("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags);#endif#ifdef TTYCLK /* * The TTYCLK option provides timestamping at the driver level. * It requires the tty_clk streams module and System V STREAMS * support. If not available, don't complain. */ if (lflags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) { int rval = 0; if (ioctl(fd, I_PUSH, "clk") < 0) { msyslog(LOG_NOTICE, "refclock_ioctl fd %d I_PUSH: %m", fd); return (0);#ifdef CLK_SETSTR } else { char *str; if (lflags & LDISC_CLKPPS) str = "\377"; else if (lflags & LDISC_ACTS) str = "*"; else str = "\n"; if (ioctl(fd, CLK_SETSTR, str) < 0) { msyslog(LOG_ERR, "refclock_ioctl fd %d CLK_SETSTR: %m", fd); return (0); }#endif /*CLK_SETSTR */ } }#endif /* TTYCLK */#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */#endif /* SYS_VXWORKS SYS_WINNT */ return (1);}/* * refclock_control - set and/or return clock values * * This routine is used mainly for debugging. It returns designated * values from the interface structure that can be displayed using * ntpdc and the clockstat command. It can also be used to initialize * configuration variables, such as fudgetimes, fudgevalues, reference * ID and stratum. */voidrefclock_control( struct sockaddr_storage *srcadr, struct refclockstat *in, struct refclockstat *out ){ struct peer *peer; struct refclockproc *pp; u_char clktype; int unit; /* * Check for valid address and running peer */ if (srcadr->ss_family != AF_INET) return; if (!ISREFCLOCKADR(srcadr)) return; clktype = (u_char)REFCLOCKTYPE(srcadr); unit = REFCLOCKUNIT(srcadr); if (clktype >= num_refclock_conf || unit >= MAXUNIT) return; peer = typeunit[clktype][unit]; if (peer == NULL) return; if (peer->procptr == NULL) return; pp = peer->procptr; /* * Initialize requested data */ if (in != 0) { if (in->haveflags & CLK_HAVETIME1) pp->fudgetime1 = in->fudgetime1; if (in->haveflags & CLK_HAVETIME2) pp->fudgetime2 = in->fudgetime2; if (in->haveflags & CLK_HAVEVAL1) peer->stratum = pp->stratum = (u_char)in->fudgeval1; if (in->haveflags & CLK_HAVEVAL2) peer->refid = pp->refid = in->fudgeval2; if (in->haveflags & CLK_HAVEFLAG1) { pp->sloppyclockflag &= ~CLK_FLAG1; pp->sloppyclockflag |= in->flags & CLK_FLAG1; } if (in->haveflags & CLK_HAVEFLAG2) { pp->sloppyclockflag &= ~CLK_FLAG2; pp->sloppyclockflag |= in->flags & CLK_FLAG2; } if (in->haveflags & CLK_HAVEFLAG3) { pp->sloppyclockflag &= ~CLK_FLAG3; pp->sloppyclockflag |= in->flags & CLK_FLAG3; } if (in->haveflags & CLK_HAVEFLAG4) { pp->sloppyclockflag &= ~CLK_FLAG4; pp->sloppyclockflag |= in->flags & CLK_FLAG4; } } /* * Readback requested data */ if (out != 0) { out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 | CLK_HAVEVAL2 | CLK_HAVEFLAG4; out->fudgetime1 = pp->fudgetime1; out->fudgetime2 = pp->fudgetime2; out->fudgeval1 = pp->stratum; out->fudgeval2 = pp->refid; out->flags = (u_char) pp->sloppyclockflag; out->timereset = current_time - pp->timestarted; out->polls = pp->polls; out->noresponse = pp->noreply; out->badformat = pp->badformat; out->baddata = pp->baddata; out->lastevent = pp->lastevent; out->currentstatus = pp->currentstatus; out->type = pp->type; out->clockdesc = pp->clockdesc; out->lencode = pp->lencode; out->p_lastcode = pp->a_lastcode; } /* * Give the stuff to the clock */ if (refclock_conf[clktype]->clock_control != noentry) (refclock_conf[clktype]->clock_control)(unit, in, out, peer);}/* * refclock_buginfo - return debugging info * * This routine is used mainly for debugging. It returns designated * values from the interface structure that can be displayed using * ntpdc and the clkbug command. */voidrefclock_buginfo( struct sockaddr_storage *srcadr, /* clock address */ struct refclockbug *bug /* output structure */ ){ struct peer *peer; struct refclockproc *pp; u_char clktype; int unit; int i; /* * Check for valid address and peer structure */ if (srcadr->ss_family != AF_INET) return; if (!ISREFCLOCKADR(srcadr)) return; clktype = (u_char) REFCLOCKTYPE(srcadr); unit = REFCLOCKUNIT(srcadr); if (clktype >= num_refclock_conf || unit >= MAXUNIT) return; peer = typeunit[clktype][unit]; if (peer == NULL) return; pp = peer->procptr; /* * Copy structure values */ bug->nvalues = 8; bug->svalues = 0x0000003f; bug->values[0] = pp->year; bug->values[1] = pp->day; bug->values[2] = pp->hour; bug->values[3] = pp->minute; bug->values[4] = pp->second; bug->values[5] = pp->nsec; bug->values[6] = pp->yearstart; bug->values[7] = pp->coderecv; bug->stimes = 0xfffffffc; bug->times[0] = pp->lastref; bug->times[1] = pp->lastrec; for (i = 2; i < (int)bug->ntimes; i++) DTOLFP(pp->filter[i - 2], &bug->times[i]); /* * Give the stuff to the clock */ if (refclock_conf[clktype]->clock_buginfo != noentry) (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);}#endif /* REFCLOCK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -