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