Ejemplo n.º 1
0
int
main(int argc, char **argv)
{
    int fd;
    pps_info_t pi;
    pps_params_t pp;
    pps_handle_t ph;
    int i, mode;
    u_int olda, oldc;
    double d = 0;
    struct timespec to;

    if (argc < 2)
        argv[1] = "/dev/cuaa1";
    setbuf(stdout, 0);
    fd = open(argv[1], O_RDONLY);
    if (fd < 0)
        err(1, argv[1]);
    i = time_pps_create(fd, &ph);
    if (i < 0)
        err(1, "time_pps_create");

    i = time_pps_getcap(ph, &mode);
    if (i < 0)
        err(1, "time_pps_getcap");

    pp.mode = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
    pp.mode = PPS_CAPTUREBOTH;
    /* pp.mode = PPS_CAPTUREASSERT; */

    i = time_pps_setparams(ph, &pp);
    if (i < 0)
        err(1, "time_pps_setparams");

    while (1) {
        to.tv_nsec = 0;
        to.tv_sec = 0;
        i = time_pps_fetch(ph, PPS_TSFMT_TSPEC, &pi, &to);
        if (i < 0)
            err(1, "time_pps_fetch");
        if (olda == pi.assert_sequence &&
                oldc == pi.clear_sequence) {
            usleep(10000);
            continue;
        }

        Chew(&pi.assert_timestamp, &pi.clear_timestamp,
             pi.assert_sequence, pi.clear_sequence);
        olda = pi.assert_sequence;
        oldc = pi.clear_sequence;
    }

    return(0);
}
Ejemplo n.º 2
0
int
serOpenDev ( serDevT* dev )
{
#ifdef ENABLE_TIMEPPS
	pps_params_t	ppsparams;
	int		ppsmode;
#endif

	dev->fd = open ( dev->dev, O_RDONLY|O_NOCTTY );

	switch ( dev->mode )
	{
#ifdef ENABLE_TIMEPPS
	case SERPORT_MODE_TIMEPPS:
		if ( time_pps_create ( dev->fd, &dev->ppshandle ) == -1 )
			return -1;

		if ( time_pps_getparams ( dev->ppshandle, &ppsparams ) == -1 )
			return -1;

		ppsparams.mode |= PPS_TSFMT_TSPEC | PPS_CAPTUREBOTH;

		if ( time_pps_setparams ( dev->ppshandle, &ppsparams ) == -1 )
			return -1;

		if ( time_pps_getcap ( dev->ppshandle, &ppsmode ) == -1 )
			return -1;

		//NOTE: these should probably be error cases, but the code is still experimental and
		//the PPS support I've used also seems to have problems
		if ( ! (ppsmode | PPS_CAPTUREASSERT) )
			loggerf ( LOGGER_NOTE, "Warning: PPS_CAPTUREASSERT not supported\n" );
		if ( ! (ppsmode | PPS_CAPTURECLEAR) )
			loggerf ( LOGGER_NOTE, "Warning: PPS_CAPTURECLEAR not supported\n" );

//!!! no point using this - too many problems
//1. linux doesn't report PPS_CANWAIT, but can
//2. FreeBSD does report PPS_CANWAIT, but can't
//(unless its me reading the docs backwards?)
//		if ( ! (ppsmode | PPS_CANWAIT) )
//			loggerf ( LOGGER_NOTE, "Warning: PPS_CANWAIT not supported (linux lies)\n" );

#endif
	}

	return dev->fd;
}
Ejemplo n.º 3
0
    PPS::PPS(const std::string& dev)
    {
      // Linux v2.6 (LinuxPPS) implementation.
#if defined(DUNE_SYS_HAS_TIMEPPS_H)
      // Try to find the source by using the supplied "path" name
      int rv = open(dev.c_str(), O_RDWR);
      if (rv < 0)
        throw std::runtime_error(Utils::String::str("unable to open PPS device '%s'\n", dev.c_str()));

      // Open the PPS source (and check the file descriptor)
      rv = time_pps_create(rv, &m_handle);
      if (rv < 0)
        throw std::runtime_error(Utils::String::str("cannot create a PPS source from device '%s'\n", dev.c_str()));

      // Find out what features are supported
      int mode = 0;
      rv = time_pps_getcap(m_handle, &mode);
      if (rv < 0)
        throw std::runtime_error(Utils::String::str("cannot get capabilities of device '%s'\n", dev.c_str()));

      if ((mode & PPS_CAPTUREASSERT) == 0)
        throw std::runtime_error("device does not support CAPTUREASSERT");

      if ((mode & PPS_OFFSETASSERT) == 0)
        throw std::runtime_error("device does not support OFFSETASSERT");

      // Capture assert timestamps, and compensate for a 675 nsec
      // propagation delay.
      pps_params_t params;
      rv = time_pps_getparams(m_handle, &params);
      if (rv < 0)
        throw std::runtime_error("unable to retrieve parameters");

      params.assert_offset.tv_sec = 0;
      params.assert_offset.tv_nsec = 675;
      params.mode |= PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
      params.mode &= ~(PPS_CAPTURECLEAR | PPS_OFFSETCLEAR);
      rv = time_pps_setparams(m_handle, &params);
      if (rv < 0)
        throw std::runtime_error("unable to set parameters");

      // Not yet implemented.
#else
      (void)dev;

#endif
    }
