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