summaryrefslogtreecommitdiff
path: root/ppscheck.c
blob: 1dc2446f98e4c12de08eb5f75b27f97a2b82bc01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * Watch a specified serial port for transitions that might be 1PPS.
 *
 * Each output line is the second and nanosecond parts of a timestamp
 * followed by the names of handshake signals then asserted.  Off
 * transitions may generate lines with no signals aserted.
 *
 * If you don't see output within a second, use gpsmon or some other
 * equivalent tool to check that your device has satellite lock and is
 * getting fixes before giving up on the possibility of 1PPS.
 *
 * Also, check your cable. Cheap DB9 to DB9 cables such as those
 * issued with UPSes often carry TXD/RXD/GND only, omitting handshake
 * lines such as DCD.  Suspect this especially if the cable jacket
 * looks too skinny to hold more than three leads!
 *
 * This code requires only ANSI/POSIX. If it doesn't compile and run
 * on your Unix there is something very wrong with your Unix.
 *
 * This code by ESR, Copyright (C) 2013, under BSD terms.
 * This file is Copyright (c)2013-2018 by the GPSD project
 * SPDX-License-Identifier: BSD-2-clause
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>	/* needed for open() and friends */
#include <sys/ioctl.h>
#include <errno.h>
#include <time.h>
#include "revision.h"

struct assoc {
    int mask;
    char *string;
};

/*
 * Possible pins for PPS: DCD, CTS, RI, DSR. Pinouts:
 *
 * DB9  DB25  Name      Full name
 * ---  ----  ----      --------------------
 *  3     2    TXD  --> Transmit Data
 *  2     3    RXD  <-- Receive Data
 *  7     4    RTS  --> Request To Send
 *  8     5    CTS  <-- Clear To Send
 *  6     6    DSR  <-- Data Set Ready
 *  4    20    DTR  --> Data Terminal Ready
 *  1     8    DCD  <-- Data Carrier Detect
 *  9    22    RI   <-- Ring Indicator
 *  5     7    GND      Signal ground
 *
 * Note that it only makes sense to wait on handshake lines
 * activated from the receive side (DCE->DTE) here; in this
 * context "DCE" is the GPS. {CD,RI,CTS,DSR} is the
 * entire set of these.
 */
static const struct assoc hlines[] = {
    {TIOCM_CD, "TIOCM_CD"},
    {TIOCM_RI, "TIOCM_RI"},
    {TIOCM_DSR, "TIOCM_DSR"},
    {TIOCM_CTS, "TIOCM_CTS"},
};

static void usage(void)
{
	(void)fprintf(stderr, "usage: ppscheck [-h] [ -V] <device>\n");
	(void)fprintf(stderr, "                 -h   print usage\n");
	(void)fprintf(stderr, "                 -V   print cwVersion\n");
	exit(1);
}

int main(int argc, char *argv[])
{
    struct timespec ts;
    int fd;
    int c;

    while((c = getopt(argc, argv, "hV")) != -1) {
	    switch(c){
	    case 'h':
	    default:
		usage();
		exit(0);
	    case 'V':
		(void)printf("%s: %s\n", argv[0], REVISION);
		exit(EXIT_SUCCESS);
	    }
    }
    argc -= optind;
    argv += optind;

    if (argc != 1)
	    usage();

    fd = open(argv[0], O_RDONLY);

    if (fd == -1) {
	(void)fprintf(stderr,
		      "open(%s) failed: %d %.40s\n",
		      argv[0], errno, strerror(errno));
	exit(1);
    }

    (void)fprintf(stdout, "# Seconds  nanoSecs   Signals\n");
    for (;;) {
	if (ioctl(fd, TIOCMIWAIT, TIOCM_CD|TIOCM_DSR|TIOCM_RI|TIOCM_CTS) != 0) {
	    (void)fprintf(stderr,
			  "PPS ioctl(TIOCMIWAIT) failed: %d %.40s\n",
			  errno, strerror(errno));
	    break;
	} else {
	    const struct assoc *sp;
	    int handshakes;

	    (void)clock_gettime(CLOCK_REALTIME, &ts);
	    (void)ioctl(fd, TIOCMGET, &handshakes);
	    (void)fprintf(stdout, "%10ld %09ld", (long)ts.tv_sec, ts.tv_nsec);
	    for (sp = hlines;
		 sp < hlines + sizeof(hlines)/sizeof(hlines[0]);
		 sp++)
		if ((handshakes & sp->mask) != 0) {
		    (void)fputc(' ', stdout);
		    (void)fputs(sp->string, stdout);
		}
	    (void)fputc('\n', stdout);
	}
    }

    exit(EXIT_SUCCESS);
}

/* end */