Beispiel #1
0
static int do_measure_overhead(const struct rtt_options* opts,
                               struct rtt_endpoint* tx_ep,
                               struct rtt_endpoint* rx_ep)
{
  int n_iters = opts->n_iters;
  struct timespec a, b;
  int i;

  int* results;
  RTT_TEST( results = malloc(n_iters * sizeof(results[0])) );

  /* NB. No need to do warm-ups here as we're only interested in the
   * median.
   */
  for( i = 0; i < n_iters; ++i ) {
    clock_gettime(CLOCK_REALTIME, &a);
    tx_ep->ping(tx_ep);
    rx_ep->pong(rx_ep);
    clock_gettime(CLOCK_REALTIME, &b);
    results[i] = timespec_diff_ns(b, a);
  }

  int median;
  qsort(results, n_iters, sizeof(int), ci_qsort_compare_int);
  ci_iarray_median(results, results + n_iters, &median);
  free(results);
  return median;
}
Beispiel #2
0
/* offset is actual_ts - clock_ts */
static void chrony_send(struct gps_device_t *session, struct timedrift_t *td)
{
    struct sock_sample sample;

    /* chrony expects tv-sec since Jan 1970 */
    sample.pulse = 0;
    sample.leap = session->context->leap_notify;
    sample.magic = SOCK_MAGIC;
    /*@-type@*//* splint is confused about struct timespec */
    TSTOTV(&sample.tv, &td->clock);
    /*@-compdef@*/
    sample.offset = timespec_diff_ns(td->real, td->clock) / 1e9;
    /*@+compdef@*/
#ifdef __COVERITY__
    sample._pad = 0;
#endif /* __COVERITY__ */
    /*@+type@*/

    /*@-type@*/ /* splint is confused about struct timespec */
    gpsd_report(&session->context->errout, LOG_RAW,
		"PPS chrony_send %lu.%09lu @ %lu.%09lu Offset: %0.9f\n",
		(unsigned long)td->real.tv_sec,
		(unsigned long)td->real.tv_nsec,
		(unsigned long)td->clock.tv_sec,
		(unsigned long)td->clock.tv_nsec,
                sample.offset);
    /*@+type@*/
    (void)send(session->chronyfd, &sample, sizeof (sample), 0);
}
Beispiel #3
0
static void do_pinger(const struct rtt_options* opts,
                      struct rtt_endpoint* tx_ep,
                      struct rtt_endpoint* rx_ep)
{
  int overhead = measure_overhead(opts);
  int n_warm_ups = opts->n_warm_ups;
  int n_iters = opts->n_iters;
  int* results;
  int i;

  RTT_TEST( results = malloc(n_iters * sizeof(results[0])) );

  for( i = 0; i < n_warm_ups; ++i ) {
    tx_ep->ping(tx_ep);
    rx_ep->pong(rx_ep);
  }

  if( tx_ep->reset_stats )
    tx_ep->reset_stats(tx_ep);
  if( rx_ep->reset_stats )
    rx_ep->reset_stats(rx_ep);

  /* Touch to ensure resident. */
  memset(results, 0, n_iters * sizeof(results[0]));
  struct timespec start, end;

  for( i = 0; i < n_iters; ++i ) {
    clock_gettime(CLOCK_REALTIME, &start);
    tx_ep->ping(tx_ep);
    rx_ep->pong(rx_ep);
    clock_gettime(CLOCK_REALTIME, &end);
    results[i] = timespec_diff_ns(end, start) - overhead;
    if( opts->inter_iter_gap_ns ) {
      do
        clock_gettime(CLOCK_REALTIME, &start);
      while( timespec_diff_ns(start, end) < opts->inter_iter_gap_ns );
    }
  }