Ejemplo n.º 4
0
static int find_source(char *path, pps_handle_t *handle, int *avail_mode)
{
	int ret;

	printf("trying PPS source \"%s\"\n", path);

	/* Try to find the source by using the supplied "path" name */
	ret = open(path, O_RDWR);
	if (ret < 0) {
		fprintf(stderr, "unable to open device \"%s\" (%m)\n", path);
		return ret;
	}

	/* Open the PPS source (and check the file descriptor) */
	ret = time_pps_create(ret, handle);
	if (ret < 0) {
		fprintf(stderr, "cannot create a PPS source from device "
				"\"%s\" (%m)\n", path);
		return -1;
	}
	printf("found PPS source \"%s\"\n", path);

	/* Find out what features are supported */
	ret = time_pps_getcap(*handle, avail_mode);
	if (ret < 0) {
		fprintf(stderr, "cannot get capabilities (%m)\n");
		return -1;
	}
	if ((*avail_mode & PPS_CAPTUREASSERT) == 0) {
		fprintf(stderr, "cannot CAPTUREASSERT\n");
		return -1;
	}
	if ((*avail_mode & PPS_OFFSETASSERT) == 0) {
		fprintf(stderr, "cannot OFFSETASSERT\n");
		return -1;
	}

	return 0;
}
Ejemplo n.º 5
0
/*@-compdestroy -nullpass -unrecog@*/
static int init_kernel_pps(struct gps_device_t *session)
/* return handle for kernel pps, or -1; requires root privileges */
{
#ifndef S_SPLINT_S
    pps_params_t pp;
#endif /* S_SPLINT_S */
    int ret;
#ifdef linux
    /* These variables are only needed by Linux to find /dev/ppsN. */
    int ldisc = 18;   /* the PPS line discipline */
    glob_t globbuf;
    size_t i;             /* to match type of globbuf.gl_pathc */
    char pps_num = '\0';  /* /dev/pps[pps_num] is our device */
    char path[GPS_PATH_MAX] = "";
#endif

    session->kernelpps_handle = -1;
    if ( isatty(session->gpsdata.gps_fd) == 0 ) {
	gpsd_report(session->context->debug, LOG_INF, "KPPS gps_fd not a tty\n");
    	return -1;
    }

    /*
     * This next code block abuses "ret" by storing the filedescriptor
     * to use for RFC2783 calls.
     */
    ret = -1;
#ifdef linux
    /*
     * On Linux, one must make calls to associate a serial port with a
     * /dev/ppsN device and then grovel in system data to determine
     * the association.
     */
    /*@+ignoresigns@*/
    /* Attach the line PPS discipline, so no need to ldattach */
    /* This activates the magic /dev/pps0 device */
    /* Note: this ioctl() requires root */
    if ( 0 > ioctl(session->gpsdata.gps_fd, TIOCSETD, &ldisc)) {
	gpsd_report(session->context->debug, LOG_INF,
		    "KPPS cannot set PPS line discipline: %s\n",
		    strerror(errno));
    	return -1;
    }
    /*@-ignoresigns@*/

    /* uh, oh, magic file names!, RFC2783 neglects to specify how
     * to associate the serial device and pps device names */
    /* need to look in /sys/devices/virtual/pps/pps?/path
     * (/sys/class/pps/pps?/path is just a link to that)
     * to find the /dev/pps? that matches our serial port.
     * this code fails if there are more then 10 pps devices.
     *
     * yes, this could be done with libsysfs, but trying to keep the
     * number of required libs small, and libsysfs would still be linux only */
    memset( (void *)&globbuf, 0, sizeof(globbuf));
    (void)glob("/sys/devices/virtual/pps/pps?/path", 0, NULL, &globbuf);

    memset( (void *)&path, 0, sizeof(path));
    for ( i = 0; i < globbuf.gl_pathc; i++ ) {
        int fd = open(globbuf.gl_pathv[i], O_RDONLY);
	if ( 0 <= fd ) {
	    ssize_t r = read( fd, path, sizeof(path) -1);
	    if ( 0 < r ) {
		path[r - 1] = '\0'; /* remove trailing \x0a */
	    }
	    (void)close(fd);
	}
	gpsd_report(session->context->debug, LOG_INF,
		    "KPPS checking %s, %s\n",
		    globbuf.gl_pathv[i], path);
	if ( 0 == strncmp( path, session->gpsdata.dev.path, sizeof(path))) {
	    /* this is the pps we are looking for */
	    /* FIXME, now build the proper pps device path */
	    pps_num = globbuf.gl_pathv[i][28];
	    break;
	}
	memset( (void *)&path, 0, sizeof(path));
    }
    /* done with blob, clear it */
    globfree(&globbuf);

    if ( 0 == (int)pps_num ) {
	gpsd_report(session->context->debug, LOG_INF,
		    "KPPS device not found.\n");
    	return -1;
    }
    /* contruct the magic device path */
    (void)snprintf(path, sizeof(path), "/dev/pps%c", pps_num);

    /* root privs are required for this device open */
    if ( 0 != getuid() ) {
	gpsd_report(session->context->debug, LOG_INF,
		    "KPPS only works as root \n");
    	return -1;
    }
    ret = open(path, O_RDWR);
    if ( 0 > ret ) {
	gpsd_report(session->context->debug, LOG_INF,
		    "KPPS cannot open %s: %s\n", path, strerror(errno));
    	return -1;
    }
#else /* not linux */
    /*
     * On BSDs that support RFC2783, one uses the API calls on serial
     * port file descriptor.
     */
    // cppcheck-suppress redundantAssignment
    ret  = session->gpsdata.gps_fd;
#endif
    /* assert(ret >= 0); */
    gpsd_report(session->context->debug, LOG_INF,
		"KPPS RFC2783 fd is %d\n",
		ret);

    /* RFC 2783 implies the time_pps_setcap() needs priviledges *
     * keep root a tad longer just in case */
    if ( 0 > time_pps_create(ret, &session->kernelpps_handle )) {
	gpsd_report(session->context->debug, LOG_INF,
		    "KPPS time_pps_create(%d) failed: %s\n",
		    ret, strerror(errno));
    	return -1;
    } else {
#ifndef S_SPLINT_S
    	/* have kernel PPS handle */
        int caps;
	/* get features  supported */
        if ( 0 > time_pps_getcap(session->kernelpps_handle, &caps)) {
	    gpsd_report(session->context->debug, LOG_ERROR,
			"KPPS time_pps_getcap() failed\n");
        } else {
	    gpsd_report(session->context->debug,
			LOG_INF, "KPPS caps %0x\n", caps);
        }

#ifdef linux
        /* linux 2.6.34 can not PPS_ECHOASSERT | PPS_ECHOCLEAR */
        memset( (void *)&pp, 0, sizeof(pps_params_t));
        pp.mode = PPS_CAPTUREBOTH;
#else /* not linux */
	/*
	 * Attempt to follow RFC2783 as straightforwardly as possible.
	 */
	pp.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREBOTH;
#endif
#endif /* S_SPLINT_S */

        if ( 0 > time_pps_setparams(session->kernelpps_handle, &pp)) {
	    gpsd_report(session->context->debug, LOG_ERROR,
		"KPPS time_pps_setparams() failed: %s\n", strerror(errno));
	    time_pps_destroy(session->kernelpps_handle);
	    return -1;
        }
    }
    return 0;
}
Ejemplo n.º 6
0
int
report_pps_capability(pps_handle_t ph, int *capability)
{
	int err;

	err = time_pps_getcap(ph, capability);
	if (err < 0) {
		fprintf(stderr, "time_pps_getcap failed");
		return err;
	}

	fprintf(stdout, "%% PPS-API Capability report:\n");

	if (*capability & PPS_CAPTUREASSERT)
		fprintf(stdout, "%%  PPS_CAPTUREASSERT:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_CAPTUREASSERT:\tno\n");

	if (*capability & PPS_CAPTURECLEAR)
		fprintf(stdout, "%%  PPS_CAPTURECLEAR:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_CAPTURECLEAR:\tno\n");

	if (*capability & PPS_OFFSETASSERT)
		fprintf(stdout, "%%  PPS_OFFSETASSERT:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_OFFSETASSERT:\tno\n");

	if (*capability & PPS_OFFSETCLEAR)
		fprintf(stdout, "%%  PPS_OFFSETCLEAR:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_OFFSETCLEAR:\tno\n");

	if (*capability & PPS_ECHOASSERT)
		fprintf(stdout, "%%  PPS_ECHOASSERT:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_ECHOASSERT:\tno\n");

	if (*capability & PPS_ECHOCLEAR)
		fprintf(stdout, "%%  PPS_ECHOCLEAR:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_ECHOCLEAR:\tno\n");

	if (*capability & PPS_CANWAIT)
		fprintf(stdout, "%%  PPS_CANWAIT:\t\tyes\n");
	else
		fprintf(stdout, "%%  PPS_CANWAIT:\t\tno\n");

	if (*capability & PPS_CANPOLL)
		fprintf(stdout, "%%  PPS_CANPOLL:\t\tyes\n");
	else
		fprintf(stdout, "%%  PPS_CANPOLL:\t\tno\n");

	if (*capability & PPS_TSFMT_TSPEC)
		fprintf(stdout, "%%  PPS_TSFMT_TSPEC:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_TSFMT_TSPEC:\tno\n");

	if (*capability & PPS_TSFMT_NTPFP)
		fprintf(stdout, "%%  PPS_TSFMT_NTPFP:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_TSFMT_NTPFP:\tno\n");

	if (*capability & PPS_TSCLK_FBCK)
		fprintf(stdout, "%%  PPS_TSCLK_FBCK:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_TSCLK_FBCK:\tno\n");

	if (*capability & PPS_TSCLK_FFWD)
		fprintf(stdout, "%%  PPS_TSCLK_FFWD:\tyes\n");
	else
		fprintf(stdout, "%%  PPS_TSCLK_FFWD:\tno\n");

	return 0;
}
Ejemplo n.º 7
0
/* return handle for kernel pps, or -1 */
static int init_kernel_pps(struct gps_device_t *session) {
    int ldisc = 18;   /* the PPS line discipline */
    pps_params_t pp;
    glob_t globbuf;
    size_t i;             /* to match type of globbuf.gl_pathc */
    char pps_num = 0;     /* /dev/pps[pps_num] is our device */
    char path[GPS_PATH_MAX] = "";

    session->kernelpps_handle = -1;
    if ( !isatty(session->gpsdata.gps_fd) ) {
	gpsd_report(LOG_INF, "KPPS gps_fd not a tty\n");
    	return -1;
    }
    /* Attach the line PPS discipline, so no need to ldattach */
    /* This activates the magic /dev/pps0 device */
    /* Note: this ioctl() requires root */
    if ( 0 > ioctl(session->gpsdata.gps_fd, TIOCSETD, &ldisc)) {
	gpsd_report(LOG_INF, "KPPS cannot set PPS line discipline: %s\n"
	    , strerror(errno));
    	return -1;
    }

    /* uh, oh, magic file names!, this is not how RFC2783 was designed */
    /* need to look in /sys/devices/virtual/pps/pps?/path
     * (/sys/class/pps/pps?/path is just a link to that)
     * to find the /dev/pps? that matches our serial port.
     * this code fails if there are more then 10 pps devices.
     *     
     * yes, this could be done with libsysfs, but trying to keep the
     * number of required libs small */
    memset( (void *)&globbuf, 0, sizeof(globbuf));
    glob("/sys/devices/virtual/pps/pps?/path", 0, NULL, &globbuf);

    memset( (void *)&path, 0, sizeof(path));
    for ( i = 0; i < globbuf.gl_pathc; i++ ) {
        int fd = open(globbuf.gl_pathv[i], O_RDONLY);
	if ( 0 <= fd ) {
	    ssize_t r = read( fd, path, sizeof(path) -1);
	    if ( 0 < r ) {
		path[r - 1] = '\0'; /* remove trailing \x0a */
	    }
	    close(fd);
	}
	gpsd_report(LOG_INF, "KPPS checking %s, %s\n"
	    , globbuf.gl_pathv[i], path);
	if ( 0 == strncmp( path, session->gpsdata.dev.path, sizeof(path))) {
	    /* this is the pps we are looking for */
	    /* FIXME, now build the proper pps device path */
	    pps_num = globbuf.gl_pathv[i][28];
	    break;
	}
	memset( (void *)&path, 0, sizeof(path));
    }
    /* done with blob, clear it */
    globfree(&globbuf);

    if ( 0 == pps_num ) {
	gpsd_report(LOG_INF, "KPPS device not found.\n");
    	return -1;
    }
    /* contruct the magic device path */
    (void)snprintf(path, sizeof(path), "/dev/pps%c", pps_num);

    /* root privs are required for this device open */
    int ret = open(path, O_RDWR);
    if ( 0 > ret ) {
	gpsd_report(LOG_INF, "KPPS cannot open %s: %s\n"
	    , path, strerror(errno));
    	return -1;
    }
    /* root privs are not required past this point */ 

    if ( 0 > time_pps_create(ret, &session->kernelpps_handle )) {
	gpsd_report(LOG_INF, "KPPS time_pps_create(%d) failed: %s\n"
	    , ret, strerror(errno));
    	return -1;
    } else {
    	/* have kernel PPS handle */
        int caps;
	/* get features  supported */
        if ( 0 > time_pps_getcap(session->kernelpps_handle, &caps)) {
	    gpsd_report(LOG_ERROR, "KPPS time_pps_getcap() failed\n");
        } else {
	    gpsd_report(LOG_INF, "KPPS caps %0x\n", caps);
        }

        /* linux 2.6.34 can not PPS_ECHOASSERT | PPS_ECHOCLEAR */
        memset( (void *)&pp, 0, sizeof(pps_params_t));
        pp.mode = PPS_CAPTUREBOTH;

        if ( 0 > time_pps_setparams(session->kernelpps_handle, &pp)) {
	    gpsd_report(LOG_ERROR, 
		"KPPS time_pps_setparams() failed: %s\n", strerror(errno));
	    time_pps_destroy(session->kernelpps_handle);
	    return -1;
        }
    }
    return 0;
}
Ejemplo n.º 8
0
static int init_kernel_pps(struct inner_context_t *inner_context)
/* return handle for kernel pps, or -1; requires root privileges */
{
    pps_params_t pp;
    int ret;
#ifdef __linux__
    /* These variables are only needed by Linux to find /dev/ppsN. */
    int ldisc = 18;   /* the PPS line discipline */
    glob_t globbuf;
#endif
    char path[PATH_MAX] = "";
    volatile struct pps_thread_t *pps_thread = inner_context->pps_thread;

    inner_context->kernelpps_handle = -1;
    inner_context->pps_canwait = false;

    /*
     * This next code block abuses "ret" by storing the filedescriptor
     * to use for RFC2783 calls.
     */
#ifndef __clang_analyzer__
    ret = -1;  /* this ret will not be unneeded when the 'else' part
                * of the followinng ifdef becomes an #elif */
#endif /* __clang_analyzer__ */
#ifdef __linux__
    /*
     * Some Linuxes, like the RasbPi's, have PPS devices preexisting.
     * Other OS have no way to automatically determine the proper /dev/ppsX.
     * Allow user to pass in an explicit PPS device path.
     *
     * (We use strncpy() here because this might be compiled where
     * strlcpy() is not available.)
     */
    if (strncmp(pps_thread->devicename, "/dev/pps", 8) == 0)
	(void)strncpy(path, pps_thread->devicename, sizeof(path));
    else {
	char pps_num = '\0';  /* /dev/pps[pps_num] is our device */
	size_t i;             /* to match type of globbuf.gl_pathc */
	/*
	 * Otherwise one must make calls to associate a serial port with a
	 * /dev/ppsN device and then grovel in system data to determine
	 * the association.
	 */

	/* Attach the line PPS discipline, so no need to ldattach */
	/* This activates the magic /dev/pps0 device */
	/* Note: this ioctl() requires root, and device is a tty */
	if ( 0 > ioctl(pps_thread->devicefd, TIOCSETD, &ldisc)) {
	    char errbuf[BUFSIZ] = "unknown error";
	    strerror_r(errno, errbuf, sizeof(errbuf));
	    pps_thread->log_hook(pps_thread, THREAD_INF,
				 "KPPS:%s cannot set PPS line discipline %s\n",
				 pps_thread->devicename, errbuf);
	    return -1;
	}

	/* uh, oh, magic file names!, RFC2783 neglects to specify how
	 * to associate the serial device and pps device names */
	/* need to look in /sys/devices/virtual/pps/pps?/path
	 * (/sys/class/pps/pps?/path is just a link to that)
	 * to find the /dev/pps? that matches our serial port.
	 * this code fails if there are more then 10 pps devices.
	 *
	 * yes, this could be done with libsysfs, but trying to keep
	 * the number of required libs small, and libsysfs would still
	 * be linux only */
	memset( (void *)&globbuf, 0, sizeof(globbuf));
	(void)glob("/sys/devices/virtual/pps/pps?/path", 0, NULL, &globbuf);

	memset( (void *)&path, 0, sizeof(path));
	for ( i = 0; i < globbuf.gl_pathc; i++ ) {
	    int fd = open(globbuf.gl_pathv[i], O_RDONLY);
	    if ( 0 <= fd ) {
		ssize_t r = read( fd, path, sizeof(path) -1);
		if ( 0 < r ) {
		    path[r - 1] = '\0'; /* remove trailing \x0a */
		}
		(void)close(fd);
	    }
	    pps_thread->log_hook(pps_thread, THREAD_PROG,
				 "KPPS:%s checking %s, %s\n",
				 pps_thread->devicename,
				 globbuf.gl_pathv[i], path);
	    if ( 0 == strncmp( path, pps_thread->devicename, sizeof(path))) {
		/* this is the pps we are looking for */
		/* FIXME, now build the proper pps device path */
		pps_num = globbuf.gl_pathv[i][28];
		break;
	    }
	    memset( (void *)&path, 0, sizeof(path));
	}
	/* done with blob, clear it */
	globfree(&globbuf);

	if ( 0 == (int)pps_num ) {
	    pps_thread->log_hook(pps_thread, THREAD_INF,
				 "KPPS:%s device not found.\n",
				 pps_thread->devicename);
	    return -1;
	}
	/* construct the magic device path */
	(void)snprintf(path, sizeof(path), "/dev/pps%c", pps_num);
    }

    /* root privs are probably required for this device open
     * do not bother to check uid, just go for the open() */

    ret = open(path, O_RDWR);
    if ( 0 > ret ) {
	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",
		    pps_thread->devicename,
                    path, errbuf);
    	return -1;
    }
