ppscheck.c 4.2 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 asserted.
  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 2013, under BSD terms.
  21. * This file is Copyright 2013 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 "timespec.h"
  36. struct assoc {
  37. int mask;
  38. char *string;
  39. };
  40. /*
  41. * Possible pins for PPS: DCD, CTS, RI, DSR. Pinouts:
  42. *
  43. * DB9 DB25 Name Full name
  44. * --- ---- ---- --------------------
  45. * 3 2 TXD --> Transmit Data
  46. * 2 3 RXD <-- Receive Data
  47. * 7 4 RTS --> Request To Send
  48. * 8 5 CTS <-- Clear To Send
  49. * 6 6 DSR <-- Data Set Ready
  50. * 4 20 DTR --> Data Terminal Ready
  51. * 1 8 DCD <-- Data Carrier Detect
  52. * 9 22 RI <-- Ring Indicator
  53. * 5 7 GND Signal ground
  54. *
  55. * Note that it only makes sense to wait on handshake lines
  56. * activated from the receive side (DCE->DTE) here; in this
  57. * context "DCE" is the GPS. {CD,RI,CTS,DSR} is the
  58. * entire set of these.
  59. */
  60. static const struct assoc hlines[] = {
  61. {TIOCM_CD, "TIOCM_CD"},
  62. {TIOCM_RI, "TIOCM_RI"},
  63. {TIOCM_DSR, "TIOCM_DSR"},
  64. {TIOCM_CTS, "TIOCM_CTS"},
  65. };
  66. static void usage(void)
  67. {
  68. (void)fprintf(stderr, "usage: ppscheck [-h] [ -V] <device>\n");
  69. (void)fprintf(stderr, " -h print usage\n");
  70. (void)fprintf(stderr, " -V print cwVersion\n");
  71. exit(1);
  72. }
  73. int main(int argc, char *argv[])
  74. {
  75. struct timespec ts;
  76. int fd;
  77. int c;
  78. char ts_buf[TIMESPEC_LEN];
  79. while((c = getopt(argc, argv, "hV")) != -1) {
  80. switch(c){
  81. case 'h':
  82. default:
  83. usage();
  84. exit(0);
  85. case 'V':
  86. (void)printf("%s: %s\n", argv[0], REVISION);
  87. exit(EXIT_SUCCESS);
  88. }
  89. }
  90. argc -= optind;
  91. argv += optind;
  92. if (argc != 1)
  93. usage();
  94. fd = open(argv[0], O_RDONLY);
  95. if (fd == -1) {
  96. (void)fprintf(stderr,
  97. "open(%s) failed: %d %.40s\n",
  98. argv[0], errno, strerror(errno));
  99. exit(1);
  100. }
  101. (void)fprintf(stdout, "# Seconds nanoSecs Signals\n");
  102. for (;;) {
  103. if (ioctl(fd, TIOCMIWAIT, TIOCM_CD|TIOCM_DSR|TIOCM_RI|TIOCM_CTS) != 0) {
  104. (void)fprintf(stderr,
  105. "PPS ioctl(TIOCMIWAIT) failed: %d %.40s\n",
  106. errno, strerror(errno));
  107. break;
  108. } else {
  109. const struct assoc *sp;
  110. int handshakes;
  111. (void)clock_gettime(CLOCK_REALTIME, &ts);
  112. (void)ioctl(fd, TIOCMGET, &handshakes);
  113. (void)fprintf(stdout, "%s",
  114. timespec_str(&ts, ts_buf, sizeof(ts_buf)));
  115. for (sp = hlines;
  116. sp < hlines + sizeof(hlines)/sizeof(hlines[0]);
  117. sp++)
  118. if ((handshakes & sp->mask) != 0) {
  119. (void)fputc(' ', stdout);
  120. (void)fputs(sp->string, stdout);
  121. }
  122. (void)fputc('\n', stdout);
  123. }
  124. }
  125. exit(EXIT_SUCCESS);
  126. }
  127. /* end */
  128. // vim: set expandtab shiftwidth=4