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

    1: /*
    2:  * refclock_dumbclock - clock driver for a unknown time distribution system
    3:  * that only provides hh:mm:ss (in local time, yet!).
    4:  */
    5: 
    6: /*
    7:  * Must interpolate back to local time.  Very annoying.
    8:  */
    9: #define GET_LOCALTIME
   10: 
   11: #ifdef HAVE_CONFIG_H
   12: #include <config.h>
   13: #endif
   14: 
   15: #if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK)
   16: 
   17: #include "ntpd.h"
   18: #include "ntp_io.h"
   19: #include "ntp_refclock.h"
   20: #include "ntp_calendar.h"
   21: #include "ntp_stdlib.h"
   22: 
   23: #include <stdio.h>
   24: #include <ctype.h>
   25: 
   26: #ifdef SYS_WINNT
   27: extern int async_write(int, const void *, unsigned int);
   28: #undef write
   29: #define write(fd, data, octets)	async_write(fd, data, octets)
   30: #endif
   31: 
   32: /*
   33:  * This driver supports a generic dumb clock that only outputs hh:mm:ss,
   34:  * in local time, no less.
   35:  *
   36:  * Input format:
   37:  *
   38:  *	hh:mm:ss   <cr>
   39:  *
   40:  * hh:mm:ss -- what you'd expect, with a 24 hour clock.  (Heck, that's the only
   41:  * way it could get stupider.)  We take time on the <cr>.
   42:  *
   43:  * The original source of this module was the WWVB module.
   44:  */
   45: 
   46: /*
   47:  * Interface definitions
   48:  */
   49: #define	DEVICE		"/dev/dumbclock%d" /* device name and unit */
   50: #define	SPEED232	B9600	/* uart speed (9600 baud) */
   51: #define	PRECISION	(-13)	/* precision assumed (about 100 us) */
   52: #define	REFID		"dumbclock"	/* reference ID */
   53: #define	DESCRIPTION	"Dumb clock" /* WRU */
   54: 
   55: 
   56: /*
   57:  * Insanity check.  Since the time is local, we need to make sure that during midnight
   58:  * transitions, we can convert back to Unix time.  If the conversion results in some number
   59:  * worse than this number of seconds away, assume the next day and retry.
   60:  */
   61: #define INSANE_SECONDS 3600
   62: 
   63: /*
   64:  * Dumb clock control structure
   65:  */
   66: struct dumbclock_unit {
   67: 	u_char	  tcswitch;	/* timecode switch */
   68: 	l_fp	  laststamp;	/* last receive timestamp */
   69: 	u_char	  lasthour;	/* last hour (for monitor) */
   70: 	u_char	  linect;	/* count ignored lines (for monitor */
   71: 	struct tm ymd;		/* struct tm for y/m/d only */
   72: };
   73: 
   74: /*
   75:  * Function prototypes
   76:  */
   77: static	int	dumbclock_start		(int, struct peer *);
   78: static	void	dumbclock_shutdown	(int, struct peer *);
   79: static	void	dumbclock_receive	(struct recvbuf *);
   80: #if 0
   81: static	void	dumbclock_poll		(int, struct peer *);
   82: #endif
   83: 
   84: /*
   85:  * Transfer vector
   86:  */
   87: struct	refclock refclock_dumbclock = {
   88: 	dumbclock_start,		     /* start up driver */
   89: 	dumbclock_shutdown,		     /* shut down driver */
   90: 	noentry,			     /* poll the driver -- a nice fabrication */
   91: 	noentry,			     /* not used */
   92: 	noentry,			     /* not used */
   93: 	noentry,			     /* not used */
   94: 	NOFLAGS				     /* not used */
   95: };
   96: 
   97: 
   98: /*
   99:  * dumbclock_start - open the devices and initialize data for processing
  100:  */
  101: static int
  102: dumbclock_start(
  103: 	int unit,
  104: 	struct peer *peer
  105: 	)
  106: {
  107: 	register struct dumbclock_unit *up;
  108: 	struct refclockproc *pp;
  109: 	int fd;
  110: 	char device[20];
  111: 	struct tm *tm_time_p;
  112: 	time_t     now;
  113: 
  114: 	/*
  115: 	 * Open serial port. Don't bother with CLK line discipline, since
  116: 	 * it's not available.
  117: 	 */
  118: 	snprintf(device, sizeof(device), DEVICE, unit);
  119: #ifdef DEBUG
  120: 	if (debug)
  121: 		printf ("starting Dumbclock with device %s\n",device);
  122: #endif
  123: 	fd = refclock_open(device, SPEED232, 0);
  124: 	if (!fd)
  125: 		return (0);
  126: 
  127: 	/*
  128: 	 * Allocate and initialize unit structure
  129: 	 */
  130: 	up = emalloc(sizeof(*up));
  131: 	memset(up, 0, sizeof(*up));
  132: 	pp = peer->procptr;
  133: 	pp->unitptr = (caddr_t)up;
  134: 	pp->io.clock_recv = dumbclock_receive;
  135: 	pp->io.srcclock = (caddr_t)peer;
  136: 	pp->io.datalen = 0;
  137: 	pp->io.fd = fd;
  138: 	if (!io_addclock(&pp->io)) {
  139: 		close(fd);
  140: 		pp->io.fd = -1;
  141: 		free(up);
  142: 		pp->unitptr = NULL;
  143: 		return (0);
  144: 	}
  145: 
  146: 
  147: 	time(&now);
  148: #ifdef GET_LOCALTIME
  149: 	tm_time_p = localtime(&now);
  150: #else
  151: 	tm_time_p = gmtime(&now);
  152: #endif
  153: 	if (tm_time_p)
  154: 		up->ymd = *tm_time_p;
  155: 	else
  156: 		return 0;
  157: 
  158: 	/*
  159: 	 * Initialize miscellaneous variables
  160: 	 */
  161: 	peer->precision = PRECISION;
  162: 	pp->clockdesc = DESCRIPTION;
  163: 	memcpy((char *)&pp->refid, REFID, 4);
  164: 	return (1);
  165: }
  166: 
  167: 
  168: /*
  169:  * dumbclock_shutdown - shut down the clock
  170:  */
  171: static void
  172: dumbclock_shutdown(
  173: 	int unit,
  174: 	struct peer *peer
  175: 	)
  176: {
  177: 	register struct dumbclock_unit *up;
  178: 	struct refclockproc *pp;
  179: 
  180: 	pp = peer->procptr;
  181: 	up = (struct dumbclock_unit *)pp->unitptr;
  182: 	if (-1 != pp->io.fd)
  183: 		io_closeclock(&pp->io);
  184: 	if (NULL != up)
  185: 		free(up);
  186: }
  187: 
  188: 
  189: /*
  190:  * dumbclock_receive - receive data from the serial interface
  191:  */
  192: static void
  193: dumbclock_receive(
  194: 	struct recvbuf *rbufp
  195: 	)
  196: {
  197: 	struct dumbclock_unit *up;
  198: 	struct refclockproc *pp;
  199: 	struct peer *peer;
  200: 
  201: 	l_fp	trtmp;		/* arrival timestamp */
  202: 	int	hours;		/* hour-of-day */
  203: 	int	minutes;	/* minutes-past-the-hour */
  204: 	int	seconds;	/* seconds */
  205: 	int	temp;		/* int temp */
  206: 	int	got_good;	/* got a good time flag */
  207: 
  208: 	/*
  209: 	 * Initialize pointers and read the timecode and timestamp
  210: 	 */
  211: 	peer = (struct peer *)rbufp->recv_srcclock;
  212: 	pp = peer->procptr;
  213: 	up = (struct dumbclock_unit *)pp->unitptr;
  214: 	temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
  215: 
  216: 	if (temp == 0) {
  217: 		if (up->tcswitch == 0) {
  218: 			up->tcswitch = 1;
  219: 			up->laststamp = trtmp;
  220: 		} else
  221: 			up->tcswitch = 0;
  222: 		return;
  223: 	}
  224: 	pp->lencode = (u_short)temp;
  225: 	pp->lastrec = up->laststamp;
  226: 	up->laststamp = trtmp;
  227: 	up->tcswitch = 1;
  228: 
  229: #ifdef DEBUG
  230: 	if (debug)
  231: 		printf("dumbclock: timecode %d %s\n",
  232: 		       pp->lencode, pp->a_lastcode);
  233: #endif
  234: 
  235: 	/*
  236: 	 * We get down to business. Check the timecode format...
  237: 	 */
  238: 	got_good=0;
  239: 	if (sscanf(pp->a_lastcode,"%02d:%02d:%02d",
  240: 		   &hours,&minutes,&seconds) == 3)
  241: 	{
  242: 	    struct tm *gmtp;
  243: 	    struct tm *lt_p;
  244: 	    time_t     asserted_time;	     /* the SPM time based on the composite time+date */
  245: 	    struct tm  asserted_tm;	     /* the struct tm of the same */
  246: 	    int        adjyear;
  247: 	    int        adjmon;
  248: 	    time_t     reality_delta;
  249: 	    time_t     now;
  250: 
  251: 
  252: 	    /*
  253: 	     * Convert to GMT for sites that distribute localtime.  This
  254: 	     * means we have to figure out what day it is.  Easier said
  255: 	     * than done...
  256: 	     */
  257: 
  258: 	    memset(&asserted_tm, 0, sizeof(asserted_tm));
  259: 
  260: 	    asserted_tm.tm_year  = up->ymd.tm_year;
  261: 	    asserted_tm.tm_mon   = up->ymd.tm_mon;
  262: 	    asserted_tm.tm_mday  = up->ymd.tm_mday;
  263: 	    asserted_tm.tm_hour  = hours;
  264: 	    asserted_tm.tm_min   = minutes;
  265: 	    asserted_tm.tm_sec   = seconds;
  266: 	    asserted_tm.tm_isdst = -1;
  267: 
  268: #ifdef GET_LOCALTIME
  269: 	    asserted_time = mktime (&asserted_tm);
  270: 	    time(&now);
  271: #else
  272: #include "GMT unsupported for dumbclock!"
  273: #endif
  274: 	    reality_delta = asserted_time - now;
  275: 
  276: 	    /*
  277: 	     * We assume that if the time is grossly wrong, it's because we got the
  278: 	     * year/month/day wrong.
  279: 	     */
  280: 	    if (reality_delta > INSANE_SECONDS)
  281: 	    {
  282: 		asserted_time -= SECSPERDAY; /* local clock behind real time */
  283: 	    }
  284: 	    else if (-reality_delta > INSANE_SECONDS)
  285: 	    {
  286: 		asserted_time += SECSPERDAY; /* local clock ahead of real time */
  287: 	    }
  288: 	    lt_p = localtime(&asserted_time);
  289: 	    if (lt_p)
  290: 	    {
  291: 		up->ymd = *lt_p;
  292: 	    }
  293: 	    else
  294: 	    {
  295: 		refclock_report (peer, CEVNT_FAULT);
  296: 		return;
  297: 	    }
  298: 
  299: 	    if ((gmtp = gmtime (&asserted_time)) == NULL)
  300: 	    {
  301: 		refclock_report (peer, CEVNT_FAULT);
  302: 		return;
  303: 	    }
  304: 	    adjyear = gmtp->tm_year+1900;
  305: 	    adjmon  = gmtp->tm_mon+1;
  306: 	    pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday);
  307: 	    pp->hour   = gmtp->tm_hour;
  308: 	    pp->minute = gmtp->tm_min;
  309: 	    pp->second = gmtp->tm_sec;
  310: #ifdef DEBUG
  311: 	    if (debug)
  312: 		printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
  313: 			adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute,
  314: 			pp->second);
  315: #endif
  316: 
  317: 	    got_good=1;
  318: 	}
  319: 
  320: 	if (!got_good)
  321: 	{
  322: 	    if (up->linect > 0)
  323: 	    	up->linect--;
  324: 	    else
  325: 	    	refclock_report(peer, CEVNT_BADREPLY);
  326: 	    return;
  327: 	}
  328: 
  329: 	/*
  330: 	 * Process the new sample in the median filter and determine the
  331: 	 * timecode timestamp.
  332: 	 */
  333: 	if (!refclock_process(pp)) {
  334: 		refclock_report(peer, CEVNT_BADTIME);
  335: 		return;
  336: 	}
  337: 	pp->lastref = pp->lastrec;
  338: 	refclock_receive(peer);
  339: 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
  340: 	up->lasthour = (u_char)pp->hour;
  341: }
  342: 
  343: #if 0
  344: /*
  345:  * dumbclock_poll - called by the transmit procedure
  346:  */
  347: static void
  348: dumbclock_poll(
  349: 	int unit,
  350: 	struct peer *peer
  351: 	)
  352: {
  353: 	register struct dumbclock_unit *up;
  354: 	struct refclockproc *pp;
  355: 	char pollchar;
  356: 
  357: 	/*
  358: 	 * Time to poll the clock. The Chrono-log clock is supposed to
  359: 	 * respond to a 'T' by returning a timecode in the format(s)
  360: 	 * specified above.  Ours does (can?) not, but this seems to be
  361: 	 * an installation-specific problem.  This code is dyked out,
  362: 	 * but may be re-enabled if anyone ever finds a Chrono-log that
  363: 	 * actually listens to this command.
  364: 	 */
  365: #if 0
  366: 	pp = peer->procptr;
  367: 	up = (struct dumbclock_unit *)pp->unitptr;
  368: 	if (peer->reach == 0)
  369: 		refclock_report(peer, CEVNT_TIMEOUT);
  370: 	if (up->linect > 0)
  371: 		pollchar = 'R';
  372: 	else
  373: 		pollchar = 'T';
  374: 	if (write(pp->io.fd, &pollchar, 1) != 1)
  375: 		refclock_report(peer, CEVNT_FAULT);
  376: 	else
  377: 		pp->polls++;
  378: #endif
  379: }
  380: #endif
  381: 
  382: #else
  383: int refclock_dumbclock_bs;
  384: #endif	/* defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK) */

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