#else /* not __linux__ */
    /*
     * On BSDs that support RFC2783, one uses the API calls on serial
     * port file descriptor.
     *
     * FIXME! need more specific than 'not linux'
     */
    (void)strlcpy(path, pps_thread->devicename, sizeof(path));
    // cppcheck-suppress redundantAssignment
    ret  = pps_thread->devicefd;
#endif
    /* assert(ret >= 0); */
    pps_thread->log_hook(pps_thread, THREAD_INF,
		"KPPS:%s RFC2783 path:%s, fd is %d\n",
	        pps_thread->devicename, path,
		ret);

    /* 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 *)&inner_context->kernelpps_handle )) {
	char errbuf[BUFSIZ] = "unknown error";
	(void)strerror_r(errno, errbuf, sizeof(errbuf));
	pps_thread->log_hook(pps_thread, THREAD_INF,
		    "KPPS:%s time_pps_create(%d) failed: %s\n",
	            pps_thread->devicename,
		    ret, errbuf);
    	return -1;
    }

    /* have kernel PPS handle */
    /* get RFC2783 features supported */
    inner_context->pps_caps = 0;
    if ( 0 > time_pps_getcap(inner_context->kernelpps_handle,
				&inner_context->pps_caps)) {
	char errbuf[BUFSIZ] = "unknown error";
	inner_context->pps_caps = 0;
	(void)strerror_r(errno, errbuf, sizeof(errbuf));
	pps_thread->log_hook(pps_thread, THREAD_INF,
		    "KPPS:%s time_pps_getcap() failed: %.100s\n",
		    pps_thread->devicename, errbuf);
    	return -1;
    } else {
	pps_thread->log_hook(pps_thread, THREAD_INF,
		    "KPPS:%s pps_caps 0x%02X\n",
		    pps_thread->devicename,
		    inner_context->pps_caps);
    }

    /* construct the setparms structure */
    memset( (void *)&pp, 0, sizeof(pps_params_t));
    pp.api_version = PPS_API_VERS_1;  /* version 1 protocol */
    if ( 0 == (PPS_TSFMT_TSPEC & inner_context->pps_caps ) ) {
       /* PPS_TSFMT_TSPEC means return a timespec
        * mandatory for driver to implement, require it */
	pps_thread->log_hook(pps_thread, THREAD_WARN,
		    "KPPS:%s fail, missing mandatory PPS_TSFMT_TSPEC\n",
		    pps_thread->devicename);
        return -1;
    }
    if ( 0 != (PPS_CANWAIT & inner_context->pps_caps ) ) {
       /* we can wait! so no need for TIOCMIWAIT */
       pps_thread->log_hook(pps_thread, THREAD_INF,
                   "KPPS:%s have PPS_CANWAIT\n",
                   pps_thread->devicename);
        inner_context->pps_canwait = true;
    }

    pp.mode = PPS_TSFMT_TSPEC;
    switch ( (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR) & inner_context->pps_caps ) {
    case PPS_CAPTUREASSERT:
	pps_thread->log_hook(pps_thread, THREAD_WARN,
		    "KPPS:%s missing PPS_CAPTURECLEAR, pulse may be offset\n",
		    pps_thread->devicename);
	pp.mode |= PPS_CAPTUREASSERT;
        break;
    case PPS_CAPTURECLEAR:
	pps_thread->log_hook(pps_thread, THREAD_WARN,
		    "KPPS:%s missing PPS_CAPTUREASSERT, pulse may be offset\n",
		    pps_thread->devicename);
	pp.mode |= PPS_CAPTURECLEAR;
        break;
    case PPS_CAPTUREASSERT | PPS_CAPTURECLEAR:
	pp.mode |= PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
        break;
    default:
        /* THREAD_ERR in the calling routine */
	pps_thread->log_hook(pps_thread, THREAD_INF,
		    "KPPS:%s missing PPS_CAPTUREASSERT and CLEAR\n",
		    pps_thread->devicename);
        return -1;
    }

    if ( 0 > time_pps_setparams(inner_context->kernelpps_handle, &pp)) {
	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",
	    pps_thread->devicename, pp.mode,
	    errbuf);
	(void)time_pps_destroy(inner_context->kernelpps_handle);
	return -1;
    }
    return 0;
}
Ejemplo n.º 9
0
int
main(int argc, char **argv)
{
	int fd;
	FILE *fdo;
	pps_info_t pi;
	pps_params_t pp;
	pps_handle_t ph;
	int i, mode;
	u_int olda, oldc;
	struct timespec to;
	char const *ofn;

	ofn = NULL;
	while ((i = getopt(argc, argv, "aAbBcCeo:uv")) != -1) {
		switch (i) {
		case 'a': aflag = 1; break;
		case 'A': Aflag = 1; break;
		case 'b': aflag = 1; cflag = 1; break;
		case 'B': Aflag = 1; Cflag = 1; break;
		case 'c': cflag = 1; break;
		case 'C': Cflag = 1; break;
		case 'e': eflag = 1; break;
		case 'o': ofn = optarg; break;
		case 'u': uflag = 1; break;
		case 'v': vflag = 1; break;
		case '?':
		default:
			fprintf(stderr,
			    "Usage: ppsapitest [-aAcC] device\n");
			exit (1);
		}
	}
	if (ofn != NULL) {
		fdo = fopen(ofn, "w");
		if (fdo == NULL)
			err(1, "Cannot open %s", ofn);
	} else {
		fdo = NULL;
	}
	argc -= optind;
	argv += optind;
	if (argc > 0) {
		fd = open(argv[0], O_RDONLY);
		if (fd < 0) 
			err(1, argv[0]);
	} else {
		fd = 0;
	}
	i = time_pps_create(fd, &ph);
	if (i < 0)
		err(1, "time_pps_create");

	i = time_pps_getcap(ph, &mode);
	if (i < 0)
		err(1, "time_pps_getcap");
	if (vflag) {
		fprintf(stderr, "Supported modebits:");
		if (mode & PPS_CAPTUREASSERT)
			fprintf(stderr, " CAPTUREASSERT");
		if (mode & PPS_CAPTURECLEAR)
			fprintf(stderr, " CAPTURECLEAR");
		if (mode & PPS_OFFSETASSERT)
			fprintf(stderr, " OFFSETASSERT");
		if (mode & PPS_OFFSETCLEAR)
			fprintf(stderr, " OFFSETCLEAR");
		if (mode & PPS_ECHOASSERT)
			fprintf(stderr, " ECHOASSERT");
		if (mode & PPS_ECHOCLEAR)
			fprintf(stderr, " ECHOCLEAR");
		if (mode & PPS_CANWAIT)
			fprintf(stderr, " CANWAIT");
		if (mode & PPS_CANPOLL)
			fprintf(stderr, " CANPOLL");
		if (mode & PPS_TSFMT_TSPEC)
			fprintf(stderr, " TSPEC");
		if (mode & PPS_TSFMT_NTPFP)
			fprintf(stderr, " NTPFP");
		fprintf(stderr, "\n");
	}

	if (!aflag && !cflag) {
		if (mode & PPS_CAPTUREASSERT)
			aflag = 1;
		if (mode & PPS_CAPTURECLEAR)
			cflag = 1;
	}
	if (!Aflag && !Cflag) {
		Aflag = aflag;
		Cflag = cflag;
	}

	if (Cflag && !(mode & PPS_CAPTURECLEAR))
		errx(1, "-C but cannot capture on clear flank");

	if (Aflag && !(mode & PPS_CAPTUREASSERT))
		errx(1, "-A but cannot capture on assert flank");

	i = time_pps_getparams(ph, &pp);
	if (i < 0)
		err(1, "time_pps_getparams():");

	if (aflag)
		pp.mode |= PPS_CAPTUREASSERT;
	if (cflag)
		pp.mode |= PPS_CAPTURECLEAR;

	if (eflag & aflag)
		pp.mode |= PPS_ECHOASSERT;

	if (eflag & cflag)
		pp.mode |= PPS_ECHOCLEAR;

	if (!(pp.mode & PPS_TSFMT_TSPEC))
		pp.mode |= PPS_TSFMT_TSPEC;
	
	i = time_pps_setparams(ph, &pp);
	if (i < 0) {
		err(1, "time_pps_setparams(mode %x):", pp.mode);
	}

	/*
	 * Pick up first event outside the loop in order to not
	 * get something ancient into the outfile.
	 */
	to.tv_nsec = 0;
	to.tv_sec = 0;
	i = time_pps_fetch(ph, PPS_TSFMT_TSPEC, &pi, &to);
	if (i < 0)
		err(1, "time_pps_fetch()");
	olda = pi.assert_sequence;
	oldc = pi.clear_sequence;

	while (1) {
		to.tv_nsec = 0;
		to.tv_sec = 0;
		i = time_pps_fetch(ph, PPS_TSFMT_TSPEC, &pi, &to);
		if (i < 0)
			err(1, "time_pps_fetch()");
		if (oldc != pi.clear_sequence && Cflag)
			;
		else if (olda != pi.assert_sequence && Aflag)
			;
		else {
			usleep(10000);
			continue;
		}
		if (fdo != NULL) {
			if (fwrite(&pi, sizeof pi, 1, fdo) != 1)
				err(1, "Write error on %s", ofn);
			if (uflag)
				fflush(fdo);
		}
		Chew(&pi.assert_timestamp, &pi.clear_timestamp,
			pi.assert_sequence, pi.clear_sequence);
		olda = pi.assert_sequence;
		oldc = pi.clear_sequence;
	}
	return(0);
}