  printf("# measurement_overhead: %d\n", overhead);
  if( tx_ep->dump_info != NULL )
    tx_ep->dump_info(tx_ep, stdout);
  if( rx_ep != tx_ep && rx_ep->dump_info != NULL )
    rx_ep->dump_info(rx_ep, stdout);
  for( i = 0; i < n_iters; ++i )
    printf("%d\n", results[i]);
}
Beispiel #4
0
static void do_warmup()
{
	struct timespec t0, t;
	int i;

	get_current_time(&t0);
	do {
		for (i = 0; i < 100000; i++)
			;
		get_current_time(&t);
	} while (timespec_diff_ns(&t0, &t) < (uint64_t)warmup * 1000000000);
}
Beispiel #5
0
int main(int argc, char **argv) {
    unsigned int exp_universe, big, exp_n, n, n_1, i, j, m, repeats, alpha;
    struct priority_queue *pq, *pq1, *pq2;
    unsigned int *elems;
    unsigned int idx;
    struct timespec before, after;

    if (argc < 6) {
        printf("Usage : run_once exp_universe exp_n percentage filename repetitions big\n");
        printf("Example : run_once 11 5 16 test_file 2 1 will run a test with:\n \t2^16 integers in the range [0,...2^11 - 1]\n\tOne of the structures will hold approximately 16 percent of the elements; the remaining amount will be in the other.\n\tThe test will be repeated (without any change in the input integers) 2 times.\n\tThe test is big so times will be measured in ms.\n");
        exit(1);
    }

    big = atoi(argv[6]);
    exp_universe = atoi(argv[1]); 
    exp_n = atoi(argv[2]); 
    alpha = atoi(argv[3]); 
    repeats = atoi(argv[5]);
    n = 1 << exp_n;

    n_1 = (alpha * n) / 100; 

    elems = gen_instance(argv[4], n, exp_universe);


    for (m = 0; m < repeats; m++) {

    pq1 = pq_new(n_1, exp_universe);
    pq2 = pq_new(n - n_1, exp_universe);


    for (i = 0; i < n_1; i++) {
        pq_insert(pq1, elems[i]);
    }
    for (; i < n; i++) {
        pq_insert(pq2, elems[i]);
    }

    clock_gettime(CLOCK_MONOTONIC, &before);
    pq = pq_merge(pq1, pq2);
    clock_gettime(CLOCK_MONOTONIC, &after);

    if (big) {
        printf("merge: %lldms\n", timespec_diff_ms(after, before));
    } else {
        printf("merge: %lldns\n", timespec_diff_ns(after, before));
    }

    pq_free(pq);
    }
    free(elems);
}
Beispiel #6
0
static uint64_t run_test_once(void *in, size_t size, TEEC_Operation *op,
			  unsigned int l)
{
	struct timespec t0, t1;
	TEEC_Result res;
	uint32_t ret_origin;

	if (random_in)
		read_random(in, size);
	get_current_time(&t0);
	res = TEEC_InvokeCommand(&sess, TA_SHA_PERF_CMD_PROCESS, op,
				 &ret_origin);
	check_res(res, "TEEC_InvokeCommand");
	get_current_time(&t1);

	return timespec_diff_ns(&t0, &t1);
}
Beispiel #7
0
static void ubx_update(void)
{
    unsigned char *buf;
    size_t data_len;
    unsigned short msgid;
#ifdef PPS_ENABLE
    struct timedrift_t drift;
#endif /* PPS_ENABLE */

    buf = session.packet.outbuffer;
    msgid = (unsigned short)((buf[2] << 8) | buf[3]);
    data_len = (size_t) getles16(buf, 4);
    switch (msgid) {
    case UBX_NAV_SVINFO:
	display_nav_svinfo(&buf[6], data_len);
	break;
    case UBX_NAV_DOP:
	display_nav_dop(&buf[6], data_len);
	break;
    case UBX_NAV_SOL:
	display_nav_sol(&buf[6], data_len);
	break;
    default:
	break;
    }

#ifdef PPS_ENABLE
    /*@-compdef@*/
    /*@-type@*/ /* splint is confused about struct timespec */
    if (pps_thread_lastpps(&session, &drift) > 0) {
	double timedelta = timespec_diff_ns(drift.real, drift.clock) * 1e-9;
	(void)mvwprintw(ppswin, 1, 13, "%.9f", timedelta);
	(void)wnoutrefresh(ppswin);
    }
    /*@+type@*/
    /*@+compdef@*/
#endif /* PPS_ENABLE */
}
Beispiel #8
0
/*@-mustfreefresh -type -unrecog -branchstate@*/
static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
{
    struct gps_device_t *session = (struct gps_device_t *)arg;
    double last_fixtime_real = 0, last_fixtime_clock = 0;
#ifndef HAVE_CLOCK_GETTIME
    struct timeval  clock_tv = {0, 0};
#endif /* HAVE_CLOCK_GETTIME */
    struct timespec clock_ts = {0, 0};
    time_t last_second_used = 0;
#if defined(TIOCMIWAIT)
    int cycle, duration; 
    /* state is the last state of the tty control ssignals */
    int state = 0, 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 */
#endif /* TIOCMIWAIT */
#if defined(HAVE_SYS_TIMEPPS_H)
    int edge_kpps = 0;       /* 0 = clear edge, 1 = assert edge */
#ifndef S_SPLINT_S
    int cycle_kpps, duration_kpps;
    /* 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;

    memset( (void *)&pi, 0, sizeof(pps_info_t));
#endif /* S_SPLINT_S */
#endif /* defined(HAVE_SYS_TIMEPPS_H) */

    /*
     * Wait for status change on any handshake line.  Just one edge,
     * 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. 
     *
     * Once we have the latest edge we compare it to the last edge which we
     * stored.  If the edge passes sanity checks we use it to send to
     * ntpshm and chrony_send
     */

    while (session->thread_report_hook != NULL 
           || session->context->pps_hook != NULL) {
	bool ok = false;
#if defined(HAVE_SYS_TIMEPPS_H)
	// cppcheck-suppress variableScope
	bool ok_kpps = false;
#endif /* HAVE_SYS_TIMEPPS_H */
	char *log = NULL;

#if defined(TIOCMIWAIT)
        /* we are lucky to have TIOCMIWAIT, so wait for next edge */
#define PPS_LINE_TIOC (TIOCM_CD|TIOCM_CAR|TIOCM_RI|TIOCM_CTS)
        if (ioctl(session->gpsdata.gps_fd, TIOCMIWAIT, PPS_LINE_TIOC) != 0) {
	    gpsd_report(session->context->debug, LOG_ERROR,
			"PPS ioctl(TIOCMIWAIT) failed: %d %.40s\n",
			errno, strerror(errno));
	    break;
	}
        /* quick, grab a copy of last_fixtime before it changes */
	last_fixtime_real = session->last_fixtime.real;
	last_fixtime_clock = session->last_fixtime.clock;

/*@-noeffect@*/
        /* get the time after we just woke up */
#ifdef HAVE_CLOCK_GETTIME
	/* using  clock_gettime() here, that is nSec,
	 * not uSec like gettimeofday */
	if ( 0 > clock_gettime(CLOCK_REALTIME, &clock_ts) ) {
	    /* uh, oh, can not get time! */
	    gpsd_report(session->context->debug, LOG_ERROR,
			"PPS clock_gettime() failed\n");
	    break;
	}
#else
	if ( 0 > gettimeofday(&clock_tv, NULL) ) {
	    /* uh, oh, can not get time! */
	    gpsd_report(session->context->debug, LOG_ERROR,
			"PPS gettimeofday() failed\n");
	    break;
	}
	TVTOTS( &clock_ts, &clock_tv);
#endif /* HAVE_CLOCK_GETTIME */
/*@+noeffect@*/

        /* got the edge, got the time just after the edge, now quickly
         * get the edge state */
	/*@ +ignoresigns */
	if (ioctl(session->gpsdata.gps_fd, TIOCMGET, &state) != 0) {
	    gpsd_report(session->context->debug, LOG_ERROR,
			"PPS ioctl(TIOCMGET) failed\n");
	    break;
	}
	/*@ -ignoresigns */

	/* mask for monitored lines */
	state &= PPS_LINE_TIOC;
	edge = (state > state_last) ? 1 : 0;
#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)
        if ( 0 <= session->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 
             */
#ifdef TIOCMIWAIT
	    /*
	     * 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));
#else /* not TIOCMIWAIT */
	    /*
	     * RFC2783 specifies that a NULL timeval means to wait.
             *
             * FIXME, this will fail on 2Hz 'PPS', maybe should wait 3 Sec.
	     */
	    kernelpps_tv.tv_sec = 1;
	    kernelpps_tv.tv_nsec = 0;
#endif
	    if ( 0 > time_pps_fetch(session->kernelpps_handle, PPS_TSFMT_TSPEC
	        , &pi, &kernelpps_tv)) {
		gpsd_report(session->context->debug, LOG_ERROR,
			    "KPPS kernel PPS failed\n");
	    } 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.
		 */
		gpsd_report(session->context->debug, LOG_PROG,
			    "KPPS assert %ld.%09ld, sequence: %ld - "
			    "clear  %ld.%09ld, sequence: %ld\n",
			    pi.assert_timestamp.tv_sec,
			    pi.assert_timestamp.tv_nsec,
			    (unsigned long) pi.assert_sequence,
			    pi.clear_timestamp.tv_sec,
			    pi.clear_timestamp.tv_nsec,
			    (unsigned long) pi.clear_sequence);
		gpsd_report(session->context->debug, LOG_PROG,
			    "KPPS data: using %s\n",
			    edge_kpps ? "assert" : "clear");

	        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;
	        gpsd_report(session->context->debug, LOG_PROG,
		    "KPPS cycle: %7d uSec, duration: %7d uSec @ %lu.%09lu\n",
		    cycle_kpps, duration_kpps,
		    (unsigned long)ts_kpps.tv_sec,
		    (unsigned long)ts_kpps.tv_nsec);
		pulse_kpps[edge_kpps] = ts_kpps;
		if (990000 < cycle_kpps && 1010000 > cycle_kpps) {
		    /* KPPS passes a basic sanity check */
		    ok_kpps = true;
		    log = "KPPS";
		}
	    }
	}
#endif /* defined(HAVE_SYS_TIMEPPS_H) && !defined(S_SPLINT_S) */

#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 @*/
	if (state == state_last) {
	    /* some pulses may be so short that state never changes */
	    if (999000 < cycle && 1001000 > cycle) {
		duration = 0;
		unchanged = 0;
		gpsd_report(session->context->debug, LOG_RAW,
			    "PPS pps-detect on %s invisible pulse\n",
			    session->gpsdata.dev.path);
	    } else if (++unchanged == 10) {
                /* not really unchanged, just out of bounds */
		unchanged = 1;
		gpsd_report(session->context->debug, LOG_WARN,
			    "PPS TIOCMIWAIT returns unchanged state, ppsmonitor sleeps 10\n");
		(void)sleep(10);
	    }
	} else {
	    gpsd_report(session->context->debug, LOG_RAW,
			"PPS pps-detect on %s changed to %d\n",
			session->gpsdata.dev.path, state);
	    unchanged = 0;
	}
	state_last = state;
        /* save this edge so we know next cycle time */
	pulse[edge] = clock_ts;
	gpsd_report(session->context->debug, LOG_PROG,
		    "PPS edge: %d, cycle: %7d uSec, duration: %7d uSec @ %lu.%09lu\n",
		    edge, cycle, duration,
		    (unsigned long)clock_ts.tv_sec,
		    (unsigned long)clock_ts.tv_nsec);
	if (unchanged) {
	    // strange, try again
	    continue;
	}

	/*
	 * The PPS pulse is normally a short pulse with a frequency of
	 * 1 Hz, and the UTC second is defined by the front edge. But we
	 * don't know the polarity of the pulse (different receivers
	 * emit different polarities). The duration variable is used to
	 * determine which way the pulse is going. The code assumes
	 * that the UTC second is changing when the signal has not
	 * been changing for at least 800ms, i.e. it assumes the duty
	 * cycle is at most 20%.
	 *
	 * Some GPSes instead output a square wave that is 0.5 Hz and each
	 * edge denotes the start of a second.
	 *
	 * Some GPSes, like the Globalsat MR-350P, output a 1uS pulse.
	 * The pulse is so short that TIOCMIWAIT sees a state change
	 * but by the time TIOCMGET is called the pulse is gone.
	 *
	 * A few stupid GPSes, like the Furuno GPSClock, output a 1.0 Hz
	 * square wave where the leading edge is the start of a second
	 *
	 * 5Hz GPS (Garmin 18-5Hz) pulses at 5Hz. Set the pulse length to
	 * 40ms which gives a 160ms pulse before going high.
	 *
	 */

	log = "Unknown error";
        if ( 0 > cycle ) {
	    log = "Rejecting negative cycle\n";
	} else if (199000 > cycle) {
	    // too short to even be a 5Hz pulse
	    log = "Too short for 5Hz\n";
	} else if (201000 > cycle) {
	    /* 5Hz cycle */
	    /* looks like 5hz PPS pulse */
	    if (100000 > duration) {
		/* BUG: how does the code know to tell ntpd
		 * which 1/5 of a second to use?? */
		ok = true;
		log = "5Hz PPS pulse\n";
	    }
	} else if (999000 > cycle) {
	    log = "Too long for 5Hz, too short for 1Hz\n";
	} else if (1001000 > cycle) {
	    /* looks like PPS pulse or square wave */
	    if (0 == duration) {
		ok = true;
		log = "invisible pulse\n";
	    } else if (499000 > duration) {
		/* end of the short "half" of the cycle */
		/* aka the trailing edge */
		log = "1Hz trailing edge\n";
	    } else if (501000 > duration) {
		/* looks like 1.0 Hz square wave, ignore trailing edge */
		if (edge == 1) {
		    ok = true;
		    log = "square\n";
		}
	    } else {
		/* end of the long "half" of the cycle */
		/* aka the leading edge */
		ok = true;
		log = "1Hz leading edge\n";
	    }
	} else if (1999000 > cycle) {
	    log = "Too long for 1Hz, too short for 2Hz\n";
	} else if (2001000 > cycle) {
	    /* looks like 0.5 Hz square wave */
	    if (999000 > duration) {
		log = "0.5 Hz square too short duration\n";
	    } else if (1001000 > duration) {
		ok = true;
		log = "0.5 Hz square wave\n";
	    } else {
		log = "0.5 Hz square too long duration\n";
	    }
	} else {
	    log = "Too long for 0.5Hz\n";
	}
#endif /* TIOCMIWAIT */
	if ( ok && last_second_used >= last_fixtime_real ) {
		/* uh, oh, this second already handled */
		ok = 0;
		log = "this second already handled\n";
	}

	if (ok) {
	    /* offset is the skew from expected to observed pulse time */
	    double offset;
	    /* delay after last fix */
	    double delay;
	    char *log1 = NULL;
	    /* drift.real is the time we think the pulse represents  */
	    struct timedrift_t drift;
	    gpsd_report(session->context->debug, LOG_RAW,
			"PPS edge accepted %.100s", log);
#if defined(HAVE_SYS_TIMEPPS_H)
            if ( 0 <= session->kernelpps_handle && ok_kpps) {
		/* use KPPS time */
		/* 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) */
	    /* 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. 
             *
             * FIXME! The GR-601W at 38,400 or faster can send the
             * serial fix before PPS by about 10 mSec!
             */

	    /*@+relaxtypes@*/
	    drift.real.tv_sec = last_fixtime_real + 1;
	    drift.real.tv_nsec = 0;  /* need to be fixed for 5Hz */
	    drift.clock = clock_ts;
	    /*@-relaxtypes@*/

	    /* check to see if we have a fresh timestamp from the
	     * GPS serial input then use that */
	    offset = (drift.real.tv_sec - drift.clock.tv_sec);
	    offset += ((drift.real.tv_nsec - drift.clock.tv_nsec) / 1e9);
	    delay = (drift.clock.tv_sec + drift.clock.tv_nsec / 1e9) - last_fixtime_clock;
	    if (0.0 > delay || 1.0 < delay) {
		gpsd_report(session->context->debug, LOG_RAW,
			    "PPS: no current GPS seconds: %f\n",
			    delay);
		log1 = "timestamp out of range";
	    } else {
		/*@-compdef@*/
		last_second_used = last_fixtime_real;
		if (session->thread_report_hook != NULL) 
		    log1 = session->thread_report_hook(session, &drift);
		else
		    log1 = "no report hook";
		if (session->context->pps_hook != NULL)
		    session->context->pps_hook(session, &drift);
		/*@ -unrecog  (splint has no pthread declarations as yet) @*/
		(void)pthread_mutex_lock(&ppslast_mutex);
		/*@ +unrecog @*/
		/*@-type@*/ /* splint is confused about struct timespec */
		session->ppslast = drift;
		/*@+type@*/
		session->ppscount++;
		/*@ -unrecog (splint has no pthread declarations as yet) @*/
		(void)pthread_mutex_unlock(&ppslast_mutex);
		/*@ +unrecog @*/
		/*@+compdef@*/
		/*@-type@*/ /* splint is confused about struct timespec */
		gpsd_report(session->context->debug, LOG_INF,
			    "PPS hooks called with %.20s %lu.%09lu offset %.9f\n",
			    log1,
			    (unsigned long)clock_ts.tv_sec,
			    (unsigned long)clock_ts.tv_nsec,
			    offset);
		/*@+type@*/
            }
	    /*@-type@*/ /* splint is confused about struct timespec */
	    gpsd_report(session->context->debug, LOG_PROG,
		    "PPS edge %.20s %lu.%09lu offset %.9f\n",
		    log1,
		    (unsigned long)clock_ts.tv_sec,
		    (unsigned long)clock_ts.tv_nsec,
		    offset);
	    /*@+type@*/
	} else {
	    gpsd_report(session->context->debug, LOG_RAW,
			"PPS edge rejected %.100s", log);
	}
    }
#if defined(HAVE_SYS_TIMEPPS_H)
    if (session->kernelpps_handle > 0) {
	gpsd_report(session->context->debug, LOG_PROG, 
            "PPS descriptor cleaned up\n");
	(void)time_pps_destroy(session->kernelpps_handle);
    }
#endif
    if (session->thread_wrap_hook != NULL)
	session->thread_wrap_hook(session);
    gpsd_report(session->context->debug, LOG_PROG, 
         "PPS gpsd_ppsmonitor exited.\n");
    return NULL;
}
Beispiel #9
0
static void event_loop(struct server_state* ss)
{
  msg(1, "Starting event loop\n");

  struct timespec tx_ts, rx_ts, next_tx_ts, lost_tx_ts = { 0, 0 };
  ss->have_sent = ss->have_tx_ts = ss->have_rx_ts = false;
  int rc, rx_left = ss->rx_msg_size;
  unsigned send_i = 0;

  clock_gettime(CLOCK_REALTIME, &next_tx_ts);
  timespec_add_ns(&next_tx_ts, ss->inter_tx_gap_ns);

  while( 1 ) {
    struct epoll_event e;
    TRY( rc = epoll_wait(ss->epoll, &e, 1, 0) );

    if( rc == 0 ) {
      struct timespec now;
      clock_gettime(CLOCK_REALTIME, &now);
      if( ! timespec_le(next_tx_ts, now) )
        continue;
      timespec_add_ns(&next_tx_ts, ss->inter_tx_gap_ns);
      if( ++send_i >= cfg_measure_nth && ! ss->have_sent ) {
        msg(3, "Send message (timed)\n");
        TEST( send(ss->udp_sock_ts, ss->tx_buf_ts, ss->tx_msg_size, 0)
                == ss->tx_msg_size );
        if( ! cfg_hw_ts ) {
          ss->have_tx_ts = true;
          tx_ts = now;
        }
        send_i = 0;
        ss->have_sent = true;
      }
      else {
        msg(3, "Send message\n");
        TEST( send(ss->udp_sock, ss->tx_buf, ss->tx_msg_size, 0)
                == ss->tx_msg_size );
        if( send_i >= cfg_measure_nth ) {
          /* Not had a reply to last timed message.  Try to detect lost
           * messages.
           */
          if( send_i == cfg_measure_nth ) {
            lost_tx_ts = now;
          }
          else if( ss->have_tx_ts &&
                   timespec_diff_ns(now, lost_tx_ts) > 10000000 ) {
            msg(2, "WARNING: No response to timed message\n");
            if( ss->rtt_n > 0 )
              ++(ss->n_lost_msgs);
            ss->have_sent = false;
            ss->have_tx_ts = false;
            ss->have_rx_ts = false;
          }
        }
      }
    }

    else if( e.data.fd == ss->tcp_sock ) {
      TEST( e.events & EPOLLIN );
      if( cfg_hw_ts ) {
        rc = recv_ts(ss->tcp_sock, ss->rx_buf, rx_left, MSG_DONTWAIT, &rx_ts);
      }
      else {
        rc = recv(ss->tcp_sock, ss->rx_buf, rx_left, MSG_DONTWAIT);
        clock_gettime(CLOCK_REALTIME, &rx_ts);
      }
      if( rc > 0 ) {
        msg(3, "Received %d from client at %d.%09d\n", rc,
            (int) rx_ts.tv_sec, (int) rx_ts.tv_nsec);
        if( (rx_left -= rc) == 0 ) {
          send(ss->tcp_sock, ss->rx_buf, 1, MSG_NOSIGNAL);
          rx_left = ss->rx_msg_size;
          ss->have_rx_ts = true;
          if( ss->have_tx_ts )
            measured_rtt(ss, tx_ts, rx_ts);
        }
      }
      else if( rc == 0 || errno == ECONNRESET ) {
        break;
      }
      else if( errno == ETIME ) {
        fprintf(stderr, "ERROR: Did not get H/W timestamp on RX\n");
        exit(3);
      }
      else {
        TRY( rc );
      }
    }

    else if( e.data.fd == ss->udp_sock_ts ) {
      assert( cfg_hw_ts );
      assert( ! ss->have_tx_ts );
      TEST( recv_ts(ss->udp_sock_ts, ss->rx_buf, 1,
                    MSG_ERRQUEUE | MSG_DONTWAIT, &tx_ts) == 1 );
      msg(3, "TX timestamp %d.%09d\n", (int) tx_ts.tv_sec,
             (int) tx_ts.tv_nsec);
      ss->have_tx_ts = true;
      if( ss->have_rx_ts )
        measured_rtt(ss, tx_ts, rx_ts);
    }
  }

  msg(1, "Client disconnected\n");
  TRY( close(ss->tcp_sock) );
}
Beispiel #10
0
/* gpsd_ppsmonitor()
 *
 * the core loop of the PPS thread.
 * All else is initialization, cleanup or subroutine
 */
