681 lines
21 KiB
C
681 lines
21 KiB
C
/* $NetBSD: refclock_bancomm.c,v 1.3 1998/03/06 18:17:23 christos Exp $ */
|
|
|
|
/*
|
|
* refclock_bancomm.c - clock driver for the Datum/Bancomm
|
|
* bc635VME Time and Frequency Processor.
|
|
* R. Schmidt, Time Service, US Naval Obs. May 94
|
|
* modelled after the TPRO NTP driver.
|
|
*
|
|
* This requires the Datum HP-UX V9.01 kernel driver and the HP-UX vme2
|
|
* driver subsystem. It has been tested on an HP9000/747i at HP-UX 9.03.
|
|
* There are no restrictions on release and use of the following code.
|
|
* The refclock type has been defined as 16.
|
|
* Installation of the Datum/Bancomm HPUX driver creates the device file
|
|
* /dev/btfp0
|
|
*
|
|
* These DEFS are included in the Makefile:
|
|
* DEFS= -DHAVE_TERMIOS -DSYS_HPUX=9
|
|
* DEFS_LOCAL= -DREFCLOCK
|
|
* CLOCKDEFS= -DBANC
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#if defined(REFCLOCK) && defined(BANC)
|
|
#include <stdio.h>
|
|
#include <syslog.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "ntpd.h"
|
|
#include "ntp_io.h"
|
|
#include "ntp_refclock.h"
|
|
#include "ntp_unixtime.h"
|
|
#include "ntp_stdlib.h"
|
|
#include "/etc/conf/machine/vme2.h"
|
|
#include "/etc/conf/h/io.h"
|
|
|
|
/* STUFF BY RES */
|
|
struct btfp_time /* Structure for reading 5 time words */
|
|
/* in one ioctl(2) operation. */
|
|
{
|
|
unsigned short btfp_time[5]; /* Time words 0,1,2,3, and 4. (16bit)*/
|
|
};
|
|
|
|
/***** Simple ioctl commands *****/
|
|
|
|
#define RUNLOCK _IO('X',19) /* Release Capture Lockout */
|
|
#define RCR0 _IOR('X',22,unsigned int) /* Read control register */
|
|
#define WCR0 _IOW('X',23,unsigned int) /* Write control register */
|
|
|
|
/***** Compound ioctl commands *****/
|
|
|
|
/* Read all 5 time words in one call. */
|
|
#define READTIME _IOR('X',32,struct btfp_time)
|
|
#define VMEFD "/dev/btfp0"
|
|
|
|
struct vmedate { /* structure returned by get_vmetime.c */
|
|
unsigned short year;
|
|
unsigned short doy;
|
|
unsigned short hr;
|
|
unsigned short mn;
|
|
unsigned short sec;
|
|
unsigned long frac;
|
|
unsigned short status;
|
|
};
|
|
|
|
/* END OF STUFF FROM RES */
|
|
|
|
/*
|
|
* Definitions
|
|
*/
|
|
#define MAXUNITS 2 /* max number of VME units */
|
|
#define BMAX 50 /* timecode buffer length */
|
|
|
|
/*
|
|
* VME interface parameters.
|
|
*/
|
|
#define VMEPRECISION (-21) /* precision assumed (1 us) */
|
|
#define USNOREFID "USNO" /* or whatever */
|
|
#define VMEREFID "USNO" /* reference id */
|
|
#define VMEDESCRIPTION "USNO Master Clock 2" /* who we are */
|
|
#define VMEHSREFID 0x7f7f1000 /* 127.127.16.00 refid hi strata */
|
|
/* clock type 16 is used here */
|
|
#define GMT 0 /* hour offset from Greenwich */
|
|
|
|
/*
|
|
* Imported from ntp_timer module
|
|
*/
|
|
extern u_long current_time; /* current time (s) */
|
|
|
|
/*
|
|
* Imported from ntpd module
|
|
*/
|
|
extern int debug; /* global debug flag */
|
|
|
|
/*
|
|
* VME unit control structure.
|
|
*/
|
|
struct vmeunit {
|
|
struct peer *peer; /* associated peer structure */
|
|
struct refclockio io; /* given to the I/O handler */
|
|
struct vmedate vmedata; /* data returned from vme read */
|
|
l_fp lastrec; /* last local time */
|
|
l_fp lastref; /* last timecode time */
|
|
char lastcode[BMAX]; /* last timecode received */
|
|
u_short lencode; /* length of last timecode */
|
|
u_long lasttime; /* last time clock heard from */
|
|
u_short unit; /* unit number for this guy */
|
|
u_short status; /* clock status */
|
|
u_short lastevent; /* last clock event */
|
|
u_short year; /* year of eternity */
|
|
u_short day; /* day of year */
|
|
u_short hour; /* hour of day */
|
|
u_short minute; /* minute of hour */
|
|
u_short second; /* seconds of minute */
|
|
u_long usec; /* microsecond of second */
|
|
u_long yearstart; /* start of current year */
|
|
u_short leap; /* leap indicators */
|
|
/*
|
|
* Status tallies
|
|
*/
|
|
u_long polls; /* polls sent */
|
|
u_long noreply; /* no replies to polls */
|
|
u_long coderecv; /* timecodes received */
|
|
u_long badformat; /* bad format */
|
|
u_long baddata; /* bad data */
|
|
u_long timestarted; /* time we started this */
|
|
};
|
|
|
|
/*
|
|
* Data space for the unit structures. Note that we allocate these on
|
|
* the fly, but never give them back.
|
|
*/
|
|
static struct vmeunit *vmeunits[MAXUNITS];
|
|
static u_char unitinuse[MAXUNITS];
|
|
|
|
/*
|
|
* Keep the fudge factors separately so they can be set even
|
|
* when no clock is configured.
|
|
*/
|
|
static l_fp fudgefactor[MAXUNITS];
|
|
static u_char stratumtouse[MAXUNITS];
|
|
static u_char sloppyclockflag[MAXUNITS];
|
|
|
|
/*
|
|
* Function prototypes
|
|
*/
|
|
static void vme_init P(());
|
|
static int vme_start P((u_int, struct peer *));
|
|
static void vme_shutdown P((int));
|
|
static void vme_report_event P((struct vmeunit *, int));
|
|
static void vme_receive P((struct recvbuf *));
|
|
static void vme_poll P((int unit, struct peer *));
|
|
static void vme_control P((u_int, struct refclockstat *, struct refclockstat *));
|
|
static void vme_buginfo P((int, struct refclockbug *));
|
|
struct vmedate *get_datumtime();
|
|
|
|
/*
|
|
* Transfer vector
|
|
*/
|
|
struct refclock refclock_bancomm = {
|
|
vme_start, vme_shutdown, vme_poll,
|
|
vme_control, vme_init, vme_buginfo, NOFLAGS
|
|
};
|
|
|
|
int fd_vme; /* file descriptor for ioctls */
|
|
int regvalue;
|
|
|
|
/*
|
|
* vme_init - initialize internal vme driver data
|
|
*/
|
|
static void
|
|
vme_init()
|
|
{
|
|
register int i;
|
|
/*
|
|
* Just zero the data arrays
|
|
*/
|
|
/*
|
|
bzero((char *)vmeunits, sizeof vmeunits);
|
|
bzero((char *)unitinuse, sizeof unitinuse);
|
|
*/
|
|
|
|
/*
|
|
* Initialize fudge factors to default.
|
|
*/
|
|
for (i = 0; i < MAXUNITS; i++) {
|
|
fudgefactor[i].l_ui = 0;
|
|
fudgefactor[i].l_uf = 0;
|
|
stratumtouse[i] = 0;
|
|
sloppyclockflag[i] = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vme_start - open the VME device and initialize data for processing
|
|
*/
|
|
static int
|
|
vme_start(unit, peer)
|
|
u_int unit;
|
|
struct peer *peer;
|
|
{
|
|
register struct vmeunit *vme;
|
|
register int i;
|
|
int dummy;
|
|
char vmedev[20];
|
|
|
|
/*
|
|
* Check configuration info.
|
|
*/
|
|
if (unit >= MAXUNITS) {
|
|
msyslog(LOG_ERR, "vme_start: unit %d invalid", unit);
|
|
return (0);
|
|
}
|
|
if (unitinuse[unit]) {
|
|
msyslog(LOG_ERR, "vme_start: unit %d in use", unit);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Open VME device
|
|
*/
|
|
#ifdef DEBUG
|
|
|
|
printf("Opening DATUM VME DEVICE \n");
|
|
#endif
|
|
if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) {
|
|
msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
|
|
return (0);
|
|
}
|
|
else { /* Release capture lockout in case it was set from before. */
|
|
if( ioctl( fd_vme, RUNLOCK, &dummy ) )
|
|
msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m");
|
|
|
|
regvalue = 0; /* More esoteric stuff to do... */
|
|
if( ioctl( fd_vme, WCR0, ®value ) )
|
|
msyslog(LOG_ERR, "vme_start: WCR0 failed %m");
|
|
}
|
|
|
|
/*
|
|
* Allocate unit structure
|
|
*/
|
|
if (vmeunits[unit] != 0) {
|
|
vme = vmeunits[unit]; /* The one we want is okay */
|
|
} else {
|
|
for (i = 0; i < MAXUNITS; i++) {
|
|
if (!unitinuse[i] && vmeunits[i] != 0)
|
|
break;
|
|
}
|
|
if (i < MAXUNITS) {
|
|
/*
|
|
* Reclaim this one
|
|
*/
|
|
vme = vmeunits[i];
|
|
vmeunits[i] = 0;
|
|
} else {
|
|
vme = (struct vmeunit *)
|
|
emalloc(sizeof(struct vmeunit));
|
|
}
|
|
}
|
|
bzero((char *)vme, sizeof(struct vmeunit));
|
|
vmeunits[unit] = vme;
|
|
|
|
/*
|
|
* Set up the structures
|
|
*/
|
|
vme->peer = peer;
|
|
vme->unit = (u_short)unit;
|
|
vme->timestarted = current_time;
|
|
|
|
vme->io.clock_recv = vme_receive;
|
|
vme->io.srcclock = (caddr_t)vme;
|
|
vme->io.datalen = 0;
|
|
vme->io.fd = fd_vme;
|
|
|
|
/*
|
|
* All done. Initialize a few random peer variables, then
|
|
* return success. Note that root delay and root dispersion are
|
|
* always zero for this clock.
|
|
*/
|
|
peer->precision = VMEPRECISION;
|
|
peer->rootdelay = 0;
|
|
peer->rootdispersion = 0;
|
|
peer->stratum = stratumtouse[unit];
|
|
memcpy( (char *)&peer->refid, USNOREFID,4);
|
|
|
|
/* peer->refid = htonl(VMEHSREFID); */
|
|
|
|
unitinuse[unit] = 1;
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* vme_shutdown - shut down a VME clock
|
|
*/
|
|
static void
|
|
vme_shutdown(unit)
|
|
int unit;
|
|
{
|
|
register struct vmeunit *vme;
|
|
|
|
if (unit >= MAXUNITS) {
|
|
msyslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit);
|
|
return;
|
|
}
|
|
if (!unitinuse[unit]) {
|
|
msyslog(LOG_ERR, "vme_shutdown: unit %d not in use", unit);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Tell the I/O module to turn us off. We're history.
|
|
*/
|
|
vme = vmeunits[unit];
|
|
io_closeclock(&vme->io);
|
|
unitinuse[unit] = 0;
|
|
}
|
|
|
|
/*
|
|
* vme_report_event - note the occurance of an event
|
|
*
|
|
* This routine presently just remembers the report and logs it, but
|
|
* does nothing heroic for the trap handler.
|
|
*/
|
|
static void
|
|
vme_report_event(vme, code)
|
|
struct vmeunit *vme;
|
|
int code;
|
|
{
|
|
struct peer *peer;
|
|
|
|
peer = vme->peer;
|
|
if (vme->status != (u_short)code) {
|
|
vme->status = (u_short)code;
|
|
if (code != CEVNT_NOMINAL)
|
|
vme->lastevent = (u_short)code;
|
|
msyslog(LOG_INFO,
|
|
"clock %s event %x", ntoa(&peer->srcadr), code);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* vme_receive - receive data from the VME device.
|
|
*
|
|
* Note: This interface would be interrupt-driven. We don't use that
|
|
* now, but include a dummy routine for possible future adventures.
|
|
*/
|
|
static void
|
|
vme_receive(rbufp)
|
|
struct recvbuf *rbufp;
|
|
{
|
|
}
|
|
|
|
/*
|
|
* vme_poll - called by the transmit procedure
|
|
*/
|
|
static void
|
|
vme_poll(unit, peer)
|
|
int unit;
|
|
struct peer *peer;
|
|
{
|
|
struct vmedate *tptr;
|
|
struct vmeunit *vme;
|
|
l_fp tstmp;
|
|
time_t tloc;
|
|
struct tm *tadr;
|
|
|
|
|
|
vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit *));
|
|
tptr = (struct vmedate *)emalloc(sizeof(struct vmedate *));
|
|
|
|
|
|
if (unit >= MAXUNITS) {
|
|
msyslog(LOG_ERR, "vme_poll: unit %d invalid", unit);
|
|
return;
|
|
}
|
|
if (!unitinuse[unit]) {
|
|
msyslog(LOG_ERR, "vme_poll: unit %d not in use", unit);
|
|
return;
|
|
}
|
|
vme = vmeunits[unit]; /* Here is the structure */
|
|
vme->polls++;
|
|
|
|
tptr = &vme->vmedata;
|
|
if ((tptr = get_datumtime()) == NULL ) {
|
|
vme_report_event(vme, CEVNT_BADREPLY);
|
|
return;
|
|
}
|
|
|
|
get_systime(&vme->lastrec);
|
|
vme->lasttime = current_time;
|
|
|
|
/*
|
|
* Get VME time and convert to timestamp format.
|
|
* The year must come from the system clock.
|
|
*/
|
|
/*
|
|
time(&tloc);
|
|
tadr = gmtime(&tloc);
|
|
tptr->year = (unsigned short)(tadr->tm_year + 1900);
|
|
*/
|
|
|
|
sprintf(vme->a_lastcode,
|
|
"%3.3d %2.2d:%2.2d:%2.2d.%.6d %1d\0",
|
|
tptr->doy, tptr->hr, tptr->mn,
|
|
tptr->sec, tptr->frac, tptr->status);
|
|
|
|
record_clock_stats(&(vme->peer->srcadr), vme->a_lastcode);
|
|
vme->lencode = (u_short) strlen(vme->a_lastcode);
|
|
|
|
vme->day = tptr->doy;
|
|
vme->hour = tptr->hr;
|
|
vme->minute = tptr->mn;
|
|
vme->second = tptr->sec;
|
|
vme->usec = tptr->frac;
|
|
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
printf("vme: %3d %02d:%02d:%02d.%06ld %1x\n",
|
|
vme->day, vme->hour, vme->minute, vme->second,
|
|
vme->usec, tptr->status);
|
|
#endif
|
|
if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */
|
|
vme_report_event(vme, CEVNT_BADREPLY);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Now, compute the reference time value. Use the heavy
|
|
* machinery for the seconds and the millisecond field for the
|
|
* fraction when present. If an error in conversion to internal
|
|
* format is found, the program declares bad data and exits.
|
|
* Note that this code does not yet know how to do the years and
|
|
* relies on the clock-calendar chip for sanity.
|
|
*/
|
|
if (!clocktime(vme->day, vme->hour, vme->minute,
|
|
vme->second, GMT, vme->lastrec.l_ui,
|
|
&vme->yearstart, &vme->lastref.l_ui)) {
|
|
vme->baddata++;
|
|
vme_report_event(vme, CEVNT_BADTIME);
|
|
msyslog(LOG_ERR, "refclock_datum: bad data!!");
|
|
return;
|
|
}
|
|
TVUTOTSF(vme->usec, vme->lastref.l_uf);
|
|
tstmp = vme->lastref;
|
|
|
|
L_SUB(&tstmp, &vme->lastrec);
|
|
vme->coderecv++;
|
|
|
|
L_ADD(&tstmp, &(fudgefactor[vme->unit]));
|
|
|
|
refclock_receive(vme->peer, &tstmp, GMT, 0,
|
|
&vme->lastrec, &vme->lastrec, vme->leap);
|
|
}
|
|
|
|
/*
|
|
* vme_control - set fudge factors, return statistics
|
|
*/
|
|
static void
|
|
vme_control(unit, in, out)
|
|
u_int unit;
|
|
struct refclockstat *in;
|
|
struct refclockstat *out;
|
|
{
|
|
register struct vmeunit *vme;
|
|
|
|
if (unit >= MAXUNITS) {
|
|
msyslog(LOG_ERR, "vme_control: unit %d invalid)", unit);
|
|
return;
|
|
}
|
|
|
|
if (in != 0) {
|
|
if (in->haveflags & CLK_HAVETIME1)
|
|
fudgefactor[unit] = in->fudgetime1;
|
|
if (in->haveflags & CLK_HAVEVAL1) {
|
|
stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
|
|
if (unitinuse[unit]) {
|
|
struct peer *peer;
|
|
|
|
/*
|
|
* Should actually reselect clock, but
|
|
* will wait for the next timecode
|
|
*/
|
|
vme = vmeunits[unit];
|
|
peer = vme->peer;
|
|
peer->stratum = stratumtouse[unit];
|
|
if (stratumtouse[unit] <= 1)
|
|
memcpy( (char *)&peer->refid, USNOREFID,4);
|
|
else
|
|
peer->refid = htonl(VMEHSREFID);
|
|
}
|
|
}
|
|
if (in->haveflags & CLK_HAVEFLAG1) {
|
|
sloppyclockflag[unit] = in->flags & CLK_FLAG1;
|
|
}
|
|
}
|
|
|
|
if (out != 0) {
|
|
/* out->type = REFCLK_IRIG_VME; */
|
|
out->type = 15; /* made up by RES */
|
|
out->haveflags
|
|
= CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1;
|
|
out->clockdesc = VMEDESCRIPTION;
|
|
out->fudgetime1 = fudgefactor[unit];
|
|
out->fudgetime2.l_ui = 0;
|
|
out->fudgetime2.l_uf = 0;
|
|
out->fudgeval1 = (long)stratumtouse[unit];
|
|
out->fudgeval2 = 0;
|
|
out->flags = sloppyclockflag[unit];
|
|
if (unitinuse[unit]) {
|
|
vme = vmeunits[unit];
|
|
out->lencode = vme->lencode;
|
|
strcpy(out->a_lastcode, vme->a_lastcode);
|
|
out->timereset = current_time - vme->timestarted;
|
|
out->polls = vme->polls;
|
|
out->noresponse = vme->noreply;
|
|
out->badformat = vme->badformat;
|
|
out->baddata = vme->baddata;
|
|
out->lastevent = vme->lastevent;
|
|
out->currentstatus = vme->status;
|
|
} else {
|
|
out->lencode = 0;
|
|
out->a_lastcode[0] = '\0';
|
|
out->polls = out->noresponse = 0;
|
|
out->badformat = out->baddata = 0;
|
|
out->timereset = 0;
|
|
out->currentstatus = out->lastevent = CEVNT_NOMINAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vme_buginfo - return clock dependent debugging info
|
|
*/
|
|
static void
|
|
vme_buginfo(unit, bug)
|
|
int unit;
|
|
register struct refclockbug *bug;
|
|
{
|
|
register struct vmeunit *vme;
|
|
|
|
if (unit >= MAXUNITS) {
|
|
msyslog(LOG_ERR, "vme_buginfo: unit %d invalid)", unit);
|
|
return;
|
|
}
|
|
|
|
if (!unitinuse[unit])
|
|
return;
|
|
vme = vmeunits[unit];
|
|
|
|
bug->nvalues = 11;
|
|
bug->ntimes = 5;
|
|
if (vme->lasttime != 0)
|
|
bug->values[0] = current_time - vme->lasttime;
|
|
else
|
|
bug->values[0] = 0;
|
|
bug->values[2] = (u_long)vme->year;
|
|
bug->values[3] = (u_long)vme->day;
|
|
bug->values[4] = (u_long)vme->hour;
|
|
bug->values[5] = (u_long)vme->minute;
|
|
bug->values[6] = (u_long)vme->second;
|
|
bug->values[7] = (u_long)vme->usec;
|
|
bug->values[9] = vme->yearstart;
|
|
bug->stimes = 0x1c;
|
|
bug->times[0] = vme->lastref;
|
|
bug->times[1] = vme->lastrec;
|
|
}
|
|
|
|
struct vmedate *get_datumtime()
|
|
{
|
|
unsigned short status;
|
|
char cbuf[7];
|
|
struct vmedate *time_vme;
|
|
struct btfp_time vts;
|
|
time_vme = (struct vmedate *)malloc(sizeof(struct vmedate ));
|
|
|
|
if( ioctl(fd_vme, READTIME, &vts))
|
|
msyslog(LOG_ERR, "get_datumtime error: %m");
|
|
|
|
/* if you want to actually check the validity of these registers, do a
|
|
define of CHECK above this. I didn't find it necessary. - RES
|
|
*/
|
|
|
|
#ifdef CHECK
|
|
|
|
/* Get doy */
|
|
sprintf(cbuf,"%3.3x\0", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
|
|
((vts.btfp_time[ 1 ] & 0xff00) >> 8));
|
|
|
|
if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) )
|
|
time_vme->doy = (unsigned short)atoi(cbuf);
|
|
else
|
|
time_vme->doy = (unsigned short) 0;
|
|
|
|
/* Get hour */
|
|
sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 1 ] & 0x00ff);
|
|
|
|
if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
|
|
time_vme->hr = (unsigned short)atoi(cbuf);
|
|
else
|
|
time_vme->hr = (unsigned short) 0;
|
|
|
|
/* Get minutes */
|
|
sprintf(cbuf,"%2.2x\0", (vts.btfp_time[ 2 ] & 0xff00) >>8);
|
|
if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
|
|
time_vme->mn = (unsigned short)atoi(cbuf);
|
|
else
|
|
time_vme->mn = (unsigned short) 0;
|
|
|
|
/* Get seconds */
|
|
sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 2 ] & 0x00ff);
|
|
|
|
if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
|
|
time_vme->sec = (unsigned short)atoi(cbuf);
|
|
else
|
|
time_vme->sec = (unsigned short) 0;
|
|
|
|
/* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can
|
|
use the TVTOTSF function later on...*/
|
|
|
|
sprintf(cbuf,"%4.4x%2.2x\0", vts.btfp_time[ 3 ],
|
|
vts.btfp_time[ 4 ]>>8);
|
|
|
|
if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2])
|
|
&& isdigit(cbuf[3]) && isdigit(cbuf[4]) && isdigit(cbuf[5]))
|
|
time_vme->frac = (u_long) atoi(cbuf);
|
|
else
|
|
time_vme->frac = (u_long) 0;
|
|
#else
|
|
|
|
/* DONT CHECK just trust the card */
|
|
|
|
/* Get doy */
|
|
sprintf(cbuf,"%3.3x\0", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
|
|
((vts.btfp_time[ 1 ] & 0xff00) >> 8));
|
|
time_vme->doy = (unsigned short)atoi(cbuf);
|
|
|
|
/* Get hour */
|
|
sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 1 ] & 0x00ff);
|
|
|
|
time_vme->hr = (unsigned short)atoi(cbuf);
|
|
|
|
/* Get minutes */
|
|
sprintf(cbuf,"%2.2x\0", (vts.btfp_time[ 2 ] & 0xff00) >>8);
|
|
time_vme->mn = (unsigned short)atoi(cbuf);
|
|
|
|
/* Get seconds */
|
|
sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 2 ] & 0x00ff);
|
|
time_vme->sec = (unsigned short)atoi(cbuf);
|
|
|
|
/* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can
|
|
use the TVTOTSF function later on...*/
|
|
|
|
sprintf(cbuf,"%4.4x%2.2x\0", vts.btfp_time[ 3 ],
|
|
vts.btfp_time[ 4 ]>>8);
|
|
|
|
time_vme->frac = (u_long) atoi(cbuf);
|
|
|
|
#endif /* CHECK */
|
|
|
|
/* Get status bit */
|
|
status = (vts.btfp_time[0] & 0x0010) >>4;
|
|
time_vme->status = status; /* Status=0 if locked to ref. */
|
|
/* Status=1 if flywheeling */
|
|
if (status) { /* lost lock ? */
|
|
return ((void *)NULL);
|
|
}
|
|
else
|
|
return (time_vme);
|
|
}
|
|
|
|
#else /* not (REFCLOCK && BANC) */
|
|
int refclock_bancomm_bs;
|
|
#endif /* not (REFCLOCK && BANC) */
|