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