/contrib/ntp/ntpd/refclock_acts.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 931 lines · 526 code · 77 blank · 328 comment · 110 complexity · 17742ab2a6ffd85797f4e173885fc332 MD5 · raw file

  1. /*
  2. * refclock_acts - clock driver for the NIST/USNO/PTB/NPL Computer Time
  3. * Services
  4. */
  5. #ifdef HAVE_CONFIG_H
  6. #include <config.h>
  7. #endif
  8. #if defined(REFCLOCK) && (defined(CLOCK_ACTS) || defined(CLOCK_PTBACTS))
  9. #include "ntpd.h"
  10. #include "ntp_io.h"
  11. #include "ntp_unixtime.h"
  12. #include "ntp_refclock.h"
  13. #include "ntp_stdlib.h"
  14. #include "ntp_control.h"
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #ifdef HAVE_SYS_IOCTL_H
  18. # include <sys/ioctl.h>
  19. #endif /* HAVE_SYS_IOCTL_H */
  20. /*
  21. * This driver supports the US (NIST, USNO) and European (PTB, NPL,
  22. * etc.) modem time services, as well as Spectracom GPS and WWVB
  23. * receivers connected via a modem. The driver periodically dials a
  24. * number from a telephone list, receives the timecode data and
  25. * calculates the local clock correction. It is designed primarily for
  26. * use as backup when neither a radio clock nor connectivity to Internet
  27. * time servers is available.
  28. *
  29. * This driver requires a modem with a Hayes-compatible command set and
  30. * control over the modem data terminal ready (DTR) control line. The
  31. * modem setup string is hard-coded in the driver and may require
  32. * changes for nonstandard modems or special circumstances. For reasons
  33. * unrelated to this driver, the data set ready (DSR) control line
  34. * should not be set when this driver is first started.
  35. *
  36. * The calling program is initiated by setting fudge flag1, either
  37. * manually or automatically. When flag1 is set, the calling program
  38. * dials the first number in the phone command of the configuration
  39. * file. If that call fails, the calling program dials the second number
  40. * and so on. The number is specified by the Hayes ATDT prefix followed
  41. * by the number itself, including the prefix and long-distance digits
  42. * and delay code, if necessary. The flag1 is reset and the calling
  43. * program terminated if (a) a valid clock update has been determined,
  44. * (b) no more numbers remain in the list, (c) a device fault or timeout
  45. * occurs or (d) fudge flag1 is reset manually.
  46. *
  47. * The driver is transparent to each of the modem time services and
  48. * Spectracom radios. It selects the parsing algorithm depending on the
  49. * message length. There is some hazard should the message be corrupted.
  50. * However, the data format is checked carefully and only if all checks
  51. * succeed is the message accepted. Corrupted lines are discarded
  52. * without complaint.
  53. *
  54. * Fudge controls
  55. *
  56. * flag1 force a call in manual mode
  57. * flag2 enable port locking (not verified)
  58. * flag3 no modem; port is directly connected to device
  59. * flag4 not used
  60. *
  61. * time1 offset adjustment (s)
  62. *
  63. * Ordinarily, the serial port is connected to a modem; however, it can
  64. * be connected directly to a device or another computer for testing and
  65. * calibration. In this case set fudge flag3 and the driver will send a
  66. * single character 'T' at each poll event. In principle, fudge flag2
  67. * enables port locking, allowing the modem to be shared when not in use
  68. * by this driver. At least on Solaris with the current NTP I/O
  69. * routines, this results only in lots of ugly error messages.
  70. */
  71. /*
  72. * National Institute of Science and Technology (NIST)
  73. *
  74. * Phone: (303) 494-4774 (Boulder, CO); (808) 335-4721 (Hawaii)
  75. *
  76. * Data Format
  77. *
  78. * National Institute of Standards and Technology
  79. * Telephone Time Service, Generator 3B
  80. * Enter question mark "?" for HELP
  81. * D L D
  82. * MJD YR MO DA H M S ST S UT1 msADV <OTM>
  83. * 47999 90-04-18 21:39:15 50 0 +.1 045.0 UTC(NIST) *<CR><LF>
  84. * ...
  85. *
  86. * MJD, DST, DUT1 and UTC are not used by this driver. The "*" or "#" is
  87. * the on-time markers echoed by the driver and used by NIST to measure
  88. * and correct for the propagation delay.
  89. *
  90. * US Naval Observatory (USNO)
  91. *
  92. * Phone: (202) 762-1594 (Washington, DC); (719) 567-6742 (Boulder, CO)
  93. *
  94. * Data Format (two lines, repeating at one-second intervals)
  95. *
  96. * jjjjj nnn hhmmss UTC<CR><LF>
  97. * *<CR><LF>
  98. *
  99. * jjjjj modified Julian day number (not used)
  100. * nnn day of year
  101. * hhmmss second of day
  102. * * on-time marker for previous timecode
  103. * ...
  104. *
  105. * USNO does not correct for the propagation delay. A fudge time1 of
  106. * about .06 s is advisable.
  107. *
  108. * European Services (PTB, NPL, etc.)
  109. *
  110. * PTB: +49 531 512038 (Germany)
  111. * NPL: 0906 851 6333 (UK only)
  112. *
  113. * Data format (see the documentation for phone numbers and formats.)
  114. *
  115. * 1995-01-23 20:58:51 MEZ 10402303260219950123195849740+40000500<CR><LF>
  116. *
  117. * Spectracom GPS and WWVB Receivers
  118. *
  119. * If a modem is connected to a Spectracom receiver, this driver will
  120. * call it up and retrieve the time in one of two formats. As this
  121. * driver does not send anything, the radio will have to either be
  122. * configured in continuous mode or be polled by another local driver.
  123. */
  124. /*
  125. * Interface definitions
  126. */
  127. #define DEVICE "/dev/acts%d" /* device name and unit */
  128. #define SPEED232 B9600 /* uart speed (9600 baud) */
  129. #define PRECISION (-10) /* precision assumed (about 1 ms) */
  130. #define LOCKFILE "/var/spool/locks/LCK..cua%d"
  131. #define DESCRIPTION "Automated Computer Time Service" /* WRU */
  132. #define REFID "NONE" /* default reference ID */
  133. #define MSGCNT 20 /* max message count */
  134. #define SMAX 256 /* max clockstats line length */
  135. /*
  136. * Calling program modes
  137. */
  138. #define MODE_AUTO 0 /* automatic mode */
  139. #define MODE_BACKUP 1 /* backup mode */
  140. #define MODE_MANUAL 2 /* manual mode */
  141. /*
  142. * Service identifiers.
  143. */
  144. #define REFACTS "NIST" /* NIST reference ID */
  145. #define LENACTS 50 /* NIST format */
  146. #define REFUSNO "USNO" /* USNO reference ID */
  147. #define LENUSNO 20 /* USNO */
  148. #define REFPTB "PTB\0" /* PTB/NPL reference ID */
  149. #define LENPTB 78 /* PTB/NPL format */
  150. #define REFWWVB "WWVB" /* WWVB reference ID */
  151. #define LENWWVB0 22 /* WWVB format 0 */
  152. #define LENWWVB2 24 /* WWVB format 2 */
  153. #define LF 0x0a /* ASCII LF */
  154. /*
  155. * Modem setup strings. These may have to be changed for some modems.
  156. *
  157. * AT command prefix
  158. * B1 US answer tone
  159. * &C0 disable carrier detect
  160. * &D2 hang up and return to command mode on DTR transition
  161. * E0 modem command echo disabled
  162. * l1 set modem speaker volume to low level
  163. * M1 speaker enabled until carrier detect
  164. * Q0 return result codes
  165. * V1 return result codes as English words
  166. */
  167. #define MODEM_SETUP "ATB1&C0&D2E0L1M1Q0V1\r" /* modem setup */
  168. #define MODEM_HANGUP "ATH\r" /* modem disconnect */
  169. /*
  170. * Timeouts (all in seconds)
  171. */
  172. #define SETUP 3 /* setup timeout */
  173. #define DTR 1 /* DTR timeout */
  174. #define ANSWER 60 /* answer timeout */
  175. #define CONNECT 20 /* first valid message timeout */
  176. #define TIMECODE 30 /* all valid messages timeout */
  177. /*
  178. * State machine codes
  179. */
  180. #define S_IDLE 0 /* wait for poll */
  181. #define S_OK 1 /* wait for modem setup */
  182. #define S_DTR 2 /* wait for modem DTR */
  183. #define S_CONNECT 3 /* wait for answer*/
  184. #define S_FIRST 4 /* wait for first valid message */
  185. #define S_MSG 5 /* wait for all messages */
  186. #define S_CLOSE 6 /* wait after sending disconnect */
  187. /*
  188. * Unit control structure
  189. */
  190. struct actsunit {
  191. int unit; /* unit number */
  192. int state; /* the first one was Delaware */
  193. int timer; /* timeout counter */
  194. int retry; /* retry index */
  195. int msgcnt; /* count of messages received */
  196. l_fp tstamp; /* on-time timestamp */
  197. char *bufptr; /* buffer pointer */
  198. };
  199. /*
  200. * Function prototypes
  201. */
  202. static int acts_start P((int, struct peer *));
  203. static void acts_shutdown P((int, struct peer *));
  204. static void acts_receive P((struct recvbuf *));
  205. static void acts_message P((struct peer *));
  206. static void acts_timecode P((struct peer *, char *));
  207. static void acts_poll P((int, struct peer *));
  208. static void acts_timeout P((struct peer *));
  209. static void acts_disc P((struct peer *));
  210. static void acts_timer P((int, struct peer *));
  211. /*
  212. * Transfer vector (conditional structure name)
  213. */
  214. struct refclock refclock_acts = {
  215. acts_start, /* start up driver */
  216. acts_shutdown, /* shut down driver */
  217. acts_poll, /* transmit poll message */
  218. noentry, /* not used */
  219. noentry, /* not used */
  220. noentry, /* not used */
  221. acts_timer /* housekeeping timer */
  222. };
  223. struct refclock refclock_ptb;
  224. /*
  225. * Initialize data for processing
  226. */
  227. static int
  228. acts_start (
  229. int unit,
  230. struct peer *peer
  231. )
  232. {
  233. struct actsunit *up;
  234. struct refclockproc *pp;
  235. /*
  236. * Allocate and initialize unit structure
  237. */
  238. up = emalloc(sizeof(struct actsunit));
  239. if (up == NULL)
  240. return (0);
  241. memset(up, 0, sizeof(struct actsunit));
  242. up->unit = unit;
  243. pp = peer->procptr;
  244. pp->unitptr = (caddr_t)up;
  245. pp->io.clock_recv = acts_receive;
  246. pp->io.srcclock = (caddr_t)peer;
  247. pp->io.datalen = 0;
  248. /*
  249. * Initialize miscellaneous variables
  250. */
  251. peer->precision = PRECISION;
  252. pp->clockdesc = DESCRIPTION;
  253. memcpy((char *)&pp->refid, REFID, 4);
  254. peer->sstclktype = CTL_SST_TS_TELEPHONE;
  255. peer->flags &= ~FLAG_FIXPOLL;
  256. up->bufptr = pp->a_lastcode;
  257. return (1);
  258. }
  259. /*
  260. * acts_shutdown - shut down the clock
  261. */
  262. static void
  263. acts_shutdown (
  264. int unit,
  265. struct peer *peer
  266. )
  267. {
  268. struct actsunit *up;
  269. struct refclockproc *pp;
  270. /*
  271. * Warning: do this only when a call is not in progress.
  272. */
  273. pp = peer->procptr;
  274. up = (struct actsunit *)pp->unitptr;
  275. free(up);
  276. }
  277. /*
  278. * acts_receive - receive data from the serial interface
  279. */
  280. static void
  281. acts_receive (
  282. struct recvbuf *rbufp
  283. )
  284. {
  285. struct actsunit *up;
  286. struct refclockproc *pp;
  287. struct peer *peer;
  288. char tbuf[BMAX];
  289. char *tptr;
  290. /*
  291. * Initialize pointers and read the timecode and timestamp. Note
  292. * we are in raw mode and victim of whatever the terminal
  293. * interface kicks up; so, we have to reassemble messages from
  294. * arbitrary fragments. Capture the timecode at the beginning of
  295. * the message and at the '*' and '#' on-time characters.
  296. */
  297. peer = (struct peer *)rbufp->recv_srcclock;
  298. pp = peer->procptr;
  299. up = (struct actsunit *)pp->unitptr;
  300. pp->lencode = refclock_gtraw(rbufp, tbuf, BMAX - (up->bufptr -
  301. pp->a_lastcode), &pp->lastrec);
  302. for (tptr = tbuf; *tptr != '\0'; tptr++) {
  303. if (*tptr == LF) {
  304. if (up->bufptr == pp->a_lastcode) {
  305. up->tstamp = pp->lastrec;
  306. continue;
  307. } else {
  308. *up->bufptr = '\0';
  309. acts_message(peer);
  310. up->bufptr = pp->a_lastcode;
  311. }
  312. } else if (!iscntrl(*tptr)) {
  313. *up->bufptr++ = *tptr;
  314. if (*tptr == '*' || *tptr == '#') {
  315. up->tstamp = pp->lastrec;
  316. write(pp->io.fd, tptr, 1);
  317. }
  318. }
  319. }
  320. }
  321. /*
  322. * acts_message - process message
  323. */
  324. void
  325. acts_message(
  326. struct peer *peer
  327. )
  328. {
  329. struct actsunit *up;
  330. struct refclockproc *pp;
  331. int dtr = TIOCM_DTR;
  332. char tbuf[SMAX];
  333. #ifdef DEBUG
  334. u_int modem;
  335. #endif
  336. /*
  337. * What to do depends on the state and the first token in the
  338. * message. A NO token sends the message to the clockstats.
  339. */
  340. pp = peer->procptr;
  341. up = (struct actsunit *)pp->unitptr;
  342. #ifdef DEBUG
  343. ioctl(pp->io.fd, TIOCMGET, (char *)&modem);
  344. sprintf(tbuf, "acts: %04x (%d %d) %lu %s", modem, up->state,
  345. up->timer, strlen(pp->a_lastcode), pp->a_lastcode);
  346. if (debug)
  347. printf("%s\n", tbuf);
  348. #endif
  349. strncpy(tbuf, pp->a_lastcode, SMAX);
  350. strtok(tbuf, " ");
  351. if (strcmp(tbuf, "NO") == 0)
  352. record_clock_stats(&peer->srcadr, pp->a_lastcode);
  353. switch(up->state) {
  354. /*
  355. * We are waiting for the OK response to the modem setup
  356. * command. When this happens, raise DTR and dial the number
  357. * followed by \r.
  358. */
  359. case S_OK:
  360. if (strcmp(tbuf, "OK") != 0) {
  361. msyslog(LOG_ERR, "acts: setup error %s",
  362. pp->a_lastcode);
  363. acts_disc(peer);
  364. return;
  365. }
  366. ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr);
  367. up->state = S_DTR;
  368. up->timer = DTR;
  369. return;
  370. /*
  371. * We are waiting for the call to be answered. All we care about
  372. * here is token CONNECT. Send the message to the clockstats.
  373. */
  374. case S_CONNECT:
  375. record_clock_stats(&peer->srcadr, pp->a_lastcode);
  376. if (strcmp(tbuf, "CONNECT") != 0) {
  377. acts_disc(peer);
  378. return;
  379. }
  380. up->state = S_FIRST;
  381. up->timer = CONNECT;
  382. return;
  383. /*
  384. * We are waiting for a timecode. Pass it to the parser.
  385. */
  386. case S_FIRST:
  387. case S_MSG:
  388. acts_timecode(peer, pp->a_lastcode);
  389. break;
  390. }
  391. }
  392. /*
  393. * acts_timecode - identify the service and parse the timecode message
  394. */
  395. void
  396. acts_timecode(
  397. struct peer *peer, /* peer structure pointer */
  398. char *str /* timecode string */
  399. )
  400. {
  401. struct actsunit *up;
  402. struct refclockproc *pp;
  403. int day; /* day of the month */
  404. int month; /* month of the year */
  405. u_long mjd; /* Modified Julian Day */
  406. double dut1; /* DUT adjustment */
  407. u_int dst; /* ACTS daylight/standard time */
  408. u_int leap; /* ACTS leap indicator */
  409. double msADV; /* ACTS transmit advance (ms) */
  410. char utc[10]; /* ACTS timescale */
  411. char flag; /* ACTS on-time character (* or #) */
  412. char synchar; /* WWVB synchronized indicator */
  413. char qualchar; /* WWVB quality indicator */
  414. char leapchar; /* WWVB leap indicator */
  415. char dstchar; /* WWVB daylight/savings indicator */
  416. int tz; /* WWVB timezone */
  417. u_int leapmonth; /* PTB/NPL month of leap */
  418. char leapdir; /* PTB/NPL leap direction */
  419. /*
  420. * The parser selects the modem format based on the message
  421. * length. Since the data are checked carefully, occasional
  422. * errors due noise are forgivable.
  423. */
  424. pp = peer->procptr;
  425. up = (struct actsunit *)pp->unitptr;
  426. pp->nsec = 0;
  427. switch(strlen(str)) {
  428. /*
  429. * For USNO format on-time character '*', which is on a line by
  430. * itself. Be sure a timecode has been received.
  431. */
  432. case 1:
  433. if (*str == '*' && up->msgcnt > 0)
  434. break;
  435. return;
  436. /*
  437. * ACTS format: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa
  438. * UTC(NIST) *"
  439. */
  440. case LENACTS:
  441. if (sscanf(str,
  442. "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %9s %c",
  443. &mjd, &pp->year, &month, &day, &pp->hour,
  444. &pp->minute, &pp->second, &dst, &leap, &dut1,
  445. &msADV, utc, &flag) != 13) {
  446. refclock_report(peer, CEVNT_BADREPLY);
  447. return;
  448. }
  449. /*
  450. * Wait until ACTS has calculated the roundtrip delay.
  451. * We don't need to do anything, as ACTS adjusts the
  452. * on-time epoch.
  453. */
  454. if (flag != '#')
  455. return;
  456. pp->day = ymd2yd(pp->year, month, day);
  457. pp->leap = LEAP_NOWARNING;
  458. if (leap == 1)
  459. pp->leap = LEAP_ADDSECOND;
  460. else if (pp->leap == 2)
  461. pp->leap = LEAP_DELSECOND;
  462. memcpy(&pp->refid, REFACTS, 4);
  463. if (up->msgcnt == 0)
  464. record_clock_stats(&peer->srcadr, str);
  465. up->msgcnt++;
  466. break;
  467. /*
  468. * USNO format: "jjjjj nnn hhmmss UTC"
  469. */
  470. case LENUSNO:
  471. if (sscanf(str, "%5ld %3d %2d%2d%2d %3s",
  472. &mjd, &pp->day, &pp->hour, &pp->minute,
  473. &pp->second, utc) != 6) {
  474. refclock_report(peer, CEVNT_BADREPLY);
  475. return;
  476. }
  477. /*
  478. * Wait for the on-time character, which follows in a
  479. * separate message. There is no provision for leap
  480. * warning.
  481. */
  482. pp->leap = LEAP_NOWARNING;
  483. memcpy(&pp->refid, REFUSNO, 4);
  484. if (up->msgcnt == 0)
  485. record_clock_stats(&peer->srcadr, str);
  486. up->msgcnt++;
  487. return;
  488. /*
  489. * PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ"
  490. */
  491. case LENPTB:
  492. if (sscanf(str,
  493. "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c",
  494. &pp->second, &pp->year, &month, &day, &pp->hour,
  495. &pp->minute, &mjd, &dut1, &leapdir, &leapmonth,
  496. &msADV, &flag) != 12) {
  497. refclock_report(peer, CEVNT_BADREPLY);
  498. return;
  499. }
  500. pp->leap = LEAP_NOWARNING;
  501. if (leapmonth == month) {
  502. if (leapdir == '+')
  503. pp->leap = LEAP_ADDSECOND;
  504. else if (leapdir == '-')
  505. pp->leap = LEAP_DELSECOND;
  506. }
  507. pp->day = ymd2yd(pp->year, month, day);
  508. memcpy(&pp->refid, REFPTB, 4);
  509. if (up->msgcnt == 0)
  510. record_clock_stats(&peer->srcadr, str);
  511. up->msgcnt++;
  512. break;
  513. /*
  514. * WWVB format 0: "I ddd hh:mm:ss DTZ=nn"
  515. */
  516. case LENWWVB0:
  517. if (sscanf(str, "%c %3d %2d:%2d:%2d %cTZ=%2d",
  518. &synchar, &pp->day, &pp->hour, &pp->minute,
  519. &pp->second, &dstchar, &tz) != 7) {
  520. refclock_report(peer, CEVNT_BADREPLY);
  521. return;
  522. }
  523. pp->leap = LEAP_NOWARNING;
  524. if (synchar != ' ')
  525. pp->leap = LEAP_NOTINSYNC;
  526. memcpy(&pp->refid, REFWWVB, 4);
  527. if (up->msgcnt == 0)
  528. record_clock_stats(&peer->srcadr, str);
  529. up->msgcnt++;
  530. break;
  531. /*
  532. * WWVB format 2: "IQyy ddd hh:mm:ss.mmm LD"
  533. */
  534. case LENWWVB2:
  535. if (sscanf(str, "%c%c%2d %3d %2d:%2d:%2d.%3ld%c%c%c",
  536. &synchar, &qualchar, &pp->year, &pp->day,
  537. &pp->hour, &pp->minute, &pp->second, &pp->nsec,
  538. &dstchar, &leapchar, &dstchar) != 11) {
  539. refclock_report(peer, CEVNT_BADREPLY);
  540. return;
  541. }
  542. pp->nsec *= 1000000;
  543. pp->leap = LEAP_NOWARNING;
  544. if (synchar != ' ')
  545. pp->leap = LEAP_NOTINSYNC;
  546. else if (leapchar == 'L')
  547. pp->leap = LEAP_ADDSECOND;
  548. memcpy(&pp->refid, REFWWVB, 4);
  549. if (up->msgcnt == 0)
  550. record_clock_stats(&peer->srcadr, str);
  551. up->msgcnt++;
  552. break;
  553. /*
  554. * None of the above. Just forget about it and wait for the next
  555. * message or timeout.
  556. */
  557. default:
  558. return;
  559. }
  560. /*
  561. * We have a valid timecode. The fudge time1 value is added to
  562. * each sample by the main line routines. Note that in current
  563. * telephone networks the propatation time can be different for
  564. * each call and can reach 200 ms for some calls.
  565. */
  566. peer->refid = pp->refid;
  567. pp->lastrec = up->tstamp;
  568. if (!refclock_process(pp)) {
  569. refclock_report(peer, CEVNT_BADTIME);
  570. return;
  571. }
  572. pp->lastref = pp->lastrec;
  573. if (peer->disp > MAXDISTANCE)
  574. refclock_receive(peer);
  575. if (up->state != S_MSG) {
  576. up->state = S_MSG;
  577. up->timer = TIMECODE;
  578. }
  579. }
  580. /*
  581. * acts_poll - called by the transmit routine
  582. */
  583. static void
  584. acts_poll (
  585. int unit,
  586. struct peer *peer
  587. )
  588. {
  589. struct actsunit *up;
  590. struct refclockproc *pp;
  591. /*
  592. * This routine is called at every system poll. All it does is
  593. * set flag1 under certain conditions. The real work is done by
  594. * the timeout routine and state machine.
  595. */
  596. pp = peer->procptr;
  597. up = (struct actsunit *)pp->unitptr;
  598. switch (peer->ttl) {
  599. /*
  600. * In manual mode the calling program is activated by the ntpdc
  601. * program using the enable flag (fudge flag1), either manually
  602. * or by a cron job.
  603. */
  604. case MODE_MANUAL:
  605. /* fall through */
  606. break;
  607. /*
  608. * In automatic mode the calling program runs continuously at
  609. * intervals determined by the poll event or specified timeout.
  610. */
  611. case MODE_AUTO:
  612. pp->sloppyclockflag |= CLK_FLAG1;
  613. break;
  614. /*
  615. * In backup mode the calling program runs continuously as long
  616. * as either no peers are available or this peer is selected.
  617. */
  618. case MODE_BACKUP:
  619. if (sys_peer == NULL || sys_peer == peer)
  620. pp->sloppyclockflag |= CLK_FLAG1;
  621. break;
  622. }
  623. }
  624. /*
  625. * acts_timer - called at one-second intervals
  626. */
  627. static void
  628. acts_timer(
  629. int unit,
  630. struct peer *peer
  631. )
  632. {
  633. struct actsunit *up;
  634. struct refclockproc *pp;
  635. /*
  636. * This routine implments a timeout which runs for a programmed
  637. * interval. The counter is initialized by the state machine and
  638. * counts down to zero. Upon reaching zero, the state machine is
  639. * called. If flag1 is set while in S_IDLE state, force a
  640. * timeout.
  641. */
  642. pp = peer->procptr;
  643. up = (struct actsunit *)pp->unitptr;
  644. if (pp->sloppyclockflag & CLK_FLAG1 && up->state == S_IDLE) {
  645. acts_timeout(peer);
  646. return;
  647. }
  648. if (up->timer == 0)
  649. return;
  650. up->timer--;
  651. if (up->timer == 0)
  652. acts_timeout(peer);
  653. }
  654. /*
  655. * acts_timeout - called on timeout
  656. */
  657. static void
  658. acts_timeout(
  659. struct peer *peer
  660. )
  661. {
  662. struct actsunit *up;
  663. struct refclockproc *pp;
  664. int fd;
  665. char device[20];
  666. char lockfile[128], pidbuf[8];
  667. char tbuf[BMAX];
  668. /*
  669. * The state machine is driven by messages from the modem, when
  670. * first stated and at timeout.
  671. */
  672. pp = peer->procptr;
  673. up = (struct actsunit *)pp->unitptr;
  674. pp->sloppyclockflag &= ~CLK_FLAG1;
  675. if (sys_phone[up->retry] == NULL && !(pp->sloppyclockflag &
  676. CLK_FLAG3)) {
  677. msyslog(LOG_ERR, "acts: no phones");
  678. return;
  679. }
  680. switch(up->state) {
  681. /*
  682. * System poll event. Lock the modem port and open the device.
  683. */
  684. case S_IDLE:
  685. /*
  686. * Lock the modem port. If busy, retry later. Note: if
  687. * something fails between here and the close, the lock
  688. * file may not be removed.
  689. */
  690. if (pp->sloppyclockflag & CLK_FLAG2) {
  691. sprintf(lockfile, LOCKFILE, up->unit);
  692. fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL,
  693. 0644);
  694. if (fd < 0) {
  695. msyslog(LOG_ERR, "acts: port busy");
  696. return;
  697. }
  698. sprintf(pidbuf, "%d\n", (u_int)getpid());
  699. write(fd, pidbuf, strlen(pidbuf));
  700. close(fd);
  701. }
  702. /*
  703. * Open the device in raw mode and link the I/O.
  704. */
  705. if (!pp->io.fd) {
  706. sprintf(device, DEVICE, up->unit);
  707. fd = refclock_open(device, SPEED232,
  708. LDISC_ACTS | LDISC_RAW | LDISC_REMOTE);
  709. if (fd == 0) {
  710. return;
  711. }
  712. pp->io.fd = fd;
  713. if (!io_addclock(&pp->io)) {
  714. msyslog(LOG_ERR,
  715. "acts: addclock fails");
  716. close(fd);
  717. pp->io.fd = 0;
  718. return;
  719. }
  720. }
  721. /*
  722. * If the port is directly connected to the device, skip
  723. * the modem business and send 'T' for Spectrabum.
  724. */
  725. if (pp->sloppyclockflag & CLK_FLAG3) {
  726. if (write(pp->io.fd, "T", 1) < 0) {
  727. msyslog(LOG_ERR, "acts: write %m");
  728. return;
  729. }
  730. up->state = S_FIRST;
  731. up->timer = CONNECT;
  732. return;
  733. }
  734. /*
  735. * Initialize the modem. This works with Hayes commands.
  736. */
  737. #ifdef DEBUG
  738. if (debug)
  739. printf("acts: setup %s\n", MODEM_SETUP);
  740. #endif
  741. if (write(pp->io.fd, MODEM_SETUP, strlen(MODEM_SETUP)) <
  742. 0) {
  743. msyslog(LOG_ERR, "acts: write %m");
  744. return;
  745. }
  746. up->state = S_OK;
  747. up->timer = SETUP;
  748. return;
  749. /*
  750. * In OK state the modem did not respond to setup.
  751. */
  752. case S_OK:
  753. msyslog(LOG_ERR, "acts: no modem");
  754. break;
  755. /*
  756. * In DTR state we are waiting for the modem to settle down
  757. * before hammering it with a dial command.
  758. */
  759. case S_DTR:
  760. sprintf(tbuf, "DIAL #%d %s", up->retry,
  761. sys_phone[up->retry]);
  762. record_clock_stats(&peer->srcadr, tbuf);
  763. #ifdef DEBUG
  764. if (debug)
  765. printf("%s\n", tbuf);
  766. #endif
  767. write(pp->io.fd, sys_phone[up->retry],
  768. strlen(sys_phone[up->retry]));
  769. write(pp->io.fd, "\r", 1);
  770. up->state = S_CONNECT;
  771. up->timer = ANSWER;
  772. return;
  773. /*
  774. * In CONNECT state the call did not complete.
  775. */
  776. case S_CONNECT:
  777. msyslog(LOG_ERR, "acts: no answer");
  778. break;
  779. /*
  780. * In FIRST state no messages were received.
  781. */
  782. case S_FIRST:
  783. msyslog(LOG_ERR, "acts: no messages");
  784. break;
  785. /*
  786. * In CLOSE state hangup is complete. Close the doors and
  787. * windows and get some air.
  788. */
  789. case S_CLOSE:
  790. /*
  791. * Close the device and unlock a shared modem.
  792. */
  793. if (pp->io.fd) {
  794. io_closeclock(&pp->io);
  795. close(pp->io.fd);
  796. if (pp->sloppyclockflag & CLK_FLAG2) {
  797. sprintf(lockfile, LOCKFILE, up->unit);
  798. unlink(lockfile);
  799. }
  800. pp->io.fd = 0;
  801. }
  802. /*
  803. * If messages were received, fold the tent and wait for
  804. * the next poll. If no messages and there are more
  805. * numbers to dial, retry after a short wait.
  806. */
  807. up->bufptr = pp->a_lastcode;
  808. up->timer = 0;
  809. up->state = S_IDLE;
  810. if ( up->msgcnt == 0) {
  811. up->retry++;
  812. if (sys_phone[up->retry] == NULL)
  813. up->retry = 0;
  814. else
  815. up->timer = SETUP;
  816. } else {
  817. up->retry = 0;
  818. }
  819. up->msgcnt = 0;
  820. return;
  821. }
  822. acts_disc(peer);
  823. }
  824. /*
  825. * acts_disc - disconnect the call and clean the place up.
  826. */
  827. static void
  828. acts_disc (
  829. struct peer *peer
  830. )
  831. {
  832. struct actsunit *up;
  833. struct refclockproc *pp;
  834. int dtr = TIOCM_DTR;
  835. /*
  836. * We get here if the call terminated successfully or if an
  837. * error occured. If the median filter has something in it,feed
  838. * the data to the clock filter. If a modem port, drop DTR to
  839. * force command mode and send modem hangup.
  840. */
  841. pp = peer->procptr;
  842. up = (struct actsunit *)pp->unitptr;
  843. if (up->msgcnt > 0)
  844. refclock_receive(peer);
  845. if (!(pp->sloppyclockflag & CLK_FLAG3)) {
  846. ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr);
  847. write(pp->io.fd, MODEM_HANGUP, strlen(MODEM_HANGUP));
  848. }
  849. up->timer = SETUP;
  850. up->state = S_CLOSE;
  851. }
  852. #else
  853. int refclock_acts_bs;
  854. #endif /* REFCLOCK */