File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_datum.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 2 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2: ** refclock_datum - clock driver for the Datum Programmable Time Server
    3: **
    4: ** Important note: This driver assumes that you have termios. If you have
    5: ** a system that does not have termios, you will have to modify this driver.
    6: **
    7: ** Sorry, I have only tested this driver on SUN and HP platforms.
    8: */
    9: 
   10: #ifdef HAVE_CONFIG_H
   11: # include <config.h>
   12: #endif
   13: 
   14: #if defined(REFCLOCK) && defined(CLOCK_DATUM)
   15: 
   16: /*
   17: ** Include Files
   18: */
   19: 
   20: #include "ntpd.h"
   21: #include "ntp_io.h"
   22: #include "ntp_refclock.h"
   23: #include "ntp_unixtime.h"
   24: #include "ntp_stdlib.h"
   25: 
   26: #include <stdio.h>
   27: #include <ctype.h>
   28: 
   29: #if defined(HAVE_BSD_TTYS)
   30: #include <sgtty.h>
   31: #endif /* HAVE_BSD_TTYS */
   32: 
   33: #if defined(HAVE_SYSV_TTYS)
   34: #include <termio.h>
   35: #endif /* HAVE_SYSV_TTYS */
   36: 
   37: #if defined(HAVE_TERMIOS)
   38: #include <termios.h>
   39: #endif
   40: #if defined(STREAM)
   41: #include <stropts.h>
   42: #if defined(WWVBCLK)
   43: #include <sys/clkdefs.h>
   44: #endif /* WWVBCLK */
   45: #endif /* STREAM */
   46: 
   47: #include "ntp_stdlib.h"
   48: 
   49: /*
   50: ** This driver supports the Datum Programmable Time System (PTS) clock.
   51: ** The clock works in very straight forward manner. When it receives a
   52: ** time code request (e.g., the ascii string "//k/mn"), it responds with
   53: ** a seven byte BCD time code. This clock only responds with a
   54: ** time code after it first receives the "//k/mn" message. It does not
   55: ** periodically send time codes back at some rate once it is started.
   56: ** the returned time code can be broken down into the following fields.
   57: **
   58: **            _______________________________
   59: ** Bit Index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
   60: **            ===============================
   61: ** byte 0:   | -   -   -   - |      H D      |
   62: **            ===============================
   63: ** byte 1:   |      T D      |      U D      |
   64: **            ===============================
   65: ** byte 2:   | -   - |  T H  |      U H      |
   66: **            ===============================
   67: ** byte 3:   | - |    T M    |      U M      |
   68: **            ===============================
   69: ** byte 4:   | - |    T S    |      U S      |
   70: **            ===============================
   71: ** byte 5:   |      t S      |      h S      |
   72: **            ===============================
   73: ** byte 6:   |      m S      | -   -   -   - |
   74: **            ===============================
   75: **
   76: ** In the table above:
   77: **
   78: **	"-" means don't care
   79: **	"H D", "T D", and "U D" means Hundreds, Tens, and Units of Days
   80: **	"T H", and "UH" means Tens and Units of Hours
   81: **	"T M", and "U M" means Tens and Units of Minutes
   82: **	"T S", and "U S" means Tens and Units of Seconds
   83: **	"t S", "h S", and "m S" means tenths, hundredths, and thousandths
   84: **				of seconds
   85: **
   86: ** The Datum PTS communicates throught the RS232 port on your machine.
   87: ** Right now, it assumes that you have termios. This driver has been tested
   88: ** on SUN and HP workstations. The Datum PTS supports various IRIG and
   89: ** NASA input codes. This driver assumes that the name of the device is
   90: ** /dev/datum. You will need to make a soft link to your RS232 device or
   91: ** create a new driver to use this refclock.
   92: */
   93: 
   94: /*
   95: ** Datum PTS defines
   96: */
   97: 
   98: /*
   99: ** Note that if GMT is defined, then the Datum PTS must use Greenwich
  100: ** time. Otherwise, this driver allows the Datum PTS to use the current
  101: ** wall clock for its time. It determines the time zone offset by minimizing
  102: ** the error after trying several time zone offsets. If the Datum PTS
  103: ** time is Greenwich time and GMT is not defined, everything should still
  104: ** work since the time zone will be found to be 0. What this really means
  105: ** is that your system time (at least to start with) must be within the
  106: ** correct time by less than +- 30 minutes. The default is for GMT to not
  107: ** defined. If you really want to force GMT without the funny +- 30 minute
  108: ** stuff then you must define (uncomment) GMT below.
  109: */
  110: 
  111: /*
  112: #define GMT
  113: #define DEBUG_DATUM_PTC
  114: #define LOG_TIME_ERRORS
  115: */
  116: 
  117: 
  118: #define	PRECISION	(-10)		/* precision assumed 1/1024 ms */
  119: #define	REFID "DATM"			/* reference id */
  120: #define DATUM_DISPERSION 0		/* fixed dispersion = 0 ms */
  121: #define DATUM_MAX_ERROR 0.100		/* limits on sigma squared */
  122: #define DATUM_DEV	"/dev/datum"	/* device name */
  123: 
  124: #define DATUM_MAX_ERROR2 (DATUM_MAX_ERROR*DATUM_MAX_ERROR)
  125: 
  126: /*
  127: ** The Datum PTS structure
  128: */
  129: 
  130: /*
  131: ** I don't use a fixed array of MAXUNITS like everyone else just because
  132: ** I don't like to program that way. Sorry if this bothers anyone. I assume
  133: ** that you can use any id for your unit and I will search for it in a
  134: ** dynamic array of units until I find it. I was worried that users might
  135: ** enter a bad id in their configuration file (larger than MAXUNITS) and
  136: ** besides, it is just cleaner not to have to assume that you have a fixed
  137: ** number of anything in a program.
  138: */
  139: 
  140: struct datum_pts_unit {
  141: 	struct peer *peer;		/* peer used by ntp */
  142: 	struct refclockio io;		/* io structure used by ntp */
  143: 	int PTS_fd;			/* file descriptor for PTS */
  144: 	u_int unit;			/* id for unit */
  145: 	u_long timestarted;		/* time started */
  146: 	l_fp lastrec;			/* time tag for the receive time (system) */
  147: 	l_fp lastref;			/* reference time (Datum time) */
  148: 	u_long yearstart;		/* the year that this clock started */
  149: 	int coderecv;			/* number of time codes received */
  150: 	int day;			/* day */
  151: 	int hour;			/* hour */
  152: 	int minute;			/* minutes */
  153: 	int second;			/* seconds */
  154: 	int msec;			/* miliseconds */
  155: 	int usec;			/* miliseconds */
  156: 	u_char leap;			/* funny leap character code */
  157: 	char retbuf[8];		/* returned time from the datum pts */
  158: 	char nbytes;			/* number of bytes received from datum pts */ 
  159: 	double sigma2;		/* average squared error (roughly) */
  160: 	int tzoff;			/* time zone offest from GMT */
  161: };
  162: 
  163: /*
  164: ** PTS static constant variables for internal use
  165: */
  166: 
  167: static char TIME_REQUEST[6];	/* request message sent to datum for time */
  168: static int nunits;		/* number of active units */
  169: static struct datum_pts_unit
  170: **datum_pts_unit;	/* dynamic array of datum PTS structures */
  171: 
  172: /*
  173: ** Callback function prototypes that ntpd needs to know about.
  174: */
  175: 
  176: static	int	datum_pts_start		(int, struct peer *);
  177: static	void	datum_pts_shutdown	(int, struct peer *);
  178: static	void	datum_pts_poll		(int, struct peer *);
  179: static	void	datum_pts_control	(int, struct refclockstat *,
  180: 					   struct refclockstat *, struct peer *);
  181: static	void	datum_pts_init		(void);
  182: static	void	datum_pts_buginfo	(int, struct refclockbug *, struct peer *);
  183: 
  184: /*
  185: ** This is the call back function structure that ntpd actually uses for
  186: ** this refclock.
  187: */
  188: 
  189: struct	refclock refclock_datum = {
  190: 	datum_pts_start,		/* start up a new Datum refclock */
  191: 	datum_pts_shutdown,		/* shutdown a Datum refclock */
  192: 	datum_pts_poll,		/* sends out the time request */
  193: 	datum_pts_control,		/* not used */
  194: 	datum_pts_init,		/* initialization (called first) */
  195: 	datum_pts_buginfo,		/* not used */
  196: 	NOFLAGS			/* we are not setting any special flags */
  197: };
  198: 
  199: /*
  200: ** The datum_pts_receive callback function is handled differently from the
  201: ** rest. It is passed to the ntpd io data structure. Basically, every
  202: ** 64 seconds, the datum_pts_poll() routine is called. It sends out the time
  203: ** request message to the Datum Programmable Time System. Then, ntpd
  204: ** waits on a select() call to receive data back. The datum_pts_receive()
  205: ** function is called as data comes back. We expect a seven byte time
  206: ** code to be returned but the datum_pts_receive() function may only get
  207: ** a few bytes passed to it at a time. In other words, this routine may
  208: ** get called by the io stuff in ntpd a few times before we get all seven
  209: ** bytes. Once the last byte is received, we process it and then pass the
  210: ** new time measurement to ntpd for updating the system time. For now,
  211: ** there is no 3 state filtering done on the time measurements. The
  212: ** jitter may be a little high but at least for its current use, it is not
  213: ** a problem. We have tried to keep things as simple as possible. This
  214: ** clock should not jitter more than 1 or 2 mseconds at the most once
  215: ** things settle down. It is important to get the right drift calibrated
  216: ** in the ntpd.drift file as well as getting the right tick set up right
  217: ** using tickadj for SUNs. Tickadj is not used for the HP but you need to
  218: ** remember to bring up the adjtime daemon because HP does not support
  219: ** the adjtime() call.
  220: */
  221: 
  222: static	void	datum_pts_receive	(struct recvbuf *);
  223: 
  224: /*......................................................................*/
  225: /*	datum_pts_start - start up the datum PTS. This means open the	*/
  226: /*	RS232 device and set up the data structure for my unit.		*/
  227: /*......................................................................*/
  228: 
  229: static int
  230: datum_pts_start(
  231: 	int unit,
  232: 	struct peer *peer
  233: 	)
  234: {
  235: 	struct datum_pts_unit **temp_datum_pts_unit;
  236: 	struct datum_pts_unit *datum_pts;
  237: 	int fd;
  238: #ifdef HAVE_TERMIOS
  239: 	struct termios arg;
  240: #endif
  241: 
  242: #ifdef DEBUG_DATUM_PTC
  243: 	if (debug)
  244: 	    printf("Starting Datum PTS unit %d\n", unit);
  245: #endif
  246: 
  247: 	/*
  248: 	** Open the Datum PTS device
  249: 	*/
  250: 	fd = open(DATUM_DEV, O_RDWR);
  251: 
  252: 	if (fd < 0) {
  253: 		msyslog(LOG_ERR, "Datum_PTS: open(\"%s\", O_RDWR) failed: %m", DATUM_DEV);
  254: 		return 0;
  255: 	}
  256: 
  257: 	/*
  258: 	** Create the memory for the new unit
  259: 	*/
  260: 
  261: 	temp_datum_pts_unit = (struct datum_pts_unit **)
  262: 		emalloc((nunits+1)*sizeof(struct datum_pts_unit *));
  263: 	if (nunits > 0) memcpy(temp_datum_pts_unit, datum_pts_unit,
  264: 			       nunits*sizeof(struct datum_pts_unit *));
  265: 	free(datum_pts_unit);
  266: 	datum_pts_unit = temp_datum_pts_unit;
  267: 	datum_pts_unit[nunits] = (struct datum_pts_unit *)
  268: 		emalloc(sizeof(struct datum_pts_unit));
  269: 	datum_pts = datum_pts_unit[nunits];
  270: 
  271: 	datum_pts->unit = unit;	/* set my unit id */
  272: 	datum_pts->yearstart = 0;	/* initialize the yearstart to 0 */
  273: 	datum_pts->sigma2 = 0.0;	/* initialize the sigma2 to 0 */
  274: 
  275: 	datum_pts->PTS_fd = fd;
  276: 
  277: 	fcntl(datum_pts->PTS_fd, F_SETFL, 0); /* clear the descriptor flags */
  278: 
  279: #ifdef DEBUG_DATUM_PTC
  280: 	if (debug)
  281: 	    printf("Opening RS232 port with file descriptor %d\n",
  282: 		   datum_pts->PTS_fd);
  283: #endif
  284: 
  285: 	/*
  286: 	** Set up the RS232 terminal device information. Note that we assume that
  287: 	** we have termios. This code has only been tested on SUNs and HPs. If your
  288: 	** machine does not have termios this driver cannot be initialized. You can change this
  289: 	** if you want by editing this source. Please give the changes back to the
  290: 	** ntp folks so that it can become part of their regular distribution.
  291: 	*/
  292: 
  293: #ifdef HAVE_TERMIOS
  294: 
  295: 	memset(&arg, 0, sizeof(arg));
  296: 
  297: 	arg.c_iflag = IGNBRK;
  298: 	arg.c_oflag = 0;
  299: 	arg.c_cflag = B9600 | CS8 | CREAD | PARENB | CLOCAL;
  300: 	arg.c_lflag = 0;
  301: 	arg.c_cc[VMIN] = 0;		/* start timeout timer right away (not used) */
  302: 	arg.c_cc[VTIME] = 30;		/* 3 second timout on reads (not used) */
  303: 
  304: 	tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg);
  305: 
  306: #else
  307: 
  308: 	msyslog(LOG_ERR, "Datum_PTS: Termios not supported in this driver");
  309: 	(void)close(datum_pts->PTS_fd);
  310: 
  311: 	peer->precision = PRECISION;
  312: 	pp->clockdesc = DESCRIPTION;
  313: 	memcpy((char *)&pp->refid, REFID, 4);
  314: 
  315: 	return 0;
  316: 
  317: #endif
  318: 
  319: 	/*
  320: 	** Initialize the ntpd IO structure
  321: 	*/
  322: 
  323: 	datum_pts->peer = peer;
  324: 	datum_pts->io.clock_recv = datum_pts_receive;
  325: 	datum_pts->io.srcclock = (caddr_t)datum_pts;
  326: 	datum_pts->io.datalen = 0;
  327: 	datum_pts->io.fd = datum_pts->PTS_fd;
  328: 
  329: 	if (!io_addclock(&(datum_pts->io))) {
  330: 
  331: #ifdef DEBUG_DATUM_PTC
  332: 		if (debug)
  333: 		    printf("Problem adding clock\n");
  334: #endif
  335: 
  336: 		msyslog(LOG_ERR, "Datum_PTS: Problem adding clock");
  337: 		(void)close(datum_pts->PTS_fd);
  338: 
  339: 		return 0;
  340: 	}
  341: 
  342: 	/*
  343: 	** Now add one to the number of units and return a successful code
  344: 	*/
  345: 
  346: 	nunits++;
  347: 	return 1;
  348: 
  349: }
  350: 
  351: 
  352: /*......................................................................*/
  353: /*	datum_pts_shutdown - this routine shuts doen the device and	*/
  354: /*	removes the memory for the unit.				*/
  355: /*......................................................................*/
  356: 
  357: static void
  358: datum_pts_shutdown(
  359: 	int unit,
  360: 	struct peer *peer
  361: 	)
  362: {
  363: 	int i,j;
  364: 	struct datum_pts_unit **temp_datum_pts_unit;
  365: 
  366: #ifdef DEBUG_DATUM_PTC
  367: 	if (debug)
  368: 	    printf("Shutdown Datum PTS\n");
  369: #endif
  370: 
  371: 	msyslog(LOG_ERR, "Datum_PTS: Shutdown Datum PTS");
  372: 
  373: 	/*
  374: 	** First we have to find the right unit (i.e., the one with the same id).
  375: 	** We do this by looping through the dynamic array of units intil we find
  376: 	** it. Note, that I don't simply use an array with a maximimum number of
  377: 	** Datum PTS units. Everything is completely dynamic.
  378: 	*/
  379: 
  380: 	for (i=0; i<nunits; i++) {
  381: 		if (datum_pts_unit[i]->unit == unit) {
  382: 
  383: 			/*
  384: 			** We found the unit so close the file descriptor and free up the memory used
  385: 			** by the structure.
  386: 			*/
  387: 
  388: 			io_closeclock(&datum_pts_unit[i]->io);
  389: 			close(datum_pts_unit[i]->PTS_fd);
  390: 			free(datum_pts_unit[i]);
  391: 
  392: 			/*
  393: 			** Now clean up the datum_pts_unit dynamic array so that there are no holes.
  394: 			** This may mean moving pointers around, etc., to keep things compact.
  395: 			*/
  396: 
  397: 			if (nunits > 1) {
  398: 
  399: 				temp_datum_pts_unit = (struct datum_pts_unit **)
  400: 					emalloc((nunits-1)*sizeof(struct datum_pts_unit *));
  401: 				if (i!= 0) memcpy(temp_datum_pts_unit, datum_pts_unit,
  402: 						  i*sizeof(struct datum_pts_unit *));
  403: 
  404: 				for (j=i+1; j<nunits; j++) {
  405: 					temp_datum_pts_unit[j-1] = datum_pts_unit[j];
  406: 				}
  407: 
  408: 				free(datum_pts_unit);
  409: 				datum_pts_unit = temp_datum_pts_unit;
  410: 
  411: 			}else{
  412: 
  413: 				free(datum_pts_unit);
  414: 				datum_pts_unit = NULL;
  415: 
  416: 			}
  417: 
  418: 			return;
  419: 
  420: 		}
  421: 	}
  422: 
  423: #ifdef DEBUG_DATUM_PTC
  424: 	if (debug)
  425: 	    printf("Error, could not shut down unit %d\n",unit);
  426: #endif
  427: 
  428: 	msyslog(LOG_ERR, "Datum_PTS: Could not shut down Datum PTS unit %d",unit);
  429: 
  430: }
  431: 
  432: /*......................................................................*/
  433: /*	datum_pts_poll - this routine sends out the time request to the */
  434: /*	Datum PTS device. The time will be passed back in the 		*/
  435: /*	datum_pts_receive() routine.					*/
  436: /*......................................................................*/
  437: 
  438: static void
  439: datum_pts_poll(
  440: 	int unit,
  441: 	struct peer *peer
  442: 	)
  443: {
  444: 	int i;
  445: 	int unit_index;
  446: 	int error_code;
  447: 	struct datum_pts_unit *datum_pts;
  448: 
  449: #ifdef DEBUG_DATUM_PTC
  450: 	if (debug)
  451: 	    printf("Poll Datum PTS\n");
  452: #endif
  453: 
  454: 	/*
  455: 	** Find the right unit and send out a time request once it is found.
  456: 	*/
  457: 
  458: 	unit_index = -1;
  459: 	for (i=0; i<nunits; i++) {
  460: 		if (datum_pts_unit[i]->unit == unit) {
  461: 			unit_index = i;
  462: 			datum_pts = datum_pts_unit[i];
  463: 			error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6);
  464: 			if (error_code != 6) perror("TIME_REQUEST");
  465: 			datum_pts->nbytes = 0;
  466: 			break;
  467: 		}
  468: 	}
  469: 
  470: 	/*
  471: 	** Print out an error message if we could not find the right unit.
  472: 	*/
  473: 
  474: 	if (unit_index == -1) {
  475: 
  476: #ifdef DEBUG_DATUM_PTC
  477: 		if (debug)
  478: 		    printf("Error, could not poll unit %d\n",unit);
  479: #endif
  480: 
  481: 		msyslog(LOG_ERR, "Datum_PTS: Could not poll unit %d",unit);
  482: 		return;
  483: 
  484: 	}
  485: 
  486: }
  487: 
  488: 
  489: /*......................................................................*/
  490: /*	datum_pts_control - not used					*/
  491: /*......................................................................*/
  492: 
  493: static void
  494: datum_pts_control(
  495: 	int unit,
  496: 	struct refclockstat *in,
  497: 	struct refclockstat *out,
  498: 	struct peer *peer
  499: 	)
  500: {
  501: 
  502: #ifdef DEBUG_DATUM_PTC
  503: 	if (debug)
  504: 	    printf("Control Datum PTS\n");
  505: #endif
  506: 
  507: }
  508: 
  509: 
  510: /*......................................................................*/
  511: /*	datum_pts_init - initializes things for all possible Datum	*/
  512: /*	time code generators that might be used. In practice, this is	*/
  513: /*	only called once at the beginning before anything else is	*/
  514: /*	called.								*/
  515: /*......................................................................*/
  516: 
  517: static void
  518: datum_pts_init(void)
  519: {
  520: 
  521: 	/*									*/
  522: 	/*...... open up the log file if we are debugging ......................*/
  523: 	/*									*/
  524: 
  525: 	/*
  526: 	** Open up the log file if we are debugging. For now, send data out to the
  527: 	** screen (stdout).
  528: 	*/
  529: 
  530: #ifdef DEBUG_DATUM_PTC
  531: 	if (debug)
  532: 	    printf("Init Datum PTS\n");
  533: #endif
  534: 
  535: 	/*
  536: 	** Initialize the time request command string. This is the only message
  537: 	** that we ever have to send to the Datum PTS (although others are defined).
  538: 	*/
  539: 
  540: 	memcpy(TIME_REQUEST, "//k/mn",6);
  541: 
  542: 	/*
  543: 	** Initialize the number of units to 0 and set the dynamic array of units to
  544: 	** NULL since there are no units defined yet.
  545: 	*/
  546: 
  547: 	datum_pts_unit = NULL;
  548: 	nunits = 0;
  549: 
  550: }
  551: 
  552: 
  553: /*......................................................................*/
  554: /*	datum_pts_buginfo - not used					*/
  555: /*......................................................................*/
  556: 
  557: static void
  558: datum_pts_buginfo(
  559: 	int unit,
  560: 	register struct refclockbug *bug,
  561: 	register struct peer *peer
  562: 	)
  563: {
  564: 
  565: #ifdef DEBUG_DATUM_PTC
  566: 	if (debug)
  567: 	    printf("Buginfo Datum PTS\n");
  568: #endif
  569: 
  570: }
  571: 
  572: 
  573: /*......................................................................*/
  574: /*	datum_pts_receive - receive the time buffer that was read in	*/
  575: /*	by the ntpd io handling routines. When 7 bytes have been	*/
  576: /*	received (it may take several tries before all 7 bytes are	*/
  577: /*	received), then the time code must be unpacked and sent to	*/
  578: /*	the ntpd clock_receive() routine which causes the systems	*/
  579: /*	clock to be updated (several layers down).			*/
  580: /*......................................................................*/
  581: 
  582: static void
  583: datum_pts_receive(
  584: 	struct recvbuf *rbufp
  585: 	)
  586: {
  587: 	int i;
  588: 	l_fp tstmp;
  589: 	struct datum_pts_unit *datum_pts;
  590: 	char *dpt;
  591: 	int dpend;
  592: 	int tzoff;
  593: 	int timerr;
  594: 	double ftimerr, abserr;
  595: #ifdef DEBUG_DATUM_PTC
  596: 	double dispersion;
  597: #endif
  598: 	int goodtime;
  599:       /*double doffset;*/
  600: 
  601: 	/*
  602: 	** Get the time code (maybe partial) message out of the rbufp buffer.
  603: 	*/
  604: 
  605: 	datum_pts = (struct datum_pts_unit *)rbufp->recv_srcclock;
  606: 	dpt = (char *)&rbufp->recv_space;
  607: 	dpend = rbufp->recv_length;
  608: 
  609: #ifdef DEBUG_DATUM_PTC
  610: 	if (debug)
  611: 	    printf("Receive Datum PTS: %d bytes\n", dpend);
  612: #endif
  613: 
  614: 	/*									*/
  615: 	/*...... save the ntp system time when the first byte is received ......*/
  616: 	/*									*/
  617: 
  618: 	/*
  619: 	** Save the ntp system time when the first byte is received. Note that
  620: 	** because it may take several calls to this routine before all seven
  621: 	** bytes of our return message are finally received by the io handlers in
  622: 	** ntpd, we really do want to use the time tag when the first byte is
  623: 	** received to reduce the jitter.
  624: 	*/
  625: 
  626: 	if (datum_pts->nbytes == 0) {
  627: 		datum_pts->lastrec = rbufp->recv_time;
  628: 	}
  629: 
  630: 	/*
  631: 	** Increment our count to the number of bytes received so far. Return if we
  632: 	** haven't gotten all seven bytes yet.
  633: 	*/
  634: 
  635: 	for (i=0; i<dpend; i++) {
  636: 		datum_pts->retbuf[datum_pts->nbytes+i] = dpt[i];
  637: 	}
  638: 
  639: 	datum_pts->nbytes += dpend;
  640: 
  641: 	if (datum_pts->nbytes != 7) {
  642: 		return;
  643: 	}
  644: 
  645: 	/*
  646: 	** Convert the seven bytes received in our time buffer to day, hour, minute,
  647: 	** second, and msecond values. The usec value is not used for anything
  648: 	** currently. It is just the fractional part of the time stored in units
  649: 	** of microseconds.
  650: 	*/
  651: 
  652: 	datum_pts->day =	100*(datum_pts->retbuf[0] & 0x0f) +
  653: 		10*((datum_pts->retbuf[1] & 0xf0)>>4) +
  654: 		(datum_pts->retbuf[1] & 0x0f);
  655: 
  656: 	datum_pts->hour =	10*((datum_pts->retbuf[2] & 0x30)>>4) +
  657: 		(datum_pts->retbuf[2] & 0x0f);
  658: 
  659: 	datum_pts->minute =	10*((datum_pts->retbuf[3] & 0x70)>>4) +
  660: 		(datum_pts->retbuf[3] & 0x0f);
  661: 
  662: 	datum_pts->second =	10*((datum_pts->retbuf[4] & 0x70)>>4) +
  663: 		(datum_pts->retbuf[4] & 0x0f);
  664: 
  665: 	datum_pts->msec =	100*((datum_pts->retbuf[5] & 0xf0) >> 4) + 
  666: 		10*(datum_pts->retbuf[5] & 0x0f) +
  667: 		((datum_pts->retbuf[6] & 0xf0)>>4);
  668: 
  669: 	datum_pts->usec =	1000*datum_pts->msec;
  670: 
  671: #ifdef DEBUG_DATUM_PTC
  672: 	if (debug)
  673: 	    printf("day %d, hour %d, minute %d, second %d, msec %d\n",
  674: 		   datum_pts->day,
  675: 		   datum_pts->hour,
  676: 		   datum_pts->minute,
  677: 		   datum_pts->second,
  678: 		   datum_pts->msec);
  679: #endif
  680: 
  681: 	/*
  682: 	** Get the GMT time zone offset. Note that GMT should be zero if the Datum
  683: 	** reference time is using GMT as its time base. Otherwise we have to
  684: 	** determine the offset if the Datum PTS is using time of day as its time
  685: 	** base.
  686: 	*/
  687: 
  688: 	goodtime = 0;		/* We are not sure about the time and offset yet */
  689: 
  690: #ifdef GMT
  691: 
  692: 	/*
  693: 	** This is the case where the Datum PTS is using GMT so there is no time
  694: 	** zone offset.
  695: 	*/
  696: 
  697: 	tzoff = 0;		/* set time zone offset to 0 */
  698: 
  699: #else
  700: 
  701: 	/*
  702: 	** This is the case where the Datum PTS is using regular time of day for its
  703: 	** time so we must compute the time zone offset. The way we do it is kind of
  704: 	** funny but it works. We loop through different time zones (0 to 24) and
  705: 	** pick the one that gives the smallest error (+- one half hour). The time
  706: 	** zone offset is stored in the datum_pts structure for future use. Normally,
  707: 	** the clocktime() routine is only called once (unless the time zone offset
  708: 	** changes due to daylight savings) since the goodtime flag is set when a
  709: 	** good time is found (with a good offset). Note that even if the Datum
  710: 	** PTS is using GMT, this mechanism will still work since it should come up
  711: 	** with a value for tzoff = 0 (assuming that your system clock is within
  712: 	** a half hour of the Datum time (even with time zone differences).
  713: 	*/
  714: 
  715: 	for (tzoff=0; tzoff<24; tzoff++) {
  716: 		if (clocktime( datum_pts->day,
  717: 			       datum_pts->hour,
  718: 			       datum_pts->minute,
  719: 			       datum_pts->second,
  720: 			       (tzoff + datum_pts->tzoff) % 24,
  721: 			       datum_pts->lastrec.l_ui,
  722: 			       &datum_pts->yearstart,
  723: 			       &datum_pts->lastref.l_ui) ) {
  724: 
  725: 			datum_pts->lastref.l_uf = 0;
  726: 			error = datum_pts->lastref.l_ui - datum_pts->lastrec.l_ui;
  727: 
  728: #ifdef DEBUG_DATUM_PTC
  729: 			printf("Time Zone (clocktime method) = %d, error = %d\n", tzoff, error);
  730: #endif
  731: 
  732: 			if ((error < 1799) && (error > -1799)) {
  733: 				tzoff = (tzoff + datum_pts->tzoff) % 24;
  734: 				datum_pts->tzoff = tzoff;
  735: 				goodtime = 1;
  736: 
  737: #ifdef DEBUG_DATUM_PTC
  738: 				printf("Time Zone found (clocktime method) = %d\n",tzoff);
  739: #endif
  740: 
  741: 				break;
  742: 			}
  743: 
  744: 		}
  745: 	}
  746: 
  747: #endif
  748: 
  749: 	/*
  750: 	** Make sure that we have a good time from the Datum PTS. Clocktime() also
  751: 	** sets yearstart and lastref.l_ui. We will have to set astref.l_uf (i.e.,
  752: 	** the fraction of a second) stuff later.
  753: 	*/
  754: 
  755: 	if (!goodtime) {
  756: 
  757: 		if (!clocktime( datum_pts->day,
  758: 				datum_pts->hour,
  759: 				datum_pts->minute,
  760: 				datum_pts->second,
  761: 				tzoff,
  762: 				datum_pts->lastrec.l_ui,
  763: 				&datum_pts->yearstart,
  764: 				&datum_pts->lastref.l_ui) ) {
  765: 
  766: #ifdef DEBUG_DATUM_PTC
  767: 			if (debug)
  768: 			{
  769: 				printf("Error: bad clocktime\n");
  770: 				printf("GMT %d, lastrec %d, yearstart %d, lastref %d\n",
  771: 				       tzoff,
  772: 				       datum_pts->lastrec.l_ui,
  773: 				       datum_pts->yearstart,
  774: 				       datum_pts->lastref.l_ui);
  775: 			}
  776: #endif
  777: 
  778: 			msyslog(LOG_ERR, "Datum_PTS: Bad clocktime");
  779: 
  780: 			return;
  781: 
  782: 		}else{
  783: 
  784: #ifdef DEBUG_DATUM_PTC
  785: 			if (debug)
  786: 			    printf("Good clocktime\n");
  787: #endif
  788: 
  789: 		}
  790: 
  791: 	}
  792: 
  793: 	/*
  794: 	** We have datum_pts->lastref.l_ui set (which is the integer part of the
  795: 	** time. Now set the microseconds field.
  796: 	*/
  797: 
  798: 	TVUTOTSF(datum_pts->usec, datum_pts->lastref.l_uf);
  799: 
  800: 	/*
  801: 	** Compute the time correction as the difference between the reference
  802: 	** time (i.e., the Datum time) minus the receive time (system time).
  803: 	*/
  804: 
  805: 	tstmp = datum_pts->lastref;		/* tstmp is the datum ntp time */
  806: 	L_SUB(&tstmp, &datum_pts->lastrec);	/* tstmp is now the correction */
  807: 	datum_pts->coderecv++;		/* increment a counter */
  808: 
  809: #ifdef DEBUG_DATUM_PTC
  810: 	dispersion = DATUM_DISPERSION;	/* set the dispersion to 0 */
  811: 	ftimerr = dispersion;
  812: 	ftimerr /= (1024.0 * 64.0);
  813: 	if (debug)
  814: 	    printf("dispersion = %d, %f\n", dispersion, ftimerr);
  815: #endif
  816: 
  817: 	/*
  818: 	** Pass the new time to ntpd through the refclock_receive function. Note
  819: 	** that we are not trying to make any corrections due to the time it takes
  820: 	** for the Datum PTS to send the message back. I am (erroneously) assuming
  821: 	** that the time for the Datum PTS to send the time back to us is negligable.
  822: 	** I suspect that this time delay may be as much as 15 ms or so (but probably
  823: 	** less). For our needs at JPL, this kind of error is ok so it is not
  824: 	** necessary to use fudge factors in the ntp.conf file. Maybe later we will.
  825: 	*/
  826:       /*LFPTOD(&tstmp, doffset);*/
  827: 	datum_pts->lastref = datum_pts->lastrec;
  828: 	refclock_receive(datum_pts->peer);
  829: 
  830: 	/*
  831: 	** Compute sigma squared (not used currently). Maybe later, this could be
  832: 	** used for the dispersion estimate. The problem is that ntpd does not link
  833: 	** in the math library so sqrt() is not available. Anyway, this is useful
  834: 	** for debugging. Maybe later I will just use absolute values for the time
  835: 	** error to come up with my dispersion estimate. Anyway, for now my dispersion
  836: 	** is set to 0.
  837: 	*/
  838: 
  839: 	timerr = tstmp.l_ui<<20;
  840: 	timerr |= (tstmp.l_uf>>12) & 0x000fffff;
  841: 	ftimerr = timerr;
  842: 	ftimerr /= 1024*1024;
  843: 	abserr = ftimerr;
  844: 	if (ftimerr < 0.0) abserr = -ftimerr;
  845: 
  846: 	if (datum_pts->sigma2 == 0.0) {
  847: 		if (abserr < DATUM_MAX_ERROR) {
  848: 			datum_pts->sigma2 = abserr*abserr;
  849: 		}else{
  850: 			datum_pts->sigma2 = DATUM_MAX_ERROR2;
  851: 		}
  852: 	}else{
  853: 		if (abserr < DATUM_MAX_ERROR) {
  854: 			datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*abserr*abserr;
  855: 		}else{
  856: 			datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*DATUM_MAX_ERROR2;
  857: 		}
  858: 	}
  859: 
  860: #ifdef DEBUG_DATUM_PTC
  861: 	if (debug)
  862: 	    printf("Time error = %f seconds\n", ftimerr);
  863: #endif
  864: 
  865: #if defined(DEBUG_DATUM_PTC) || defined(LOG_TIME_ERRORS)
  866: 	if (debug)
  867: 	    printf("PTS: day %d, hour %d, minute %d, second %d, msec %d, Time Error %f\n",
  868: 		   datum_pts->day,
  869: 		   datum_pts->hour,
  870: 		   datum_pts->minute,
  871: 		   datum_pts->second,
  872: 		   datum_pts->msec,
  873: 		   ftimerr);
  874: #endif
  875: 
  876: }
  877: #else
  878: int refclock_datum_bs;
  879: #endif /* REFCLOCK */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>