diff options
Diffstat (limited to 'ntpd/refclock_gpsvme.c')
| -rw-r--r-- | ntpd/refclock_gpsvme.c | 784 |
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, ®p[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, <emp); - L_ADD(&vme->lastrec, <emp); - 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 */ |
