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