pps_params_t params; /* PPS parameters set by user */
} pps_unit_t;
-typedef pps_unit_t* pps_handle_t; /* pps handlebars */
-
/*
*------ Here begins the implementation-specific part! ------
*/
#include <errno.h>
+/*
+ * pps handlebars, which are required to be an opaque scalar. This
+ * implementation uses the handle as a pointer so it must be large
+ * enough. uintptr_t is as large as a pointer.
+ */
+typedef uintptr_t pps_handle_t;
+
/*
* create PPS handle from file descriptor
*/
pps_handle_t *handle /* returned handle */
)
{
+ pps_unit_t *punit;
int one = 1;
/*
* Allocate and initialize default unit structure.
*/
- *handle = malloc(sizeof(pps_unit_t));
- if (!(*handle)) {
- errno = EBADF;
+ punit = malloc(sizeof(*punit));
+ if (NULL == punit) {
+ errno = ENOMEM;
return (-1); /* what, no memory? */
}
- memset(*handle, 0, sizeof(pps_unit_t));
- (*handle)->filedes = filedes;
- (*handle)->params.api_version = PPS_API_VERS_1;
- (*handle)->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC;
+ memset(punit, 0, sizeof(*punit));
+ punit->filedes = filedes;
+ punit->params.api_version = PPS_API_VERS_1;
+ punit->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC;
+
+ *handle = (pps_handle_t)punit;
return (0);
}
pps_handle_t handle
)
{
+ pps_unit_t *punit;
+
/*
* Check for valid arguments and detach PPS signal.
*/
errno = EBADF;
return (-1); /* bad handle */
}
- free(handle);
+ punit = (pps_unit_t *)handle;
+ free(punit);
return (0);
}
const pps_params_t *params
)
{
- int mode, mode_in;
+ pps_unit_t * punit;
+ int mode, mode_in;
/*
* Check for valid arguments and set parameters.
*/
*/
mode_in = params->mode;
+ punit = (pps_unit_t *)handle;
/*
* Only one of the time formats may be selected
if ((mode_in & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) ==
(PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) {
- if (handle->params.assert_offset.tv_sec ||
- handle->params.assert_offset.tv_nsec) {
+ if (punit->params.assert_offset.tv_sec ||
+ punit->params.assert_offset.tv_nsec) {
errno = EINVAL;
return(-1);
* ok, ready to go.
*/
- mode = handle->params.mode;
- memcpy(&handle->params, params, sizeof(pps_params_t));
- handle->params.api_version = PPS_API_VERS_1;
- handle->params.mode = mode | mode_in;
+ mode = punit->params.mode;
+ memcpy(&punit->params, params, sizeof(punit->params));
+ punit->params.api_version = PPS_API_VERS_1;
+ punit->params.mode = mode | mode_in;
return (0);
}
pps_params_t *params
)
{
+ pps_unit_t * punit;
+
/*
* Check for valid arguments and get parameters.
*/
return (-1); /* bad argument */
}
- memcpy(params, &handle->params, sizeof(pps_params_t));
+ punit = (pps_unit_t *)handle;
+ memcpy(params, &punit->params, sizeof(params));
return (0);
}
-/* (
+/*
* get capabilities for handle
*/
u_int serial;
} ev;
- pps_info_t infobuf;
+ pps_info_t infobuf;
+ pps_unit_t * punit;
/*
* Check for valid arguments and fetch timestamps
*/
memset(&infobuf, 0, sizeof(infobuf));
+ punit = (pps_unit_t *)handle;
/*
* if not captureassert, nothing to return.
*/
- if (!handle->params.mode & PPS_CAPTUREASSERT) {
- memcpy(ppsinfo, &infobuf, sizeof(pps_info_t));
+ if (!punit->params.mode & PPS_CAPTUREASSERT) {
+ memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
return (0);
}
- if (ioctl(handle->filedes, TIOCGPPSEV, (caddr_t) &ev) < 0) {
+ if (ioctl(punit->filedes, TIOCGPPSEV, (caddr_t) &ev) < 0) {
perror("time_pps_fetch:");
errno = EOPNOTSUPP;
return(-1);
switch (tsformat) {
case PPS_TSFMT_TSPEC:
/* timespec format requires no conversion */
- if (handle->params.mode & PPS_OFFSETASSERT) {
+ if (punit->params.mode & PPS_OFFSETASSERT) {
infobuf.assert_timestamp.tv_sec +=
- handle->params.assert_offset.tv_sec;
+ punit->params.assert_offset.tv_sec;
infobuf.assert_timestamp.tv_nsec +=
- handle->params.assert_offset.tv_nsec;
+ punit->params.assert_offset.tv_nsec;
PPS_NORMALIZE(infobuf.assert_timestamp);
}
break;
case PPS_TSFMT_NTPFP:
/* NTP format requires conversion to fraction form */
PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp);
- if (handle->params.mode & PPS_OFFSETASSERT)
+ if (punit->params.mode & PPS_OFFSETASSERT)
NTPFP_L_ADDS(&infobuf.assert_timestamp_ntpfp,
- &handle->params.assert_offset_ntpfp);
+ &punit->params.assert_offset_ntpfp);
break;
default:
return (-1);
}
- infobuf.current_mode = handle->params.mode;
- memcpy(ppsinfo, &infobuf, sizeof(pps_info_t));
+ infobuf.current_mode = punit->params.mode;
+ memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
return (0);
}
time_pps_kcbind(
pps_handle_t handle,
const int kernel_consumer,
- const int edge, const int tsformat
+ const int edge,
+ const int tsformat
)
{
/*
#ifdef HAVE_PPSAPI
# include "ppsapi_timepps.h"
+#include "refclock_atom.h"
#endif /* HAVE_PPSAPI */
#ifdef SYS_WINNT
* Unit control structure
*/
struct nmeaunit {
- int pollcnt; /* poll message counter */
- int polled; /* Hand in a sample? */
- l_fp tstamp; /* timestamp of last poll */
- int gps_time; /* 0 UTC, 1 GPS time */
#ifdef HAVE_PPSAPI
- struct timespec ts; /* last timestamp */
- pps_params_t pps_params; /* pps parameters */
- pps_info_t pps_info; /* last pps data */
- pps_handle_t handle; /* pps handlebars */
+ struct refclock_atom atom; /* PPSAPI structure */
+ int tcount; /* timecode sample counter */
+ int pcount; /* PPS sample counter */
#endif /* HAVE_PPSAPI */
+ l_fp tstamp; /* timestamp of last poll */
+ int gps_time; /* 0 UTC, 1 GPS time */
};
/*
*/
static int nmea_start (int, struct peer *);
static void nmea_shutdown (int, struct peer *);
-#ifdef HAVE_PPSAPI
-static void nmea_control (int, struct refclockstat *, struct
- refclockstat *, struct peer *);
-static int nmea_ppsapi (struct peer *, int, int, double *);
-static int nmea_pps (struct nmeaunit *, l_fp *);
-#endif /* HAVE_PPSAPI */
static void nmea_receive (struct recvbuf *);
static void nmea_poll (int, struct peer *);
+#ifdef HAVE_PPSAPI
+static void nmea_timer (int, struct peer *);
+#endif /* HAVE_PPSAPI */
static void gps_send (int, const char *, struct peer *);
-static char *field_parse (char *, int);
+static char * field_parse (char *, int);
static int nmea_checksum_ok(const char *);
/*
*/
struct refclock refclock_nmea = {
nmea_start, /* start up driver */
- nmea_shutdown, /* shut down driver */
+ nmea_shutdown, /* shut down driver */
nmea_poll, /* transmit poll message */
-#ifdef HAVE_PPSAPI
- nmea_control, /* fudge control */
-#else
noentry, /* fudge control */
-#endif /* HAVE_PPSAPI */
noentry, /* initialize driver */
noentry, /* buginfo */
- NOFLAGS /* not used */
+#ifdef HAVE_PPSAPI
+ nmea_timer, /* called once per second */
+#else
+ noentry, /* timer */
+#endif
};
/*
/*
* Allocate and initialize unit structure
*/
- up = (struct nmeaunit *)emalloc(sizeof(*up));
- if (!up) {
+ up = emalloc(sizeof(*up));
+ if (NULL == up) {
close(fd);
return (0);
}
- memset((char *)up, 0, sizeof(struct nmeaunit));
+ memset(up, 0, sizeof(*up));
pp = peer->procptr;
pp->io.clock_recv = nmea_receive;
pp->io.srcclock = (caddr_t)peer;
peer->precision = PRECISION;
pp->clockdesc = DESCRIPTION;
memcpy((char *)&pp->refid, REFID, 4);
- up->pollcnt = 2;
- gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
+
+ gps_send(fd,"$PMOTG,RMC,0000*1D\r\n", peer);
#ifdef HAVE_PPSAPI
/*
- * Start the PPSAPI interface if it is there. Default to use
- * the assert edge and do not enable the kernel hardpps.
+ * Light up the PPSAPI interface.
*/
- if (time_pps_create(fd, &up->handle) < 0) {
- up->handle = 0;
- msyslog(LOG_ERR,
- "refclock_nmea: time_pps_create failed: %m");
- return (1);
- }
- return(nmea_ppsapi(peer, 0, 0, NULL));
-#else
+ return (refclock_ppsapi(fd, &up->atom));
+#else /* HAVE_PPSAPI */
return (1);
#endif /* HAVE_PPSAPI */
}
pp = peer->procptr;
up = (struct nmeaunit *)pp->unitptr;
-#ifdef HAVE_PPSAPI
- if (NULL != up && up->handle)
- time_pps_destroy(up->handle);
-#endif /* HAVE_PPSAPI */
io_closeclock(&pp->io);
- if (NULL != up)
- free(up);
+ free(up);
}
-#ifdef HAVE_PPSAPI
/*
- * nmea_control - fudge control
+ * nmea_timer - called once per second, fetches PPS
+ * timestamp and stuffs in median filter.
*/
+#ifdef HAVE_PPSAPI
static void
-nmea_control(
- int unit, /* unit (not used */
- struct refclockstat *in, /* input parameters (not uded) */
- struct refclockstat *out, /* output parameters (not used) */
- struct peer *peer /* peer structure pointer */
+nmea_timer(
+ int unit,
+ struct peer * peer
)
{
+ struct nmeaunit *up;
struct refclockproc *pp;
- pp = peer->procptr;
- nmea_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
- pp->sloppyclockflag & CLK_FLAG3, &(pp->fudgetime1));
-}
-
-
-/*
- * Initialize PPSAPI
- */
-int
-nmea_ppsapi(
- struct peer *peer, /* peer structure pointer */
- int enb_clear, /* clear enable */
- int enb_hardpps, /* hardpps enable */
- double *fudge /* fudge value for time1 */
- )
-{
- struct refclockproc *pp;
- struct nmeaunit *up;
- int capability;
+ UNUSED_ARG(unit);
pp = peer->procptr;
up = (struct nmeaunit *)pp->unitptr;
- if (time_pps_getcap(up->handle, &capability) < 0) {
- msyslog(LOG_ERR,
- "refclock_nmea: time_pps_getcap failed: %m");
- return (0);
- }
- memset(&up->pps_params, 0, sizeof(pps_params_t));
- up->pps_params.api_version = PPS_API_VERS_1;
- if (enb_clear)
- up->pps_params.mode = capability & PPS_CAPTURECLEAR;
- else
- up->pps_params.mode = capability & PPS_CAPTUREASSERT;
- if (!up->pps_params.mode) {
- msyslog(LOG_ERR,
- "refclock_nmea: invalid capture edge %d",
- !enb_clear);
- return (0);
- }
- up->pps_params.mode |= PPS_TSFMT_TSPEC;
-
- /* Fudge time1 onto the pps in the kernel */
- if ((enb_hardpps) && (fudge != NULL )) {
- if (!enb_clear && (capability & PPS_OFFSETASSERT)) {
- /* Offset on assert */
- up->pps_params.mode |= PPS_OFFSETASSERT;
- up->pps_params.assert_off_tu.tspec.tv_sec =
- (time_t)(-*fudge);
- up->pps_params.assert_off_tu.tspec.tv_nsec = (long)
- ((*fudge - (long)*fudge) * -1e9);
- } else if (enb_clear && (capability & PPS_OFFSETCLEAR)) {
- /* Offset on clear */
- up->pps_params.mode |= PPS_OFFSETCLEAR;
- up->pps_params.clear_off_tu.tspec.tv_sec =
- (time_t)(-*fudge);
- up->pps_params.clear_off_tu.tspec.tv_nsec = (long)
- ((*fudge - (long)*fudge) * -1e9);
- }
- }
-
- if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
- msyslog(LOG_ERR,
- "refclock_nmea: time_pps_setparams failed: %m");
- return (0);
- }
- if (enb_hardpps) {
- if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
- up->pps_params.mode & 0x0F,
- PPS_TSFMT_TSPEC) < 0) {
- msyslog(LOG_ERR,
- "refclock_nmea: time_pps_kcbind failed: %m");
- return (0);
+
+ if (pp->sloppyclockflag & CLK_FLAG1) {
+ if (refclock_pps(peer, &up->atom, pp->sloppyclockflag) >
+ 0) {
+ up->pcount++,
+ peer->flags |= FLAG_PPS;
}
- pps_enable = 1;
- }
- peer->precision = PPS_PRECISION;
-
-#if DEBUG
- if (debug) {
- time_pps_getparams(up->handle, &up->pps_params);
- printf(
- "refclock_ppsapi: capability 0x%x version %d mode 0x%x kern %d\n",
- capability, up->pps_params.api_version,
- up->pps_params.mode, enb_hardpps);
}
-#endif
-
- return (1);
}
+#endif /* HAVE_PPSAPI */
-/*
- * Get PPSAPI timestamps.
- *
- * Return 0 on failure and 1 on success.
- */
-static int
-nmea_pps(
- struct nmeaunit *up,
- l_fp *tsptr
- )
-{
- pps_info_t pps_info;
- struct timespec timeout, ts;
- double dtemp;
- l_fp tstmp;
-
- /*
- * Convert the timespec nanoseconds field to ntp l_fp units.
- */
- if (up->handle == 0)
- return (0);
- timeout.tv_sec = 0;
- timeout.tv_nsec = 0;
- memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
- if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
- &timeout) < 0)
- return (0);
- if (up->pps_params.mode & PPS_CAPTUREASSERT) {
- if (pps_info.assert_sequence ==
- up->pps_info.assert_sequence)
- return (0);
- ts = up->pps_info.assert_timestamp;
- } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
- if (pps_info.clear_sequence ==
- up->pps_info.clear_sequence)
- return (0);
- ts = up->pps_info.clear_timestamp;
- } else {
- return (0);
- }
- if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
- return (0);
- up->ts = ts;
-
- tstmp.l_ui = (int32)(ts.tv_sec + JAN_1970);
- dtemp = ts.tv_nsec * FRAC / 1e9;
- tstmp.l_uf = (u_int32)dtemp;
- *tsptr = tstmp;
- return (1);
-}
-#endif /* HAVE_PPSAPI */
/*
* nmea_receive - receive data from the serial interface
cp = pp->a_lastcode;
pp->lastrec = up->tstamp = rd_timestamp;
- up->pollcnt = 2;
DPRINTF(1, ("nmea: timecode %d %s\n", pp->lencode, pp->a_lastcode));
cp = dp = NULL;
}
- /*
- * Blanking everything after the decimal point '.' is easy and
- * gives enough error for at least a few neighbors to be as
- * likely as you to be the one with the reflock. We're keeping
- * degrees and minutes but tossing the seconds (expressed as
- * decimal fractions of a minute). Degrees minutes seconds,
- * not hours minutes seconds. :)
- */
+ /* Blank the entire latitude & longitude. */
while (cp) {
while (',' != *cp) {
if ('.' != *cp)
cp++;
}
- /*
- * blank the longitude at cp then the latitude at dp
- * then we're done.
- */
+ /* Longitude at cp then latitude at dp */
if (cp < dp)
cp = dp;
else
cp = NULL;
}
- /*
- * blank the checksum, last two characters on the line
- */
+ /* Blank the checksum, the last two characters */
if (dp) {
cp = pp->a_lastcode + pp->lencode - 2;
if (0 == cp[2])
}
-#ifdef HAVE_PPSAPI
- /*
- * If the PPSAPI is working, rather use its timestamps.
- * assume that the PPS occurs on the second so blow any msec
- */
- if (nmea_pps(up, &rd_timestamp) == 1) {
- pp->lastrec = up->tstamp = rd_timestamp;
- pp->nsec = 0;
- }
-#endif /* HAVE_PPSAPI */
-
/*
- * Process the new sample in the median filter and determine the
- * reference clock offset and dispersion. We use lastrec as both
- * the reference time and receive time, in order to avoid being
- * cute, like setting the reference time later than the receive
- * time, which may cause a paranoid protocol module to chuck out
- * the data.
- */
-
- if (!refclock_process(pp)) {
- refclock_report(peer, CEVNT_BADTIME);
- return;
- }
-
- /*
- * Note that we're only using GPS timescale from now on.
+ * Note if we're only using GPS timescale from now on.
*/
if (cmdtypezdg && !up->gps_time) {
up->gps_time = 1;
}
/*
- * Only go on if we had been polled.
+ * Process the new sample in the median filter and determine the
+ * timecode timestamp, but only if the PPS is not in control.
*/
- if (!up->polled)
+#ifdef HAVE_PPSAPI
+ up->tcount++;
+ if (peer->flags & FLAG_PPS)
return;
- up->polled = 0;
- pp->lastref = pp->lastrec;
- refclock_receive(peer);
-
- /* If we get here - what we got from the clock is OK, so say so */
- refclock_report(peer, CEVNT_NOMINAL);
-
- record_clock_stats(&peer->srcadr, pp->a_lastcode);
+#endif /* HAVE_PPSAPI */
+ if (!refclock_process(pp))
+ refclock_report(peer, CEVNT_BADTIME);
}
pp = peer->procptr;
up = (struct nmeaunit *)pp->unitptr;
- if (up->pollcnt == 0)
- refclock_report(peer, CEVNT_TIMEOUT);
- else
- up->pollcnt--;
+
+ /*
+ * Process median filter samples. If none received, declare a
+ * timeout and keep going.
+ */
+#ifdef HAVE_PPSAPI
+ if (up->pcount == 0)
+ peer->flags &= ~FLAG_PPS;
+ if (up->tcount == 0) {
+ pp->coderecv = pp->codeproc;
+ refclock_report(peer, CEVNT_TIMEOUT);
+ return;
+ }
+ up->pcount = up->tcount = 0;
+#else /* HAVE_PPSAPI */
+ if (pp->coderecv == pp->codeproc) {
+ refclock_report(peer, CEVNT_TIMEOUT);
+ return;
+ }
+#endif /* HAVE_PPSAPI */
+
pp->polls++;
- up->polled = 1;
+ pp->lastref = pp->lastrec;
+ refclock_receive(peer);
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
/*
* usually nmea_receive can get a timestamp every second,
}
#else
int refclock_nmea_bs;
-#endif /* REFCLOCK */
+#endif /* REFCLOCK && CLOCK_NMEA */