summaryrefslogtreecommitdiff
path: root/ppsthread.c
diff options
context:
space:
mode:
authorGary E. Miller <gem@rellim.com>2015-03-30 12:08:47 -0700
committerGary E. Miller <gem@rellim.com>2015-03-30 14:25:08 -0700
commit00bddf3b6bf0f376771963e62df0c0d099f0be2e (patch)
tree6344bccc68fce76150295c9381cdf9fec8964d83 /ppsthread.c
parent28bf37132d86cc59320e21d843960d086cef664c (diff)
downloadgpsd-00bddf3b6bf0f376771963e62df0c0d099f0be2e.tar.gz
Don't throw the baby out with the bathwater.
'reverting' 4336209683d0f5927e32a4edf9131a17e1618253
Diffstat (limited to 'ppsthread.c')
-rw-r--r--ppsthread.c579
1 files changed, 354 insertions, 225 deletions
diff --git a/ppsthread.c b/ppsthread.c
index 6ab332b4..dcc84bcf 100644
--- a/ppsthread.c
+++ b/ppsthread.c
@@ -65,8 +65,6 @@ struct timespec
long tv_nsec; /* Nanoseconds. */
};
/*@+matchfields@*/
-extern int pthread_mutex_lock (pthread_mutex_t *__mutex);
-extern int pthread_mutex_unlock (pthread_mutex_t *__mutex);
#else
#include <pthread.h>
#include <sys/socket.h>
@@ -93,16 +91,27 @@ extern int pthread_mutex_unlock (pthread_mutex_t *__mutex);
*/
#include <sys/ioctl.h>
+#include <pthread.h> /* pacifies OpenBSD's compiler */
#if defined(HAVE_SYS_TIMEPPS_H)
#include <glob.h>
#endif
#if defined(TIOCMIWAIT)
-static int get_edge_tiocmiwait( volatile struct pps_thread_t *,
- struct timespec *, int *,
+static int get_edge_tiocmiwait( volatile struct pps_thread_t *,
+ struct timespec *, int *,
volatile struct timedelta_t *);
#endif /* TIOCMIWAIT */
+#if defined(HAVE_SYS_TIMEPPS_H)
+static int get_edge_rfc2783( volatile struct pps_thread_t *,
+ bool ,
+ struct timespec *,
+ int *,
+ struct timespec *,
+ int *,
+ volatile struct timedelta_t *);
+#endif /* defined(HAVE_SYS_TIMEPPS_H) */
+
/* normalize a timespec
*
* three cases to note
@@ -149,15 +158,17 @@ static inline void TS_NORM( struct timespec *ts)
TS_NORM( r ); \
} while (0)
-/*@i1@*/static pthread_mutex_t ppslast_mutex = PTHREAD_MUTEX_INITIALIZER;
+/*@-type@*/
+static pthread_mutex_t ppslast_mutex = PTHREAD_MUTEX_INITIALIZER;
+/*@+type@*/
#if defined(HAVE_SYS_TIMEPPS_H)
-/*@-unrecog@*/
static int init_kernel_pps(volatile struct pps_thread_t *pps_thread)
/* return handle for kernel pps, or -1; requires root privileges */
{
#ifndef S_SPLINT_S
pps_params_t pp;
+ int pps_caps;
#endif /* S_SPLINT_S */
int ret;
#ifdef __linux__
@@ -173,6 +184,7 @@ static int init_kernel_pps(volatile struct pps_thread_t *pps_thread)
* This next code block abuses "ret" by storing the filedescriptor
* to use for RFC2783 calls.
*/
+ ret = -1;
#ifdef __linux__
/*
* Some Linuxes, like the RasbPi's, have PPS devices preexisting.
@@ -256,7 +268,7 @@ static int init_kernel_pps(volatile struct pps_thread_t *pps_thread)
char errbuf[BUFSIZ] = "unknown error";
(void)strerror_r(errno, errbuf, sizeof(errbuf));
pps_thread->log_hook(pps_thread, THREAD_INF,
- "KPPS:%s cannot open %s: %s\n",
+ "KPPS:%s cannot open %s: %s\n",
pps_thread->devicename,
path, errbuf);
return -1;
@@ -278,6 +290,7 @@ static int init_kernel_pps(volatile struct pps_thread_t *pps_thread)
pps_thread->devicename, path,
ret);
+#ifndef S_SPLINT_S
/* RFC 2783 implies the time_pps_setcap() needs priviledges *
* keep root a tad longer just in case */
if ( 0 > time_pps_create(ret, (pps_handle_t *)&pps_thread->kernelpps_handle )) {
@@ -289,22 +302,22 @@ static int init_kernel_pps(volatile struct pps_thread_t *pps_thread)
ret, errbuf);
return -1;
}
-#ifndef S_SPLINT_S
+
/* have kernel PPS handle */
- int pps_caps;
/* get RFC2783 features supported */
+ pps_caps = 0;
if ( 0 > time_pps_getcap(pps_thread->kernelpps_handle, &pps_caps)) {
pps_caps = 0;
pps_thread->log_hook(pps_thread, THREAD_ERROR,
"KPPS:%s time_pps_getcap() failed\n",
pps_thread->devicename);
+ return -1;
} else {
- pps_thread->log_hook(pps_thread, THREAD_INF,
- "KPPS:%s pps_caps 0x%02X\n",
+ pps_thread->log_hook(pps_thread, THREAD_INF,
+ "KPPS:%s pps_caps 0x%02X\n",
pps_thread->devicename,
pps_caps);
}
-#endif /* S_SPLINT_S */
/* construct the setparms structure */
memset( (void *)&pp, 0, sizeof(pps_params_t));
@@ -345,24 +358,24 @@ static int init_kernel_pps(volatile struct pps_thread_t *pps_thread)
char errbuf[BUFSIZ] = "unknown error";
(void)strerror_r(errno, errbuf, sizeof(errbuf));
pps_thread->log_hook(pps_thread, THREAD_ERROR,
- "KPPS:%s time_pps_setparams(mode=0x%02X) failed: %s\n",
+ "KPPS:%s time_pps_setparams(mode=0x%02X) failed: %s\n",
pps_thread->devicename, pp.mode,
errbuf);
(void)time_pps_destroy(pps_thread->kernelpps_handle);
return -1;
}
+#endif /* S_SPLINT_S */
return 0;
}
-/*@+unrecog@*/
#endif /* defined(HAVE_SYS_TIMEPPS_H) */
#if defined(TIOCMIWAIT)
-/* wait for, and get, an edge using TIOCMIWAIT
+/* wait for, and get, an edge using TIOCMIWAIT
* return -1 for error
* 0 for OK
*/
static int get_edge_tiocmiwait( volatile struct pps_thread_t *thread_context,
- struct timespec *clock_ts,
+ struct timespec *clock_ts,
int *state,
volatile struct timedelta_t *last_fixtime)
{
@@ -400,17 +413,18 @@ static int get_edge_tiocmiwait( volatile struct pps_thread_t *thread_context,
}
/*
- * Start of time critical section
+ * Start of time critical section
* Only error reporting, not success reporting in critical section
*/
+ /* duplicate copy in get_edge_rfc2783 */
/* quick, grab a copy of last_fixtime before it changes */
pthread_err = pthread_mutex_lock(&ppslast_mutex);
if ( 0 != pthread_err ) {
char errbuf[BUFSIZ] = "unknown error";
(void)strerror_r(errno, errbuf, sizeof(errbuf));
thread_context->log_hook(thread_context, THREAD_ERROR,
- "TPPS:%s pthread_mutex_lock() : %s\n",
+ "TPPS:%s pthread_mutex_lock() : %s\n",
thread_context->devicename, errno, errbuf);
}
*last_fixtime = thread_context->fixin;
@@ -419,29 +433,28 @@ static int get_edge_tiocmiwait( volatile struct pps_thread_t *thread_context,
char errbuf[BUFSIZ] = "unknown error";
(void)strerror_r(errno, errbuf, sizeof(errbuf));
thread_context->log_hook(thread_context, THREAD_ERROR,
- "TPPS:%s pthread_mutex_unlock() : %s\n",
+ "TPPS:%s pthread_mutex_unlock() : %s\n",
thread_context->devicename, errno, errbuf);
}
+ /* end duplicate copy in get_edge_rfc2783 */
/* get the time after we just woke up */
if ( 0 > clock_gettime(CLOCK_REALTIME, clock_ts) ) {
/* uh, oh, can not get time! */
thread_context->log_hook(thread_context, THREAD_ERROR,
- "PPS:%s clock_gettime() failed\n",
+ "TPPS:%s clock_gettime() failed\n",
thread_context->devicename);
return -1;;
}
-
+
/* got the edge, got the time just after the edge, now quickly
* get the edge state */
- /*@+ignoresigns@*/
- if (ioctl(thread_context->devicefd, TIOCMGET, state) != 0) {
+ if (ioctl(thread_context->devicefd, (unsigned long)TIOCMGET, state) != 0) {
thread_context->log_hook(thread_context, THREAD_ERROR,
"TPPS:%s ioctl(TIOCMGET) failed\n",
thread_context->devicename);
return -1;
}
- /*@-ignoresigns@*/
/* end of time critical section */
/* mask for monitored lines */
@@ -457,52 +470,206 @@ static int get_edge_tiocmiwait( volatile struct pps_thread_t *thread_context,
#endif /* TIOCMIWAIT */
-/*@-mustfreefresh -type -unrecog -branchstate@*/
+#if defined(HAVE_SYS_TIMEPPS_H)
+/* wait for, and get, last two edges using RFC2783
+ * return -1 for error
+ * 0 for OK
+ * 1 no edge found, continue
+ *
+ * on a quad core 2.4GHz Xeon using KPPS timestamp instead of plain
+ * PPS timestamp removes about 20uS of latency, and about +/-5uS
+ * of jitter
+ */
+static int get_edge_rfc2783( volatile struct pps_thread_t *thread_context,
+ bool pps_canwait,
+ struct timespec *prev_clock_ts,
+ int *prev_edge,
+ struct timespec *clock_ts,
+ int *edge,
+ volatile struct timedelta_t *last_fixtime)
+{
+#ifndef S_SPLINT_S
+ pps_info_t pi;
+ char ts_str1[TIMESPEC_LEN], ts_str2[TIMESPEC_LEN];
+#endif /* S_SPLINT_S */
+ struct timespec kernelpps_tv;
+
+ if ( pps_canwait ) {
+ /*
+ * RFC2783 specifies that a NULL timeval means to wait, if
+ * PPS_CANWAIT is available.
+ *
+ * since we pps_canwait, we skipped the TIOMCIWAIT
+ *
+ * 3 second time out, some GPS output 0.5Hz and some RFC2783
+ * can only trigger on one edge
+ * a better and more complex solution would be to wait
+ * for 1/20 second and suffer the cycles
+ */
+ kernelpps_tv.tv_sec = 3;
+ kernelpps_tv.tv_nsec = 0;
+ } else {
+ /*
+ * We use of a non-NULL zero timespec here,
+ * which means to return immediately with -1 (section
+ * 3.4.3). This is because we know we just got a pulse because
+ * TIOCMIWAIT just woke up.
+ * The timestamp has already been captured in the kernel, and we
+ * are merely fetching it here.
+ */
+ memset( (void *)&kernelpps_tv, 0, sizeof(kernelpps_tv));
+ }
+#ifndef S_SPLINT_S
+ memset( (void *)&pi, 0, sizeof(pi)); /* paranoiia, and to shutup splint */
+ if ( 0 > time_pps_fetch(thread_context->kernelpps_handle, PPS_TSFMT_TSPEC
+ , &pi, &kernelpps_tv)) {
+
+ char errbuf[BUFSIZ] = "unknown error";
+ (void)strerror_r(errno, errbuf, sizeof(errbuf));
+ thread_context->log_hook(thread_context, THREAD_ERROR,
+ "KPPS:%s kernel PPS failed %s\n",
+ thread_context->devicename, errbuf);
+ if ( ETIMEDOUT == errno || EINTR == errno ) {
+ /* just a timeout */
+ return 1;
+ }
+ return 0;
+ }
+#endif /* S_SPLINT_S */
+ if ( pps_canwait ) {
+ int pthread_err; /* return code from pthread functions */
+
+ /* get_edge_tiocmiwait() got this if !pps_canwait */
+
+ /* duplicate copy in get_edge_tiocmiwait */
+ /* quick, grab a copy of last_fixtime before it changes */
+ pthread_err = pthread_mutex_lock(&ppslast_mutex);
+ if ( 0 != pthread_err ) {
+ char errbuf[BUFSIZ] = "unknown error";
+ (void)strerror_r(errno, errbuf, sizeof(errbuf));
+ thread_context->log_hook(thread_context, THREAD_ERROR,
+ "TPPS:%s pthread_mutex_lock() : %s\n",
+ thread_context->devicename, errno, errbuf);
+ }
+ *last_fixtime = thread_context->fixin;
+ pthread_err = pthread_mutex_unlock(&ppslast_mutex);
+ if ( 0 != pthread_err ) {
+ char errbuf[BUFSIZ] = "unknown error";
+ (void)strerror_r(errno, errbuf, sizeof(errbuf));
+ thread_context->log_hook(thread_context, THREAD_ERROR,
+ "TPPS:%s pthread_mutex_unlock() : %s\n",
+ thread_context->devicename, errno, errbuf);
+ }
+ /* end duplicate copy in get_edge_tiocmiwait */
+ }
+
+
+#ifndef S_SPLINT_S
+ // find the last edge
+ if ( pi.assert_timestamp.tv_sec > pi.clear_timestamp.tv_sec ) {
+ /* assert 1 sec or more after than clear */
+ *edge = 1;
+ } else if ( pi.assert_timestamp.tv_sec < pi.clear_timestamp.tv_sec ) {
+ /* assert 1 sec or more before than clear */
+ *edge = 0;
+ } else if ( pi.assert_timestamp.tv_nsec > pi.clear_timestamp.tv_nsec ) {
+ /* assert less than 1 sec after clear */
+ *edge = 1;
+ } else {
+ /* assert less than 1 sec before clear */
+ *edge = 0;
+ }
+ if ( 1 == *edge ) {
+ /* assert after clear */
+ *prev_edge = 0;
+ if ( 0 == pi.clear_timestamp.tv_sec ) {
+ /* brain damaged pps-gpio sometimes never fills in clear
+ * so make it look like an invisible pulse
+ * if clear is the leading edge, then we are off by the
+ * pulse width */
+ *prev_clock_ts = pi.assert_timestamp;
+ } else {
+ *prev_clock_ts = pi.clear_timestamp;
+ }
+ *clock_ts = pi.assert_timestamp;
+ } else {
+ /* assert before clear */
+ *prev_edge = 1;
+ *prev_clock_ts = pi.assert_timestamp;
+ *clock_ts = pi.clear_timestamp;
+ }
+ /*
+ * pps_seq_t is uint32_t on NetBSD, so cast to
+ * unsigned long as a wider-or-equal type to
+ * accomodate Linux's type.
+ */
+ timespec_str( &pi.assert_timestamp, ts_str1, sizeof(ts_str1) );
+ timespec_str( &pi.clear_timestamp, ts_str2, sizeof(ts_str2) );
+ thread_context->log_hook(thread_context, THREAD_PROG,
+ "KPP:%s assert %s, sequence: %ld - "
+ "clear %s, sequence: %ld\n",
+ thread_context->devicename,
+ ts_str1,
+ (unsigned long) pi.assert_sequence,
+ ts_str2,
+ (unsigned long) pi.clear_sequence);
+#endif /* S_SPLINT_S */
+ thread_context->log_hook(thread_context, THREAD_PROG,
+ "KPPS:%s data: last edge %s\n",
+ thread_context->devicename,
+ *edge ? "assert" : "clear");
+
+ return 0;
+}
+#endif /* defined(HAVE_SYS_TIMEPPS_H) */
+
static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
{
char ts_str1[TIMESPEC_LEN], ts_str2[TIMESPEC_LEN];
volatile struct pps_thread_t *thread_context = (struct pps_thread_t *)arg;
- /* the system clock time, to the nSec, when the last fix received */
- /* using a double would cause loss of precision */
+ /* the GPS time and system clock timme, to the nSec,
+ * when the last fix received
+ * using a double would cause loss of precision */
volatile struct timedelta_t last_fixtime = {{0, 0}, {0, 0}};
struct timespec clock_ts = {0, 0};
time_t last_second_used = 0;
-#if defined(TIOCMIWAIT)
- int cycle, duration;
+ long cycle = 0, duration = 0;
/* state is the last state of the tty control signals */
- int state = 0, unchanged = 0;
+ int state = 0;
+ /* count of how many cycles unchanged data */
+ int unchanged = 0;
/* state_last is previous state */
int state_last = 0;
- /* pulse stores the time of the last two edges */
- struct timespec pulse[2] = { {0, 0}, {0, 0} };
/* edge, used as index into pulse to find previous edges */
int edge = 0; /* 0 = clear edge, 1 = assert edge */
+
+#if defined(TIOCMIWAIT)
+ int edge_tio = 0;
+ long cycle_tio = 0;
+ long duration_tio = 0;
+ int state_tio = 0;
+ int state_last_tio = 0;
+ struct timespec clock_ts_tio = {0, 0};
+ /* pulse stores the time of the last two edges */
+ struct timespec pulse_tio[2] = { {0, 0}, {0, 0} };
#endif /* TIOCMIWAIT */
+
#if defined(HAVE_SYS_TIMEPPS_H)
#ifndef S_SPLINT_S
int pps_caps;
- int edge_kpps = 0; /* 0 = clear edge, 1 = assert edge */
- int cycle_kpps, duration_kpps;
+#endif /* S_SPLINT_S */
+ long cycle_kpps = 0, duration_kpps = 0;
/* kpps_pulse stores the time of the last two edges */
struct timespec pulse_kpps[2] = { {0, 0}, {0, 0} };
- struct timespec ts_kpps;
- pps_info_t pi;
-#endif /* S_SPLINT_S */
#endif /* defined(HAVE_SYS_TIMEPPS_H) */
/* pthread error return */
- int pthread_err;
+ int pthread_err;
bool not_a_tty = false;
bool pps_canwait = false;
-#if defined(HAVE_SYS_TIMEPPS_H)
-#ifndef S_SPLINT_S
- memset( (void *)&pi, 0, sizeof(pps_info_t));
-#endif /* S_SPLINT_S */
-#endif /* defined(HAVE_SYS_TIMEPPS_H) */
-
if ( isatty(thread_context->devicefd) == 0 ) {
- thread_context->log_hook(thread_context, THREAD_INF,
- "KPPS:%s gps_fd:%d not a tty\n",
+ thread_context->log_hook(thread_context, THREAD_INF,
+ "KPPS:%s gps_fd:%d not a tty\n",
thread_context->devicename,
thread_context->devicefd);
/* why do we care the device is a tty? so as not to ioctl(TIO..)
@@ -514,24 +681,28 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
#ifndef S_SPLINT_S
#if defined(HAVE_SYS_TIMEPPS_H)
/* get RFC2783 features supported */
- if ( 0 > time_pps_getcap(thread_context->kernelpps_handle, &pps_caps)) {
+ pps_caps = 0;
+ if ( 0 <= thread_context->kernelpps_handle ) {
+ /* no pps handle to use, thus no caps */
+ pps_caps = 0;
+ } else if ( 0 > time_pps_getcap(thread_context->kernelpps_handle, &pps_caps)) {
pps_caps = 0;
thread_context->log_hook(thread_context, THREAD_ERROR,
"KPPS:%s time_pps_getcap() failed\n",
thread_context->devicename);
} else {
- thread_context->log_hook(thread_context, THREAD_INF,
- "KPPS:%s pps_caps 0x%02X\n",
+ thread_context->log_hook(thread_context, THREAD_INF,
+ "KPPS:%s pps_caps 0x%02X\n",
thread_context->devicename,
pps_caps);
}
if ( 0 != (PPS_CANWAIT & pps_caps ) ) {
- /* we can wait! */
+ /* we can wait! so no need for TIOCMIWAIT */
thread_context->log_hook(thread_context, THREAD_PROG,
"KPPS:%s have PPS_CANWAIT\n",
thread_context->devicename);
- // pps_canwait = true; // broken now,
+ pps_canwait = true;
}
#endif /* HAVE_SYS_TIMEPPS_H */
#endif /* S_SPLINT_S */
@@ -546,7 +717,7 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
* we do not want to be spinning waiting for the trailing edge of
* a pulse. The only assumption here is that no GPS lights up more
* than one of these pins. By waiting on all of them we remove a
- * configuration switch.
+ * configuration switch.
*
* Once we have the latest edge we compare it to the last edge which we
* stored. If the edge passes sanity checks we pass is out through
@@ -555,12 +726,6 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
while (thread_context->report_hook != NULL
|| thread_context->pps_hook != NULL) {
bool ok = false;
-#ifndef S_SPLINT_S
-#if defined(HAVE_SYS_TIMEPPS_H)
- // cppcheck-suppress variableScope
- bool ok_kpps = false;
-#endif /* HAVE_SYS_TIMEPPS_H */
-#endif /* S_SPLINT_S */
char *log = NULL;
#if defined(TIOCMIWAIT)
@@ -570,136 +735,125 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
/* we are a tty, so can TIOCMIWAIT */
/* we have no PPS_CANWAIT, so must TIOCMIWAIT */
- ret = get_edge_tiocmiwait( thread_context, &clock_ts, &state,
- &last_fixtime );
+ ret = get_edge_tiocmiwait( thread_context, &clock_ts_tio,
+ &state_tio, &last_fixtime );
if ( 0 != ret ) {
+ thread_context->log_hook(thread_context, THREAD_PROG,
+ "PPS:%s die: TIOCMIWAIT Error\n",
+ thread_context->devicename);
break;
}
-
- edge = (state > state_last) ? 1 : 0;
+
+ edge_tio = (state_tio > state_last_tio) ? 1 : 0;
/* three things now known about the current edge:
* clock_ts - time of the edge
* state - the serial line input states
* edge - rising edge (1), falling edge (0) or invisble edge (0)
*/
+
+ /* calculate cycle and duration from previsou edges */
+ cycle_tio = timespec_diff_ns(clock_ts_tio, pulse_tio[edge_tio]);
+ cycle_tio /= 1000; /* nsec to usec */
+ duration_tio = timespec_diff_ns(clock_ts_tio,
+ pulse_tio[edge_tio ? 0 : 1])/1000;
+
+ /* save this edge so we know next cycle time */
+ pulse_tio[edge_tio] = clock_ts_tio;
+
+ /* use this data */
+ ok = true;
+ state = edge_tio;
+ edge = edge_tio;
+ cycle = cycle_tio;
+ duration = duration_tio;
+
+ timespec_str( &clock_ts_tio, ts_str1, sizeof(ts_str1) );
+ thread_context->log_hook(thread_context, THREAD_PROG,
+ "TPPS:%s TIOCMIWAIT, cycle: %d, duration: %d, edge:%d @ %s\n",
+ thread_context->devicename, cycle, duration, edge,
+ ts_str1);
+
}
#endif /* TIOCMIWAIT */
/* ok and log used by KPPS and TIOCMIWAIT */
// cppcheck-suppress redundantAssignment
- ok = false;
- log = NULL;
-#if defined(HAVE_SYS_TIMEPPS_H) && !defined(S_SPLINT_S)
+ ok = false;
+ log = NULL;
+#if defined(HAVE_SYS_TIMEPPS_H)
if ( 0 <= thread_context->kernelpps_handle ) {
- struct timespec kernelpps_tv;
- /* on a quad core 2.4GHz Xeon using KPPS timestamp instead of plain
- * PPS timestamp removes about 20uS of latency, and about +/-5uS
- * of jitter
+ int ret;
+ int edge_kpps = 0; /* 0 = clear edge, 1 = assert edge */
+ /* time of the last edge */
+ struct timespec clock_ts_kpps = {0, 0};
+ /* time of the edge before the last edge */
+ struct timespec prev_clock_ts = {0, 0};
+ /* direction of next to last edge 1 = assert, 0 = clear */
+ int prev_edge = 0;
+
+ /* get last and previsou edges, in order
+ * optionally wait for goood data
*/
- if ( pps_canwait ) {
- /*
- * RFC2783 specifies that a NULL timeval means to wait, if
- * PPS_CANWAIT is available.
- *
- * since we pps_canwait, we skipped the TIOMCIWAIT
- *
- * 3 second time out, some GPS output 0.5Hz and some RFC2783
- * can only trigger on one edge
- * a better and more complex solution would be to wait
- * for 1/20 second and suffer the cycles
- */
- kernelpps_tv.tv_sec = 3;
- kernelpps_tv.tv_nsec = 0;
- } else {
- /*
- * We use of a non-NULL zero timespec here,
- * which means to return immediately with -1 (section
- * 3.4.3). This is because we know we just got a pulse because
- * TIOCMIWAIT just woke up.
- * The timestamp has already been captured in the kernel, and we
- * are merely fetching it here.
- */
- memset( (void *)&kernelpps_tv, 0, sizeof(kernelpps_tv));
- }
- if ( 0 > time_pps_fetch(thread_context->kernelpps_handle, PPS_TSFMT_TSPEC
- , &pi, &kernelpps_tv)) {
-
- char errbuf[BUFSIZ] = "unknown error";
- (void)strerror_r(errno, errbuf, sizeof(errbuf));
- thread_context->log_hook(thread_context, THREAD_ERROR,
- "KPPS:%s kernel PPS failed %s\n",
- thread_context->devicename, errbuf);
- if ( ETIMEDOUT == errno || EINTR == errno ) {
- /* just a timeout */
- continue;
- }
- break;
- } else {
- // find the last edge
- // FIXME a bit simplistic, should hook into the
- // cycle/duration check below.
- if ( pi.assert_timestamp.tv_sec > pi.clear_timestamp.tv_sec ) {
- edge_kpps = 1;
- ts_kpps = pi.assert_timestamp;
- } else if ( pi.assert_timestamp.tv_sec < pi.clear_timestamp.tv_sec ) {
- edge_kpps = 0;
- ts_kpps = pi.clear_timestamp;
- } else if ( pi.assert_timestamp.tv_nsec > pi.clear_timestamp.tv_nsec ) {
- edge_kpps = 1;
- ts_kpps = pi.assert_timestamp;
- } else {
- edge_kpps = 0;
- ts_kpps = pi.clear_timestamp;
- }
- /*
- * pps_seq_t is uint32_t on NetBSD, so cast to
- * unsigned long as a wider-or-equal type to
- * accomodate Linux's type.
- */
- timespec_str( &pi.assert_timestamp, ts_str1, sizeof(ts_str1) );
- timespec_str( &pi.clear_timestamp, ts_str2, sizeof(ts_str2) );
- thread_context->log_hook(thread_context, THREAD_PROG,
- "KPP:%s assert %s, sequence: %ld - "
- "clear %s, sequence: %ld\n",
- thread_context->devicename,
- ts_str1,
- (unsigned long) pi.assert_sequence,
- ts_str2,
- (unsigned long) pi.clear_sequence);
+ ret = get_edge_rfc2783( thread_context,
+ pps_canwait,
+ &prev_clock_ts,
+ &prev_edge,
+ &clock_ts_kpps,
+ &edge_kpps,
+ &last_fixtime);
+
+ if ( -1 == ret ) {
+ /* error, so break */
thread_context->log_hook(thread_context, THREAD_PROG,
- "KPPS:%s data: using %s\n",
- thread_context->devicename,
- edge_kpps ? "assert" : "clear");
-
- /* WARNING! this will fail if delta more than a few seconds,
- that should not be the case here */
- cycle_kpps = timespec_diff_ns(ts_kpps, pulse_kpps[edge_kpps])/1000;
- duration_kpps = timespec_diff_ns(ts_kpps, pulse_kpps[(int)(edge_kpps == 0)])/1000;
- timespec_str( &ts_kpps, ts_str1, sizeof(ts_str1) );
- thread_context->log_hook(thread_context, THREAD_PROG,
- "KPPS:%s cycle: %7d uSec, duration: %7d uSec @ %s\n",
- thread_context->devicename,
- cycle_kpps, duration_kpps, ts_str1);
- pulse_kpps[edge_kpps] = ts_kpps;
- if (990000 < cycle_kpps && 1010000 > cycle_kpps) {
- /* KPPS passes a basic sanity check */
- ok_kpps = true;
- }
- }
+ "PPS:%s die: RFC2783 Error\n",
+ thread_context->devicename);
+ break;
+ }
+
+ if ( 1 == ret ) {
+ /* no edge found, so continue */
+ /* maybe use TIOCMIWAIT edge instead?? */
+ continue;
+ }
+ /* for now, as we have been doing all of gpsd 3.x, just
+ *use the last edge, not the previous edge */
+
+ /* compare to previous saved similar edge */
+ cycle_kpps = timespec_diff_ns(clock_ts_kpps, pulse_kpps[edge_kpps]);
+ cycle_kpps /= 1000;
+ duration_kpps = timespec_diff_ns(clock_ts_kpps, prev_clock_ts)/1000;
+
+ timespec_str( &clock_ts_kpps, ts_str1, sizeof(ts_str1) );
+ thread_context->log_hook(thread_context, THREAD_PROG,
+ "KPPS:%s cycle: %7d uSec, duration: %7d uSec @ %s\n",
+ thread_context->devicename,
+ cycle_kpps, duration_kpps, ts_str1);
+
+ /* save for later */
+ pulse_kpps[edge_kpps] = clock_ts_kpps;
+ pulse_kpps[edge_kpps ? 0 : 1] = prev_clock_ts;
+ /* sanity checks are later */
+ log = "KPPS";
+
+ /* use this data */
+ state = edge_kpps;
+ clock_ts = clock_ts_kpps;
+ cycle = cycle_kpps;
+ duration = duration_kpps;
}
-#endif /* defined(HAVE_SYS_TIMEPPS_H) && !defined(S_SPLINT_S) */
+#endif /* defined(HAVE_SYS_TIMEPPS_H) */
+
if ( not_a_tty && !pps_canwait ) {
/* uh, oh, no TIOMCIWAIT, nor RFC2783, die */
+ thread_context->log_hook(thread_context, THREAD_PROG,
+ "PPS:%s die: no TIOMCIWAIT, nor RFC2783 CANWAIT\n",
+ thread_context->devicename);
break;
}
-#if defined(TIOCMIWAIT)
- /*@ +boolint @*/
- cycle = timespec_diff_ns(clock_ts, pulse[edge]) / 1000;
- duration = timespec_diff_ns(clock_ts, pulse[(int)(edge == 0)])/1000;
- /*@ -boolint @*/
+ /* now, validate, using TIOCMIWAIT or RFC2783 values */
if (state == state_last) {
/* some pulses may be so short that state never changes */
if (999000 < cycle && 1001000 > cycle) {
@@ -712,7 +866,7 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
/* not really unchanged, just out of bounds */
unchanged = 1;
thread_context->log_hook(thread_context, THREAD_WARN,
- "PPS:%s TIOCMIWAIT returns unchanged state, ppsmonitor sleeps 10\n",
+ "PPS:%s unchanged state, ppsmonitor sleeps 10\n",
thread_context->devicename);
(void)sleep(10);
}
@@ -723,13 +877,11 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
unchanged = 0;
}
state_last = state;
- /* save this edge so we know next cycle time */
- pulse[edge] = clock_ts;
timespec_str( &clock_ts, ts_str1, sizeof(ts_str1) );
thread_context->log_hook(thread_context, THREAD_PROG,
- "PPS:%s edge: %d, cycle: %7d uSec, duration: %7d uSec @ %s\n",
+ "PPS:%s cycle: %7d uSec, duration: %7d, edge: %d, uSec @ %s\n",
thread_context->devicename,
- edge, cycle, duration, ts_str1);
+ cycle, duration, edge, ts_str1);
if (unchanged) {
// strange, try again
continue;
@@ -777,7 +929,7 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
}
} else if (900000 > cycle) {
/* Yes, 10% window. The Rasberry Pi clock is very coarse
- * when it starts and chronyd may be doing a fast slew.
+ * when it starts and chronyd may be doing a fast slew.
* chronyd by default will slew up to 8.334% !
* Don't worry, ntpd and chronyd will do further sanitizing.*/
log = "Too long for 5Hz, too short for 1Hz\n";
@@ -818,12 +970,6 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
} else {
log = "Too long for 0.5Hz\n";
}
-#endif /* TIOCMIWAIT */
- if ( ok && last_second_used >= last_fixtime.real.tv_sec ) {
- /* uh, oh, this second already handled */
- ok = 0;
- log = "this second already handled\n";
- }
/*
* If there has not yet been any valid in-band time stashed
@@ -834,10 +980,16 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
* fixtime, while autobauding.
*/
if (last_fixtime.real.tv_sec == 0) {
- /* probably should log computed offset jjust for grins here */
- continue;
- }
-
+ /* probably should log computed offset just for grins here */
+ ok = false;
+ log = "missing last_fixtime\n";
+ /*@+longintegral@*/
+ } else if ( ok && last_second_used >= last_fixtime.real.tv_sec ) {
+ /*@-longintegral@*/
+ /* uh, oh, this second already handled */
+ ok = false;
+ log = "this second already handled\n";
+ }
if (ok) {
/* offset is the skew from expected to observed pulse time */
@@ -848,39 +1000,21 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
struct timespec delay;
/* delay as a printable string */
char delay_str[TIMESPEC_LEN];
- /*@observer@*/ char *log1 = NULL;
+ /*@observer@*/ char *log1 = "";
/* ppstimes.real is the time we think the pulse represents */
struct timedelta_t ppstimes;
thread_context->log_hook(thread_context, THREAD_RAW,
- "PPS:%s edge accepted %.100s",
+ "PPS:%s edge accepted %.100s",
thread_context->devicename, log);
-#ifndef S_SPLINT_S
-#if defined(HAVE_SYS_TIMEPPS_H)
- if ( 0 <= thread_context->kernelpps_handle && ok_kpps) {
- /* use KPPS time */
- thread_context->log_hook(thread_context, THREAD_RAW,
- "KPPS:%s using edge %d",
- thread_context->devicename,
- edge_kpps );
- /* pick the right edge */
- if ( edge_kpps ) {
- clock_ts = pi.assert_timestamp; /* structure copy */
- } else {
- clock_ts = pi.clear_timestamp; /* structure copy */
- }
- }
-#endif /* defined(HAVE_SYS_TIMEPPS_H) */
-#endif /* S_SPLINT_S */
- /* else, use plain PPS */
/* This innocuous-looking "+ 1" embodies a significant
* assumption: that GPSes report time to the second over the
* serial stream *after* emitting PPS for the top of second.
* Thus, when we see PPS our available report is from the
- * previous cycle and we must increment.
+ * previous cycle and we must increment.
*
* FIXME! The GR-601W at 38,400 or faster can send the
- * serial fix before the interrupt event carrying the PPS
+ * serial fix before the interrupt event carrying the PPS
* line assertion by about 10 mSec!
*/
@@ -900,7 +1034,7 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
thread_context->devicename,
delay_str);
log1 = "system clock went backwards";
- } else if ( ( 2 < delay.tv_sec)
+ } else if ( ( 2 < delay.tv_sec)
|| ( 1 == delay.tv_sec && 100000000 > delay.tv_nsec ) ) {
/* system clock could be slewing so allow 1.1 sec delay */
thread_context->log_hook(thread_context, THREAD_RAW,
@@ -909,9 +1043,8 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
delay_str);
log1 = "timestamp out of range";
} else {
- /*@-compdef@*/
last_second_used = last_fixtime.real.tv_sec;
- if (thread_context->report_hook != NULL)
+ if (thread_context->report_hook != NULL)
log1 = thread_context->report_hook(thread_context, &ppstimes);
else
log1 = "no report hook";
@@ -922,7 +1055,7 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
char errbuf[BUFSIZ] = "unknown error";
(void)strerror_r(errno, errbuf, sizeof(errbuf));
thread_context->log_hook(thread_context, THREAD_ERROR,
- "PPS:%s pthread_mutex_lock() : %s\n",
+ "PPS:%s pthread_mutex_lock() : %s\n",
thread_context->devicename, errbuf);
}
thread_context->ppsout_last = ppstimes;
@@ -941,38 +1074,35 @@ static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
"PPS:%s hooks called with %.20s clock: %s real: %s\n",
thread_context->devicename,
log1, ts_str1, ts_str2);
- /*@+compdef@*/
}
- /*@-compdef@*/
timespec_str( &clock_ts, ts_str1, sizeof(ts_str1) );
timespec_str( &offset, offset_str, sizeof(offset_str) );
+ /* FIXME? show edge here ? */
thread_context->log_hook(thread_context, THREAD_PROG,
- "PPS:%s edge %.20s @ %s offset %.20s\n",
+ "PPS:%s %.30s @ %s offset %.20s\n",
thread_context->devicename,
log1, ts_str1, offset_str);
- /*@+compdef@*/
} else {
- thread_context->log_hook(thread_context, THREAD_RAW,
- "PPS:%s edge rejected %.100s",
+ thread_context->log_hook(thread_context, THREAD_PROG,
+ "PPS:%s edge rejected %.100s",
thread_context->devicename, log);
}
}
#if defined(HAVE_SYS_TIMEPPS_H)
if (thread_context->kernelpps_handle > 0) {
- thread_context->log_hook(thread_context, THREAD_PROG,
+ thread_context->log_hook(thread_context, THREAD_PROG,
"PPS:%s descriptor cleaned up\n",
thread_context->devicename);
- (void)time_pps_destroy(thread_context->kernelpps_handle);
+ /*@i1@*/(void)time_pps_destroy(thread_context->kernelpps_handle);
}
#endif
if (thread_context->wrap_hook != NULL)
thread_context->wrap_hook(thread_context);
- thread_context->log_hook(thread_context, THREAD_PROG,
+ thread_context->log_hook(thread_context, THREAD_PROG,
"PPS:%s gpsd_ppsmonitor exited.\n",
thread_context->devicename);
return NULL;
}
-/*@+mustfreefresh +type +unrecog +branchstate@*/
/*
* Entry points begin here.
@@ -992,9 +1122,8 @@ void pps_thread_activate(volatile struct pps_thread_t *pps_thread)
pps_thread->devicename);
}
#endif
- /*@-compdef -nullpass -unrecog@*/
- retval = pthread_create(&pt, NULL, gpsd_ppsmonitor, (void *)pps_thread);
- /*@+compdef +nullpass +unrecog@*/
+ memset( &pt, 0, sizeof(pt));
+ /*@i1@*/retval = pthread_create(&pt, NULL, gpsd_ppsmonitor, (void *)pps_thread);
pps_thread->log_hook(pps_thread, THREAD_PROG, "PPS:%s thread %s\n",
pps_thread->devicename,
(retval==0) ? "launched" : "FAILED");
@@ -1003,13 +1132,13 @@ void pps_thread_activate(volatile struct pps_thread_t *pps_thread)
void pps_thread_deactivate(volatile struct pps_thread_t *pps_thread)
/* cleanly terminate PPS thread */
{
- /*@-nullstate -mustfreeonly@*/
+ /*@-mustfreeonly@*/
pps_thread->report_hook = NULL;
+ /*@+mustfreeonly@*/
pps_thread->pps_hook = NULL;
- /*@+nullstate +mustfreeonly@*/
}
-void pps_thread_fixin(volatile struct pps_thread_t *pps_thread,
+void pps_thread_fixin(volatile struct pps_thread_t *pps_thread,
volatile struct timedelta_t *fixin)
/* thread-safe update of last fix time - only way we pass data in */
{
@@ -1018,7 +1147,7 @@ void pps_thread_fixin(volatile struct pps_thread_t *pps_thread,
char errbuf[BUFSIZ] = "unknown error";
(void)strerror_r(errno, errbuf, sizeof(errbuf));
pps_thread->log_hook(pps_thread, THREAD_ERROR,
- "PPS:%s pthread_mutex_lock() : %s\n",
+ "PPS:%s pthread_mutex_lock() : %s\n",
pps_thread->devicename, errbuf);
}
pps_thread->fixin = *fixin;
@@ -1038,14 +1167,14 @@ int pps_thread_ppsout(volatile struct pps_thread_t *pps_thread,
{
volatile int ret;
/* pthread error return */
- int pthread_err;
+ int pthread_err;
pthread_err = pthread_mutex_lock(&ppslast_mutex);
if ( 0 != pthread_err ) {
char errbuf[BUFSIZ] = "unknown error";
(void)strerror_r(errno, errbuf, sizeof(errbuf));
pps_thread->log_hook(pps_thread, THREAD_ERROR,
- "PPS:%s pthread_mutex_lock() : %s\n",
+ "PPS:%s pthread_mutex_lock() : %s\n",
pps_thread->devicename, errbuf);
}
*td = pps_thread->ppsout_last;