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