aboutsummaryrefslogtreecommitdiff
path: root/ntpd/refclock_gpsvme.c
diff options
context:
space:
mode:
Diffstat (limited to 'ntpd/refclock_gpsvme.c')
-rw-r--r--ntpd/refclock_gpsvme.c784
1 files changed, 208 insertions, 576 deletions
diff --git a/ntpd/refclock_gpsvme.c b/ntpd/refclock_gpsvme.c
index a7fcf5f62eb8..9f9e85c9fa8d 100644
--- a/ntpd/refclock_gpsvme.c
+++ b/ntpd/refclock_gpsvme.c
@@ -1,622 +1,254 @@
-/*
- * refclock_gpsvme.c NTP clock driver for the TrueTime GPS-VME
- * R. Schmidt, Time Service, US Naval Obs. res@tuttle.usno.navy.mil
- *
- * The refclock type has been defined as 16 (until new id assigned).
- * These DEFS are included in the Makefile:
- * DEFS= -DHAVE_TERMIOS -DSYS_HPUX=9
- * DEFS_LOCAL= -DREFCLOCK
- * CLOCKDEFS= -DGPSVME
- * The file map_vme.c does the VME memory mapping, and includes vme_init().
- * map_vme.c is HP-UX specific, because HPUX cannot mmap() device files! Boo!
- * The file gps.h provides TrueTime register info.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+/* refclock_psc.c: clock driver for Brandywine PCI-SyncClock32/HP-UX 11.X */
-#if defined(REFCLOCK) && defined(CLOCK_GPSVME)
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
-#include "ntpd.h"
-#include "ntp_io.h"
-#include "ntp_refclock.h"
-#include "ntp_unixtime.h"
-#include "ntp_stdlib.h"
+#if defined(REFCLOCK) && defined(CLOCK_GPSVME)
-#include <stdio.h>
-#include <syslog.h>
-#include <ctype.h>
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_stdlib.h"
-#include "gps.h"
-#include "/etc/conf/h/io.h"
+#ifdef __hpux
+#include <sys/rtprio.h> /* may already be included above */
+#include <sys/lock.h> /* NEEDED for PROCLOCK */
+#endif /* __hpux */
-/* GLOBAL STUFF BY RES */
+#ifdef __linux__
+#include <sys/ioctl.h> /* for _IOR, ioctl */
+#endif /* __linux__ */
-#include <time.h>
-
-#define PRIO 120 /* set the realtime priority */
-#define NREGS 7 /* number of registers we will use */
-
-extern int init_vme(); /* This is just a call to map_vme() */
- /* It doesn't have to be extern */
- /* the map_vme() call */
-extern unsigned short *greg[NREGS]; /* made extern to avoid being in both map_vme.c and this file */
-extern void *gps_base; /* mjb lmco 12/20/99 */
-
-extern caddr_t map_vme ();
-extern void unmap_vme(); /* Unmaps the VME space */
-
-struct vmedate { /* structure needed by ntp */
- unsigned short year; /* *tptr is a pointer to this */
- unsigned short doy;
- unsigned short hr;
- unsigned short mn;
- unsigned short sec;
- unsigned long frac;
- unsigned short status;
+enum { /* constants */
+ BUFSIZE = 32,
+ PSC_SYNC_OK = 0x40, /* Sync status bit */
+ DP_LEAPSEC_DAY10DAY1 = 0x82, /* DP RAM address */
+ DP_LEAPSEC_DAY1000DAY100 = 0x83,
+ DELAY = 1,
+ NUNIT = 2 /* max UNITS */
};
-struct vmedate *get_gpsvme_time();
-struct vmedate * time_vme; /* added to emulate LM refclock_gpsvme
- (Made global per RES suggestion to fix mem leak DW lmco) mjb lmco 12/15/99 */
-
-/* END OF STUFF FROM RES */
-
-/*
- * Definitions
- */
-#define MAXUNITS 2 /* max number of VME units */
-#define BMAX 50 /* timecode buffer length */
+/* clock card registers */
+struct psc_regs {
+ uint32_t low_time; /* card base + 0x00 */
+ uint32_t high_time; /* card base + 0x04 */
+ uint32_t ext_low_time; /* card base + 0x08 */
+ uint32_t ext_high_time; /* card base + 0x0C */
+ uint8_t device_status; /* card base + 0x10 */
+ uint8_t device_control; /* card base + 0x11 */
+ uint8_t reserved0; /* card base + 0x12 */
+ uint8_t ext_100ns; /* card base + 0x13 */
+ uint8_t match_usec; /* card base + 0x14 */
+ uint8_t match_msec; /* card base + 0x15 */
+ uint8_t reserved1; /* card base + 0x16 */
+ uint8_t reserved2; /* card base + 0x17 */
+ uint8_t reserved3; /* card base + 0x18 */
+ uint8_t reserved4; /* card base + 0x19 */
+ uint8_t dp_ram_addr; /* card base + 0x1A */
+ uint8_t reserved5; /* card base + 0x1B */
+ uint8_t reserved6; /* card base + 0x1C */
+ uint8_t reserved7; /* card base + 0x1D */
+ uint8_t dp_ram_data; /* card base + 0x1E */
+ uint8_t reserved8; /* card base + 0x1F */
+} *volatile regp[NUNIT];
-/*
- * VME interface parameters.
- */
-#define VMEPRECISION (-21) /* precision assumed (1 us) */
-#define USNOREFID "USNO\0" /* Or whatever? */
-#define VMEREFID "GPS" /* reference id */
-#define VMEDESCRIPTION "GPS" /* who we are */
-#define VMEHSREFID 0x7f7f1001 /* 127.127.16.01 refid hi strata */
+#define PSC_REGS _IOR('K', 0, long) /* ioctl argument */
-/* I'm using clock type 16 until one is assigned */
-/* This is set also in vme_control, below */
+/* Macros to swap byte order and convert BCD to binary */
+#define SWAP(val) ( ((val) >> 24) | (((val) & 0x00ff0000) >> 8) | \
+(((val) & 0x0000ff00) << 8) | (((val) & 0x000000ff) << 24) )
+#define BCD2INT2(val) ( ((val) >> 4 & 0x0f)*10 + ((val) & 0x0f) )
+#define BCD2INT3(val) ( ((val) >> 8 & 0x0f)*100 + ((val) >> 4 & 0x0f)*10 + \
+((val) & 0x0f) )
+/* PSC interface definitions */
+#define PRECISION (-20) /* precision assumed (1 us) */
+#define REFID "USNO" /* reference ID */
+#define DESCRIPTION "Brandywine PCI-SyncClock32"
+#define DEVICE "/dev/refclock%1d" /* device file */
-#define GMT 0 /* hour offset from Greenwich */
-
-/*
- * 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 */
+/* clock unit control structure */
+struct psc_unit {
+ short unit; /* NTP refclock unit number */
+ short last_hour; /* last hour (monitor leap sec) */
+ int msg_flag[2]; /* count error messages */
};
+int fd[NUNIT]; /* file descriptor */
-/*
- * 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 (void);
-static int vme_start (int, struct peer *);
-static void vme_shutdown (int, struct peer *);
-static void vme_report_event (struct vmeunit *, int);
-static void vme_receive (struct recvbuf *);
-static void vme_poll (int unit, struct peer *);
-static void vme_control (int, struct refclockstat *, struct refclockstat *, struct peer *);
-static void vme_buginfo (int, struct refclockbug *, struct peer *);
+/* Local function prototypes */
+static int psc_start(int, struct peer *);
+static void psc_shutdown(int, struct peer *);
+static void psc_poll(int, struct peer *);
+static void check_leap_sec(struct refclockproc *, int);
-/*
- * Transfer vector
- */
-struct refclock refclock_gpsvme = {
- vme_start, vme_shutdown, vme_poll,
- vme_control, vme_init, vme_buginfo, NOFLAGS
+/* Transfer vector */
+struct refclock refclock_gpsvme = {
+ psc_start, psc_shutdown, psc_poll, noentry, noentry, noentry, NOFLAGS
};
-int fd_vme; /* file descriptor for ioctls */
-int regvalue;
-
-/*
- * vme_init - initialize internal vme driver data
- */
-static void
-vme_init(void)
-{
- 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
- */
+/* psc_start: open device and initialize data for processing */
static int
-vme_start(
- u_int unit,
- struct peer *peer
- )
+psc_start(
+ int unit,
+ struct peer *peer
+ )
{
- register struct vmeunit *vme;
- register int i;
- int dummy;
- char vmedev[20];
+ char buf[BUFSIZE];
+ struct refclockproc *pp;
+ struct psc_unit *up = emalloc(sizeof *up);
- /*
- * 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
+ if (unit < 0 || unit > 1) { /* support units 0 and 1 */
+ msyslog(LOG_ERR, "psc_start: bad unit: %d", unit);
+ return 0;
+ }
- printf("Opening VME DEVICE \n");
-#endif
- init_vme(); /* This is in the map_vme.c external file */
-
- /*
- * 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));
- time_vme = (struct vmedate *)malloc(sizeof(struct vmedate)); /* Added to emulate LM's refclock_gpsvme
- (added to fix mem lead DW lmco) mjb lmco 12/22/99 */
- }
- }
- bzero((char *)vme, sizeof(struct vmeunit));
- vmeunits[unit] = vme;
+ if (!up) {
+ msyslog(LOG_ERR, "psc_start: unit: %d, emalloc: %m", unit);
+ return 0;
+ }
+ memset(up, '\0', sizeof *up);
- /*
- * Set up the structures
- */
- vme->peer = peer;
- vme->unit = (u_short)unit;
- vme->timestarted = current_time;
+ sprintf(buf, DEVICE, unit); /* dev file name */
+ fd[unit] = open(buf, O_RDONLY); /* open device file */
+ if (fd[unit] < 0) {
+ msyslog(LOG_ERR, "psc_start: unit: %d, open failed. %m", unit);
+ return 0;
+ }
+
+ /* get the address of the mapped regs */
+ if (ioctl(fd[unit], PSC_REGS, &regp[unit]) < 0) {
+ msyslog(LOG_ERR, "psc_start: unit: %d, ioctl failed. %m", unit);
+ return 0;
+ }
- 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.
- */
- peer->precision = VMEPRECISION;
- 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(
- 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.
- */
- unmap_vme();
- 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(
- 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);
- }
+ /* initialize peer variables */
+ pp = peer->procptr;
+ pp->io.clock_recv = noentry;
+ pp->io.srcclock = (caddr_t) peer;
+ pp->io.datalen = 0;
+ pp->io.fd = -1;
+ pp->unitptr = (caddr_t) up;
+ get_systime(&pp->lastrec);
+ memcpy((char *)&pp->refid, REFID, 4);
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ up->unit = unit;
+#ifdef __hpux
+ rtprio(0,120); /* set real time priority */
+ plock(PROCLOCK); /* lock process in memory */
+#endif /* __hpux */
+ return 1;
}
-
-/*
- * 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.
- */
+/* psc_shutdown: shut down the clock */
static void
-vme_receive(
- struct recvbuf *rbufp
- )
+psc_shutdown(
+ int unit,
+ struct peer *peer
+ )
{
+ free(peer->procptr->unitptr);
+ close(fd[unit]);
}
-/*
- * vme_poll - called by the transmit procedure
- */
+/* psc_poll: read, decode, and record device time */
static void
-vme_poll(
- int unit,
- struct peer *peer
- )
+psc_poll(
+ int unit,
+ struct peer *peer
+ )
{
- struct vmedate *tptr;
- struct vmeunit *vme;
- l_fp tstmp;
- time_t tloc;
- struct tm *tadr;
- long ltemp;
+ struct refclockproc *pp = peer->procptr;
+ struct psc_unit *up;
+ unsigned tlo, thi;
+ unsigned char status;
-
-
- 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++;
+ up = (struct psc_unit *) pp->unitptr;
+ tlo = regp[unit]->low_time; /* latch and read first 4 bytes */
+ thi = regp[unit]->high_time; /* read 4 higher order bytes */
+ status = regp[unit]->device_status; /* read device status byte */
- tptr = &vme->vmedata;
-
- if ((tptr = get_gpsvme_time()) == NULL ) {
- vme_report_event(vme, CEVNT_BADREPLY);
- return;
+ if (!(status & PSC_SYNC_OK)) {
+ refclock_report(peer, CEVNT_BADTIME);
+ if (!up->msg_flag[unit]) { /* write once to system log */
+ msyslog(LOG_WARNING,
+ "SYNCHRONIZATION LOST on unit %1d, status %02x\n",
+ status, unit);
+ up->msg_flag[unit] = 1;
}
+ return;
+ }
- get_systime(&vme->lastrec);
- vme->lasttime = current_time;
+ get_systime(&pp->lastrec);
+ pp->polls++;
+
+ tlo = SWAP(tlo); /* little to big endian swap on */
+ thi = SWAP(thi); /* copy of data */
+ /* convert the BCD time to broken down time used by refclockproc */
+ pp->day = BCD2INT3((thi & 0x0FFF0000) >> 16);
+ pp->hour = BCD2INT2((thi & 0x0000FF00) >> 8);
+ pp->minute = BCD2INT2(thi & 0x000000FF);
+ pp->second = BCD2INT2(tlo >> 24);
+ /* ntp_process() in ntp_refclock.c appears to use usec as fraction of
+ second in microseconds if usec is nonzero. */
+ pp->nsec = 1000000*BCD2INT3((tlo & 0x00FFF000) >> 12) +
+ BCD2INT3(tlo & 0x00000FFF);
- /*
- * 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(pp->a_lastcode, "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x",
+ pp->day, pp->hour, pp->minute, pp->second, pp->nsec, status, thi,
+ tlo);
+ pp->lencode = strlen(pp->a_lastcode);
- sprintf(vme->lastcode,
- "%3.3d %2.2d:%2.2d:%2.2d.%.6d %1d\0",
- tptr->doy, tptr->hr, tptr->mn,
- tptr->sec, tptr->frac, tptr->status);
+ /* compute the timecode timestamp */
+ if (!refclock_process(pp)) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ /* simulate the NTP receive and packet procedures */
+ refclock_receive(peer);
+ /* write clock statistics to file */
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
- record_clock_stats(&(vme->peer->srcadr), vme->lastcode);
- vme->lencode = (u_short) strlen(vme->lastcode);
-
- vme->day = tptr->doy;
- vme->hour = tptr->hr;
- vme->minute = tptr->mn;
- vme->second = tptr->sec;
- vme->nsec = tptr->frac * 1000;
-
-#ifdef DEBUG
- if (debug)
- printf("vme: %3d %02d:%02d:%02d.%06ld %1x\n",
- vme->day, vme->hour, vme->minute, vme->second,
- vme->nsec, 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_gpsvme: bad data!!");
- return;
- }
- vme->lastref.l_uf = 0;
- DTOLFP(vme->nsec / 1e9, &ltemp);
- L_ADD(&vme->lastrec, &ltemp);
- tstmp = vme->lastref;
-
- L_SUB(&tstmp, &vme->lastrec);
- vme->coderecv++;
-
- L_ADD(&tstmp, &(fudgefactor[vme->unit]));
- vme->lastref = vme->lastrec;
- refclock_receive(vme->peer);
-}
-
-/*
- * vme_control - set fudge factors, return statistics2
- */
-static void
-vme_control(
- u_int unit,
- struct refclockstat *in,
- struct refclockstat *out,
- struct peer * peer
- )
-{
- 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)
- DTOLFP(in->fudgetime1, &fudgefactor[unit]); /* added mjb lmco 12/20/99 */
-
- 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 = 16; /*set by RES SHOULD BE CHANGED */
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1;
- out->clockdesc = VMEDESCRIPTION;
- LFPTOD(&fudgefactor[unit], out->fudgetime1); /* added mjb lmco 12/20/99 */
-
- out ->fudgetime2 = 0; /* should do what above was supposed to do mjb lmco 12/20/99 */
-
- out->fudgeval1 = (long)stratumtouse[unit]; /*changed from above LONG was not
- defined mjb lmco 12/15/99 */
-
- out->fudgeval2 = 0;
- out->flags = sloppyclockflag[unit];
- if (unitinuse[unit]) {
- vme = vmeunits[unit];
- out->lencode = vme->lencode;
- out->p_lastcode = vme->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->p_lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
+ /* With the first timecode beginning the day, check for a GPS
+ leap second notification. */
+ if (pp->hour < up->last_hour) {
+ check_leap_sec(pp, unit);
+ up->msg_flag[0] = up->msg_flag[1] = 0; /* reset flags */
+ }
+ up->last_hour = pp->hour;
}
-/*
- * vme_buginfo - return clock dependent debugging info
- */
+/* check_leap_sec: read the Dual Port RAM leap second day registers. The
+ onboard GPS receiver should write the hundreds digit of day of year in
+ DP_LeapSec_Day1000Day100 and the tens and ones digits in
+ DP_LeapSec_Day10Day1. If these values are nonzero and today, we have
+ a leap second pending, so we set the pp->leap flag to LEAP_ADDSECOND.
+ If the BCD data are zero or a date other than today, set pp->leap to
+ LEAP_NOWARNING. */
static void
-vme_buginfo(
- int unit,
- register struct refclockbug *bug,
- struct peer * peer
- )
-{
- 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->nsec;
- bug->values[9] = vme->yearstart;
- bug->stimes = 0x1c;
- bug->times[0] = vme->lastref;
- bug->times[1] = vme->lastrec;
-}
-/* -------------------------------------------------------*/
-/* get_gpsvme_time() */
-/* R. Schmidt, USNO, 1995 */
-/* It's ugly, but hey, it works and its free */
-
-#include "gps.h" /* defines for TrueTime GPS-VME */
-
-#define PBIAS 193 /* 193 microsecs to read the GPS experimentally found */
-
-struct vmedate *
-get_gpsvme_time(void)
+check_leap_sec(struct refclockproc *pp, int unit)
{
- extern struct vmedate *time_vme;
- unsigned short set, hr, min, sec, ums, hms, status;
- int ret;
- char ti[3];
-
- long tloc ;
- time_t mktime(),time();
- struct tm *gmtime(), *gmt;
- char *gpsmicro;
- gpsmicro = (char *) malloc(7);
-
- *greg = (unsigned short *)malloc(sizeof(short) * NREGS);
-
-
- /* reference the freeze command address general register 1 */
- set = *greg[0];
- /* read the registers : */
- /* get year */
- time_vme->year = (unsigned short) *greg[6];
- /* Get doy */
- time_vme->doy = (unsigned short) (*greg[5] & MASKDAY);
- /* Get hour */
- time_vme->hr = (unsigned short) ((*greg[4] & MASKHI) >>8);
- /* Get minutes */
- time_vme->mn = (unsigned short) (*greg[4] & MASKLO);
- /* Get seconds */
- time_vme->sec = (unsigned short) (*greg[3] & MASKHI) >>8;
- /* get microseconds in 2 parts and put together */
- ums = *greg[2];
- hms = *greg[3] & MASKLO;
+ unsigned char dhi, dlo;
+ int leap_day;
+
+ regp[unit]->dp_ram_addr = DP_LEAPSEC_DAY10DAY1;
+ usleep(DELAY);
+ dlo = regp[unit]->dp_ram_data;
+ regp[unit]->dp_ram_addr = DP_LEAPSEC_DAY1000DAY100;
+ usleep(DELAY);
+ dhi = regp[unit]->dp_ram_data;
+ leap_day = BCD2INT2(dlo) + 100*(dhi & 0x0F);
- time_vme->status = (unsigned short) *greg[5] >>13;
-
- /* reference the unfreeze command address general register 1 */
- set = *greg[1];
-
- sprintf(gpsmicro,"%2.2x%4.4x\0", hms, ums);
- time_vme->frac = (u_long) gpsmicro;
-
- /* unmap_vme(); */
-
- if (!status) {
- return (NULL); /* fixed mjb lmco 12/20/99 */
- }
- else
- return (time_vme);
+ pp->leap = LEAP_NOWARNING; /* default */
+ if (leap_day && leap_day == pp->day) {
+ pp->leap = LEAP_ADDSECOND; /* leap second today */
+ msyslog(LOG_ERR, "LEAP_ADDSECOND flag set, day %d (%x %x).",
+ leap_day, dhi, dlo);
+ }
}
#else
-int refclock_gpsvme_bs;
-#endif /* REFCLOCK */
+int refclock_gpsvme_bs;
+#endif /* REFCLOCK */