/*
* This driver supports a generic dumb clock that only outputs hh:mm:ss,
* in local time, no less.
*
* Input format:
*
* hh:mm:ss <cr>
*
* hh:mm:ss -- what you'd expect, with a 24 hour clock. (Heck, that's the only
* way it could get stupider.) We take time on the <cr>.
*
* The original source of this module was the WWVB module.
*/
/*
* Insanity check. Since the time is local, we need to make sure that during midnight
* transitions, we can convert back to Unix time. If the conversion results in some number
* worse than this number of seconds away, assume the next day and retry.
*/
#define INSANE_SECONDS 3600
/*
* Transfer vector
*/
struct refclock refclock_dumbclock = {
dumbclock_start, /* start up driver */
dumbclock_shutdown, /* shut down driver */
noentry, /* poll the driver -- a nice fabrication */
noentry, /* not used */
noentry, /* not used */
noentry, /* not used */
NOFLAGS /* not used */
};
/*
* dumbclock_start - open the devices and initialize data for processing
*/
static int
dumbclock_start(
int unit,
struct peer *peer
)
{
register struct dumbclock_unit *up;
struct refclockproc *pp;
int fd;
char device[20];
struct tm *tm_time_p;
time_t now;
/*
* Open serial port. Don't bother with CLK line discipline, since
* it's not available.
*/
snprintf(device, sizeof(device), DEVICE, unit);
#ifdef DEBUG
if (debug)
printf ("starting Dumbclock with device %s\n",device);
#endif
fd = refclock_open(&peer->srcadr, device, SPEED232, 0);
if (fd <= 0)
return (0);
/*
* dumbclock_shutdown - shut down the clock
*/
static void
dumbclock_shutdown(
int unit,
struct peer *peer
)
{
register struct dumbclock_unit *up;
struct refclockproc *pp;
pp = peer->procptr;
up = pp->unitptr;
if (-1 != pp->io.fd)
io_closeclock(&pp->io);
if (NULL != up)
free(up);
}
/*
* dumbclock_receive - receive data from the serial interface
*/
static void
dumbclock_receive(
struct recvbuf *rbufp
)
{
struct dumbclock_unit *up;
struct refclockproc *pp;
struct peer *peer;
l_fp trtmp; /* arrival timestamp */
int hours; /* hour-of-day */
int minutes; /* minutes-past-the-hour */
int seconds; /* seconds */
int temp; /* int temp */
int got_good; /* got a good time flag */
/*
* Initialize pointers and read the timecode and timestamp
*/
peer = rbufp->recv_peer;
pp = peer->procptr;
up = pp->unitptr;
temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
/*
* We get down to business. Check the timecode format...
*/
got_good=0;
if (sscanf(pp->a_lastcode,"%02d:%02d:%02d",
&hours,&minutes,&seconds) == 3)
{
struct tm *gmtp;
struct tm *lt_p;
time_t asserted_time; /* the SPM time based on the composite time+date */
struct tm asserted_tm; /* the struct tm of the same */
int adjyear;
int adjmon;
time_t reality_delta;
time_t now;
/*
* Convert to GMT for sites that distribute localtime. This
* means we have to figure out what day it is. Easier said
* than done...
*/
/*
* We assume that if the time is grossly wrong, it's because we got the
* year/month/day wrong.
*/
if (reality_delta > INSANE_SECONDS)
{
asserted_time -= SECSPERDAY; /* local clock behind real time */
}
else if (-reality_delta > INSANE_SECONDS)
{
asserted_time += SECSPERDAY; /* local clock ahead of real time */
}
lt_p = localtime(&asserted_time);
if (lt_p)
{
up->ymd = *lt_p;
}
else
{
refclock_report (peer, CEVNT_FAULT);
return;
}
if (!got_good)
{
if (up->linect > 0)
up->linect--;
else
refclock_report(peer, CEVNT_BADREPLY);
return;
}
/*
* Process the new sample in the median filter and determine the
* timecode timestamp.
*/
if (!refclock_process(pp)) {
refclock_report(peer, CEVNT_BADTIME);
return;
}
pp->lastref = pp->lastrec;
refclock_receive(peer);
record_clock_stats(&peer->srcadr, pp->a_lastcode);
up->lasthour = (u_char)pp->hour;
}
#if 0
/*
* dumbclock_poll - called by the transmit procedure
*/
static void
dumbclock_poll(
int unit,
struct peer *peer
)
{
register struct dumbclock_unit *up;
struct refclockproc *pp;
char pollchar;
/*
* Time to poll the clock. The Chrono-log clock is supposed to
* respond to a 'T' by returning a timecode in the format(s)
* specified above. Ours does (can?) not, but this seems to be
* an installation-specific problem. This code is dyked out,
* but may be re-enabled if anyone ever finds a Chrono-log that
* actually listens to this command.
*/
#if 0
pp = peer->procptr;
up = pp->unitptr;
if (peer->reach == 0)
refclock_report(peer, CEVNT_TIMEOUT);
if (up->linect > 0)
pollchar = 'R';
else
pollchar = 'T';
if (refclock_fdwrite(peer, pp->io.fd, &pollchar, 1) != 1)
refclock_report(peer, CEVNT_FAULT);
else
pp->polls++;
#endif
}
#endif