]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/ntpd/refclock_acts.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ntp / ntpd / refclock_acts.c
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 */