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