Commit 89107dda authored by Alessandro Rubini's avatar Alessandro Rubini

tools: added pps-out and documented it

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 14436bb4
......@@ -531,6 +531,50 @@ This is, for example, the dump of two UDP frames:
DUMP: 02 00 00 00 51 36 2a 1f 39 19 34 c5
@end smallexample
@c ==========================================================================
@node pps-out
@section pps-out
The tools outputs a pulse-per-second signal to a parallel port or a
serial port. Most likely it only works on an x86 Linux system because
of direct access to I/O ports -- no such portability problem is
expected for serial ports. For this reason it is not built by
default in the distributed @t{tools/Makefile}
The program receives a single argument on the command line, which is
either an hex port number (with or without leading @t{0x}) or an
absolute filename:
@example
./tools/pps-out 378
./tools/pps-out /dev/ttyS0
@end example
When passed a port number, the program toggles all bits assuming it
refers to a parallel port. When passed a pathname, the program assumes
it is a serial port and it toggles the DTR and RTS modem control signals
(on pins 4 and 7 of the DB9 male connector).
By setting the @t{VERBOSE} environment variable you ask the program
to report how late it was before and after generating the rising
edge:
@example
morgana$ VERBOSE=1 ./tools/pps-out /dev/ttyS0
gettimeofday takes 0.2 usec
udelay takes 4.0 usec
delayed between 0 and 2 usecs
delayed between 0 and 4 usecs
[...]
@end example
@t{pps-out} can be used to verify on a scope the level of
synchronization of two or more computers, but please note that the
user-space software-only approach shows some jitter; on my systems the
delay is usually a few microseconds, up to around a dozen (in general,
use of the parallel port has less delay and less jitter). In any case
this offers a second source to check what NTP or PTP daemons report.
@c ==========================================================================
@node jmptime
@section jmptime
......
/*
* Trivial tool to output a software-generated pps pulse.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/io.h>
#include <sys/time.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
struct timeval tv, tv2;
unsigned long sec;
struct sched_param param;
int port, sfd, mask, m1, diff, d2;
char c;
if (argc != 2) {
fprintf(stderr, "%s: use \"%s <hex-port-or-/dev/serial>\" \n",
argv[0], argv[0]);
exit(1);
}
if (sscanf(argv[1], "%x%c", &port, &c) == 1) {
sfd = 0;
if (ioperm(port, 1, 1) < 0) {
fprintf(stderr, "%s: ioperm(0x%x): %s\n",
argv[0], port,
strerror(errno));
exit(1);
}
} else if (argv[1][0] != '/') {
fprintf(stderr, "%s: not a hex number nor a device\"%s\"\n",
argv[0], argv[1]);
exit(1);
} else {
sfd = open(argv[1], O_RDWR);
if (sfd < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1],
strerror(errno));
exit(1);
}
if (ioctl(sfd, TIOCMGET, &mask) < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1],
strerror(errno));
exit(1);
}
mask &= ~(TIOCM_RTS | TIOCM_DTR);
m1 = mask | TIOCM_RTS | TIOCM_DTR;
}
/* Get high priority, but continue anyways on failure */
param.sched_priority = 10;
if (sched_setscheduler(0, SCHED_FIFO, &param)<0) {
fprintf(stderr, "%s: setscheduler: %s\n",
argv[0], strerror(errno));
}
/* Check how much we take, doing things 10 times */
gettimeofday(&tv, NULL);
gettimeofday(&tv2, NULL); gettimeofday(&tv2, NULL);
gettimeofday(&tv2, NULL); gettimeofday(&tv2, NULL);
gettimeofday(&tv2, NULL);
gettimeofday(&tv2, NULL); gettimeofday(&tv2, NULL);
gettimeofday(&tv2, NULL); gettimeofday(&tv2, NULL);
gettimeofday(&tv2, NULL);
diff = tv2.tv_usec - tv.tv_usec;
if (diff < 0)
diff += 1000 * 1000;
if (getenv("VERBOSE"))
printf("gettimeofday takes %i.%i usec\n", diff / 10, diff % 10);
gettimeofday(&tv, NULL);
usleep(0); usleep(0); usleep(0); usleep(0); usleep(0);
usleep(0); usleep(0); usleep(0); usleep(0); usleep(0);
gettimeofday(&tv2, NULL);
d2 = diff;
diff = tv2.tv_usec - tv.tv_usec;
if (diff < 0)
diff += 1000 * 1000;
diff -= (d2 + 5) / 10;
if (getenv("VERBOSE"))
printf("udelay takes %i.%i usec\n", diff / 10, diff % 10);
/* prepare */
if (sfd)
ioctl(sfd, TIOCMSET, &mask);
else
outb(0x00, port);
gettimeofday(&tv, NULL);
sec = tv.tv_sec;
/* run */
while (1) {
sec++;
while (gettimeofday(&tv, NULL), tv.tv_sec < sec)
if (tv.tv_usec < 990 * 1000)
usleep((1000 * 1000 - tv.tv_usec) / 2);
if (sfd)
ioctl(sfd, TIOCMSET, &m1);
else
outb(0xff, port);
gettimeofday(&tv2, NULL);
if (getenv("VERBOSE"))
printf("delayed between %3i and %3i usecs\n",
(int)tv.tv_usec, (int)tv2.tv_usec);
usleep(50 * 1000);
if (sfd)
ioctl(sfd, TIOCMSET, &mask);
else
outb(0x00, port);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment