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 */
26extern 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 */
182const char def_modem_setup[] = "ATB1&C0&D2E0L1M1Q0V1Y1";
183const 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 */
197typedef 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 */
207struct 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 */
221static	int	acts_start	(int, struct peer *);
222static	void	acts_shutdown	(int, struct peer *);
223static	void	acts_receive	(struct recvbuf *);
224static	void	acts_message	(struct peer *, const char *);
225static	void	acts_timecode	(struct peer *, const char *);
226static	void	acts_poll	(int, struct peer *);
227static	void	acts_timeout	(struct peer *, teModemState);
228static	void	acts_timer	(int, struct peer *);
229static	void	acts_close	(struct peer *);
230
231/*
232 * Transfer vector (conditional structure name)
233 */
234struct 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 */
247static int
248acts_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 */
290static void
291acts_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 */
312static void
313acts_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 */
361void
362acts_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 */
461static void
462acts_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 */
598void
599acts_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 */
638static void
639acts_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 */
692static void
693acts_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 */
724void
725acts_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
910int refclock_acts_bs;
911#endif /* REFCLOCK */
912