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