Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / ntp / dist / ntpd / refclock_acts.c
blobda2dfe89f7d993c0d98421470167905d253f47bb
1 /* $NetBSD: refclock_acts.c,v 1.5 2007/01/06 19:45:23 kardel Exp $ */
3 /*
4 * refclock_acts - clock driver for the NIST/USNO/PTB/NPL Computer Time
5 * Services
6 */
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
11 #if defined(REFCLOCK) && (defined(CLOCK_ACTS) || defined(CLOCK_PTBACTS))
13 #include "ntpd.h"
14 #include "ntp_io.h"
15 #include "ntp_unixtime.h"
16 #include "ntp_refclock.h"
17 #include "ntp_stdlib.h"
18 #include "ntp_control.h"
20 #include <stdio.h>
21 #include <ctype.h>
22 #ifdef HAVE_SYS_IOCTL_H
23 # include <sys/ioctl.h>
24 #endif /* HAVE_SYS_IOCTL_H */
27 * This driver supports the US (NIST, USNO) and European (PTB, NPL,
28 * etc.) modem time services, as well as Spectracom GPS and WWVB
29 * receivers connected via a modem. The driver periodically dials a
30 * number from a telephone list, receives the timecode data and
31 * calculates the local clock correction. It is designed primarily for
32 * use as backup when neither a radio clock nor connectivity to Internet
33 * time servers is available.
35 * This driver requires a modem with a Hayes-compatible command set and
36 * control over the modem data terminal ready (DTR) control line. The
37 * modem setup string is hard-coded in the driver and may require
38 * changes for nonstandard modems or special circumstances. For reasons
39 * unrelated to this driver, the data set ready (DSR) control line
40 * should not be set when this driver is first started.
42 * The calling program is initiated by setting fudge flag1, either
43 * manually or automatically. When flag1 is set, the calling program
44 * dials the first number in the phone command of the configuration
45 * file. If that call fails, the calling program dials the second number
46 * and so on. The number is specified by the Hayes ATDT prefix followed
47 * by the number itself, including the prefix and long-distance digits
48 * and delay code, if necessary. The flag1 is reset and the calling
49 * program terminated if (a) a valid clock update has been determined,
50 * (b) no more numbers remain in the list, (c) a device fault or timeout
51 * occurs or (d) fudge flag1 is reset manually.
53 * The driver is transparent to each of the modem time services and
54 * Spectracom radios. It selects the parsing algorithm depending on the
55 * message length. There is some hazard should the message be corrupted.
56 * However, the data format is checked carefully and only if all checks
57 * succeed is the message accepted. Corrupted lines are discarded
58 * without complaint.
60 * Fudge controls
62 * flag1 force a call in manual mode
63 * flag2 enable port locking (not verified)
64 * flag3 no modem; port is directly connected to device
65 * flag4 not used
67 * time1 offset adjustment (s)
69 * Ordinarily, the serial port is connected to a modem; however, it can
70 * be connected directly to a device or another computer for testing and
71 * calibration. In this case set fudge flag3 and the driver will send a
72 * single character 'T' at each poll event. In principle, fudge flag2
73 * enables port locking, allowing the modem to be shared when not in use
74 * by this driver. At least on Solaris with the current NTP I/O
75 * routines, this results only in lots of ugly error messages.
78 * National Institute of Science and Technology (NIST)
80 * Phone: (303) 494-4774 (Boulder, CO); (808) 335-4721 (Hawaii)
82 * Data Format
84 * National Institute of Standards and Technology
85 * Telephone Time Service, Generator 3B
86 * Enter question mark "?" for HELP
87 * D L D
88 * MJD YR MO DA H M S ST S UT1 msADV <OTM>
89 * 47999 90-04-18 21:39:15 50 0 +.1 045.0 UTC(NIST) *<CR><LF>
90 * ...
92 * MJD, DST, DUT1 and UTC are not used by this driver. The "*" or "#" is
93 * the on-time markers echoed by the driver and used by NIST to measure
94 * and correct for the propagation delay.
96 * US Naval Observatory (USNO)
98 * Phone: (202) 762-1594 (Washington, DC); (719) 567-6742 (Boulder, CO)
100 * Data Format (two lines, repeating at one-second intervals)
102 * jjjjj nnn hhmmss UTC<CR><LF>
103 * *<CR><LF>
105 * jjjjj modified Julian day number (not used)
106 * nnn day of year
107 * hhmmss second of day
108 * * on-time marker for previous timecode
109 * ...
111 * USNO does not correct for the propagation delay. A fudge time1 of
112 * about .06 s is advisable.
114 * European Services (PTB, NPL, etc.)
116 * PTB: +49 531 512038 (Germany)
117 * NPL: 0906 851 6333 (UK only)
119 * Data format (see the documentation for phone numbers and formats.)
121 * 1995-01-23 20:58:51 MEZ 10402303260219950123195849740+40000500<CR><LF>
123 * Spectracom GPS and WWVB Receivers
125 * If a modem is connected to a Spectracom receiver, this driver will
126 * call it up and retrieve the time in one of two formats. As this
127 * driver does not send anything, the radio will have to either be
128 * configured in continuous mode or be polled by another local driver.
131 * Interface definitions
133 #define DEVICE "/dev/acts%d" /* device name and unit */
134 #define SPEED232 B9600 /* uart speed (9600 baud) */
135 #define PRECISION (-10) /* precision assumed (about 1 ms) */
136 #define LOCKFILE "/var/spool/locks/LCK..cua%d"
137 #define DESCRIPTION "Automated Computer Time Service" /* WRU */
138 #define REFID "NONE" /* default reference ID */
139 #define MSGCNT 20 /* max message count */
140 #define SMAX 256 /* max clockstats line length */
141 #define MAXPHONE 10 /* max number of phone numbers */
144 * Calling program modes
146 #define MODE_AUTO 0 /* automatic mode */
147 #define MODE_BACKUP 1 /* backup mode */
148 #define MODE_MANUAL 2 /* manual mode */
151 * Service identifiers.
153 #define REFACTS "NIST" /* NIST reference ID */
154 #define LENACTS 50 /* NIST format */
155 #define REFUSNO "USNO" /* USNO reference ID */
156 #define LENUSNO 20 /* USNO */
157 #define REFPTB "PTB\0" /* PTB/NPL reference ID */
158 #define LENPTB 78 /* PTB/NPL format */
159 #define REFWWVB "WWVB" /* WWVB reference ID */
160 #define LENWWVB0 22 /* WWVB format 0 */
161 #define LENWWVB2 24 /* WWVB format 2 */
162 #define LF 0x0a /* ASCII LF */
165 * Modem setup strings. These may have to be changed for some modems.
167 * AT command prefix
168 * B1 US answer tone
169 * &C0 disable carrier detect
170 * &D2 hang up and return to command mode on DTR transition
171 * E0 modem command echo disabled
172 * l1 set modem speaker volume to low level
173 * M1 speaker enabled until carrier detect
174 * Q0 return result codes
175 * V1 return result codes as English words
177 #define MODEM_SETUP "ATB1&C0&D2E0L1M1Q0V1\r" /* modem setup */
178 #define MODEM_HANGUP "ATH\r" /* modem disconnect */
181 * Timeouts (all in seconds)
183 #define SETUP 3 /* setup timeout */
184 #define DTR 1 /* DTR timeout */
185 #define ANSWER 60 /* answer timeout */
186 #define CONNECT 20 /* first valid message timeout */
187 #define TIMECODE 30 /* all valid messages timeout */
190 * State machine codes
192 #define S_IDLE 0 /* wait for poll */
193 #define S_OK 1 /* wait for modem setup */
194 #define S_DTR 2 /* wait for modem DTR */
195 #define S_CONNECT 3 /* wait for answer*/
196 #define S_FIRST 4 /* wait for first valid message */
197 #define S_MSG 5 /* wait for all messages */
198 #define S_CLOSE 6 /* wait after sending disconnect */
201 * Unit control structure
203 struct actsunit {
204 int unit; /* unit number */
205 int state; /* the first one was Delaware */
206 int timer; /* timeout counter */
207 int retry; /* retry index */
208 int msgcnt; /* count of messages received */
209 l_fp tstamp; /* on-time timestamp */
210 char *bufptr; /* buffer pointer */
214 * Function prototypes
216 static int acts_start (int, struct peer *);
217 static void acts_shutdown (int, struct peer *);
218 static void acts_receive (struct recvbuf *);
219 static void acts_message (struct peer *);
220 static void acts_timecode (struct peer *, char *);
221 static void acts_poll (int, struct peer *);
222 static void acts_timeout (struct peer *);
223 static void acts_disc (struct peer *);
224 static void acts_timer (int, struct peer *);
227 * Transfer vector (conditional structure name)
229 struct refclock refclock_acts = {
230 acts_start, /* start up driver */
231 acts_shutdown, /* shut down driver */
232 acts_poll, /* transmit poll message */
233 noentry, /* not used */
234 noentry, /* not used */
235 noentry, /* not used */
236 acts_timer /* housekeeping timer */
240 * Initialize data for processing
242 static int
243 acts_start (
244 int unit,
245 struct peer *peer
248 struct actsunit *up;
249 struct refclockproc *pp;
252 * Allocate and initialize unit structure
254 up = emalloc(sizeof(struct actsunit));
255 memset(up, 0, sizeof(struct actsunit));
256 up->unit = unit;
257 pp = peer->procptr;
258 pp->unitptr = (caddr_t)up;
259 pp->io.clock_recv = acts_receive;
260 pp->io.srcclock = (caddr_t)peer;
261 pp->io.datalen = 0;
264 * Initialize miscellaneous variables
266 peer->precision = PRECISION;
267 pp->clockdesc = DESCRIPTION;
268 memcpy((char *)&pp->refid, REFID, 4);
269 peer->sstclktype = CTL_SST_TS_TELEPHONE;
270 up->bufptr = pp->a_lastcode;
271 return (1);
276 * acts_shutdown - shut down the clock
278 static void
279 acts_shutdown (
280 int unit,
281 struct peer *peer
284 struct actsunit *up;
285 struct refclockproc *pp;
288 * Warning: do this only when a call is not in progress.
290 pp = peer->procptr;
291 up = (struct actsunit *)pp->unitptr;
292 free(up);
297 * acts_receive - receive data from the serial interface
299 static void
300 acts_receive (
301 struct recvbuf *rbufp
304 struct actsunit *up;
305 struct refclockproc *pp;
306 struct peer *peer;
307 char tbuf[BMAX];
308 char *tptr;
311 * Initialize pointers and read the timecode and timestamp. Note
312 * we are in raw mode and victim of whatever the terminal
313 * interface kicks up; so, we have to reassemble messages from
314 * arbitrary fragments. Capture the timecode at the beginning of
315 * the message and at the '*' and '#' on-time characters.
317 peer = (struct peer *)rbufp->recv_srcclock;
318 pp = peer->procptr;
319 up = (struct actsunit *)pp->unitptr;
320 pp->lencode = refclock_gtraw(rbufp, tbuf, BMAX - (up->bufptr -
321 pp->a_lastcode), &pp->lastrec);
322 for (tptr = tbuf; *tptr != '\0'; tptr++) {
323 if (*tptr == LF) {
324 if (up->bufptr == pp->a_lastcode) {
325 up->tstamp = pp->lastrec;
326 continue;
328 } else {
329 *up->bufptr = '\0';
330 acts_message(peer);
331 up->bufptr = pp->a_lastcode;
333 } else if (!iscntrl((unsigned char)*tptr)) {
334 *up->bufptr++ = *tptr;
335 if (*tptr == '*' || *tptr == '#') {
336 up->tstamp = pp->lastrec;
337 write(pp->io.fd, tptr, 1);
345 * acts_message - process message
347 void
348 acts_message(
349 struct peer *peer
352 struct actsunit *up;
353 struct refclockproc *pp;
354 int dtr = TIOCM_DTR;
355 char tbuf[SMAX];
356 #ifdef DEBUG
357 u_int modem;
358 #endif
361 * What to do depends on the state and the first token in the
362 * message. */
363 pp = peer->procptr;
364 up = (struct actsunit *)pp->unitptr;
365 #ifdef DEBUG
366 ioctl(pp->io.fd, TIOCMGET, (char *)&modem);
367 snprintf(tbuf, sizeof(tbuf), "acts: %04x (%d %d) %zu %s", modem,
368 up->state, up->timer, strlen(pp->a_lastcode),
369 pp->a_lastcode);
370 if (debug)
371 printf("%s\n", tbuf);
372 #endif
375 * Extract the first token in the line. A NO token sends the
376 * message to the clockstats.
378 strncpy(tbuf, pp->a_lastcode, SMAX);
379 strtok(tbuf, " ");
380 if (strcmp(tbuf, "NO") == 0) {
381 report_event(PEVNT_CLOCK, peer, pp->a_lastcode);
382 return;
384 switch(up->state) {
387 * We are waiting for the OK response to the modem setup
388 * command. When this happens, raise DTR and dial the number
389 * followed by \r.
391 case S_OK:
392 if (strcmp(tbuf, "OK") != 0) {
393 msyslog(LOG_ERR, "acts: setup error %s",
394 pp->a_lastcode);
395 acts_disc(peer);
396 return;
398 ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr);
399 up->state = S_DTR;
400 up->timer = DTR;
401 return;
404 * We are waiting for the call to be answered. All we care about
405 * here is token CONNECT. Send the message to the clockstats.
407 case S_CONNECT:
408 report_event(PEVNT_CLOCK, peer, pp->a_lastcode);
409 if (strcmp(tbuf, "CONNECT") != 0) {
410 acts_disc(peer);
411 return;
413 up->state = S_FIRST;
414 up->timer = CONNECT;
415 return;
418 * We are waiting for a timecode. Pass it to the parser.
420 case S_FIRST:
421 case S_MSG:
422 acts_timecode(peer, pp->a_lastcode);
423 break;
428 * acts_timecode - identify the service and parse the timecode message
430 void
431 acts_timecode(
432 struct peer *peer, /* peer structure pointer */
433 char *str /* timecode string */
436 struct actsunit *up;
437 struct refclockproc *pp;
438 int day; /* day of the month */
439 int month; /* month of the year */
440 u_long mjd; /* Modified Julian Day */
441 double dut1; /* DUT adjustment */
443 u_int dst; /* ACTS daylight/standard time */
444 u_int leap; /* ACTS leap indicator */
445 double msADV; /* ACTS transmit advance (ms) */
446 char utc[10]; /* ACTS timescale */
447 char flag; /* ACTS on-time character (* or #) */
449 char synchar; /* WWVB synchronized indicator */
450 char qualchar; /* WWVB quality indicator */
451 char leapchar; /* WWVB leap indicator */
452 char dstchar; /* WWVB daylight/savings indicator */
453 int tz; /* WWVB timezone */
455 u_int leapmonth; /* PTB/NPL month of leap */
456 char leapdir; /* PTB/NPL leap direction */
459 * The parser selects the modem format based on the message
460 * length. Since the data are checked carefully, occasional
461 * errors due noise are forgivable.
463 pp = peer->procptr;
464 up = (struct actsunit *)pp->unitptr;
465 pp->nsec = 0;
466 switch(strlen(str)) {
469 * For USNO format on-time character '*', which is on a line by
470 * itself. Be sure a timecode has been received.
472 case 1:
473 if (*str == '*' && up->msgcnt > 0)
474 break;
476 return;
479 * ACTS format: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa
480 * UTC(NIST) *"
482 case LENACTS:
483 if (sscanf(str,
484 "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %9s %c",
485 &mjd, &pp->year, &month, &day, &pp->hour,
486 &pp->minute, &pp->second, &dst, &leap, &dut1,
487 &msADV, utc, &flag) != 13) {
488 refclock_report(peer, CEVNT_BADREPLY);
489 return;
493 * Wait until ACTS has calculated the roundtrip delay.
494 * We don't need to do anything, as ACTS adjusts the
495 * on-time epoch.
497 if (flag != '#')
498 return;
500 pp->day = ymd2yd(pp->year, month, day);
501 pp->leap = LEAP_NOWARNING;
502 if (leap == 1)
503 pp->leap = LEAP_ADDSECOND;
504 else if (pp->leap == 2)
505 pp->leap = LEAP_DELSECOND;
506 memcpy(&pp->refid, REFACTS, 4);
507 if (up->msgcnt == 0)
508 record_clock_stats(&peer->srcadr, str);
509 up->msgcnt++;
510 break;
513 * USNO format: "jjjjj nnn hhmmss UTC"
515 case LENUSNO:
516 if (sscanf(str, "%5ld %3d %2d%2d%2d %3s",
517 &mjd, &pp->day, &pp->hour, &pp->minute,
518 &pp->second, utc) != 6) {
519 refclock_report(peer, CEVNT_BADREPLY);
520 return;
524 * Wait for the on-time character, which follows in a
525 * separate message. There is no provision for leap
526 * warning.
528 pp->leap = LEAP_NOWARNING;
529 memcpy(&pp->refid, REFUSNO, 4);
530 if (up->msgcnt == 0)
531 record_clock_stats(&peer->srcadr, str);
532 up->msgcnt++;
533 return;
536 * PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ"
538 case LENPTB:
539 if (sscanf(str,
540 "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c",
541 &pp->second, &pp->year, &month, &day, &pp->hour,
542 &pp->minute, &mjd, &dut1, &leapdir, &leapmonth,
543 &msADV, &flag) != 12) {
544 refclock_report(peer, CEVNT_BADREPLY);
545 return;
547 pp->leap = LEAP_NOWARNING;
548 if (leapmonth == month) {
549 if (leapdir == '+')
550 pp->leap = LEAP_ADDSECOND;
551 else if (leapdir == '-')
552 pp->leap = LEAP_DELSECOND;
554 pp->day = ymd2yd(pp->year, month, day);
555 memcpy(&pp->refid, REFPTB, 4);
556 if (up->msgcnt == 0)
557 record_clock_stats(&peer->srcadr, str);
558 up->msgcnt++;
559 break;
563 * WWVB format 0: "I ddd hh:mm:ss DTZ=nn"
565 case LENWWVB0:
566 if (sscanf(str, "%c %3d %2d:%2d:%2d %cTZ=%2d",
567 &synchar, &pp->day, &pp->hour, &pp->minute,
568 &pp->second, &dstchar, &tz) != 7) {
569 refclock_report(peer, CEVNT_BADREPLY);
570 return;
572 pp->leap = LEAP_NOWARNING;
573 if (synchar != ' ')
574 pp->leap = LEAP_NOTINSYNC;
575 memcpy(&pp->refid, REFWWVB, 4);
576 if (up->msgcnt == 0)
577 record_clock_stats(&peer->srcadr, str);
578 up->msgcnt++;
579 break;
582 * WWVB format 2: "IQyy ddd hh:mm:ss.mmm LD"
584 case LENWWVB2:
585 if (sscanf(str, "%c%c%2d %3d %2d:%2d:%2d.%3ld%c%c%c",
586 &synchar, &qualchar, &pp->year, &pp->day,
587 &pp->hour, &pp->minute, &pp->second, &pp->nsec,
588 &dstchar, &leapchar, &dstchar) != 11) {
589 refclock_report(peer, CEVNT_BADREPLY);
590 return;
592 pp->nsec *= 1000000;
593 pp->leap = LEAP_NOWARNING;
594 if (synchar != ' ')
595 pp->leap = LEAP_NOTINSYNC;
596 else if (leapchar == 'L')
597 pp->leap = LEAP_ADDSECOND;
598 memcpy(&pp->refid, REFWWVB, 4);
599 if (up->msgcnt == 0)
600 record_clock_stats(&peer->srcadr, str);
601 up->msgcnt++;
602 break;
605 * None of the above. Just forget about it and wait for the next
606 * message or timeout.
608 default:
609 return;
613 * We have a valid timecode. The fudge time1 value is added to
614 * each sample by the main line routines. Note that in current
615 * telephone networks the propatation time can be different for
616 * each call and can reach 200 ms for some calls.
618 peer->refid = pp->refid;
619 pp->lastrec = up->tstamp;
620 if (!refclock_process(pp)) {
621 refclock_report(peer, CEVNT_BADTIME);
622 return;
624 pp->lastref = pp->lastrec;
625 if (up->state != S_MSG) {
626 up->state = S_MSG;
627 up->timer = TIMECODE;
633 * acts_poll - called by the transmit routine
635 static void
636 acts_poll (
637 int unit,
638 struct peer *peer
641 struct actsunit *up;
642 struct refclockproc *pp;
645 * This routine is called at every system poll. All it does is
646 * set flag1 under certain conditions. The real work is done by
647 * the timeout routine and state machine.
649 pp = peer->procptr;
650 up = (struct actsunit *)pp->unitptr;
651 switch (peer->ttl) {
654 * In manual mode the calling program is activated by the ntpdc
655 * program using the enable flag (fudge flag1), either manually
656 * or by a cron job.
658 case MODE_MANUAL:
659 /* fall through */
660 break;
663 * In automatic mode the calling program runs continuously at
664 * intervals determined by the poll event or specified timeout.
666 case MODE_AUTO:
667 pp->sloppyclockflag |= CLK_FLAG1;
668 break;
671 * In backup mode the calling program runs continuously as long
672 * as either no peers are available or this peer is selected.
674 case MODE_BACKUP:
675 if (sys_peer == NULL || sys_peer == peer)
676 pp->sloppyclockflag |= CLK_FLAG1;
677 break;
683 * acts_timer - called at one-second intervals
685 static void
686 acts_timer(
687 int unit,
688 struct peer *peer
691 struct actsunit *up;
692 struct refclockproc *pp;
695 * This routine implments a timeout which runs for a programmed
696 * interval. The counter is initialized by the state machine and
697 * counts down to zero. Upon reaching zero, the state machine is
698 * called. If flag1 is set while in S_IDLE state, force a
699 * timeout.
701 pp = peer->procptr;
702 up = (struct actsunit *)pp->unitptr;
703 if (pp->sloppyclockflag & CLK_FLAG1 && up->state == S_IDLE) {
704 acts_timeout(peer);
705 return;
707 if (up->timer == 0)
708 return;
710 up->timer--;
711 if (up->timer == 0)
712 acts_timeout(peer);
717 * acts_timeout - called on timeout
719 static void
720 acts_timeout(
721 struct peer *peer
724 struct actsunit *up;
725 struct refclockproc *pp;
726 int fd;
727 char device[20];
728 char lockfile[128], pidbuf[8];
729 char tbuf[SMAX];
732 * The state machine is driven by messages from the modem, when
733 * first stated and at timeout.
735 pp = peer->procptr;
736 up = (struct actsunit *)pp->unitptr;
737 pp->sloppyclockflag &= ~CLK_FLAG1;
738 if (sys_phone[up->retry] == NULL && !(pp->sloppyclockflag &
739 CLK_FLAG3)) {
740 msyslog(LOG_ERR, "acts: no phones");
741 return;
743 switch(up->state) {
746 * System poll event. Lock the modem port and open the device.
748 case S_IDLE:
751 * Lock the modem port. If busy, retry later. Note: if
752 * something fails between here and the close, the lock
753 * file may not be removed.
755 if (pp->sloppyclockflag & CLK_FLAG2) {
756 snprintf(lockfile, sizeof(lockfile), LOCKFILE,
757 up->unit);
758 fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL,
759 0644);
760 if (fd < 0) {
761 msyslog(LOG_ERR, "acts: port busy");
762 return;
764 snprintf(pidbuf, sizeof(pidbuf), "%d\n",
765 (u_int)getpid());
766 write(fd, pidbuf, strlen(pidbuf));
767 close(fd);
771 * Open the device in raw mode and link the I/O.
773 if (!pp->io.fd) {
774 snprintf(device, sizeof(device), DEVICE,
775 up->unit);
776 fd = refclock_open(device, SPEED232,
777 LDISC_ACTS | LDISC_RAW | LDISC_REMOTE);
778 if (fd == 0) {
779 msyslog(LOG_ERR,
780 "acts: open fails");
781 return;
783 pp->io.fd = fd;
784 if (!io_addclock(&pp->io)) {
785 msyslog(LOG_ERR,
786 "acts: addclock fails");
787 close(fd);
788 pp->io.fd = 0;
789 return;
794 * If the port is directly connected to the device, skip
795 * the modem business and send 'T' for Spectrabum.
797 if (pp->sloppyclockflag & CLK_FLAG3) {
798 if (write(pp->io.fd, "T", 1) < 0) {
799 msyslog(LOG_ERR, "acts: write %m");
800 return;
802 up->state = S_FIRST;
803 up->timer = CONNECT;
804 return;
808 * Initialize the modem. This works with Hayes commands.
810 #ifdef DEBUG
811 if (debug)
812 printf("acts: setup %s\n", MODEM_SETUP);
813 #endif
814 if (write(pp->io.fd, MODEM_SETUP, strlen(MODEM_SETUP)) <
815 0) {
816 msyslog(LOG_ERR, "acts: write %m");
817 return;
819 up->state = S_OK;
820 up->timer = SETUP;
821 return;
824 * In OK state the modem did not respond to setup.
826 case S_OK:
827 msyslog(LOG_ERR, "acts: no modem");
828 break;
831 * In DTR state we are waiting for the modem to settle down
832 * before hammering it with a dial command.
834 case S_DTR:
835 snprintf(tbuf, sizeof(tbuf), "DIAL #%d %s", up->retry,
836 sys_phone[up->retry]);
837 report_event(PEVNT_CLOCK, peer, tbuf);
838 #ifdef DEBUG
839 if (debug)
840 printf("%s\n", tbuf);
841 #endif
842 write(pp->io.fd, sys_phone[up->retry],
843 strlen(sys_phone[up->retry]));
844 write(pp->io.fd, "\r", 1);
845 up->state = S_CONNECT;
846 up->timer = ANSWER;
847 return;
850 * In CONNECT state the call did not complete.
852 case S_CONNECT:
853 msyslog(LOG_ERR, "acts: no answer");
854 break;
857 * In FIRST state no messages were received.
859 case S_FIRST:
860 msyslog(LOG_ERR, "acts: no messages");
861 break;
864 * In CLOSE state hangup is complete. Close the doors and
865 * windows and get some air.
867 case S_CLOSE:
870 * Close the device and unlock a shared modem.
872 if (pp->io.fd) {
873 io_closeclock(&pp->io);
874 close(pp->io.fd);
875 if (pp->sloppyclockflag & CLK_FLAG2) {
876 snprintf(lockfile, sizeof(lockfile),
877 LOCKFILE, up->unit);
878 unlink(lockfile);
880 pp->io.fd = 0;
884 * If messages were received, fold the tent and wait for
885 * the next poll. If no messages and there are more
886 * numbers to dial, retry after a short wait.
888 up->bufptr = pp->a_lastcode;
889 up->timer = 0;
890 up->state = S_IDLE;
891 if ( up->msgcnt == 0) {
892 up->retry++;
893 if (sys_phone[up->retry] == NULL)
894 up->retry = 0;
895 else
896 up->timer = SETUP;
897 } else {
898 up->retry = 0;
900 up->msgcnt = 0;
901 return;
903 acts_disc(peer);
908 * acts_disc - disconnect the call and clean the place up.
910 static void
911 acts_disc (
912 struct peer *peer
915 struct actsunit *up;
916 struct refclockproc *pp;
917 int dtr = TIOCM_DTR;
920 * We get here if the call terminated successfully or if an
921 * error occured. If the median filter has something in it,
922 * feed the data to the clock filter. If a modem port, drop DTR
923 * to force command mode and send modem hangup.
925 pp = peer->procptr;
926 up = (struct actsunit *)pp->unitptr;
927 if (up->msgcnt > 0)
928 refclock_receive(peer);
929 if (!(pp->sloppyclockflag & CLK_FLAG3)) {
930 ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr);
931 write(pp->io.fd, MODEM_HANGUP, strlen(MODEM_HANGUP));
933 up->timer = SETUP;
934 up->state = S_CLOSE;
936 #else
937 int refclock_acts_bs;
938 #endif /* REFCLOCK */