static void *gpsd_ppsmonitor(void *arg)
{
    char ts_str1[TIMESPEC_LEN], ts_str2[TIMESPEC_LEN];
    struct inner_context_t inner_context = *((struct inner_context_t *)arg);
    volatile struct pps_thread_t *thread_context = inner_context.pps_thread;
    /* 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;
    long cycle = 0, duration = 0;
    /* state is the last state of the tty control signals */
    int state = 0;
    /* count of how many cycles unchanged data */
    int  unchanged = 0;
    /* state_last is previous state */
    int state_last = 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)
    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} };
#endif /* defined(HAVE_SYS_TIMEPPS_H) */
    bool not_a_tty = false;

    /* before the loop, figure out how we can detect edges:
     * TIOMCIWAIT, which is linux specifix
     * RFC2783, a.k.a kernel PPS (KPPS)
     * or if KPPS is deficient a combination of the two */
    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->devicename,
            thread_context->devicefd);
        /* why do we care the device is a tty? so as not to ioctl(TIO..)
        * /dev/pps0 is not a tty and we need to use it */
        not_a_tty = true;
    }
    /* if no TIOCMIWAIT, we hope to have PPS_CANWAIT */

    if ( not_a_tty && !inner_context.pps_canwait ) {
	/* for now, no way to wait for an edge, in the future maybe figure out
         * a sleep */
    }

    /*
     * this is the main loop, exit and never any further PPS processing.
     *
     * Four stages to the loop,
     * an unwanted condition at any point and the loop restarts
     * an error condition and we exit for all time.
     *
     * Stage One: wait for the next edge.
     *      If we have KPPS
     *         If we have PPS_CANWAIT
     *             use KPPS and PPS_CANWAIT - this is the most accurate
     *         else
     *             use KPPS and TIOMCIWAIT together - this is pretty accurate
     *      else If we have TIOMCIWAIT
     *         use TIOMCIWAIT - this is the least accurate
     *      else
     *         give up
     *
     * Success is we have a good edge, otherwise loop some more
     *
     * On a successul stage one, we know this about the exact moment
     * of current pulse:
     *      GPS (real) time
     *      system (clock) time
     *      edge type: Assert (rising) or Clear (falling)
     *
     * From the above 3 items, we can compute:
     *      cycle length - elapsed time from the previous edge of the same type
     *      pulse length (duration) - elapsed time from the previous edge
     *                            (the previous edge would be the opposite type)
     *
     * Stage Two:  Categorize the current edge
     *      Decide if we have 0.5Hz, 1Hz, 5 Hz cycle time
     *      knowing cycle time determine if we have the leading or trailing edge
     *      restart the loop if the edge looks dodgy
     *
     * Stage Three: Calculate
     *	    Calculate the offset (difference) between the system time
     *      and the GPS time at the pulse moment
     *      restart the loop if the offset looks dodgy
     *
     * Stage Four: Tell ntpd, chronyd, or gpsmon what we learned
     *       a few more sanity checks
     *       call the report hook with our PPS report
     */
    while (thread_context->report_hook != NULL) {
	bool ok = false;
	char *log = NULL;
        char *edge_str = "";

	if (++unchanged == 10) {
            /* last ten edges no good, stop spinning, just wait 10 seconds */
	    unchanged = 0;
	    thread_context->log_hook(thread_context, THREAD_WARN,
		    "PPS:%s unchanged state, ppsmonitor sleeps 10\n",
		    thread_context->devicename);
	    (void)sleep(10);
        }

        /* Stage One; wait for the next edge */
#if defined(TIOCMIWAIT)
        if ( !not_a_tty && !inner_context.pps_canwait ) {
            int ret;

            /* we are a tty, so can TIOCMIWAIT */
            /* we have no PPS_CANWAIT, so must TIOCMIWAIT */

	    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_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 previous 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;
	    clock_ts = clock_ts_tio;
	    state = edge_tio;
	    edge = edge_tio;
            edge_str = edge ? "Assert" : "Clear";
	    cycle = cycle_tio;
	    duration = duration_tio;

	    timespec_str( &clock_ts, ts_str1, sizeof(ts_str1) );
	    thread_context->log_hook(thread_context, THREAD_PROG,
		    "TPPS:%s %.10s cycle: %d, duration: %d @ %s\n",
		    thread_context->devicename, edge_str, cycle, duration,
                    ts_str1);

        }
#endif /* TIOCMIWAIT */

	/* ok and log used by KPPS and TIOCMIWAIT */
	log = NULL;
#if defined(HAVE_SYS_TIMEPPS_H)
        if ( 0 <= inner_context.kernelpps_handle ) {
	    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
             */
	    ret = get_edge_rfc2783(&inner_context,
                         &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_ERROR,
			    "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 */

            /* compute time from previous saved similar edge */
	    cycle_kpps = timespec_diff_ns(clock_ts_kpps, pulse_kpps[edge_kpps]);
	    cycle_kpps /= 1000;
            /* compute time from previous saved dis-similar edge */
	    duration_kpps = timespec_diff_ns(clock_ts_kpps, prev_clock_ts)/1000;

	    /* save for later */
	    pulse_kpps[edge_kpps] = clock_ts_kpps;
	    pulse_kpps[edge_kpps ? 0 : 1] = prev_clock_ts;
            /* sanity checks are later */

            /* use this data */
	    state = edge_kpps;
	    edge = edge_kpps;
            edge_str = edge ? "Assert" : "Clear";
	    clock_ts = clock_ts_kpps;
	    cycle = cycle_kpps;
	    duration = duration_kpps;

	    timespec_str( &clock_ts_kpps, ts_str1, sizeof(ts_str1) );
	    thread_context->log_hook(thread_context, THREAD_PROG,
		"KPPS:%s %.10s cycle: %7d, duration: %7d @ %s\n",
		thread_context->devicename,
		edge_str,
		cycle_kpps, duration_kpps, ts_str1);

	}
#endif /* defined(HAVE_SYS_TIMEPPS_H) */

        if ( not_a_tty && !inner_context.pps_canwait ) {
	    /* uh, oh, no TIOMCIWAIT, nor RFC2783, die */
	    thread_context->log_hook(thread_context, THREAD_WARN,
			"PPS:%s die: no TIOMCIWAIT, nor RFC2783 CANWAIT\n",
			thread_context->devicename);
	    break;
	}
	/*
         * End of Stge One
	 * we now know this about the exact moment of current pulse:
	 *      GPS (real) time
	 *      system (clock) time
	 *      edge type: Assert (rising) or Clear (falling)
	 *
	 * we have computed:
	 *      cycle length
	 *      pulse length (duration)
	 */

	/*
	 * Stage Two:  Categorize the current edge
	 *      Decide if we have 0.5Hz, 1Hz, 5 Hz cycle time
	 *      determine if we have the leading or trailing edge
	 */

	/* FIXME! this block duplicates a lot of the next block
         * of cycle detetion code */
	if (state != state_last) {
	    thread_context->log_hook(thread_context, THREAD_RAW,
			"PPS:%s %.10s pps-detect changed to %d\n",
			thread_context->devicename, edge_str, state);
	    unchanged = 0;
        } else if ( (180000 < cycle &&  220000 > cycle)      /* 5Hz */
	        ||  (900000 < cycle && 1100000 > cycle)      /* 1Hz */
	        || (1800000 < cycle && 2200000 > cycle) ) {  /* 2Hz */

	    /* some pulses may be so short that state never changes
	     * and some RFC2783 only can detect one edge */

	    duration = 0;
	    unchanged = 0;
	    thread_context->log_hook(thread_context, THREAD_RAW,
			"PPS:%s %.10s pps-detect invisible pulse\n",
			thread_context->devicename, edge_str);
	}
        /* else, unchannged state, and weird cycle time */

	state_last = state;
	timespec_str( &clock_ts, ts_str1, sizeof(ts_str1) );
	thread_context->log_hook(thread_context, THREAD_PROG,
	    "PPS:%s %.10s cycle: %7d, duration: %7d @ %s\n",
	    thread_context->devicename,
	    edge_str,
	    cycle, duration, ts_str1);
	if (unchanged) {
	    // strange, try again
	    continue;
	}

	/*
	 * The PPS pulse is normally a short pulse with a frequency of
	 * 1 Hz, and the UTC second is defined by the front edge. But we
	 * don't know the polarity of the pulse (different receivers
	 * emit different polarities). The duration variable is used to
	 * determine which way the pulse is going.  When the duration
         * is less than 1/2 the cycle we are on the trailing edge.
	 *
	 * Some GPSes instead output a square wave that is 0.5 Hz and each
	 * edge denotes the start of a second.
	 *
	 * Some GPSes, like the Globalsat MR-350P, output a 1uS pulse.
	 * The pulse is so short that TIOCMIWAIT sees a state change
	 * but by the time TIOCMGET is called the pulse is gone.  gpsd
         * calls that an invisible pulse.
	 *
	 * A few stupid GPSes, like the Furuno GPSClock, output a 1.0 Hz
	 * square wave where the leading edge is the start of a second
         * gpsd can only guess the correct edge.
	 *
	 * 5Hz GPS (Garmin 18-5Hz) pulses at 5Hz. Set the pulse length to
	 * 40ms which gives a 160ms pulse before going high.
	 *
	 * You may think that PPS is very accurate, so the cycle time
         * valid window should be very small.  This is not the case,
         * The Rasberry Pi clock is very coarse when it starts and chronyd
         * may be doing a fast slew.  chronyd by default will slew up
         * to 8.334%!  So the cycle time as measured by the system clock
         * may be almost +/- 9%. Therefore, gpsd uses a 10% window.
	 * Don't worry, ntpd and chronyd will do further validation.
	 */

	log = "Unknown error";
        if ( 0 > cycle ) {
	    log = "Rejecting negative cycle\n";
	} else if (199000 > cycle) {
	    // too short to even be a 5Hz pulse
	    log = "Too short for 5Hz\n";
	} else if (201000 > cycle) {
	    /* 5Hz cycle */
	    /* looks like 5hz PPS pulse */
	    if (100000 > duration) {
		/* BUG: how does the code know to tell ntpd
		 * which 1/5 of a second to use?? */
		ok = true;
		log = "5Hz PPS pulse\n";
	    }
	} 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.
             * 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";
	} else if (1100000 > cycle) {
            /* Yes, 10% window.  */
	    /* looks like PPS pulse or square wave */
	    if (0 == duration) {
		ok = true;
		log = "invisible pulse\n";
	    } else if (499000 > duration) {
		/* end of the short "half" of the cycle */
		/* aka the trailing edge */
		log = "1Hz trailing edge\n";
	    } else if (501000 > duration) {
		/* looks like 1.0 Hz square wave, ignore trailing edge */
		if (edge == 1) {
		    ok = true;
		    log = "square\n";
		}
	    } else {
		/* end of the long "half" of the cycle */
		/* aka the leading edge */
		ok = true;
		log = "1Hz leading edge\n";
	    }
	} else if (1999000 > cycle) {
	    log = "Too long for 1Hz, too short for 2Hz\n";
	} else if (2001000 > cycle) {
	    /* looks like 0.5 Hz square wave */
	    if (999000 > duration) {
		log = "0.5 Hz square too short duration\n";
	    } else if (1001000 > duration) {
		ok = true;
		log = "0.5 Hz square wave\n";
	    } else {
		log = "0.5 Hz square too long duration\n";
	    }
	} else {
	    log = "Too long for 0.5Hz\n";
	}

	/* end of Stage two
         * we now know what type of PPS pulse, and if we have the
         * leading edge
         */

	/* Stage Three: Calculate
	 *	Calculate the offset (difference) between the system time
	 *      and the GPS time at the pulse moment
         */

	/*
	 * If there has not yet been any valid in-band time stashed
	 * from the GPS when the PPS event was asserted, we can do
	 * nothing further.  gpsd can not tell what second this pulse is
         * in reference to.
         *
         * Some GPSes like Garmin always send a PPS, valid or not.
         * Other GPSes like some uBlox may only send PPS when time is valid.
         * It is common to get PPS, and no fixtime, while autobauding.
	 */
        if (last_fixtime.real.tv_sec == 0) {
	    /* probably should log computed offset just for grins here */
	    ok = false;
	    log = "missing last_fixtime\n";
        } else if ( ok && last_second_used >= last_fixtime.real.tv_sec ) {
	    /* uh, oh, this second already handled */
	    ok = false;
	    log = "this second already handled\n";
	}

	if ( !ok ) {
            /* can not use this pulse, reject and retry */
	    thread_context->log_hook(thread_context, THREAD_PROG,
			"PPS:%s %.10s rejected %.100s",
			thread_context->devicename, edge_str,  log);
	    continue;
        }

        /* we have validated a goood cycle, mark it */
	unchanged = 0;
	/* offset is the skew from expected to observed pulse time */
	struct timespec offset;
	/* offset as a printable string */
	char offset_str[TIMESPEC_LEN];
	/* delay after last fix */
	struct timespec  delay;
	/* delay as a printable string */
	char delay_str[TIMESPEC_LEN];
	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 %.10s categorized %.100s",
		    thread_context->devicename, edge_str, log);

	/* FIXME! The GR-601W at 38,400 or faster can send the
	 * serial fix before the interrupt event carrying the PPS
	 * line assertion by about 10 mSec!
	 */

	/*
	 * We get the time of the last fix recorded before the PPS came in,
	 * which is for the previous cycle.  Only works for integral cycle
         * times, but more than 1Hz is pointless.
	 */

	ppstimes.real.tv_sec = (time_t)last_fixtime.real.tv_sec + 1;
	ppstimes.real.tv_nsec = 0;  /* need to be fixed for 5Hz */
	ppstimes.clock = clock_ts;

	TS_SUB( &offset, &ppstimes.real, &ppstimes.clock);
	TS_SUB( &delay, &ppstimes.clock, &last_fixtime.clock);
	timespec_str( &delay, delay_str, sizeof(delay_str) );

	/* end Stage Three: now known about the exact edge moment:
	 *	UTC time of PPS edge
	 *      offset of system time to PS time
         */

	/* Stage Four: Tell ntpd, chronyd, or gpsmon what we learned
	 *       a few more sanity checks
	 *       call the report hook with our PPS report
         */

	if ( 0> delay.tv_sec || 0 > delay.tv_nsec ) {
	    thread_context->log_hook(thread_context, THREAD_RAW,
			"PPS:%s %.10s system clock went backwards: %.20s\n",
			thread_context->devicename,
			edge_str,
			delay_str);
	    log1 = "system clock went backwards";
	} 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,
			"PPS:%s %.10s no current GPS seconds: %.20s\n",
			thread_context->devicename,
			edge_str,
			delay_str);
	    log1 = "timestamp out of range";
	} else {
	    last_second_used = last_fixtime.real.tv_sec;
	    if (thread_context->report_hook != NULL)
		log1 = thread_context->report_hook(thread_context, &ppstimes);
	    else
		log1 = "no report hook";
	    thread_lock(thread_context);
	    thread_context->pps_out = ppstimes;
	    thread_context->ppsout_count++;
	    thread_unlock(thread_context);
	    timespec_str( &ppstimes.clock, ts_str1, sizeof(ts_str1) );
	    timespec_str( &ppstimes.real, ts_str2, sizeof(ts_str2) );
	    thread_context->log_hook(thread_context, THREAD_INF,
		"PPS:%s %.10s hooks called clock: %s real: %s: %.20s\n",
		thread_context->devicename,
		edge_str,
		ts_str1, ts_str2, log1);
	}
	timespec_str( &clock_ts, ts_str1, sizeof(ts_str1) );
	timespec_str( &offset, offset_str, sizeof(offset_str) );
	thread_context->log_hook(thread_context, THREAD_PROG,
		"PPS:%s %.10s %.30s @ %s offset %.20s\n",
		thread_context->devicename,
		edge_str,
		log1, ts_str1, offset_str);
        /* end Stage four, end of the loop, do it again */
    }
