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