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
acts_start(int unit,struct peer * peer)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
acts_shutdown(int unit,struct peer * peer)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
acts_receive(struct recvbuf * rbufp)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
acts_message(struct peer * peer,const char * msg)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
acts_timeout(struct peer * peer,teModemState dstate)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
acts_close(struct peer * peer)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
acts_poll(int unit,struct peer * peer)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
acts_timer(int unit,struct peer * peer)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
acts_timecode(struct peer * peer,const char * str)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