#if defined(HAVE_SYS_TIMEPPS_H)
    if (inner_context.kernelpps_handle > 0) {
	thread_context->log_hook(thread_context, THREAD_PROG,
            "PPS:%s descriptor cleaned up\n",
	    thread_context->devicename);
	(void)time_pps_destroy(inner_context.kernelpps_handle);
    }
#endif
    thread_context->log_hook(thread_context, THREAD_PROG,
		"PPS:%s gpsd_ppsmonitor exited.\n",
		thread_context->devicename);
    return NULL;
}
Beispiel #11
0
/*@ -globstate -nullpass (splint is confused) */
static void nmea_update(void)
{
    char **fields;
#ifdef PPS_ENABLE
    struct timedrift_t drift;
#endif /* PPS_ENABLE */

    assert(cookedwin != NULL);
    assert(nmeawin != NULL);
    assert(gpgsawin != NULL);
    assert(gpggawin != NULL);
    assert(gprmcwin != NULL);
    assert(gpgstwin != NULL);

    /* can be NULL if packet was overlong */
    fields = session.driver.nmea.field;

    if (session.packet.outbuffer[0] == (unsigned char)'$' 
		&& fields != NULL && fields[0] != NULL) {
	int ymax, xmax;
	timestamp_t now;
	getmaxyx(nmeawin, ymax, xmax);
	assert(ymax > 0);
	if (strstr(sentences, fields[0]) == NULL) {
	    char *s_end = sentences + strlen(sentences);
	    if ((int)(strlen(sentences) + strlen(fields[0])) < xmax - 2) {
		*s_end++ = ' ';
		(void)strlcpy(s_end, fields[0], NMEA_MAX);
	    } else {
		*--s_end = '.';
		*--s_end = '.';
		*--s_end = '.';
	    }
	    (void)mvwaddstr(nmeawin, SENTENCELINE, 1, sentences);
	}

	/*
	 * If the interval between this and last update is
	 * the longest we've seen yet, boldify the corresponding
	 * tag.
	 */
	now = timestamp();
	if (now > last_tick && (now - last_tick) > tick_interval) {
	    char *findme = strstr(sentences, fields[0]);

	    tick_interval = now - last_tick;
	    if (findme != NULL) {
		(void)mvwchgat(nmeawin, SENTENCELINE, 1, xmax - 13, A_NORMAL, 0,
			       NULL);
		(void)mvwchgat(nmeawin, SENTENCELINE, 1 + (findme - sentences),
			       (int)strlen(fields[0]), A_BOLD, 0, NULL);
	    }
	}
	last_tick = now;

	if (strcmp(fields[0], "GPGSV") == 0
	    || strcmp(fields[0], "GNGSV") == 0
	    || strcmp(fields[0], "GLGSV") == 0) {
	    int i;
	    int nsats =
		(session.gpsdata.satellites_visible <
		 MAXSATS) ? session.gpsdata.satellites_visible : MAXSATS;

	    for (i = 0; i < nsats; i++) {
		(void)wmove(satwin, i + 2, 3);
		(void)wprintw(satwin, " %3d %3d%3d %3.0f",
			      session.gpsdata.PRN[i],
			      session.gpsdata.azimuth[i],
			      session.gpsdata.elevation[i],
			      session.gpsdata.ss[i]);
	    }
	    /* add overflow mark to the display */
	    if (nsats <= MAXSATS)
		(void)mvwaddch(satwin, MAXSATS + 2, 18, ACS_HLINE);
	    else
		(void)mvwaddch(satwin, MAXSATS + 2, 18, ACS_DARROW);
	}

	if (strcmp(fields[0], "GPRMC") == 0
	    || strcmp(fields[0], "GNRMC") == 0
	    || strcmp(fields[0], "GLRMC") == 0) {
	    /* time, lat, lon, course, speed */
	    (void)mvwaddstr(gprmcwin, 1, 12, fields[1]);
	    (void)mvwprintw(gprmcwin, 2, 12, "%12s %s", fields[3], fields[4]);
	    (void)mvwprintw(gprmcwin, 3, 12, "%12s %s", fields[5], fields[6]);
	    (void)mvwaddstr(gprmcwin, 4, 12, fields[7]);
	    (void)mvwaddstr(gprmcwin, 5, 12, fields[8]);
	    /* the status field, FAA code, and magnetic variation */
	    (void)mvwaddstr(gprmcwin, 6, 12, fields[2]);
	    (void)mvwaddstr(gprmcwin, 6, 25, fields[12]);
	    (void)mvwprintw(gprmcwin, 7, 12, "%-5s%s", fields[10],
			    fields[11]);

	    cooked_pvt();	/* cooked version of PVT */
	}

	if (strcmp(fields[0], "GPGSA") == 0
	    || strcmp(fields[0], "GNGSA") == 0
	    || strcmp(fields[0], "GLGSA") == 0) {
	    char scr[128];
	    int i;
	    (void)mvwprintw(gpgsawin, 1, 7, "%1s %s", fields[1], fields[2]);
	    (void)wmove(gpgsawin, 2, 7);
	    (void)wclrtoeol(gpgsawin);
	    scr[0] = '\0';
	    for (i = 0; i < session.gpsdata.satellites_used; i++) {
		(void)snprintf(scr + strlen(scr), sizeof(scr) - strlen(scr),
			       "%d ", session.gpsdata.used[i]);
	    }
	    getmaxyx(gpgsawin, ymax, xmax);
	    (void)mvwaddnstr(gpgsawin, 2, 7, scr, xmax - 2 - 7);
	    if (strlen(scr) >= (size_t) (xmax - 2)) {
		(void)mvwaddch(gpgsawin, 2, xmax - 2 - 7, (chtype) '.');
		(void)mvwaddch(gpgsawin, 2, xmax - 3 - 7, (chtype) '.');
		(void)mvwaddch(gpgsawin, 2, xmax - 4 - 7, (chtype) '.');
	    }
	    monitor_fixframe(gpgsawin);
	    (void)mvwprintw(gpgsawin, 3, 8, "%-5s", fields[16]);
	    (void)mvwprintw(gpgsawin, 3, 16, "%-5s", fields[17]);
	    (void)mvwprintw(gpgsawin, 3, 24, "%-5s", fields[15]);
	    monitor_fixframe(gpgsawin);
	}
	if (strcmp(fields[0], "GPGGA") == 0
	    || strcmp(fields[0], "GNGGA") == 0
	    || strcmp(fields[0], "GLGGA") == 0) {
	    (void)mvwprintw(gpggawin, 1, 12, "%-17s", fields[1]);
	    (void)mvwprintw(gpggawin, 2, 12, "%-17s", fields[2]);
	    (void)mvwprintw(gpggawin, 3, 12, "%-17s", fields[4]);
	    (void)mvwprintw(gpggawin, 4, 12, "%-17s", fields[9]);
	    (void)mvwprintw(gpggawin, 5, 12, "%1.1s", fields[6]);
	    (void)mvwprintw(gpggawin, 5, 22, "%2.2s", fields[7]);
	    (void)mvwprintw(gpggawin, 6, 12, "%-5.5s", fields[8]);
	    (void)mvwprintw(gpggawin, 7, 12, "%-5.5s", fields[11]);
	}
	if (strcmp(fields[0], "GPGST") == 0) {
	    (void)mvwprintw(gpgstwin, 1,  6, "%-10s", fields[1]);
	    (void)mvwprintw(gpgstwin, 1, 21,  "%-8s", fields[2]);
	    (void)mvwprintw(gpgstwin, 2,  6, "%-10s", fields[3]);
	    (void)mvwprintw(gpgstwin, 2, 21,  "%-8s", fields[4]);
	    (void)mvwprintw(gpgstwin, 3,  6, "%-10s", fields[5]);
	    (void)mvwprintw(gpgstwin, 3, 21,  "%-8s", fields[6]);
	    (void)mvwprintw(gpgstwin, 4,  6, "%-10s", fields[7]);
	    (void)mvwprintw(gpgstwin, 4, 21,  "%-8s", fields[8]);
	}
    }

#ifdef PPS_ENABLE
    /*@-compdef@*/
    /*@-type@*/ /* splint is confused about struct timespec */
    if (pps_thread_lastpps(&session, &drift) > 0) {
	double timedelta = timespec_diff_ns(drift.real, drift.clock) * 1e-9;
	(void)mvwprintw(gpgsawin, 4, 13, "%.9f", timedelta);
	(void)wnoutrefresh(gpgsawin);
    }
    /*@+type@*/
    /*@+compdef@*/
#endif /* PPS_ENABLE */
}
Beispiel #12
0
 void stop() {
     clock_gettime(CLOCK_REALTIME, &t1);
     timespec_diff_ns(t0, t1);
 }
