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