refclock_usno.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (c) 1996 by Sun Microsystems, Inc.
* All Rights Reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* refclock_usno - clock driver for the Naval Observatory dialup
* Michael Shields <shields@tembel.org> 1995/02/25
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_SYS_IOCTL_H
#endif /* HAVE_SYS_IOCTL_H */
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_unixtime.h"
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
#include "ntp_control.h"
/*
* This driver supports the Naval Observatory dialup at +1 202 653 0351.
* It is a hacked-up version of the ACTS driver.
*
* This driver does not support the `phone' configuration because that
* is needlessly global; it would clash with the ACTS driver.
*
* The Naval Observatory does not support the echo-delay measurement scheme.
*
* However, this driver *does* support UUCP port locking, allowing the
* line to be shared with other processes when not actually dialing
* for time.
*/
/*
* Interface definitions
*/
#define PHONE "atdt 202 653 0351"
/* #define PHONE "atdt 1 202 653 0351" */
#define DESCRIPTION "Naval Observatory dialup"
#define MODE_AUTO 0 /* automatic mode */
/*
* Modem control strings. These may have to be changed for some modems.
*
* AT command prefix
* B1 initiate call negotiation using Bell 212A
* &C1 enable carrier detect
* &D2 hang up and return to command mode on DTR transition
* E0 modem command echo disabled
* l1 set modem speaker volume to low level
* M1 speaker enabled untill carrier detect
* Q0 return result codes
* V1 return result codes as English words
*/
/*
* Timeouts
*/
/*
* Imported from ntp_timer module
*/
/*
* Imported from ntpd module
*/
extern int debug; /* global debug flag */
/*
* Imported from ntp_proto module
*/
/*
* Unit control structure
*/
struct usnounit {
int pollcnt; /* poll message counter */
int state; /* the first one was Delaware */
int run; /* call program run switch */
int msgcnt; /* count of time messages received */
long redial; /* interval to next automatic call */
int unit; /* unit number (= port) */
};
/*
* Function prototypes
*/
static int usno_start P((int, struct peer *));
static void usno_shutdown P((int, struct peer *));
static void usno_receive P((struct recvbuf *));
static void usno_timeout P((struct peer *));
static int usno_write P((struct peer *, char *));
/*
* Transfer vector
*/
struct refclock refclock_usno = {
usno_start, /* start up driver */
usno_shutdown, /* shut down driver */
usno_poll, /* transmit poll message */
noentry, /* not used (usno_control) */
noentry, /* not used (usno_init) */
noentry, /* not used (usno_buginfo) */
NOFLAGS /* not used */
};
/*
* usno_start - open the devices and initialize data for processing
*/
static int
int unit;
{
struct refclockproc *pp;
/*
* Initialize miscellaneous variables
*/
/*
* Allocate and initialize unit structure
*/
return (0);
/*
* Set up the driver timeout
*/
return (1);
}
/*
* usno_shutdown - shut down the clock
*/
static void
int unit;
{
struct refclockproc *pp;
#ifdef DEBUG
if (debug)
#endif
}
/*
* usno_receive - receive data from the serial interface
*/
static void
{
struct refclockproc *pp;
/*
* Initialize pointers and read the timecode and timestamp. If
* the OK modem status code, leave it where folks can find it.
*/
return;
}
#ifdef DEBUG
if (debug)
pp->a_lastcode);
#endif
case 0:
/*
* State 0. We are not expecting anything. Probably
* modem disconnect noise. Go back to sleep.
*/
return;
case 1:
/*
* State 1. We are about to dial. Just drop it.
*/
return;
case 2:
/*
* State 2. We are waiting for the call to be answered.
* All we care about here is CONNECT as the first token
* in the string. If the modem signals BUSY, ERROR, NO
* ANSWER, NO CARRIER or NO DIALTONE, we immediately
* hang up the phone. If CONNECT doesn't happen after
* ANSWER seconds, hang up the phone. If everything is
* okay, start the connect timeout and slide into state
* 3.
*/
"clock %s USNO modem status %s",
} else {
"clock %s USNO unknown modem status %s",
}
return;
case 3:
/*
* State 3. The call has been answered and we are
* waiting for the first message. If this doesn't
* happen within the timecode timeout, hang up the
* phone. We probably got a wrong number or they are
* down.
*/
return;
case 4:
/*
* State 4. We are reading a timecode. It's an actual
* timecode, or it's the `*' OTM.
*
* jjjjj nnn hhmmss UTC
*/
#ifdef DEBUG
if (debug)
printf("usno: bad timecode format\n");
#endif
} else
return;
return;
/* else, OTM; drop out of switch */
}
/*
* Colossal hack here. We process each sample in a trimmed-mean
* filter and determine the reference clock offset and
* dispersion. The fudge time1 value is added to each sample as
* received.
*/
#ifdef DEBUG
if (debug)
printf("usno: time rejected\n");
#endif
return;
return;
/*
* We have a filtered sample offset ready for peer processing.
* We use lastrec as both the reference time and receive time in
* order to avoid being cute, like setting the reference time
* later than the receive time, which may cause a paranoid
* protocol module to chuck out the data. Finaly, we unhook the
* timeout, arm for the next call, fold the tent and go home.
*/
}
/*
* usno_poll - called by the transmit routine
*/
static void
int unit;
{
struct refclockproc *pp;
/*
* If the driver is running, we set the enable flag (fudge
* flag1), which causes the driver timeout routine to initiate a
* call. If not, the enable flag can be set using
* xntpdc. If this is the sustem peer, then follow the system
* poll interval.
*/
else
}
}
/*
* usno_timeout - called by the timer interrupt
*/
static void
{
struct refclockproc *pp;
int fd;
char device[20];
/*
* If a timeout occurs in other than state 0, the call has
* failed. If in state 0, we just see if there is other work to
* do.
*/
return;
}
/*
* Call, and start the answer timeout. We think it
* strange if the OK status has not been received from
* the modem, but plow ahead anyway.
*
* This code is *here* because we had to stick in a brief
* delay to let the modem settle down after raising DTR,
* and for the OK to be received. State machines are
* contorted.
*/
return;
}
/*
* In manual mode the calling program is activated
* by the xntpdc program using the enable flag (fudge
* flag1), either manually or by a cron job.
*/
case MODE_MANUAL:
break;
/*
* In automatic mode the calling program runs
* continuously at intervals determined by the sys_poll
* variable.
*/
case MODE_AUTO:
break;
/*
* In backup mode the calling program is disabled,
* unless no system peer has been selected for MAXOUTAGE
* (3600 s). Once enabled, it runs until some other NTP
* peer shows up.
*/
case MODE_BACKUP:
"clock %s USNO backup started ",
}
"clock %s USNO backup stopped",
}
break;
default:
}
/*
* by the code or via xntpdc, the calling program is
* started; if reset, the phones stop ringing.
*/
return;
}
/*
* Lock the port.
*/
if (fd < 0) {
return;
}
/*
* Open serial port. Use ACTS line discipline, if available. It
* pumps a timestamp into the data stream at every on-time
* character '*' found. Note: the port must have modem control
* or deep pockets for the phone bill. HP-UX 9.03 users should
* have very deep pockets.
*/
return;
}
return;
}
/*
* Initialize modem and kill DTR. We skedaddle if this comes
* bum.
*/
return;
}
/*
* Initiate a call to the Observatory. If we wind up here in
* other than state 0, a successful call could not be completed
* within minpoll seconds.
*/
"clock %s USNO calling program terminated",
#ifdef DEBUG
if (debug)
printf("usno: calling program terminated\n");
#endif
return;
}
/*
* Raise DTR, and let the modem settle. Then we'll dial.
*/
}
/*
* usno_disc - disconnect the call and wait for the ruckus to cool
*/
static void
{
struct refclockproc *pp;
char lockfile[128];
/*
* We should never get here other than in state 0, unless a call
* has timed out. We drop DTR, which will reliably get the modem
* off the air, even while the modem is hammering away full tilt.
*/
#ifdef DEBUG
if (debug)
#endif
}
}
/*
* usno_write - write a message to the serial port
*/
static int
char *str;
{
struct refclockproc *pp;
int len;
int code;
char cr = '\r';
/*
* Not much to do here, other than send the message, handle
* debug and report faults.
*/
#ifdef DEBUG
if (debug)
str);
#endif
if (!code)
return (code);
}
#else /* not (REFCLOCK && USNO) */
int refclock_usno_bs;
#endif /* not (REFCLOCK && USNO) */