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