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