/contrib/ntp/ntpd/refclock_true.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 873 lines · 553 code · 72 blank · 248 comment · 99 complexity · 49b57653f8f5c29f3d4ec92e804af81c MD5 · raw file

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