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

📄 refclock_acts.c

📁 网络时间协议NTP 源码 版本v4.2.0b 该源码用于linux平台下
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * refclock_acts - clock driver for the NIST/USNO/PTB/NPL Computer Time *	Services */#ifdef HAVE_CONFIG_H#include <config.h>#endif#if defined(REFCLOCK) && (defined(CLOCK_ACTS) || defined(CLOCK_PTBACTS))#include "ntpd.h"#include "ntp_io.h"#include "ntp_unixtime.h"#include "ntp_refclock.h"#include "ntp_stdlib.h"#include "ntp_control.h"#include <stdio.h>#include <ctype.h>#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif /* HAVE_SYS_IOCTL_H *//* * This driver supports the US (NIST, USNO) and European (PTB, NPL, * etc.) modem time services, as well as Spectracom GPS and WWVB * receivers connected via a modem. The driver periodically dials a * number from a telephone list, receives the timecode data and * calculates the local clock correction. It is designed primarily for * use as backup when neither a radio clock nor connectivity to Internet * time servers is available. * * This driver requires a modem with a Hayes-compatible command set and * control over the modem data terminal ready (DTR) control line. The * modem setup string is hard-coded in the driver and may require * changes for nonstandard modems or special circumstances. For reasons * unrelated to this driver, the data set ready (DSR) control line * should not be set when this driver is first started. * * The calling program is initiated by setting fudge flag1, either * manually or automatically. When flag1 is set, the calling program * dials the first number in the phone command of the configuration * file. If that call fails, the calling program dials the second number * and so on. The number is specified by the Hayes ATDT prefix followed * by the number itself, including the prefix and long-distance digits * and delay code, if necessary. The flag1 is reset and the calling * program terminated if (a) a valid clock update has been determined, * (b) no more numbers remain in the list, (c) a device fault or timeout * occurs or (d) fudge flag1 is reset manually. * * The driver is transparent to each of the modem time services and * Spectracom radios. It selects the parsing algorithm depending on the * message length. There is some hazard should the message be corrupted. * However, the data format is checked carefully and only if all checks * succeed is the message accepted. Corrupted lines are discarded * without complaint. * * Fudge controls * * flag1	force a call in manual mode * flag2	enable port locking (not verified) * flag3	no modem; port is directly connected to device * flag4	not used * * time1	offset adjustment (s) * * Ordinarily, the serial port is connected to a modem; however, it can * be connected directly to a device or another computer for testing and * calibration. In this case set fudge flag3 and the driver will send a * single character 'T' at each poll event. In principle, fudge flag2 * enables port locking, allowing the modem to be shared when not in use * by this driver. At least on Solaris with the current NTP I/O * routines, this results only in lots of ugly error messages. *//* * National Institute of Science and Technology (NIST) * * Phone: (303) 494-4774 (Boulder, CO); (808) 335-4721 (Hawaii) * * Data Format * * National Institute of Standards and Technology * Telephone Time Service, Generator 3B * Enter question mark "?" for HELP *                         D  L D *  MJD  YR MO DA H  M  S  ST S UT1 msADV        <OTM> * 47999 90-04-18 21:39:15 50 0 +.1 045.0 UTC(NIST) *<CR><LF> * ... * * MJD, DST, DUT1 and UTC are not used by this driver. The "*" or "#" is * the on-time markers echoed by the driver and used by NIST to measure * and correct for the propagation delay. * * US Naval Observatory (USNO) * * Phone: (202) 762-1594 (Washington, DC); (719) 567-6742 (Boulder, CO) * * Data Format (two lines, repeating at one-second intervals) * * jjjjj nnn hhmmss UTC<CR><LF> * *<CR><LF> * * jjjjj	modified Julian day number (not used) * nnn		day of year * hhmmss	second of day * *		on-time marker for previous timecode * ... * * USNO does not correct for the propagation delay. A fudge time1 of * about .06 s is advisable. * * European Services (PTB, NPL, etc.) * * PTB: +49 531 512038 (Germany) * NPL: 0906 851 6333 (UK only) * * Data format (see the documentation for phone numbers and formats.) * * 1995-01-23 20:58:51 MEZ  10402303260219950123195849740+40000500<CR><LF> * * Spectracom GPS and WWVB Receivers * * If a modem is connected to a Spectracom receiver, this driver will * call it up and retrieve the time in one of two formats. As this * driver does not send anything, the radio will have to either be * configured in continuous mode or be polled by another local driver. *//* * Interface definitions */#define	DEVICE		"/dev/acts%d" /* device name and unit */#define	SPEED232	B9600	/* uart speed (9600 baud) */#define	PRECISION	(-10)	/* precision assumed (about 1 ms) */#define LOCKFILE	"/var/spool/locks/LCK..cua%d"#define DESCRIPTION	"Automated Computer Time Service" /* WRU */#define REFID		"NONE"	/* default reference ID */#define MSGCNT		20	/* max message count */#define SMAX		256	/* max clockstats line length *//* * Calling program modes */#define MODE_AUTO	0	/* automatic mode */#define MODE_BACKUP	1	/* backup mode */#define MODE_MANUAL	2	/* manual mode *//* * Service identifiers. */#define REFACTS		"NIST"	/* NIST reference ID */#define LENACTS		50	/* NIST format */#define REFUSNO		"USNO"	/* USNO reference ID */#define LENUSNO		20	/* USNO */#define REFPTB		"PTB\0"	/* PTB/NPL reference ID */#define LENPTB		78	/* PTB/NPL format */#define REFWWVB		"WWVB"	/* WWVB reference ID */#define	LENWWVB0	22	/* WWVB format 0 */#define	LENWWVB2	24	/* WWVB format 2 */#define LF		0x0a	/* ASCII LF *//* * Modem setup strings. These may have to be changed for some modems. * * AT	command prefix * B1	US answer tone * &C0	disable carrier detect * &D2	hang up and return to command mode on DTR transition * E0	modem command echo disabled * l1	set modem speaker volume to low level * M1	speaker enabled until carrier detect * Q0	return result codes * V1	return result codes as English words */#define MODEM_SETUP	"ATB1&C0&D2E0L1M1Q0V1\r" /* modem setup */#define MODEM_HANGUP	"ATH\r"	/* modem disconnect *//* * Timeouts (all in seconds) */#define SETUP		3	/* setup timeout */#define	DTR		1	/* DTR timeout */#define ANSWER		60	/* answer timeout */#define CONNECT		20	/* first valid message timeout */#define TIMECODE	30	/* all valid messages timeout *//* * State machine codes */#define S_IDLE		0	/* wait for poll */#define S_OK		1	/* wait for modem setup */#define S_DTR		2	/* wait for modem DTR */#define S_CONNECT	3	/* wait for answer*/#define S_FIRST		4	/* wait for first valid message */#define S_MSG		5	/* wait for all messages */#define S_CLOSE		6	/* wait after sending disconnect *//* * Unit control structure */struct actsunit {	int	unit;		/* unit number */	int	state;		/* the first one was Delaware */	int	timer;		/* timeout counter */	int	retry;		/* retry index */	int	msgcnt;		/* count of messages received */	l_fp	tstamp;		/* on-time timestamp */	char	*bufptr;	/* buffer pointer */};/* * Function prototypes */static	int	acts_start	P((int, struct peer *));static	void	acts_shutdown	P((int, struct peer *));static	void	acts_receive	P((struct recvbuf *));static	void	acts_message	P((struct peer *));static	void	acts_timecode	P((struct peer *, char *));static	void	acts_poll	P((int, struct peer *));static	void	acts_timeout	P((struct peer *));static	void	acts_disc	P((struct peer *));static	void	acts_timer	P((int, struct peer *));/* * Transfer vector (conditional structure name) */struct	refclock refclock_acts = {	acts_start,		/* start up driver */	acts_shutdown,		/* shut down driver */	acts_poll,		/* transmit poll message */	noentry,		/* not used */	noentry,		/* not used */	noentry,		/* not used */	acts_timer		/* housekeeping timer */};struct	refclock refclock_ptb;/* * Initialize data for processing */static intacts_start (	int	unit,	struct peer *peer	){	struct actsunit *up;	struct refclockproc *pp;	/*	 * Allocate and initialize unit structure	 */	up = emalloc(sizeof(struct actsunit));	if (up == NULL)		return (0);	memset(up, 0, sizeof(struct actsunit));	up->unit = unit;	pp = peer->procptr;	pp->unitptr = (caddr_t)up;	pp->io.clock_recv = acts_receive;	pp->io.srcclock = (caddr_t)peer;	pp->io.datalen = 0;	/*	 * Initialize miscellaneous variables	 */	peer->precision = PRECISION;	pp->clockdesc = DESCRIPTION;	memcpy((char *)&pp->refid, REFID, 4);	peer->sstclktype = CTL_SST_TS_TELEPHONE;	peer->flags &= ~FLAG_FIXPOLL;	up->bufptr = pp->a_lastcode;	return (1);}/* * acts_shutdown - shut down the clock */static voidacts_shutdown (	int	unit,	struct peer *peer	){	struct actsunit *up;	struct refclockproc *pp;	/*	 * Warning: do this only when a call is not in progress.	 */	pp = peer->procptr;	up = (struct actsunit *)pp->unitptr;	free(up);}/* * acts_receive - receive data from the serial interface */static voidacts_receive (	struct recvbuf *rbufp	){	struct actsunit *up;	struct refclockproc *pp;	struct peer *peer;	char	tbuf[BMAX];	char	*tptr;	/*	 * Initialize pointers and read the timecode and timestamp. Note	 * we are in raw mode and victim of whatever the terminal	 * interface kicks up; so, we have to reassemble messages from	 * arbitrary fragments. Capture the timecode at the beginning of	 * the message and at the '*' and '#' on-time characters.	 */	peer = (struct peer *)rbufp->recv_srcclock;	pp = peer->procptr;	up = (struct actsunit *)pp->unitptr;	pp->lencode = refclock_gtraw(rbufp, tbuf, BMAX - (up->bufptr -	    pp->a_lastcode), &pp->lastrec);	for (tptr = tbuf; *tptr != '\0'; tptr++) {		if (*tptr == LF) {			if (up->bufptr == pp->a_lastcode) {				up->tstamp = pp->lastrec;				continue;			} else {				*up->bufptr = '\0';				acts_message(peer);				up->bufptr = pp->a_lastcode;			}		} else {			*up->bufptr++ = *tptr;			if (*tptr == '*' || *tptr == '#') {				up->tstamp = pp->lastrec;				write(pp->io.fd, tptr, 1);			}		}	}}/* * acts_message - process message */voidacts_message(	struct peer *peer	){	struct actsunit *up;	struct refclockproc *pp;	int	dtr = TIOCM_DTR;	char	tbuf[SMAX];#ifdef DEBUG	u_int	modem;#endif	/*	 * What to do depends on the state and the first token in the	 * message. A NO token sends the message to the clockstats.	 */	pp = peer->procptr;	up = (struct actsunit *)pp->unitptr;#ifdef DEBUG	ioctl(pp->io.fd, TIOCMGET, (char *)&modem);	sprintf(tbuf, "acts: %04x (%d %d) %d %s", modem, up->state,	    up->timer, strlen(pp->a_lastcode), pp->a_lastcode);	if (debug)		printf("%s\n", tbuf);#endif	strncpy(tbuf, pp->a_lastcode, SMAX);	strtok(tbuf, " ");	if (strcmp(tbuf, "NO") == 0)		record_clock_stats(&peer->srcadr, pp->a_lastcode);	switch(up->state) {	/*	 * We are waiting for the OK response to the modem setup	 * command. When this happens, raise DTR and dial the number	 * followed by \r.	 */	case S_OK:		if (strcmp(tbuf, "OK") != 0) {			msyslog(LOG_ERR, "acts: setup error %s",			    pp->a_lastcode);			acts_disc(peer);			return;		}		ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr);		up->state = S_DTR;		up->timer = DTR;		return;	/*	 * We are waiting for the call to be answered. All we care about	 * here is token CONNECT. Send the message to the clockstats.	 */	case S_CONNECT:		record_clock_stats(&peer->srcadr, pp->a_lastcode);		if (strcmp(tbuf, "CONNECT") != 0) {			acts_disc(peer);			return;		}		up->state = S_FIRST;		up->timer = CONNECT;		return;	/*	 * We are waiting for a timecode. Pass it to the parser.	 */	case S_FIRST:	case S_MSG:		acts_timecode(peer, pp->a_lastcode);		break;	}}/* * acts_timecode - identify the service and parse the timecode message */voidacts_timecode(	struct peer *peer,	/* peer structure pointer */	char	*str		/* timecode string */	){	struct actsunit *up;	struct refclockproc *pp;	int	day;		/* day of the month */	int	month;		/* month of the year */	u_long	mjd;		/* Modified Julian Day */	double	dut1;		/* DUT adjustment */	u_int	dst;		/* ACTS daylight/standard time */	u_int	leap;		/* ACTS leap indicator */	double	msADV;		/* ACTS transmit advance (ms) */	char	utc[10];	/* ACTS timescale */	char	flag;		/* ACTS on-time character (* or #) */	char	synchar;	/* WWVB synchronized indicator */	char	qualchar;	/* WWVB quality indicator */	char	leapchar;	/* WWVB leap indicator */	char	dstchar;	/* WWVB daylight/savings indicator */	int	tz;		/* WWVB timezone */	u_int	leapmonth;	/* PTB/NPL month of leap */	char	leapdir;	/* PTB/NPL leap direction */	/*	 * The parser selects the modem format based on the message	 * length. Since the data are checked carefully, occasional	 * errors due noise are forgivable.	 */	pp = peer->procptr;	up = (struct actsunit *)pp->unitptr;	pp->nsec = 0;	switch(strlen(str)) {	/*	 * For USNO format on-time character '*', which is on a line by	 * itself. Be sure a timecode has been received.

⌨️ 快捷键说明

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