ppscheck.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * Watch a specified serial port for transitions that might be 1PPS.
  3. *
  4. * Each output line is the second and nanosecond parts of a timestamp
  5. * followed by the names of handshake signals then asserted. Off
  6. * transitions may generate lines with no signals aserted.
  7. *
  8. * If you don't see output within a second, use gpsmon or some other
  9. * equivalent tool to check that your device has satellite lock and is
  10. * getting fixes before giving up on the possibility of 1PPS.
  11. *
  12. * Also, check your cable. Cheap DB9 to DB9 cables such as those
  13. * issued with UPSes often carry TXD/RXD/GND only, omitting handshake
  14. * lines such as DCD. Suspect this especially if the cable jacket
  15. * looks too skinny to hold more than three leads!
  16. *
  17. * This code requires only ANSI/POSIX. If it doesn't compile and run
  18. * on your Unix there is something very wrong with your Unix.
  19. *
  20. * This code by ESR, Copyright (C) 2013, under BSD terms.
  21. * This file is Copyright (c)2013-2018 by the GPSD project
  22. * SPDX-License-Identifier: BSD-2-clause
  23. */
  24. #include "gpsd_config.h" /* must be before all includes */
  25. #include <errno.h>
  26. #include <fcntl.h> /* needed for open() and friends */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <sys/ioctl.h>
  31. #include <sys/stat.h>
  32. #include <sys/types.h>
  33. #include <time.h>
  34. #include <unistd.h>
  35. #include "revision.h"
  36. #include "timespec.h"
  37. struct assoc {
  38. int mask;
  39. char *string;
  40. };
  41. /*
  42. * Possible pins for PPS: DCD, CTS, RI, DSR. Pinouts:
  43. *
  44. * DB9 DB25 Name Full name
  45. * --- ---- ---- --------------------
  46. * 3 2 TXD --> Transmit Data
  47. * 2 3 RXD <-- Receive Data
  48. * 7 4 RTS --> Request To Send
  49. * 8 5 CTS <-- Clear To Send
  50. * 6 6 DSR <-- Data Set Ready
  51. * 4 20 DTR --> Data Terminal Ready
  52. * 1 8 DCD <-- Data Carrier Detect
  53. * 9 22 RI <-- Ring Indicator
  54. * 5 7 GND Signal ground
  55. *
  56. * Note that it only makes sense to wait on handshake lines
  57. * activated from the receive side (DCE->DTE) here; in this
  58. * context "DCE" is the GPS. {CD,RI,CTS,DSR} is the
  59. * entire set of these.
  60. */
  61. static const struct assoc hlines[] = {
  62. {TIOCM_CD, "TIOCM_CD"},
  63. {TIOCM_RI, "TIOCM_RI"},
  64. {TIOCM_DSR, "TIOCM_DSR"},
  65. {TIOCM_CTS, "TIOCM_CTS"},
  66. };
  67. static void usage(void)
  68. {
  69. (void)fprintf(stderr, "usage: ppscheck [-h] [ -V] <device>\n");
  70. (void)fprintf(stderr, " -h print usage\n");
  71. (void)fprintf(stderr, " -V print cwVersion\n");
  72. exit(1);
  73. }
  74. int main(int argc, char *argv[])
  75. {
  76. struct timespec ts;
  77. int fd;
  78. int c;
  79. char ts_buf[TIMESPEC_LEN];
  80. while((c = getopt(argc, argv, "hV")) != -1) {
  81. switch(c){
  82. case 'h':
  83. default:
  84. usage();
  85. exit(0);
  86. case 'V':
  87. (void)printf("%s: %s\n", argv[0], REVISION);
  88. exit(EXIT_SUCCESS);
  89. }
  90. }
  91. argc -= optind;
  92. argv += optind;
  93. if (argc != 1)
  94. usage();
  95. fd = open(argv[0], O_RDONLY);
  96. if (fd == -1) {
  97. (void)fprintf(stderr,
  98. "open(%s) failed: %d %.40s\n",
  99. argv[0], errno, strerror(errno));
  100. exit(1);
  101. }
  102. (void)fprintf(stdout, "# Seconds nanoSecs Signals\n");
  103. for (;;) {
  104. if (ioctl(fd, TIOCMIWAIT, TIOCM_CD|TIOCM_DSR|TIOCM_RI|TIOCM_CTS) != 0) {
  105. (void)fprintf(stderr,
  106. "PPS ioctl(TIOCMIWAIT) failed: %d %.40s\n",
  107. errno, strerror(errno));
  108. break;
  109. } else {
  110. const struct assoc *sp;
  111. int handshakes;
  112. (void)clock_gettime(CLOCK_REALTIME, &ts);
  113. (void)ioctl(fd, TIOCMGET, &handshakes);
  114. (void)fprintf(stdout, "%s",
  115. timespec_str(&ts, ts_buf, sizeof(ts_buf)));
  116. for (sp = hlines;
  117. sp < hlines + sizeof(hlines)/sizeof(hlines[0]);
  118. sp++)
  119. if ((handshakes & sp->mask) != 0) {
  120. (void)fputc(' ', stdout);
  121. (void)fputs(sp->string, stdout);
  122. }
  123. (void)fputc('\n', stdout);
  124. }
  125. }
  126. exit(EXIT_SUCCESS);
  127. }
  128. /* end */