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