File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_chronolog.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 ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * refclock_chronolog - clock driver for Chronolog K-series WWVB receiver.
    3:  */
    4: 
    5: /*
    6:  * Must interpolate back to local time.  Very annoying.
    7:  */
    8: #define GET_LOCALTIME
    9: 
   10: #ifdef HAVE_CONFIG_H
   11: #include <config.h>
   12: #endif
   13: 
   14: #if defined(REFCLOCK) && defined(CLOCK_CHRONOLOG)
   15: 
   16: #include "ntpd.h"
   17: #include "ntp_io.h"
   18: #include "ntp_refclock.h"
   19: #include "ntp_calendar.h"
   20: #include "ntp_stdlib.h"
   21: 
   22: #include <stdio.h>
   23: #include <ctype.h>
   24: 
   25: /*
   26:  * This driver supports the Chronolog K-series WWVB receiver.
   27:  *
   28:  * Input format:
   29:  *
   30:  *	Y YY/MM/DD<cr><lf>
   31:  *      Z hh:mm:ss<cr><lf>
   32:  *
   33:  * YY/MM/DD -- what you'd expect.  This arrives a few seconds before the
   34:  * timestamp.
   35:  * hh:mm:ss -- what you'd expect.  We take time on the <cr>.
   36:  *
   37:  * Our Chronolog writes time out at 2400 bps 8/N/1, but it can be configured
   38:  * otherwise.  The clock seems to appear every 60 seconds, which doesn't make
   39:  * for good statistics collection.
   40:  *
   41:  * The original source of this module was the WWVB module.
   42:  */
   43: 
   44: /*
   45:  * Interface definitions
   46:  */
   47: #define	DEVICE		"/dev/chronolog%d" /* device name and unit */
   48: #define	SPEED232	B2400	/* uart speed (2400 baud) */
   49: #define	PRECISION	(-13)	/* precision assumed (about 100 us) */
   50: #define	REFID		"chronolog"	/* reference ID */
   51: #define	DESCRIPTION	"Chrono-log K" /* WRU */
   52: 
   53: #define MONLIN		15	/* number of monitoring lines */
   54: 
   55: /*
   56:  * Chrono-log unit control structure
   57:  */
   58: struct chronolog_unit {
   59: 	u_char	tcswitch;	/* timecode switch */
   60: 	l_fp	laststamp;	/* last receive timestamp */
   61: 	u_char	lasthour;	/* last hour (for monitor) */
   62: 	int   	year;	        /* Y2K-adjusted year */
   63: 	int   	day;	        /* day-of-month */
   64:         int   	month;	        /* month-of-year */
   65: };
   66: 
   67: /*
   68:  * Function prototypes
   69:  */
   70: static	int	chronolog_start		(int, struct peer *);
   71: static	void	chronolog_shutdown	(int, struct peer *);
   72: static	void	chronolog_receive	(struct recvbuf *);
   73: static	void	chronolog_poll		(int, struct peer *);
   74: 
   75: /*
   76:  * Transfer vector
   77:  */
   78: struct	refclock refclock_chronolog = {
   79: 	chronolog_start,	/* start up driver */
   80: 	chronolog_shutdown,	/* shut down driver */
   81: 	chronolog_poll,		/* poll the driver -- a nice fabrication */
   82: 	noentry,		/* not used */
   83: 	noentry,		/* not used */
   84: 	noentry,		/* not used */
   85: 	NOFLAGS			/* not used */
   86: };
   87: 
   88: 
   89: /*
   90:  * chronolog_start - open the devices and initialize data for processing
   91:  */
   92: static int
   93: chronolog_start(
   94: 	int unit,
   95: 	struct peer *peer
   96: 	)
   97: {
   98: 	register struct chronolog_unit *up;
   99: 	struct refclockproc *pp;
  100: 	int fd;
  101: 	char device[20];
  102: 
  103: 	/*
  104: 	 * Open serial port. Don't bother with CLK line discipline, since
  105: 	 * it's not available.
  106: 	 */
  107: 	snprintf(device, sizeof(device), DEVICE, unit);
  108: #ifdef DEBUG
  109: 	if (debug)
  110: 		printf ("starting Chronolog with device %s\n",device);
  111: #endif
  112: 	if (!(fd = refclock_open(device, SPEED232, 0)))
  113: 		return (0);
  114: 
  115: 	/*
  116: 	 * Allocate and initialize unit structure
  117: 	 */
  118: 	up = emalloc(sizeof(*up));
  119: 	memset(up, 0, sizeof(*up));
  120: 	pp = peer->procptr;
  121: 	pp->unitptr = (caddr_t)up;
  122: 	pp->io.clock_recv = chronolog_receive;
  123: 	pp->io.srcclock = (caddr_t)peer;
  124: 	pp->io.datalen = 0;
  125: 	pp->io.fd = fd;
  126: 	if (!io_addclock(&pp->io)) {
  127: 		close(fd);
  128: 		pp->io.fd = -1;
  129: 		free(up);
  130: 		pp->unitptr = NULL;
  131: 		return (0);
  132: 	}
  133: 
  134: 	/*
  135: 	 * Initialize miscellaneous variables
  136: 	 */
  137: 	peer->precision = PRECISION;
  138: 	pp->clockdesc = DESCRIPTION;
  139: 	memcpy((char *)&pp->refid, REFID, 4);
  140: 	return (1);
  141: }
  142: 
  143: 
  144: /*
  145:  * chronolog_shutdown - shut down the clock
  146:  */
  147: static void
  148: chronolog_shutdown(
  149: 	int unit,
  150: 	struct peer *peer
  151: 	)
  152: {
  153: 	register struct chronolog_unit *up;
  154: 	struct refclockproc *pp;
  155: 
  156: 	pp = peer->procptr;
  157: 	up = (struct chronolog_unit *)pp->unitptr;
  158: 	if (-1 != pp->io.fd)
  159: 		io_closeclock(&pp->io);
  160: 	if (NULL != up)
  161: 		free(up);
  162: }
  163: 
  164: 
  165: /*
  166:  * chronolog_receive - receive data from the serial interface
  167:  */
  168: static void
  169: chronolog_receive(
  170: 	struct recvbuf *rbufp
  171: 	)
  172: {
  173: 	struct chronolog_unit *up;
  174: 	struct refclockproc *pp;
  175: 	struct peer *peer;
  176: 
  177: 	l_fp	     trtmp;	/* arrival timestamp */
  178: 	int          hours;	/* hour-of-day */
  179: 	int	     minutes;	/* minutes-past-the-hour */
  180: 	int          seconds;	/* seconds */
  181: 	int	     temp;	/* int temp */
  182: 	int          got_good;	/* got a good time flag */
  183: 
  184: 	/*
  185: 	 * Initialize pointers and read the timecode and timestamp
  186: 	 */
  187: 	peer = (struct peer *)rbufp->recv_srcclock;
  188: 	pp = peer->procptr;
  189: 	up = (struct chronolog_unit *)pp->unitptr;
  190: 	temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
  191: 
  192: 	if (temp == 0) {
  193: 		if (up->tcswitch == 0) {
  194: 			up->tcswitch = 1;
  195: 			up->laststamp = trtmp;
  196: 		} else
  197: 		    up->tcswitch = 0;
  198: 		return;
  199: 	}
  200: 	pp->lencode = temp;
  201: 	pp->lastrec = up->laststamp;
  202: 	up->laststamp = trtmp;
  203: 	up->tcswitch = 1;
  204: 
  205: #ifdef DEBUG
  206: 	if (debug)
  207: 		printf("chronolog: timecode %d %s\n", pp->lencode,
  208: 		    pp->a_lastcode);
  209: #endif
  210: 
  211: 	/*
  212: 	 * We get down to business. Check the timecode format and decode
  213: 	 * its contents. This code uses the first character to see whether
  214: 	 * we're looking at a date or a time.  We store data data across
  215: 	 * calls since it is transmitted a few seconds ahead of the
  216: 	 * timestamp.
  217: 	 */
  218: 	got_good=0;
  219: 	if (sscanf(pp->a_lastcode, "Y %d/%d/%d", &up->year,&up->month,&up->day))
  220: 	{
  221: 	    /*
  222: 	     * Y2K convert the 2-digit year
  223: 	     */
  224: 	    up->year = up->year >= 69 ? up->year : up->year + 100;
  225: 	    return;
  226: 	}
  227: 	if (sscanf(pp->a_lastcode,"Z %02d:%02d:%02d",
  228: 		   &hours,&minutes,&seconds) == 3)
  229: 	{
  230: #ifdef GET_LOCALTIME
  231: 	    struct tm  local;
  232: 	    struct tm *gmtp;
  233: 	    time_t     unixtime;
  234: 	    int        adjyear;
  235: 	    int        adjmon;
  236: 
  237: 	    /*
  238: 	     * Convert to GMT for sites that distribute localtime.  This
  239:              * means we have to do Y2K conversion on the 2-digit year;
  240: 	     * otherwise, we get the time wrong.
  241: 	     */
  242: 	    
  243: 	    memset(&local, 0, sizeof(local));
  244: 
  245: 	    local.tm_year  = up->year;
  246: 	    local.tm_mon   = up->month-1;
  247: 	    local.tm_mday  = up->day;
  248: 	    local.tm_hour  = hours;
  249: 	    local.tm_min   = minutes;
  250: 	    local.tm_sec   = seconds;
  251: 	    local.tm_isdst = -1;
  252: 
  253: 	    unixtime = mktime (&local);
  254: 	    if ((gmtp = gmtime (&unixtime)) == NULL)
  255: 	    {
  256: 		refclock_report (peer, CEVNT_FAULT);
  257: 		return;
  258: 	    }
  259: 	    adjyear = gmtp->tm_year+1900;
  260: 	    adjmon  = gmtp->tm_mon+1;
  261: 	    pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday);
  262: 	    pp->hour   = gmtp->tm_hour;
  263: 	    pp->minute = gmtp->tm_min;
  264: 	    pp->second = gmtp->tm_sec;
  265: #ifdef DEBUG
  266: 	    if (debug)
  267: 		printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
  268: 			adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute,
  269: 			pp->second);
  270: #endif
  271: 	    
  272: #else
  273: 	    /*
  274: 	     * For more rational sites distributing UTC
  275: 	     */
  276: 	    pp->day    = ymd2yd(year+1900,month,day);
  277: 	    pp->hour   = hours;
  278: 	    pp->minute = minutes;
  279: 	    pp->second = seconds;
  280: 
  281: #endif
  282: 	    got_good=1;
  283: 	}
  284: 
  285: 	if (!got_good)
  286: 	    return;
  287: 
  288: 
  289: 	/*
  290: 	 * Process the new sample in the median filter and determine the
  291: 	 * timecode timestamp.
  292: 	 */
  293: 	if (!refclock_process(pp)) {
  294: 		refclock_report(peer, CEVNT_BADTIME);
  295: 		return;
  296: 	}
  297: 	pp->lastref = pp->lastrec;
  298: 	refclock_receive(peer);
  299: 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
  300: 	up->lasthour = pp->hour;
  301: }
  302: 
  303: 
  304: /*
  305:  * chronolog_poll - called by the transmit procedure
  306:  */
  307: static void
  308: chronolog_poll(
  309: 	int unit,
  310: 	struct peer *peer
  311: 	)
  312: {
  313: 	/*
  314: 	 * Time to poll the clock. The Chrono-log clock is supposed to
  315: 	 * respond to a 'T' by returning a timecode in the format(s)
  316: 	 * specified above.  Ours does (can?) not, but this seems to be
  317: 	 * an installation-specific problem.  This code is dyked out,
  318: 	 * but may be re-enabled if anyone ever finds a Chrono-log that
  319: 	 * actually listens to this command.
  320: 	 */
  321: #if 0
  322: 	register struct chronolog_unit *up;
  323: 	struct refclockproc *pp;
  324: 	char pollchar;
  325: 
  326: 	pp = peer->procptr;
  327: 	up = (struct chronolog_unit *)pp->unitptr;
  328: 	if (peer->burst == 0 && peer->reach == 0)
  329: 		refclock_report(peer, CEVNT_TIMEOUT);
  330: 	if (up->linect > 0)
  331: 		pollchar = 'R';
  332: 	else
  333: 		pollchar = 'T';
  334: 	if (write(pp->io.fd, &pollchar, 1) != 1)
  335: 		refclock_report(peer, CEVNT_FAULT);
  336: 	else
  337: 		pp->polls++;
  338: #endif
  339: }
  340: 
  341: #else
  342: int refclock_chronolog_bs;
  343: #endif /* REFCLOCK */

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