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

📄 refclock_leitch.c

📁 网络时间协议NTP 源码 版本v4.2.0b 该源码用于linux平台下
💻 C
字号:
/* * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock */#ifdef HAVE_CONFIG_H# include <config.h>#endif#if defined(REFCLOCK) && defined(CLOCK_LEITCH)#include "ntpd.h"#include "ntp_io.h"#include "ntp_refclock.h"#include "ntp_unixtime.h"#include <stdio.h>#include <ctype.h>#ifdef STREAM#include <stropts.h>#if defined(LEITCHCLK)#include <sys/clkdefs.h>#endif /* LEITCHCLK */#endif /* STREAM */#include "ntp_stdlib.h"/* * Driver for Leitch CSD-5300 Master Clock System * * COMMANDS: *	DATE:	D <CR> *	TIME:	T <CR> *	STATUS:	S <CR> *	LOOP:	L <CR> * * FORMAT: *	DATE: YYMMDD<CR> *	TIME: <CR>/HHMMSS <CR>/HHMMSS <CR>/HHMMSS <CR>/ *		second bondaried on the stop bit of the <CR> *		second boundaries at '/' above. *	STATUS: G (good), D (diag fail), T (time not provided) or *		P (last phone update failed) */#define MAXUNITS 1		/* max number of LEITCH units */#define LEITCHREFID	"ATOM"	/* reference id */#define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver"#define LEITCH232 "/dev/leitch%d"	/* name of radio device */#define SPEED232 B300		/* uart speed (300 baud) */ #define leitch_send(A,M) \if (debug) fprintf(stderr,"write leitch %s\n",M); \if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\						      if (debug) \									 fprintf(stderr, "leitch_send: unit %d send failed\n", A->unit); \																		 else \																			      msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);}		#define STATE_IDLE 0#define STATE_DATE 1#define STATE_TIME1 2#define STATE_TIME2 3#define STATE_TIME3 4/* * LEITCH unit control structure */struct leitchunit {	struct peer *peer;	struct refclockio leitchio;	u_char unit;	short year;	short yearday;	short month;	short day;	short hour;	short second;	short minute;	short state;	u_short fudge1;	l_fp reftime1;	l_fp reftime2;	l_fp reftime3;	l_fp codetime1;	l_fp codetime2;	l_fp codetime3;	u_long yearstart;};/* * Function prototypes */static	void	leitch_init	P((void));static	int	leitch_start	P((int, struct peer *));static	void	leitch_shutdown	P((int, struct peer *));static	void	leitch_poll	P((int, struct peer *));static	void	leitch_control	P((int, struct refclockstat *, struct refclockstat *, struct peer *));#define	leitch_buginfo	noentrystatic	void	leitch_receive	P((struct recvbuf *));static	void	leitch_process	P((struct leitchunit *));#if 0static	void	leitch_timeout	P((struct peer *));#endifstatic	int	leitch_get_date	P((struct recvbuf *, struct leitchunit *));static	int	leitch_get_time	P((struct recvbuf *, struct leitchunit *, int));static	int	days_per_year		P((int));static struct leitchunit leitchunits[MAXUNITS];static u_char unitinuse[MAXUNITS];static u_char stratumtouse[MAXUNITS];static u_int32 refid[MAXUNITS];static	char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };/* * Transfer vector */struct	refclock refclock_leitch = {	leitch_start, leitch_shutdown, leitch_poll,	leitch_control, leitch_init, leitch_buginfo, NOFLAGS};/* * leitch_init - initialize internal leitch driver data */static voidleitch_init(void){	int i;	memset((char*)leitchunits, 0, sizeof(leitchunits));	memset((char*)unitinuse, 0, sizeof(unitinuse));	for (i = 0; i < MAXUNITS; i++)	    memcpy((char *)&refid[i], LEITCHREFID, 4);}/* * leitch_shutdown - shut down a LEITCH clock */static voidleitch_shutdown(	int unit,	struct peer *peer	){#ifdef DEBUG	if (debug)	    fprintf(stderr, "leitch_shutdown()\n");#endif}/* * leitch_poll - called by the transmit procedure */static voidleitch_poll(	int unit,	struct peer *peer	){	struct leitchunit *leitch;	/* start the state machine rolling */#ifdef DEBUG	if (debug)	    fprintf(stderr, "leitch_poll()\n");#endif	if (unit > MAXUNITS) {		/* XXXX syslog it */		return;	}	leitch = &leitchunits[unit];	if (leitch->state != STATE_IDLE) {		/* reset and wait for next poll */		/* XXXX syslog it */		leitch->state = STATE_IDLE;	} else {		leitch_send(leitch,"D\r");		leitch->state = STATE_DATE;	}}static voidleitch_control(	int unit,	struct refclockstat *in,	struct refclockstat *out,	struct peer *passed_peer	){	if (unit >= MAXUNITS) {		msyslog(LOG_ERR,			"leitch_control: unit %d invalid", unit);		return;	}	if (in) {		if (in->haveflags & CLK_HAVEVAL1)		    stratumtouse[unit] = (u_char)(in->fudgeval1);		if (in->haveflags & CLK_HAVEVAL2)		    refid[unit] = in->fudgeval2;		if (unitinuse[unit]) {			struct peer *peer;			peer = (&leitchunits[unit])->peer;			peer->stratum = stratumtouse[unit];			peer->refid = refid[unit];		}	}	if (out) {		memset((char *)out, 0, sizeof (struct refclockstat));		out->type = REFCLK_ATOM_LEITCH;		out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;		out->fudgeval1 = (int32)stratumtouse[unit];		out->fudgeval2 = refid[unit];		out->p_lastcode = "";		out->clockdesc = LEITCH_DESCRIPTION;	}}/* * leitch_start - open the LEITCH devices and initialize data for processing */static intleitch_start(	int unit,	struct peer *peer	){	struct leitchunit *leitch;	int fd232;	char leitchdev[20];	/*	 * Check configuration info.	 */	if (unit >= MAXUNITS) {		msyslog(LOG_ERR, "leitch_start: unit %d invalid", unit);		return (0);	}	if (unitinuse[unit]) {		msyslog(LOG_ERR, "leitch_start: unit %d in use", unit);		return (0);	}	/*	 * Open serial port.	 */	(void) sprintf(leitchdev, LEITCH232, unit);	fd232 = open(leitchdev, O_RDWR, 0777);	if (fd232 == -1) {		msyslog(LOG_ERR,			"leitch_start: open of %s: %m", leitchdev);		return (0);	}	leitch = &leitchunits[unit];	memset((char*)leitch, 0, sizeof(*leitch));#if defined(HAVE_SYSV_TTYS)	/*	 * System V serial line parameters (termio interface)	 *	 */	{	struct termio ttyb;	if (ioctl(fd232, TCGETA, &ttyb) < 0) {		msyslog(LOG_ERR,			"leitch_start: ioctl(%s, TCGETA): %m", leitchdev);		goto screwed;	}	ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;	ttyb.c_oflag = 0;	ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;	ttyb.c_lflag = ICANON;	ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';	if (ioctl(fd232, TCSETA, &ttyb) < 0) {		msyslog(LOG_ERR,			"leitch_start: ioctl(%s, TCSETA): %m", leitchdev);		goto screwed;	}	}#endif /* HAVE_SYSV_TTYS */#if defined(HAVE_TERMIOS)	/*	 * POSIX serial line parameters (termios interface)	 *	 * The LEITCHCLK option provides timestamping at the driver level. 	 * It requires the tty_clk streams module.	 */	{	struct termios ttyb, *ttyp;	ttyp = &ttyb;	if (tcgetattr(fd232, ttyp) < 0) {		msyslog(LOG_ERR,			"leitch_start: tcgetattr(%s): %m", leitchdev);		goto screwed;	}	ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;	ttyp->c_oflag = 0;	ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;	ttyp->c_lflag = ICANON;	ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';	if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {		msyslog(LOG_ERR,			"leitch_start: tcsetattr(%s): %m", leitchdev);		goto screwed;	}	if (tcflush(fd232, TCIOFLUSH) < 0) {		msyslog(LOG_ERR,			"leitch_start: tcflush(%s): %m", leitchdev);		goto screwed;	}	}#endif /* HAVE_TERMIOS */#ifdef STREAM#if defined(LEITCHCLK)	if (ioctl(fd232, I_PUSH, "clk") < 0)	    msyslog(LOG_ERR,		    "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev);	if (ioctl(fd232, CLK_SETSTR, "\n") < 0)	    msyslog(LOG_ERR,		    "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev);#endif /* LEITCHCLK */#endif /* STREAM */#if defined(HAVE_BSD_TTYS)	/*	 * 4.3bsd serial line parameters (sgttyb interface)	 *	 * The LEITCHCLK option provides timestamping at the driver level. 	 * It requires the tty_clk line discipline and 4.3bsd or later.	 */	{	struct sgttyb ttyb;#if defined(LEITCHCLK)	int ldisc = CLKLDISC;#endif /* LEITCHCLK */	if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {		msyslog(LOG_ERR,			"leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev);		goto screwed;	}	ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;#if defined(LEITCHCLK)	ttyb.sg_erase = ttyb.sg_kill = '\r';	ttyb.sg_flags = RAW;#else	ttyb.sg_erase = ttyb.sg_kill = '\0';	ttyb.sg_flags = EVENP|ODDP|CRMOD;#endif /* LEITCHCLK */	if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {		msyslog(LOG_ERR,			"leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev);		goto screwed;	}#if defined(LEITCHCLK)	if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {		msyslog(LOG_ERR,			"leitch_start: ioctl(%s, TIOCSETD): %m",leitchdev);		goto screwed;	}#endif /* LEITCHCLK */	}#endif /* HAVE_BSD_TTYS */	/*	 * Set up the structures	 */	leitch->peer = peer;	leitch->unit = unit;	leitch->state = STATE_IDLE;	leitch->fudge1 = 15;	/* 15ms */	leitch->leitchio.clock_recv = leitch_receive;	leitch->leitchio.srcclock = (caddr_t) leitch;	leitch->leitchio.datalen = 0;	leitch->leitchio.fd = fd232;	if (!io_addclock(&leitch->leitchio)) {		goto screwed;	}	/*	 * All done.  Initialize a few random peer variables, then	 * return success.	 */	peer->precision = 0;	peer->stratum = stratumtouse[unit];	peer->refid = refid[unit];	unitinuse[unit] = 1;	return(1);	/*	 * Something broke; abandon ship.	 */    screwed:	close(fd232);	return(0);}/* * leitch_receive - receive data from the serial interface on a leitch * clock */static voidleitch_receive(	struct recvbuf *rbufp	){	struct leitchunit *leitch = (struct leitchunit *)rbufp->recv_srcclock;#ifdef DEBUG	if (debug)	    fprintf(stderr, "leitch_recieve(%*.*s)\n", 		    rbufp->recv_length, rbufp->recv_length,		    rbufp->recv_buffer);#endif	if (rbufp->recv_length != 7)	    return; /* The date is return with a trailing newline,		       discard it. */	switch (leitch->state) {	    case STATE_IDLE:	/* unexpected, discard and resync */		return;	    case STATE_DATE:		if (!leitch_get_date(rbufp,leitch)) {			leitch->state = STATE_IDLE;			break;		}		leitch_send(leitch,"T\r");#ifdef DEBUG		if (debug)		    fprintf(stderr, "%u\n",leitch->yearday);#endif		leitch->state = STATE_TIME1;		break;	    case STATE_TIME1:		if (!leitch_get_time(rbufp,leitch,1)) {		}		if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,			       leitch->second, 1, rbufp->recv_time.l_ui,			       &leitch->yearstart, &leitch->reftime1.l_ui)) {			leitch->state = STATE_IDLE;			break;		}		leitch->reftime1.l_uf = 0;#ifdef DEBUG		if (debug)		    fprintf(stderr, "%lu\n", (u_long)leitch->reftime1.l_ui);#endif		MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf);		leitch->codetime1 = rbufp->recv_time;		leitch->state = STATE_TIME2;		break;	    case STATE_TIME2:		if (!leitch_get_time(rbufp,leitch,2)) {		}		if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,			       leitch->second, 1, rbufp->recv_time.l_ui,			       &leitch->yearstart, &leitch->reftime2.l_ui)) {			leitch->state = STATE_IDLE;			break;		}#ifdef DEBUG		if (debug)		    fprintf(stderr, "%lu\n", (u_long)leitch->reftime2.l_ui);#endif		MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf);		leitch->codetime2 = rbufp->recv_time;		leitch->state = STATE_TIME3;		break;	    case STATE_TIME3:		if (!leitch_get_time(rbufp,leitch,3)) {		}		if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,			       leitch->second, GMT, rbufp->recv_time.l_ui,			       &leitch->yearstart, &leitch->reftime3.l_ui)) {			leitch->state = STATE_IDLE;			break;		}#ifdef DEBUG		if (debug)		    fprintf(stderr, "%lu\n", (u_long)leitch->reftime3.l_ui);#endif		MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf);		leitch->codetime3 = rbufp->recv_time;		leitch_process(leitch);		leitch->state = STATE_IDLE;		break;	    default:		msyslog(LOG_ERR,			"leitech_receive: invalid state %d unit %d",			leitch->state, leitch->unit);	}}/* * leitch_process - process a pile of samples from the clock * * This routine uses a three-stage median filter to calculate offset and * dispersion. reduce jitter. The dispersion is calculated as the span * of the filter (max - min), unless the quality character (format 2) is * non-blank, in which case the dispersion is calculated on the basis of * the inherent tolerance of the internal radio oscillator, which is * +-2e-5 according to the radio specifications. */static voidleitch_process(	struct leitchunit *leitch	){	l_fp off;	l_fp tmp_fp;      /*double doffset;*/	off = leitch->reftime1;	L_SUB(&off,&leitch->codetime1);	tmp_fp = leitch->reftime2;	L_SUB(&tmp_fp,&leitch->codetime2);	if (L_ISGEQ(&off,&tmp_fp))	    off = tmp_fp;	tmp_fp = leitch->reftime3;	L_SUB(&tmp_fp,&leitch->codetime3);	if (L_ISGEQ(&off,&tmp_fp))	    off = tmp_fp;      /*LFPTOD(&off, doffset);*/	refclock_receive(leitch->peer);}/* * days_per_year */static intdays_per_year(	int year	){	if (year%4) {	/* not a potential leap year */		return (365);	} else {		if (year % 100) {	/* is a leap year */			return (366);		} else {				if (year % 400) {				return (365);			} else {				return (366);			}		}	}}static intleitch_get_date(	struct recvbuf *rbufp,	struct leitchunit *leitch	){	int i;	if (rbufp->recv_length < 6)	    return(0);#undef  BAD    /* confict: defined as (-1) in AIX sys/param.h */#define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9')	if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))	    return(0);#define ATOB(A) ((rbufp->recv_buffer[A])-'0')	leitch->year = ATOB(0)*10 + ATOB(1);	leitch->month = ATOB(2)*10 + ATOB(3);	leitch->day = ATOB(4)*10 + ATOB(5);	/* sanity checks */	if (leitch->month > 12)	    return(0);	if (leitch->day > days_in_month[leitch->month-1])	    return(0);	/* calculate yearday */	i = 0;	leitch->yearday = leitch->day;	while ( i < (leitch->month-1) )	    leitch->yearday += days_in_month[i++];	if ((days_per_year((leitch->year>90?1900:2000)+leitch->year)==365) && 	    leitch->month > 2)	    leitch->yearday--;	return(1);}/* * leitch_get_time */static intleitch_get_time(	struct recvbuf *rbufp,	struct leitchunit *leitch,	int which	){	if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))	    return(0);	leitch->hour = ATOB(0)*10 +ATOB(1);	leitch->minute = ATOB(2)*10 +ATOB(3);	leitch->second = ATOB(4)*10 +ATOB(5);	if ((leitch->hour > 23) || (leitch->minute > 60) ||	    (leitch->second > 60))	    return(0);	return(1);}#elseint refclock_leitch_bs;#endif /* REFCLOCK */

⌨️ 快捷键说明

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