Annotation of embedaddon/ntp/ntpd/refclock_true.c, revision 1.1
1.1 ! misho 1: /*
! 2: * refclock_true - clock driver for the Kinemetrics Truetime receivers
! 3: * Receiver Version 3.0C - tested plain, with CLKLDISC
! 4: * Developement work being done:
! 5: * - Properly handle varying satellite positions (more acurately)
! 6: * - Integrate GPSTM and/or OMEGA and/or TRAK and/or ??? drivers
! 7: */
! 8:
! 9: #ifdef HAVE_CONFIG_H
! 10: #include <config.h>
! 11: #endif
! 12:
! 13: #if defined(REFCLOCK) && defined(CLOCK_TRUETIME)
! 14:
! 15: #include "ntpd.h"
! 16: #include "ntp_io.h"
! 17: #include "ntp_refclock.h"
! 18: #include "ntp_unixtime.h"
! 19: #include "ntp_stdlib.h"
! 20:
! 21: #include <stdio.h>
! 22: #include <ctype.h>
! 23:
! 24: #ifdef SYS_WINNT
! 25: extern int async_write(int, const void *, unsigned int);
! 26: #undef write
! 27: #define write(fd, data, octets) async_write(fd, data, octets)
! 28: #endif
! 29:
! 30: /* This should be an atom clock but those are very hard to build.
! 31: *
! 32: * The PCL720 from P C Labs has an Intel 8253 lookalike, as well as a bunch
! 33: * of TTL input and output pins, all brought out to the back panel. If you
! 34: * wire a PPS signal (such as the TTL PPS coming out of a GOES or other
! 35: * Kinemetrics/Truetime clock) to the 8253's GATE0, and then also wire the
! 36: * 8253's OUT0 to the PCL720's INPUT3.BIT0, then we can read CTR0 to get the
! 37: * number of uSecs since the last PPS upward swing, mediated by reading OUT0
! 38: * to find out if the counter has wrapped around (this happens if more than
! 39: * 65535us (65ms) elapses between the PPS event and our being called.)
! 40: */
! 41: #ifdef CLOCK_PPS720
! 42: # undef min /* XXX */
! 43: # undef max /* XXX */
! 44: # include <machine/inline.h>
! 45: # include <sys/pcl720.h>
! 46: # include <sys/i8253.h>
! 47: # define PCL720_IOB 0x2a0 /* XXX */
! 48: # define PCL720_CTR 0 /* XXX */
! 49: #endif
! 50:
! 51: /*
! 52: * Support for Kinemetrics Truetime Receivers
! 53: * GOES
! 54: * GPS/TM-TMD
! 55: * XL-DC (a 151-602-210, reported by the driver as a GPS/TM-TMD)
! 56: * GPS-800 TCU (an 805-957 with the RS232 Talker/Listener module)
! 57: * OM-DC: getting stale ("OMEGA")
! 58: *
! 59: * Most of this code is originally from refclock_wwvb.c with thanks.
! 60: * It has been so mangled that wwvb is not a recognizable ancestor.
! 61: *
! 62: * Timcode format: ADDD:HH:MM:SSQCL
! 63: * A - control A (this is stripped before we see it)
! 64: * Q - Quality indication (see below)
! 65: * C - Carriage return
! 66: * L - Line feed
! 67: *
! 68: * Quality codes indicate possible error of
! 69: * 468-DC GOES Receiver:
! 70: * GPS-TM/TMD Receiver: (default quality codes for XL-DC)
! 71: * ? +/- 1 milliseconds # +/- 100 microseconds
! 72: * * +/- 10 microseconds . +/- 1 microsecond
! 73: * space less than 1 microsecond
! 74: * OM-DC OMEGA Receiver: (default quality codes for OMEGA)
! 75: * WARNING OMEGA navigation system is no longer existent
! 76: * > >+- 5 seconds
! 77: * ? >+/- 500 milliseconds # >+/- 50 milliseconds
! 78: * * >+/- 5 milliseconds . >+/- 1 millisecond
! 79: * A-H less than 1 millisecond. Character indicates which station
! 80: * is being received as follows:
! 81: * A = Norway, B = Liberia, C = Hawaii, D = North Dakota,
! 82: * E = La Reunion, F = Argentina, G = Australia, H = Japan.
! 83: *
! 84: * The carriage return start bit begins on 0 seconds and extends to 1 bit time.
! 85: *
! 86: * Notes on 468-DC and OMEGA receiver:
! 87: *
! 88: * Send the clock a 'R' or 'C' and once per second a timestamp will
! 89: * appear. Send a 'P' to get the satellite position once (GOES only.)
! 90: *
! 91: * Notes on the 468-DC receiver:
! 92: *
! 93: * Since the old east/west satellite locations are only historical, you can't
! 94: * set your clock propagation delay settings correctly and still use
! 95: * automatic mode. The manual says to use a compromise when setting the
! 96: * switches. This results in significant errors. The solution; use fudge
! 97: * time1 and time2 to incorporate corrections. If your clock is set for
! 98: * 50 and it should be 58 for using the west and 46 for using the east,
! 99: * use the line
! 100: *
! 101: * fudge 127.127.5.0 time1 +0.008 time2 -0.004
! 102: *
! 103: * This corrects the 4 milliseconds advance and 8 milliseconds retard
! 104: * needed. The software will ask the clock which satellite it sees.
! 105: *
! 106: * Ntp.conf parameters:
! 107: * time1 - offset applied to samples when reading WEST satellite (default = 0)
! 108: * time2 - offset applied to samples when reading EAST satellite (default = 0)
! 109: * val1 - stratum to assign to this clock (default = 0)
! 110: * val2 - refid assigned to this clock (default = "TRUE", see below)
! 111: * flag1 - will silence the clock side of ntpd, just reading the clock
! 112: * without trying to write to it. (default = 0)
! 113: * flag2 - generate a debug file /tmp/true%d.
! 114: * flag3 - enable ppsclock streams module
! 115: * flag4 - use the PCL-720 (BSD/OS only)
! 116: */
! 117:
! 118:
! 119: /*
! 120: * Definitions
! 121: */
! 122: #define DEVICE "/dev/true%d"
! 123: #define SPEED232 B9600 /* 9600 baud */
! 124:
! 125: /*
! 126: * Radio interface parameters
! 127: */
! 128: #define PRECISION (-10) /* precision assumed (about 1 ms) */
! 129: #define REFID "TRUE" /* reference id */
! 130: #define DESCRIPTION "Kinemetrics/TrueTime Receiver"
! 131:
! 132: /*
! 133: * Tags which station (satellite) we see
! 134: */
! 135: #define GOES_WEST 0 /* Default to WEST satellite and apply time1 */
! 136: #define GOES_EAST 1 /* until you discover otherwise */
! 137:
! 138: /*
! 139: * used by the state machine
! 140: */
! 141: enum true_event {e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite,
! 142: e_Poll, e_Location, e_TS, e_Max};
! 143: const char *events[] = {"Init", "Huh", "F18", "F50", "F51", "Satellite",
! 144: "Poll", "Location", "TS"};
! 145: #define eventStr(x) (((int)x<(int)e_Max) ? events[(int)x] : "?")
! 146:
! 147: enum true_state {s_Base, s_InqTM, s_InqTCU, s_InqOmega, s_InqGOES,
! 148: s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max};
! 149: const char *states[] = {"Base", "InqTM", "InqTCU", "InqOmega", "InqGOES",
! 150: "Init", "F18", "F50", "Start", "Auto"};
! 151: #define stateStr(x) (((int)x<(int)s_Max) ? states[(int)x] : "?")
! 152:
! 153: enum true_type {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_Max};
! 154: const char *types[] = {"unknown", "goes", "tm", "tcu", "omega"};
! 155: #define typeStr(x) (((int)x<(int)t_Max) ? types[(int)x] : "?")
! 156:
! 157: /*
! 158: * unit control structure
! 159: */
! 160: struct true_unit {
! 161: unsigned int pollcnt; /* poll message counter */
! 162: unsigned int station; /* which station we are on */
! 163: unsigned int polled; /* Hand in a time sample? */
! 164: enum true_state state; /* state machine */
! 165: enum true_type type; /* what kind of clock is it? */
! 166: int unit; /* save an extra copy of this */
! 167: FILE *debug; /* debug logging file */
! 168: #ifdef CLOCK_PPS720
! 169: int pcl720init; /* init flag for PCL 720 */
! 170: #endif
! 171: };
! 172:
! 173: /*
! 174: * Function prototypes
! 175: */
! 176: static int true_start (int, struct peer *);
! 177: static void true_shutdown (int, struct peer *);
! 178: static void true_receive (struct recvbuf *);
! 179: static void true_poll (int, struct peer *);
! 180: static void true_send (struct peer *, const char *);
! 181: static void true_doevent (struct peer *, enum true_event);
! 182:
! 183: #ifdef CLOCK_PPS720
! 184: static u_long true_sample720 (void);
! 185: #endif
! 186:
! 187: /*
! 188: * Transfer vector
! 189: */
! 190: struct refclock refclock_true = {
! 191: true_start, /* start up driver */
! 192: true_shutdown, /* shut down driver */
! 193: true_poll, /* transmit poll message */
! 194: noentry, /* not used (old true_control) */
! 195: noentry, /* initialize driver (not used) */
! 196: noentry, /* not used (old true_buginfo) */
! 197: NOFLAGS /* not used */
! 198: };
! 199:
! 200:
! 201: #if !defined(__STDC__)
! 202: # define true_debug (void)
! 203: #else
! 204: static void
! 205: true_debug(struct peer *peer, const char *fmt, ...)
! 206: {
! 207: va_list ap;
! 208: int want_debugging, now_debugging;
! 209: struct refclockproc *pp;
! 210: struct true_unit *up;
! 211:
! 212: va_start(ap, fmt);
! 213: pp = peer->procptr;
! 214: up = (struct true_unit *)pp->unitptr;
! 215:
! 216: want_debugging = (pp->sloppyclockflag & CLK_FLAG2) != 0;
! 217: now_debugging = (up->debug != NULL);
! 218: if (want_debugging != now_debugging)
! 219: {
! 220: if (want_debugging) {
! 221: char filename[40];
! 222: int fd;
! 223:
! 224: snprintf(filename, sizeof(filename), "/tmp/true%d.debug", up->unit);
! 225: fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0600);
! 226: if (fd >= 0 && (up->debug = fdopen(fd, "r+"))) {
! 227: #ifdef HAVE_SETVBUF
! 228: static char buf[BUFSIZ];
! 229: setvbuf(up->debug, buf, _IOLBF, BUFSIZ);
! 230: #else
! 231: setlinebuf(up->debug);
! 232: #endif
! 233: }
! 234: } else {
! 235: fclose(up->debug);
! 236: up->debug = NULL;
! 237: }
! 238: }
! 239:
! 240: if (up->debug) {
! 241: fprintf(up->debug, "true%d: ", up->unit);
! 242: vfprintf(up->debug, fmt, ap);
! 243: }
! 244: va_end(ap);
! 245: }
! 246: #endif /*STDC*/
! 247:
! 248: /*
! 249: * true_start - open the devices and initialize data for processing
! 250: */
! 251: static int
! 252: true_start(
! 253: int unit,
! 254: struct peer *peer
! 255: )
! 256: {
! 257: register struct true_unit *up;
! 258: struct refclockproc *pp;
! 259: char device[40];
! 260: int fd;
! 261:
! 262: /*
! 263: * Open serial port
! 264: */
! 265: (void)snprintf(device, sizeof(device), DEVICE, unit);
! 266: if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
! 267: return (0);
! 268:
! 269: /*
! 270: * Allocate and initialize unit structure
! 271: */
! 272: if (!(up = (struct true_unit *)
! 273: emalloc(sizeof(struct true_unit)))) {
! 274: (void) close(fd);
! 275: return (0);
! 276: }
! 277: memset((char *)up, 0, sizeof(struct true_unit));
! 278: pp = peer->procptr;
! 279: pp->io.clock_recv = true_receive;
! 280: pp->io.srcclock = (caddr_t)peer;
! 281: pp->io.datalen = 0;
! 282: pp->io.fd = fd;
! 283: if (!io_addclock(&pp->io)) {
! 284: (void) close(fd);
! 285: free(up);
! 286: return (0);
! 287: }
! 288: pp->unitptr = (caddr_t)up;
! 289:
! 290: /*
! 291: * Initialize miscellaneous variables
! 292: */
! 293: peer->precision = PRECISION;
! 294: pp->clockdesc = DESCRIPTION;
! 295: memcpy((char *)&pp->refid, REFID, 4);
! 296: up->pollcnt = 2;
! 297: up->type = t_unknown;
! 298: up->state = s_Base;
! 299:
! 300: /*
! 301: * Send a CTRL-C character at the start,
! 302: * just in case the clock is already
! 303: * sending timecodes
! 304: */
! 305: true_send(peer, "\03\r");
! 306:
! 307: true_doevent(peer, e_Init);
! 308:
! 309: return (1);
! 310: }
! 311:
! 312: /*
! 313: * true_shutdown - shut down the clock
! 314: */
! 315: static void
! 316: true_shutdown(
! 317: int unit,
! 318: struct peer *peer
! 319: )
! 320: {
! 321: register struct true_unit *up;
! 322: struct refclockproc *pp;
! 323:
! 324: pp = peer->procptr;
! 325: up = (struct true_unit *)pp->unitptr;
! 326: io_closeclock(&pp->io);
! 327: free(up);
! 328: }
! 329:
! 330:
! 331: /*
! 332: * true_receive - receive data from the serial interface on a clock
! 333: */
! 334: static void
! 335: true_receive(
! 336: struct recvbuf *rbufp
! 337: )
! 338: {
! 339: register struct true_unit *up;
! 340: struct refclockproc *pp;
! 341: struct peer *peer;
! 342: u_short new_station;
! 343: char synced;
! 344: int i;
! 345: int lat, lon, off; /* GOES Satellite position */
! 346: /* Use these variable to hold data until we decide its worth keeping */
! 347: char rd_lastcode[BMAX];
! 348: l_fp rd_tmp;
! 349: u_short rd_lencode;
! 350:
! 351: /*
! 352: * Get the clock this applies to and pointers to the data.
! 353: */
! 354: peer = (struct peer *)rbufp->recv_srcclock;
! 355: pp = peer->procptr;
! 356: up = (struct true_unit *)pp->unitptr;
! 357:
! 358: /*
! 359: * Read clock output. Automatically handles STREAMS, CLKLDISC.
! 360: */
! 361: rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
! 362: rd_lastcode[rd_lencode] = '\0';
! 363:
! 364: /*
! 365: * There is a case where <cr><lf> generates 2 timestamps.
! 366: */
! 367: if (rd_lencode == 0)
! 368: return;
! 369: pp->lencode = rd_lencode;
! 370: strcpy(pp->a_lastcode, rd_lastcode);
! 371: pp->lastrec = rd_tmp;
! 372: true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode, pp->lencode);
! 373:
! 374: up->pollcnt = 2;
! 375: record_clock_stats(&peer->srcadr, pp->a_lastcode);
! 376:
! 377: /*
! 378: * We get down to business, check the timecode format and decode
! 379: * its contents. This code decodes a multitude of different
! 380: * clock messages. Timecodes are processed if needed. All replies
! 381: * will be run through the state machine to tweak driver options
! 382: * and program the clock.
! 383: */
! 384:
! 385: /*
! 386: * Clock misunderstood our last command?
! 387: */
! 388: if (pp->a_lastcode[0] == '?' ||
! 389: strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) {
! 390: true_doevent(peer, e_Huh);
! 391: return;
! 392: }
! 393:
! 394: /*
! 395: * Timecode: "nnnnn+nnn-nnn"
! 396: * (from GOES clock when asked about satellite position)
! 397: */
! 398: if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') &&
! 399: (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') &&
! 400: sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3
! 401: ) {
! 402: const char *label = "Botch!";
! 403:
! 404: /*
! 405: * This is less than perfect. Call the (satellite)
! 406: * either EAST or WEST and adjust slop accodingly
! 407: * Perfectionists would recalculate the exact delay
! 408: * and adjust accordingly...
! 409: */
! 410: if (lon > 7000 && lon < 14000) {
! 411: if (lon < 10000) {
! 412: new_station = GOES_EAST;
! 413: label = "EAST";
! 414: } else {
! 415: new_station = GOES_WEST;
! 416: label = "WEST";
! 417: }
! 418:
! 419: if (new_station != up->station) {
! 420: double dtemp;
! 421:
! 422: dtemp = pp->fudgetime1;
! 423: pp->fudgetime1 = pp->fudgetime2;
! 424: pp->fudgetime2 = dtemp;
! 425: up->station = new_station;
! 426: }
! 427: }
! 428: else {
! 429: /*refclock_report(peer, CEVNT_BADREPLY);*/
! 430: label = "UNKNOWN";
! 431: }
! 432: true_debug(peer, "GOES: station %s\n", label);
! 433: true_doevent(peer, e_Satellite);
! 434: return;
! 435: }
! 436:
! 437: /*
! 438: * Timecode: "Fnn"
! 439: * (from TM/TMD clock when it wants to tell us what it's up to.)
! 440: */
! 441: if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) {
! 442: switch (i) {
! 443: case 50:
! 444: true_doevent(peer, e_F50);
! 445: break;
! 446: case 51:
! 447: true_doevent(peer, e_F51);
! 448: break;
! 449: default:
! 450: true_debug(peer, "got F%02d - ignoring\n", i);
! 451: break;
! 452: }
! 453: return;
! 454: }
! 455:
! 456: /*
! 457: * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
! 458: * (from a TM/TMD/XL clock during initialization.)
! 459: */
! 460: if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
! 461: strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
! 462: true_doevent(peer, e_F18);
! 463: NLOG(NLOG_CLOCKSTATUS) {
! 464: msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode);
! 465: }
! 466: return;
! 467: }
! 468:
! 469: /*
! 470: * Timecode: "N03726428W12209421+000033"
! 471: * 1 2
! 472: * 0123456789012345678901234
! 473: * (from a TCU during initialization)
! 474: */
! 475: if ((pp->a_lastcode[0] == 'N' || pp->a_lastcode[0] == 'S') &&
! 476: (pp->a_lastcode[9] == 'W' || pp->a_lastcode[9] == 'E') &&
! 477: pp->a_lastcode[18] == '+') {
! 478: true_doevent(peer, e_Location);
! 479: NLOG(NLOG_CLOCKSTATUS) {
! 480: msyslog(LOG_INFO, "TCU-800: %s", pp->a_lastcode);
! 481: }
! 482: return;
! 483: }
! 484: /*
! 485: * Timecode: "ddd:hh:mm:ssQ"
! 486: * (from all clocks supported by this driver.)
! 487: */
! 488: if (pp->a_lastcode[3] == ':' &&
! 489: pp->a_lastcode[6] == ':' &&
! 490: pp->a_lastcode[9] == ':' &&
! 491: sscanf(pp->a_lastcode, "%3d:%2d:%2d:%2d%c",
! 492: &pp->day, &pp->hour, &pp->minute,
! 493: &pp->second, &synced) == 5) {
! 494:
! 495: /*
! 496: * Adjust the synchronize indicator according to timecode
! 497: * say were OK, and then say not if we really are not OK
! 498: */
! 499: if (synced == '>' || synced == '#' || synced == '?'
! 500: || synced == 'X')
! 501: pp->leap = LEAP_NOTINSYNC;
! 502: else
! 503: pp->leap = LEAP_NOWARNING;
! 504:
! 505: true_doevent(peer, e_TS);
! 506:
! 507: #ifdef CLOCK_PPS720
! 508: /* If it's taken more than 65ms to get here, we'll lose. */
! 509: if ((pp->sloppyclockflag & CLK_FLAG4) && up->pcl720init) {
! 510: l_fp off;
! 511:
! 512: #ifdef CLOCK_ATOM
! 513: /*
! 514: * find out what time it really is. Include
! 515: * the count from the PCL720
! 516: */
! 517: if (!clocktime(pp->day, pp->hour, pp->minute,
! 518: pp->second, GMT, pp->lastrec.l_ui,
! 519: &pp->yearstart, &off.l_ui)) {
! 520: refclock_report(peer, CEVNT_BADTIME);
! 521: return;
! 522: }
! 523: off.l_uf = 0;
! 524: #endif
! 525:
! 526: pp->usec = true_sample720();
! 527: #ifdef CLOCK_ATOM
! 528: TVUTOTSF(pp->usec, off.l_uf);
! 529: #endif
! 530:
! 531: /*
! 532: * Stomp all over the timestamp that was pulled out
! 533: * of the input stream. It's irrelevant since we've
! 534: * adjusted the input time to reflect now (via pp->usec)
! 535: * rather than when the data was collected.
! 536: */
! 537: get_systime(&pp->lastrec);
! 538: #ifdef CLOCK_ATOM
! 539: /*
! 540: * Create a true offset for feeding to pps_sample()
! 541: */
! 542: L_SUB(&off, &pp->lastrec);
! 543:
! 544: pps_sample(peer, &off);
! 545: #endif
! 546: true_debug(peer, "true_sample720: %luus\n", pp->usec);
! 547: }
! 548: #endif
! 549:
! 550: /*
! 551: * The clock will blurt a timecode every second but we only
! 552: * want one when polled. If we havn't been polled, bail out.
! 553: */
! 554: if (!up->polled)
! 555: return;
! 556:
! 557: true_doevent(peer, e_Poll);
! 558: if (!refclock_process(pp)) {
! 559: refclock_report(peer, CEVNT_BADTIME);
! 560: return;
! 561: }
! 562: /*
! 563: * If clock is good we send a NOMINAL message so that
! 564: * any previous BAD messages are nullified
! 565: */
! 566: pp->lastref = pp->lastrec;
! 567: refclock_receive(peer);
! 568: refclock_report(peer, CEVNT_NOMINAL);
! 569:
! 570: /*
! 571: * We have succedded in answering the poll.
! 572: * Turn off the flag and return
! 573: */
! 574: up->polled = 0;
! 575:
! 576: return;
! 577: }
! 578:
! 579: /*
! 580: * No match to known timecodes, report failure and return
! 581: */
! 582: refclock_report(peer, CEVNT_BADREPLY);
! 583: return;
! 584: }
! 585:
! 586:
! 587: /*
! 588: * true_send - time to send the clock a signal to cough up a time sample
! 589: */
! 590: static void
! 591: true_send(
! 592: struct peer *peer,
! 593: const char *cmd
! 594: )
! 595: {
! 596: struct refclockproc *pp;
! 597:
! 598: pp = peer->procptr;
! 599: if (!(pp->sloppyclockflag & CLK_FLAG1)) {
! 600: register int len = strlen(cmd);
! 601:
! 602: true_debug(peer, "Send '%s'\n", cmd);
! 603: if (write(pp->io.fd, cmd, (unsigned)len) != len)
! 604: refclock_report(peer, CEVNT_FAULT);
! 605: else
! 606: pp->polls++;
! 607: }
! 608: }
! 609:
! 610:
! 611: /*
! 612: * state machine for initializing and controlling a clock
! 613: */
! 614: static void
! 615: true_doevent(
! 616: struct peer *peer,
! 617: enum true_event event
! 618: )
! 619: {
! 620: struct true_unit *up;
! 621: struct refclockproc *pp;
! 622:
! 623: pp = peer->procptr;
! 624: up = (struct true_unit *)pp->unitptr;
! 625: if (event != e_TS) {
! 626: NLOG(NLOG_CLOCKSTATUS) {
! 627: msyslog(LOG_INFO, "TRUE: clock %s, state %s, event %s",
! 628: typeStr(up->type),
! 629: stateStr(up->state),
! 630: eventStr(event));
! 631: }
! 632: }
! 633: true_debug(peer, "clock %s, state %s, event %s\n",
! 634: typeStr(up->type), stateStr(up->state), eventStr(event));
! 635: switch (up->type) {
! 636: case t_goes:
! 637: switch (event) {
! 638: case e_Init: /* FALLTHROUGH */
! 639: case e_Satellite:
! 640: /*
! 641: * Switch back to on-second time codes and return.
! 642: */
! 643: true_send(peer, "C");
! 644: up->state = s_Start;
! 645: break;
! 646: case e_Poll:
! 647: /*
! 648: * After each poll, check the station (satellite).
! 649: */
! 650: true_send(peer, "P");
! 651: /* No state change needed. */
! 652: break;
! 653: default:
! 654: break;
! 655: }
! 656: /* FALLTHROUGH */
! 657: case t_omega:
! 658: switch (event) {
! 659: case e_Init:
! 660: true_send(peer, "C");
! 661: up->state = s_Start;
! 662: break;
! 663: case e_TS:
! 664: if (up->state != s_Start && up->state != s_Auto) {
! 665: true_send(peer, "\03\r");
! 666: break;
! 667: }
! 668: up->state = s_Auto;
! 669: break;
! 670: default:
! 671: break;
! 672: }
! 673: break;
! 674: case t_tm:
! 675: switch (event) {
! 676: case e_Init:
! 677: true_send(peer, "F18\r");
! 678: up->state = s_Init;
! 679: break;
! 680: case e_F18:
! 681: true_send(peer, "F50\r");
! 682: up->state = s_F18;
! 683: break;
! 684: case e_F50:
! 685: true_send(peer, "F51\r");
! 686: up->state = s_F50;
! 687: break;
! 688: case e_F51:
! 689: true_send(peer, "F08\r");
! 690: up->state = s_Start;
! 691: break;
! 692: case e_TS:
! 693: if (up->state != s_Start && up->state != s_Auto) {
! 694: true_send(peer, "\03\r");
! 695: break;
! 696: }
! 697: up->state = s_Auto;
! 698: break;
! 699: default:
! 700: break;
! 701: }
! 702: break;
! 703: case t_tcu:
! 704: switch (event) {
! 705: case e_Init:
! 706: true_send(peer, "MD3\r"); /* GPS Synch'd Gen. */
! 707: true_send(peer, "TSU\r"); /* UTC, not GPS. */
! 708: true_send(peer, "AU\r"); /* Auto Timestamps. */
! 709: up->state = s_Start;
! 710: break;
! 711: case e_TS:
! 712: if (up->state != s_Start && up->state != s_Auto) {
! 713: true_send(peer, "\03\r");
! 714: break;
! 715: }
! 716: up->state = s_Auto;
! 717: break;
! 718: default:
! 719: break;
! 720: }
! 721: break;
! 722: case t_unknown:
! 723: switch (up->state) {
! 724: case s_Base:
! 725: if (event != e_Init)
! 726: abort();
! 727: true_send(peer, "P\r");
! 728: up->state = s_InqGOES;
! 729: break;
! 730: case s_InqGOES:
! 731: switch (event) {
! 732: case e_Satellite:
! 733: up->type = t_goes;
! 734: true_doevent(peer, e_Init);
! 735: break;
! 736: case e_Init: /*FALLTHROUGH*/
! 737: case e_Huh: /*FALLTHROUGH*/
! 738: case e_TS:
! 739: up->state = s_InqOmega;
! 740: true_send(peer, "C\r");
! 741: break;
! 742: default:
! 743: abort();
! 744: }
! 745: break;
! 746: case s_InqOmega:
! 747: switch (event) {
! 748: case e_TS:
! 749: up->type = t_omega;
! 750: up->state = s_Auto; /* Inq side-effect. */
! 751: break;
! 752: case e_Init: /*FALLTHROUGH*/
! 753: case e_Huh:
! 754: up->state = s_InqTM;
! 755: true_send(peer, "F18\r");
! 756: break;
! 757: default:
! 758: abort();
! 759: }
! 760: break;
! 761: case s_InqTM:
! 762: switch (event) {
! 763: case e_F18:
! 764: up->type = t_tm;
! 765: true_doevent(peer, e_Init);
! 766: break;
! 767: case e_Init: /*FALLTHROUGH*/
! 768: case e_Huh:
! 769: true_send(peer, "PO\r");
! 770: up->state = s_InqTCU;
! 771: break;
! 772: default:
! 773: abort();
! 774: }
! 775: break;
! 776: case s_InqTCU:
! 777: switch (event) {
! 778: case e_Location:
! 779: up->type = t_tcu;
! 780: true_doevent(peer, e_Init);
! 781: break;
! 782: case e_Init: /*FALLTHROUGH*/
! 783: case e_Huh:
! 784: up->state = s_Base;
! 785: sleep(1); /* XXX */
! 786: break;
! 787: default:
! 788: abort();
! 789: }
! 790: break;
! 791: /*
! 792: * An expedient hack to prevent lint complaints,
! 793: * these don't actually need to be used here...
! 794: */
! 795: case s_Init:
! 796: case s_F18:
! 797: case s_F50:
! 798: case s_Start:
! 799: case s_Auto:
! 800: case s_Max:
! 801: msyslog(LOG_INFO, "TRUE: state %s is unexpected!", stateStr(up->state));
! 802: }
! 803: break;
! 804: default:
! 805: abort();
! 806: /* NOTREACHED */
! 807: }
! 808:
! 809: #ifdef CLOCK_PPS720
! 810: if ((pp->sloppyclockflag & CLK_FLAG4) && !up->pcl720init) {
! 811: /* Make counter trigger on gate0, count down from 65535. */
! 812: pcl720_load(PCL720_IOB, PCL720_CTR, i8253_oneshot, 65535);
! 813: /*
! 814: * (These constants are OK since
! 815: * they represent hardware maximums.)
! 816: */
! 817: NLOG(NLOG_CLOCKINFO) {
! 818: msyslog(LOG_NOTICE, "PCL-720 initialized");
! 819: }
! 820: up->pcl720init++;
! 821: }
! 822: #endif
! 823:
! 824:
! 825: }
! 826:
! 827: /*
! 828: * true_poll - called by the transmit procedure
! 829: */
! 830: static void
! 831: true_poll(
! 832: int unit,
! 833: struct peer *peer
! 834: )
! 835: {
! 836: struct true_unit *up;
! 837: struct refclockproc *pp;
! 838:
! 839: /*
! 840: * You don't need to poll this clock. It puts out timecodes
! 841: * once per second. If asked for a timestamp, take note.
! 842: * The next time a timecode comes in, it will be fed back.
! 843: */
! 844: pp = peer->procptr;
! 845: up = (struct true_unit *)pp->unitptr;
! 846: if (up->pollcnt > 0)
! 847: up->pollcnt--;
! 848: else {
! 849: true_doevent(peer, e_Init);
! 850: refclock_report(peer, CEVNT_TIMEOUT);
! 851: }
! 852:
! 853: /*
! 854: * polled every 64 seconds. Ask true_receive to hand in a
! 855: * timestamp.
! 856: */
! 857: up->polled = 1;
! 858: pp->polls++;
! 859: }
! 860:
! 861: #ifdef CLOCK_PPS720
! 862: /*
! 863: * true_sample720 - sample the PCL-720
! 864: */
! 865: static u_long
! 866: true_sample720(void)
! 867: {
! 868: unsigned long f;
! 869:
! 870: /* We wire the PCL-720's 8253.OUT0 to bit 0 of connector 3.
! 871: * If it is not being held low now, we did not get called
! 872: * within 65535us.
! 873: */
! 874: if (inb(pcl720_data_16_23(PCL720_IOB)) & 0x01) {
! 875: NLOG(NLOG_CLOCKINFO) {
! 876: msyslog(LOG_NOTICE, "PCL-720 out of synch");
! 877: }
! 878: return (0);
! 879: }
! 880: f = (65536 - pcl720_read(PCL720_IOB, PCL720_CTR));
! 881: #ifdef PPS720_DEBUG
! 882: msyslog(LOG_DEBUG, "PCL-720: %luus", f);
! 883: #endif
! 884: return (f);
! 885: }
! 886: #endif
! 887:
! 888: #else
! 889: int refclock_true_bs;
! 890: #endif /* REFCLOCK */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>