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); }
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; }
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, ¶ms); 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, ¶ms); if (rv < 0) throw std::runtime_error("unable to set parameters"); // Not yet implemented. #else (void)dev; #endif }
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; }
/*@-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; }
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; }
/* 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; }
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; }
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); }