From 9c028895aa8a6ae1a26e2b9d87f6a9675b97434a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 7 May 2018 13:06:03 -0700 Subject: Video timing measurement tool Uses a device that signals whether it sees white or black over USB to measure accuracy of frame timing reports. Signed-off-by: Keith Packard --- Makefile | 7 +++ vidtime.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 Makefile create mode 100644 vidtime.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..65acc36 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +SRCS=vidtime.c +OBJS=$(SRCS:.c=.o) +LIBS=-lX11 -lpthread +CFLAGS=-O0 -g + +vidtime: $(OBJS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) diff --git a/vidtime.c b/vidtime.c new file mode 100644 index 0000000..59cabf7 --- /dev/null +++ b/vidtime.c @@ -0,0 +1,146 @@ +/* + * Copyright © 2018 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct monitor { + int fd; +}; + +static uint64_t vid_clock(void) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec); +} + +static void flush(int fd) +{ + char buf[1024]; + int n; + int avail; + for (;;) { + n = ioctl(fd, FIONREAD, &avail); + if (n < 0 || avail <= 0) + break; + read(fd, buf, avail); + } +} + +static uint64_t vid_time[2]; + +static pthread_mutex_t time_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t time_cond = PTHREAD_COND_INITIALIZER; + + +static void *monitor_device(void *arg) +{ + struct monitor *m = arg; + int fd = m->fd; + char buf[256]; + int n; + struct termios termios; + uint64_t t; + + tcgetattr(fd, &termios); + cfmakeraw(&termios); + cfsetospeed(&termios, B9600); + cfsetispeed(&termios, B9600); + tcsetattr(fd, TCSAFLUSH, &termios); + flush(fd); + write(fd, "E 0\nV 0\n", 8); + sleep(1); + flush(fd); + write(fd, "V 1\n", 4); + for (;;) { + n = read(fd, buf, sizeof(buf)); + if (n < 0) { + perror("read"); + return NULL; + } + t = vid_clock(); + switch(buf[0]) { + case '1': + case '0': + pthread_mutex_lock(&time_mutex); + vid_time[buf[0] - '0'] = t; + pthread_cond_signal(&time_cond); + pthread_mutex_unlock(&time_mutex); + break; + } + } +} + +#define W 512 +#define H 512 +#define DEV "/dev/ttyACM0" + +int main(int argc, char **argv) +{ + Display *dpy; + int scr; + Window root; + Window w; + GC gc; + Pixmap pix; + int v = 0; + struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; + pthread_t monitor_thread; + struct monitor monitor; + uint64_t put, got; + + monitor.fd = open(DEV, O_RDWR); + if (monitor.fd < 0) { + perror(DEV); + exit(1); + } + pthread_create(&monitor_thread, NULL, monitor_device, &monitor); + + dpy = XOpenDisplay(NULL); + scr = DefaultScreen(dpy); + root = RootWindow(dpy, scr); + w = XCreateSimpleWindow(dpy, root, 0, 0, W, H, 0, 0, 0); + gc = XCreateGC(dpy, w, 0, NULL); + XMapWindow(dpy, w); + for (;;) { + XSetForeground(dpy, gc, v ? WhitePixel(dpy, scr) : BlackPixel(dpy, scr)); + XFillRectangle(dpy, w, gc, 0, 0, W, H); + put = vid_clock(); + XFlush(dpy); + pthread_mutex_lock(&time_mutex); + for (;;) { + if (vid_time[v] > put) { + got = vid_time[v]; + break; + } + pthread_cond_wait (&time_cond, &time_mutex); + } + pthread_mutex_unlock(&time_mutex); + printf("delay %f\n", (got - put) / 1e9); + v = 1-v; + } +} -- cgit v1.2.3