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