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