Beispiel #13
0
int main(int argc, char **argv)
{
    int option;
    int	i;
    bool killall = false;
    bool verbose = false;
    int nsamples = INT_MAX;
    time_t timeout = (time_t)0, starttime = time(NULL);
    /* a copy of all old segments */
    struct shm_stat_t	shm_stat_old[NTPSEGMENTS + 1];;

    memset( shm_stat_old, 0 ,sizeof( shm_stat_old));

    while ((option = getopt(argc, argv, "hn:st:vV")) != -1) {
	switch (option) {
	case 'n':
	    nsamples = atoi(optarg);
	    break;
	case 's':
	    killall = true;
	    break;
	case 't':
	    timeout = (time_t)atoi(optarg);
	    break;
	case 'v':
	    verbose = true;
	    break;
	case 'V':
	    (void)fprintf(stderr, "%s: version %s (revision %s)\n",
			  argv[0], VERSION, REVISION);
	    exit(EXIT_SUCCESS);
	case 'h':
	    fprintf(stderr,
                "usage: ntpshmmon [-s] [-n max] [-t timeout] [-v] [-h] [-V]\n"
                "  -h           print this help\n"
                "  -n nsamples  exit after nsamples\n"
                "  -s           remove SHMs and exit\n"
                "  -t nseconds  exit after nseconds\n"
                "  -v           be verbose\n"
                "  -V           print version and exit\n"
		);
	    exit(EXIT_SUCCESS);
	default:
	    /* no option, just go and do it */
	    break;
	}
    }

    /* grab all segments, keep the non-null ones */
    for (i = 0; i < NTPSEGMENTS; i++) {
	segments[i] = shm_get(i, false, true);
	if (verbose && segments[i] != NULL)
	    fprintf(stderr, "unit %d opened\n", i);
    }

    if (killall) {
	struct shmTime **pp;

	for (pp = segments; pp < segments + NTPSEGMENTS; pp++)
	    if (*pp != NULL)
		(void)shmdt((void *)(*pp));
	exit(EXIT_SUCCESS);
    }

    /*
     * We want line buffering even if stdout is going to a file.  This
     * is a (possibly futile) attempt to avoid writing an incomplete
     * line on interrupt.
     */
    setvbuf(stdout, NULL, _IOLBF, 0);

    (void)printf("ntpshmmon version 1\n");
    (void)printf("#      Name Seen@                Clock                Real                 L Prec\n");

    do {
	/* the current segment */
	struct shm_stat_t	shm_stat;
	struct timespec delay;

	for (i = 0; i < NTPSEGMENTS; i++) {
	    long long diff;  /* 32 bit long is too short for a timespec */
	    enum segstat_t status = ntp_read(segments[i], &shm_stat, false);
	    if (verbose)
		fprintf(stderr, "unit %d status %d\n", i, status);
	    switch(status) {
	    case OK:
		/* ntpd can slew the clock at 120% real time
                 * so do not lock out slightly short cycles
		 * use 50% of cycle time as lock out limit.
                 * ignore that system time may jump. */
		diff = timespec_diff_ns(shm_stat.tvr, shm_stat_old[i].tvr);
		if ( 0 == diff) {
		    /* no change in tvr */
		    break;
		}
		diff = timespec_diff_ns(shm_stat.tvt, shm_stat_old[i].tvt);
		if ( 0 == diff) {
		    /* no change in tvt */
		    break;
		}
		/* time stamp it */
		clock_gettime(CLOCK_REALTIME, &shm_stat.tvc);
		printf("sample %s %ld.%09ld %ld.%09ld %ld.%09ld %d %3d\n",
		       ntp_name(i),
		       (long)shm_stat.tvc.tv_sec, shm_stat.tvc.tv_nsec,
		       (long)shm_stat.tvr.tv_sec, shm_stat.tvr.tv_nsec,
		       (long)shm_stat.tvt.tv_sec, shm_stat.tvt.tv_nsec,
		       shm_stat.leap, shm_stat.precision);
		--nsamples;
		/* save the new time stamp */
		shm_stat_old[i] = shm_stat; /* structure copy */

		break;
	    case NO_SEGMENT:
		break;
	    case NOT_READY:
		/* do nothing, data not ready, wait another cycle */
		break;
	    case BAD_MODE:
		fprintf(stderr, "ntpshmmon: unknown mode %d on segment %s\n",
			shm_stat.status, ntp_name(i));
		break;
	    case CLASH:
		/* do nothing, data is corrupt, wait another cycle */
		break;
	    default:
		fprintf(stderr, "ntpshmmon: unknown status %d on segment %s\n",
			status, ntp_name(i));
		break;
	    }
	}
	/* all segments now checked */

	/*
	 * Even on a 1 Hz PPS, a sleep(1) may end up
         * being sleep(1.1) and missing a beat.  Since
	 * we're ignoring duplicates via timestamp, polling
	 * at fast intervals should not be a problem
	 *
	 * PPS is not always one pulse per second.
	 * the Garmin GPS 18x-5Hz outputs 5 pulses per second.
         * That is a 200 millSec cycle, minimum 20 milliSec duration
         * we will wait 1 milliSec out of caution
         *
         * and, of course, nanosleep() may sleep a lot longer than we ask...
	 */
	if ( timeout ) {
	    /* do not read time unless it matters */
	    if ( time(NULL) > (starttime + timeout ) ) {
		/* time to exit */
		break;
	    }
	}

        /* wait 1,000 uSec */
	delay.tv_sec = 0;
	delay.tv_nsec = 1000000L;
	nanosleep(&delay, NULL);
    } while ( 0 < nsamples );

    exit(EXIT_SUCCESS);
}