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