⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ntp_refclock.c

📁 Unix/Linux 网络时间协议版本3 Network Time Protocol Version 3 (NTP) distribution for Unix systems
💻 C
📖 第 1 页 / 共 3 页
字号:
 * assembles the samples in a shift register. It implements a recursive * median filter to suppress spikes in the data, as well as determine a * rough dispersion estimate. A configuration constant time adjustment * fudgetime1 can be added to the final offset to compensate for various * systematic errors. The routine returns one if success and zero if * failure due to invalid timecode data or very noisy offsets. * * This interface is needed to allow for clocks (e. g. parse) that can * provide the correct offset including year information (though NTP * usually gives up on offsets greater than 1000 seconds). */intrefclock_sample(sample_offset, pp, nstart, nskeep)        l_fp *sample_offset;	/* input offset (offset! - not a time stamp)				   for filter machine */	struct refclockproc *pp; /* peer structure pointer */	int nstart;		/* stages of median filter */	int nskeep;		/* stages after outlyer trim */{	int i, n;	l_fp offset, median, lftmp;	l_fp off[MAXSTAGE];	u_fp disp;        /*	 * Subtract the receive timestamp from the timecode timestamp	 * to form the raw offset. Insert in the median filter shift	 * register.	 */	pp->nstages = nstart;	offset = *sample_offset;        i = ((int)(pp->coderecv)) % pp->nstages;	pp->filter[i] = offset;	if (pp->coderecv == 0)		for (i = 1; (u_int) i < pp->nstages; i++)			pp->filter[i] = pp->filter[0];	pp->coderecv++;	/*	 * Copy the raw offsets and sort into ascending order	 */	for (i = 0; (u_int) i < pp->nstages; i++)		off[i] = pp->filter[i];	qsort((char *)off, pp->nstages, sizeof(l_fp), refclock_cmpl_fp);	/*	 * Reject the furthest from the median of nstages samples until	 * nskeep samples remain.	 */	i = 0;	n = pp->nstages;	while ((n - i) > nskeep) {		lftmp = off[n - 1];		median = off[(n + i) / 2];		L_SUB(&lftmp, &median);		L_SUB(&median, &off[i]);		if (L_ISHIS(&median, &lftmp)) {			/* reject low end */			i++;		} else {			/* reject high end */			n--;		}	}	/*	 * Compute the dispersion based on the difference between the	 * extremes of the remaining offsets. Add to this the time since	 * the last clock update, which represents the dispersion	 * increase with time. We know that NTP_MAXSKEW is 16. If the	 * sum is greater than the allowed sample dispersion, bail out.	 * If the loop is unlocked, return the most recent offset;	 * otherwise, return the median offset.	 */	lftmp = off[n - 1];	L_SUB(&lftmp, &off[i]);	disp = LFPTOFP(&lftmp) + current_time - pp->lasttime;	if (disp > REFCLOCKMAXDISPERSE)		return (0);        	pp->offset = offset;	pp->dispersion = disp;	return (1);}/* * refclock_receive - simulate the receive and packet procedures * * This routine simulates the NTP receive and packet procedures for a * reference clock. This provides a mechanism in which the ordinary NTP * filter, selection and combining algorithms can be used to suppress * misbehaving radios and to mitigate between them when more than one is * available for backup. */voidrefclock_receive(peer, offset, delay, dispersion, reftime, rectime, leap)	struct peer *peer;	/* peer structure pointer */	l_fp *offset;		/* computed offset (s) */	s_fp delay;		/* computed delay to peer */	u_fp dispersion;	/* computed dispersion to peer */	l_fp *reftime;		/* time at last clock update */	l_fp *rectime;		/* time at last peer update */	int leap;		/* synchronization/leap code */{	int restrict;	int trustable;	int refclock_own_states;	u_fp precision;	peer->received++;#ifdef DEBUG	if (debug)		printf("refclock_receive: %s %s %s %s)\n",		    ntoa(&peer->srcadr), lfptoa(offset, 6),		    fptoa(delay, 5), ufptoa(dispersion, 5));#endif	/*     * some refclock implementations do a complete state and	 * event handling. reporting events must be disabled for	 * these critters (namely parse)	 */		refclock_own_states = leap & REFCLOCK_OWN_STATES;	leap &= ~REFCLOCK_OWN_STATES;	/*	 * The authentication and access-control machinery works, but	 * its utility may be questionable.	 */	restrict = restrictions(&peer->srcadr);	if (restrict & (RES_IGNORE|RES_DONTSERVE))		return;	peer->processed++;	peer->timereceived = current_time;	if (restrict & RES_DONTTRUST)		trustable = 0;	else		trustable = 1;	if (peer->flags & FLAG_AUTHENABLE) {		if (trustable)			peer->flags |= FLAG_AUTHENTIC;		else			peer->flags &= ~FLAG_AUTHENTIC;	}	peer->leap = leap;	/*	 * Set the timestamps. rec and org are in local time, while ref	 * is in timecode time.	 */	peer->rec = peer->org = *rectime;	peer->reftime = *reftime;	/*	 * If the interface has been set to any_interface, set it to the	 * loopback address if we have one. This is so that peers which	 * are unreachable are easy to see in the peer display.	 */	if (peer->dstadr == any_interface && loopback_interface != 0)		peer->dstadr = loopback_interface;	/*	 * Set peer.pmode based on the hmode. For appearances only.	 */	switch (peer->hmode) {	case MODE_ACTIVE:		peer->pmode = MODE_PASSIVE;		break;	default:		peer->pmode = MODE_SERVER;		break;	}	/*	 * Abandon ship if the radio came bum. We only got this far	 * in order to make pretty billboards, even if bum.	 */	if (leap == LEAP_NOTINSYNC)		return;	/*	 * If this guy was previously unreachable, report him	 * reachable.	 */	if (peer->reach == 0) report_event(EVNT_REACH, peer);		peer->reach |= 1;	/*	 * Give the data to the clock filter and update the clock. Note	 * the clock reading precision initialized by the driver is	 * added at this point.	 */	precision = FP_SECOND >> -(int)peer->precision;	if (precision == 0)		precision = 1;	if (!refclock_own_states)	  refclock_report(peer, CEVNT_NOMINAL);	clock_filter(peer, offset, delay, dispersion + precision);	clock_update(peer);}/* * refclock_gtlin - groom next input line and extract timestamp * * This routine processes the timecode received from the clock and * removes the parity bit and control characters. If a timestamp is * present in the timecode, as produced by the tty_clk line * discipline/streams module, it returns that as the timestamp; * otherwise, it returns the buffer timestamp. The routine return code * is the number of characters in the line. */intrefclock_gtlin(rbufp, lineptr, bmax, tsptr)	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;	int i;	l_fp trtmp, tstmp;	char c;	/*	 * Check for the presence of a timestamp left by the tty_clock	 * line discipline/streams 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_space;	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) {					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;		}	}	/*	 * Edit timecode to remove control chars. Don't monkey with the	 * line buffer if the input buffer contains no ASCII printing	 * characters.	 */	if (dpend - dpt > bmax - 1)		dpend = dpt + bmax - 1;	for (dp = lineptr; dpt < dpend; dpt++) {		c = *dpt & 0x7f;		if (c >= ' ')			*dp++ = c;	}	i = dp - lineptr;	if (i > 0)		*dp = '\0';#ifdef DEBUG	if (debug)        	printf("refclock_gtlin: 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(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(dev, speed, flags)	char *dev;		/* device name pointer */	int speed;		/* serial port speed (code) */	int flags;		/* line discipline flags */{	int fd;#ifdef HAVE_TERMIOS	struct termios ttyb, *ttyp;#endif /* HAVE_TERMIOS */#ifdef HAVE_SYSV_TTYS	struct termio ttyb, *ttyp;#endif /* HAVE_SYSV_TTYS */#ifdef HAVE_BSD_TTYS	struct sgttyb ttyb, *ttyp;#endif /* HAVE_BSD_TTYS */#ifdef TIOCMGET	u_long ltemp;#endif /* TIOCMGET */	/*	 * Open serial port and set default options	 */	fd = open(dev, O_RDWR#ifdef O_NONBLOCK		       | O_NONBLOCK#endif		  , 0777);	if (fd == -1) {		msyslog(LOG_ERR, "refclock_open: %s: %m", dev);		return (0);	}	/*	 * The following sections initialize the serial line port in	 * canonical (line-oriented) mode and set the specified line	 * speed, 8 bits and no parity. The modem control, break, erase	 * and kill functions are normally disabled. There is a	 * different section for each terminal interface, as selected at	 * compile time.	 */	ttyp = &ttyb;#ifdef HAVE_TERMIOS	/*	 * POSIX serial line parameters (termios interface)	 */	if (tcgetattr(fd, ttyp) < 0) {		msyslog(LOG_ERR,		    "refclock_open: 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.	 */	ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;	ttyp->c_oflag = 0;	ttyp->c_cflag = CS8 | CLOCAL | CREAD;	(void)cfsetispeed(&ttyb, speed);	(void)cfsetospeed(&ttyb, speed);	ttyp->c_lflag = ICANON;	ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';#ifdef TIOCMGET	/*	 * 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.	 */	ltemp = 0;	if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)		msyslog(LOG_ERR,		    "refclock_open: fd %d TIOCMGET failed: %m", fd);#if DEBUG	if (debug)		printf("refclock_open: fd %d modem status %lx\n",		    fd, ltemp);#endif	if (ltemp & TIOCM_DSR)		ttyp->c_cflag &= ~CLOCAL;#endif /* TIOCMGET */	if (tcsetattr(fd, TCSANOW, ttyp) < 0) {		msyslog(LOG_ERR,		    "refclock_open: fd %d TCSANOW failed: %m", fd);		return (0);	}	if (tcflush(fd, TCIOFLUSH) < 0) {		msyslog(LOG_ERR,		    "refclock_open: fd %d TCIOFLUSH failed: %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_open: fd %d TCGETA failed: %m", fd);		return (0);	}	/*	 * Set canonical mode and local connection; set specified speed,	 * 8 bits and no parity; map CR to NL; ignore break.	 */	ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;	ttyp->c_oflag = 0;	ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD;	ttyp->c_lflag = ICANON;	ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';#ifdef TIOCMGET	/*	 * 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.	 */	ltemp = 0;	if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)		msyslog(LOG_ERR,		    "refclock_open: fd %d TIOCMGET failed: %m", fd);#if DEBUG	if (debug)		printf("refclock_open: fd %d modem status %lx\n",		    fd, ltemp);#endif	if (ltemp & TIOCM_DSR)		ttyp->c_cflag &= ~CLOCAL;#endif /* TIOCMGET */	if (ioctl(fd, TCSETA, ttyp) < 0) {		msyslog(LOG_ERR,		    "refclock_open: fd %d TCSETA failed: %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_open: fd %d TIOCGETP %m", fd);		return (0);	}	ttyp->sg_ispeed = ttyp->sg_ospeed = speed;	ttyp->sg_flags = EVENP | ODDP | CRMOD;	if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {		msyslog(LOG_ERR,		    "refclock_open: TIOCSETP failed: %m");		return (0);	}#endif /* HAVE_BSD_TTYS */	if (!refclock_ioctl(fd, flags)) {		(void)close(fd);		msyslog(LOG_ERR, "refclock_open: fd %d ioctl fails",		    fd);		return (0);	}	return (fd);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -