Annotation of embedaddon/ntp/ntpd/refclock_dumbclock.c, revision 1.1
1.1 ! misho 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>