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