summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/refclock_gpsvme.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/ntpd/refclock_gpsvme.c')
-rw-r--r--contrib/ntp/ntpd/refclock_gpsvme.c613
1 files changed, 613 insertions, 0 deletions
diff --git a/contrib/ntp/ntpd/refclock_gpsvme.c b/contrib/ntp/ntpd/refclock_gpsvme.c
new file mode 100644
index 0000000..a7c6d23
--- /dev/null
+++ b/contrib/ntp/ntpd/refclock_gpsvme.c
@@ -0,0 +1,613 @@
+/*
+ * 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
+
+#if defined(REFCLOCK) && defined(CLOCK_GPSVME)
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/time.h>
+
+#include "gps.h"
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_stdlib.h"
+#include "/etc/conf/h/io.h"
+
+/* GLOBAL STUFF BY RES */
+
+#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 */
+unsigned short *greg[NREGS]; /* GPS registers defined in gps.h */
+void *gps_base; /* Base address of GPS VME card returned by */
+ /* the map_vme() call */
+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;
+};
+
+struct vmedate *get_gpsvme_time();
+
+/* 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\0" /* Or whatever? */
+#define VMEREFID "GPS" /* reference id */
+#define VMEDESCRIPTION "GPS" /* who we are */
+#define VMEHSREFID 0x7f7f1001 /* 127.127.16.01 refid hi strata */
+
+/* I'm using clock type 16 until one is assigned */
+/* This is set also in vme_control, below */
+
+
+#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 */
+};
+
+/*
+ * 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 (u_int, struct peer *);
+static void vme_shutdown (int);
+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 (u_int, struct refclockstat *, struct refclockstat *);
+static void vme_buginfo (int, struct refclockbug *);
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_gpsvme = {
+ 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(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
+ */
+static int
+vme_start(
+ 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 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));
+ }
+ }
+ 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.
+ */
+ 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);
+ }
+}
+
+
+/*
+ * 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(
+ struct recvbuf *rbufp
+ )
+{
+}
+
+/*
+ * vme_poll - called by the transmit procedure
+ */
+static void
+vme_poll(
+ 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_gpsvme_time()) == 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->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->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->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_gpsvme: 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);
+}
+
+/*
+ * vme_control - set fudge factors, return statistics
+ */
+static void
+vme_control(
+ 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 = 16; /*set by RES SHOULD BE CHANGED */
+ 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;
+ out->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->lastcode = "";
+ 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(
+ 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;
+}
+/* -------------------------------------------------------*/
+/* 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)
+{
+ 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);
+
+ time_vme = (struct vmedate *)malloc(sizeof(struct vmedate ));
+ *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;
+
+ 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 ((void *)NULL);
+ }
+ else
+ return (time_vme);
+}
+
+#else
+int refclock_gpsvme_bs;
+#endif /* REFCLOCK */
OpenPOWER on IntegriCloud