1044 lines
24 KiB
Diff
1044 lines
24 KiB
Diff
From 08cb75f6dfa6885e7c63a82bb8ae40bc4e7306e7 Mon Sep 17 00:00:00 2001
|
|
From: Peter Hutterer <peter.hutterer@who-t.net>
|
|
Date: Tue, 18 Mar 2014 10:44:46 +1000
|
|
Subject: [PATCH 11/14] tools: split out the debugger into the actual debugger
|
|
and shared code
|
|
|
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
|
|
---
|
|
tools/Makefile.am | 4 +
|
|
tools/isdv4-serial-debugger.c | 450 +-------------------------------------
|
|
tools/tools-shared.c | 487 ++++++++++++++++++++++++++++++++++++++++++
|
|
tools/tools-shared.h | 41 ++++
|
|
4 files changed, 534 insertions(+), 448 deletions(-)
|
|
create mode 100644 tools/tools-shared.c
|
|
create mode 100644 tools/tools-shared.h
|
|
|
|
diff --git a/tools/Makefile.am b/tools/Makefile.am
|
|
index 5cd40e2..5eba0a6 100644
|
|
--- a/tools/Makefile.am
|
|
+++ b/tools/Makefile.am
|
|
@@ -24,6 +24,10 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
|
|
AM_CFLAGS = $(XORG_CFLAGS) $(X11_CFLAGS)
|
|
AM_LDFLAGS = $(X11_LIBS)
|
|
|
|
+shared_sources = tools-shared.h tools-shared.c
|
|
+
|
|
+isdv4_serial_debugger_SOURCES = isdv4-serial-debugger.c $(shared_sources)
|
|
+
|
|
|
|
if UNITTESTS
|
|
check_PROGRAMS = xsetwacom-test
|
|
diff --git a/tools/isdv4-serial-debugger.c b/tools/isdv4-serial-debugger.c
|
|
index 65bed85..64d7a5b 100644
|
|
--- a/tools/isdv4-serial-debugger.c
|
|
+++ b/tools/isdv4-serial-debugger.c
|
|
@@ -39,12 +39,9 @@
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
-#include "isdv4.h"
|
|
+#include "tools-shared.h"
|
|
|
|
-#define TRACE(...) \
|
|
- do { if (verbose) printf("... " __VA_ARGS__); } while(0)
|
|
-
|
|
-static int verbose = 0;
|
|
+int verbose = 0;
|
|
|
|
static void usage(void)
|
|
{
|
|
@@ -58,449 +55,6 @@ static void usage(void)
|
|
" --reset - send reset command before doing anything\n");
|
|
}
|
|
|
|
-static void version(void)
|
|
-{
|
|
- printf("%d.%d.%d\n", PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR,
|
|
- PACKAGE_VERSION_PATCHLEVEL);
|
|
-}
|
|
-
|
|
-int open_device(const char *path)
|
|
-{
|
|
- int fd;
|
|
- struct serial_struct ser;
|
|
-
|
|
- TRACE("Opening device '%s'.\n", path);
|
|
- fd = open(path, O_RDWR | O_NOCTTY);
|
|
-
|
|
- if (fd < 1)
|
|
- perror("Failed to open device file");
|
|
-
|
|
- if (ioctl(fd, TIOCGSERIAL, &ser) == -1)
|
|
- {
|
|
- perror("Not a serial device?");
|
|
- close(fd);
|
|
- fd = -1;
|
|
- goto out;
|
|
- }
|
|
-
|
|
-out:
|
|
- return fd;
|
|
-}
|
|
-
|
|
-int set_serial_attr(int fd, unsigned int baud)
|
|
-{
|
|
- struct termios t;
|
|
-
|
|
- if (tcgetattr(fd, &t) == -1)
|
|
- memset(&t, 0, sizeof(t));
|
|
-
|
|
- /* defaults from xf86OpenSerial */
|
|
- t.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
|
- t.c_oflag &= ~OPOST;
|
|
- t.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
|
- t.c_cflag &= ~(CSIZE|PARENB);
|
|
- t.c_cflag |= CS8|CLOCAL;
|
|
-
|
|
- /* wacom-specific */
|
|
- t.c_cflag &= ~(CSTOPB); /* stopbits 1 */
|
|
- t.c_cflag &= ~(CSIZE); /* databits 8 */
|
|
- t.c_cflag |= (CS8); /* databits 8 */
|
|
- t.c_cflag &= ~(PARENB); /* parity none */
|
|
- t.c_cc[VMIN] = 1; /* vmin 1 */
|
|
- t.c_cc[VTIME] = 10; /* vtime 10 */
|
|
- t.c_iflag |= IXOFF; /* flow controll xoff */
|
|
-
|
|
- TRACE("Baud rate is %d\n", baud);
|
|
-
|
|
- switch(baud)
|
|
- {
|
|
- case 19200: baud = B19200; break;
|
|
- case 38400: baud = B38400; break;
|
|
- default:
|
|
- fprintf(stderr, "Unsupported baud rate.\n");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- cfsetispeed(&t, baud);
|
|
- cfsetospeed(&t, baud);
|
|
-
|
|
- return tcsetattr(fd, TCSANOW, &t);
|
|
-
|
|
-}
|
|
-
|
|
-static int write_to_tablet(int fd, char *command)
|
|
-{
|
|
- int len = 0;
|
|
-
|
|
- do {
|
|
- int l;
|
|
- l = write(fd, &command[len], strlen(command) - len);
|
|
-
|
|
- TRACE("Written '%s'.\n", command);
|
|
-
|
|
- if (l == -1 && errno != EAGAIN)
|
|
- {
|
|
- perror("not written.\n");
|
|
- break;
|
|
- }
|
|
- len += l;
|
|
- } while (errno == EAGAIN && len < strlen(command));
|
|
-
|
|
- return !(len == strlen(command));
|
|
-}
|
|
-
|
|
-static int stop_tablet(int fd)
|
|
-{
|
|
- int rc;
|
|
- char buffer[10];
|
|
- int fd_flags;
|
|
-
|
|
- TRACE("Writing STOP command.\n");
|
|
- rc = write_to_tablet(fd, ISDV4_STOP);
|
|
-
|
|
- usleep(250000);
|
|
-
|
|
- /* flush the line */
|
|
- fd_flags = fcntl(fd, F_GETFL);
|
|
- if (fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK) == 0)
|
|
- {
|
|
- while (read(fd, buffer, sizeof(buffer)) > 0)
|
|
- TRACE("garbage flushed\n");
|
|
- fcntl(fd, F_SETFL, fd_flags);
|
|
- }
|
|
-
|
|
- return rc;
|
|
-}
|
|
-
|
|
-static int start_tablet(int fd)
|
|
-{
|
|
- TRACE("Writing SAMPLING command.\n");
|
|
- return write_to_tablet(fd, ISDV4_SAMPLING);
|
|
-}
|
|
-
|
|
-static int wait_for_tablet(int fd)
|
|
-{
|
|
-#if 0
|
|
- struct pollfd pfd = { fd, POLLIN, 0 };
|
|
- int rc;
|
|
-
|
|
- TRACE("Waiting for tablet...");
|
|
- rc = poll(&pfd, 1, 1000);
|
|
- if (rc < 0) {
|
|
- perror("poll failed.");
|
|
- return -1;
|
|
- } else if (rc == 0) {
|
|
- fprintf(stderr, "timeout.\n");
|
|
- return -1;
|
|
- } else if (pfd.revents & POLLIN)
|
|
- TRACE("data available.\n");
|
|
-
|
|
-#endif
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void memdump(const unsigned char *buffer, int len)
|
|
-{
|
|
- int n = 0;
|
|
- if (!len)
|
|
- return;
|
|
-
|
|
- while(len-- && ++n) {
|
|
- TRACE("%#hhx ", *buffer++);
|
|
- if (n % 8 == 0)
|
|
- TRACE("\n");
|
|
- }
|
|
-
|
|
- TRACE("\n");
|
|
-}
|
|
-
|
|
-static int skip_garbage(unsigned char *buffer, size_t len)
|
|
-{
|
|
- int i;
|
|
- for (i = 0; i < len; i++)
|
|
- if (buffer[i] & HEADER_BIT)
|
|
- break;
|
|
-
|
|
- if (i != 0)
|
|
- TRACE("skipping over %d bytes.\n", (i < len) ? i : -1);
|
|
-
|
|
- return (i < len) ? i : -1;
|
|
-}
|
|
-
|
|
-static int read_data(int fd, unsigned char* buffer, int min_len)
|
|
-{
|
|
- int len = 0;
|
|
- int attempts = 10;
|
|
- int skip;
|
|
-
|
|
- TRACE("Reading %d bytes from device.\n", min_len);
|
|
-redo:
|
|
- do {
|
|
- int l = read(fd, &buffer[len], min_len);
|
|
-
|
|
- if (l == -1) {
|
|
- if (errno != EAGAIN) {
|
|
- perror("Error reading data.");
|
|
- return -1;
|
|
- }
|
|
- wait_for_tablet(fd);
|
|
- attempts--;
|
|
- continue;
|
|
- } else {
|
|
- TRACE("read %d bytes in one chunk.\n", l);
|
|
- len += l;
|
|
- }
|
|
-
|
|
- } while (len < min_len && attempts);
|
|
-
|
|
- if (!attempts) {
|
|
- fprintf(stderr, "Only able to read %d bytes.\n", len);
|
|
- memdump(buffer, len);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- TRACE("Read %d bytes.\n", len);
|
|
-
|
|
- skip = skip_garbage(buffer, len);
|
|
- if (skip > 0) {
|
|
- TRACE("%d bytes garbage.\n", skip);
|
|
- len -= skip;
|
|
- memmove(buffer, &buffer[skip], len);
|
|
- goto redo;
|
|
- }
|
|
-
|
|
- if (len > min_len)
|
|
- {
|
|
- TRACE("%d bytes unexpected data.\n", (len - min_len));
|
|
- memdump(&buffer[min_len], len - min_len);
|
|
- }
|
|
-
|
|
-
|
|
- return len;
|
|
-}
|
|
-
|
|
-static int query_tablet(int fd)
|
|
-{
|
|
- ISDV4QueryReply reply;
|
|
- ISDV4TouchQueryReply touch;
|
|
-
|
|
- unsigned char buffer[ISDV4_PKGLEN_TPCCTL];
|
|
- int len, rc;
|
|
-
|
|
- TRACE("Querying tablet.\n");
|
|
-
|
|
- if (stop_tablet(fd)) goto out;
|
|
- if (write_to_tablet(fd, ISDV4_QUERY)) goto out;
|
|
- if (wait_for_tablet(fd)) goto out;
|
|
-
|
|
- len = read_data(fd, buffer, ISDV4_PKGLEN_TPCCTL);
|
|
- if (len < 1)
|
|
- goto out;
|
|
-
|
|
- if (!(buffer[0] & CONTROL_BIT))
|
|
- {
|
|
- TRACE("+++ out of cheese error +++ redo from start +++\n");
|
|
- /* X driver claims that the first read may fail ??? */
|
|
- len = read_data(fd, buffer, ISDV4_PKGLEN_TPCCTL);
|
|
- }
|
|
-
|
|
- TRACE("Parsing query reply.\n");
|
|
- rc = isdv4ParseQuery(buffer, len, &reply);
|
|
- if (rc < 0)
|
|
- {
|
|
- fprintf(stderr, "parsing error code %d\n", rc);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- printf("TABLET: version: %d\n", reply.version);
|
|
- printf("TABLET: x max: %d y max %d\n", reply.x_max, reply.y_max);
|
|
- printf("TABLET: tilt_x max: %d tilt_y max %d\n", reply.tilt_x_max, reply.tilt_y_max);
|
|
- printf("TABLET: pressure max: %d\n", reply.pressure_max);
|
|
-
|
|
- /* check for touch capabilities */
|
|
- TRACE("Trying touch query\n");
|
|
- if (stop_tablet(fd)) goto out;
|
|
- if (write_to_tablet(fd, ISDV4_TOUCH_QUERY)) goto out;
|
|
- if (wait_for_tablet(fd)) goto out;
|
|
-
|
|
- memset(buffer, 0, sizeof(buffer));
|
|
- len = read_data(fd, buffer, ISDV4_PKGLEN_TPCCTL);
|
|
- if (len < 1 && errno != EAGAIN)
|
|
- goto out;
|
|
-
|
|
- TRACE("Parsing touch query reply.\n");
|
|
- rc = isdv4ParseTouchQuery(buffer, len, &touch);
|
|
- if (rc < 0)
|
|
- {
|
|
- fprintf(stderr, "touch parsing error code %d\n", rc);
|
|
- /* failure to parse touch query is not fatal */
|
|
- } else {
|
|
- printf("TOUCH version: %d\n", touch.version);
|
|
- printf("TOUCH x max: %d y max %d\n", touch.x_max, touch.y_max);
|
|
- printf("TOUCH panel resolution: %d\n", touch.panel_resolution);
|
|
- printf("TOUCH capacity resolution: %d\n", touch.capacity_resolution);
|
|
- printf("TOUCH sensor id: %d\n", touch.sensor_id);
|
|
- }
|
|
-
|
|
- return touch.sensor_id;
|
|
-
|
|
-out:
|
|
- fprintf(stderr, "error during query.\n");
|
|
- return -1;
|
|
-}
|
|
-
|
|
-static int reset_tablet(int fd)
|
|
-{
|
|
- char buffer[10];
|
|
- TRACE("Reset requested, resetting tablet\n");
|
|
-
|
|
- if (stop_tablet(fd)) goto out;
|
|
- if (write_to_tablet(fd, ISDV4_RESET)) goto out;
|
|
- if (wait_for_tablet(fd)) goto out;
|
|
-
|
|
- memset(buffer, 0, sizeof(buffer));
|
|
- if (read(fd, buffer, sizeof(buffer)) < 1 && errno != EAGAIN)
|
|
- goto out;
|
|
-
|
|
- if (buffer[0] == '&')
|
|
- return 0;
|
|
-
|
|
-out:
|
|
- fprintf(stderr, "failed to reset tablet.\n");
|
|
- return 1;
|
|
-}
|
|
-
|
|
-static int parse_pen_packet(unsigned char* buffer)
|
|
-{
|
|
- int rc;
|
|
- ISDV4CoordinateData coord;
|
|
-
|
|
- TRACE("Parsing coordinate data.\n");
|
|
- rc = isdv4ParseCoordinateData(buffer, ISDV4_PKGLEN_TPCPEN, &coord);
|
|
- if (rc == -1) {
|
|
- fprintf(stderr, "failed to parse coordinate data.\n");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- printf("PEN ");
|
|
- printf("%ld:", time(NULL));
|
|
- printf("%5d/%5d | pressure: %3d | ", coord.x, coord.y, coord.pressure);
|
|
- printf(" %3d/%3d |", coord.tilt_x, coord.tilt_y);
|
|
- printf("%1s %1s %1s %1s |\n", coord.proximity ? "p" : "",
|
|
- coord.tip ? "t" : "",
|
|
- coord.side ? "s" : "",
|
|
- coord.eraser ? "e" : "");
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int parse_touch_packet(unsigned char* buffer, int packetlength)
|
|
-{
|
|
- ISDV4TouchData touchdata;
|
|
- int rc;
|
|
-
|
|
- rc = isdv4ParseTouchData(buffer, packetlength, packetlength, &touchdata);
|
|
- if (rc == -1) {
|
|
- fprintf(stderr, "failed to parse touch data.\n");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- printf("TOUCH ");
|
|
- printf("%ld:", time(NULL));
|
|
- printf("%5d/%5d | capacity: %3d | ", touchdata.x, touchdata.y, touchdata.capacity);
|
|
- printf("%d | ", touchdata.status);
|
|
-
|
|
- if (packetlength == ISDV4_PKGLEN_TOUCH2FG)
|
|
- printf("%d | %d/%d |", touchdata.finger2.status, touchdata.finger2.x, touchdata.finger2.y);
|
|
-
|
|
- printf("\n");
|
|
-
|
|
- return 0;
|
|
-
|
|
-}
|
|
-
|
|
-static int event_loop(int fd, int sensor_id)
|
|
-{
|
|
- unsigned char buffer[256];
|
|
- int dlen = 0;
|
|
- int packetlength = ISDV4_PKGLEN_TPCPEN;
|
|
-
|
|
- TRACE("Waiting for events\n");
|
|
-
|
|
- if (fcntl(fd, F_SETFD, O_NONBLOCK) == -1)
|
|
- perror("Nonblock failed.");
|
|
-
|
|
- memset(buffer, 0, sizeof(buffer));
|
|
-
|
|
- while (1) {
|
|
- int r, garbage = 0;
|
|
- r = read(fd, &buffer[dlen], sizeof(buffer) - dlen);
|
|
-
|
|
- if (r == -1) {
|
|
- if (errno == EAGAIN)
|
|
- continue;
|
|
- else {
|
|
- perror("Error during read.");
|
|
- goto out;
|
|
- }
|
|
- }
|
|
-
|
|
- dlen += r;
|
|
-
|
|
- if (buffer[0] & HEADER_BIT)
|
|
- {
|
|
- packetlength = ISDV4_PKGLEN_TPCPEN;
|
|
- if (buffer[0] & TOUCH_CONTROL_BIT)
|
|
- packetlength = ISDV4PacketLengths[sensor_id];
|
|
- } else {
|
|
- int bytes = skip_garbage(buffer, dlen);
|
|
- if (bytes > 0) {
|
|
- dlen -= bytes;
|
|
- memmove(buffer, &buffer[bytes], sizeof(buffer) - bytes);
|
|
- }
|
|
- continue;
|
|
- }
|
|
-
|
|
-
|
|
- if (dlen < packetlength)
|
|
- continue;
|
|
- TRACE("Expecting packet sized %d\n", packetlength);
|
|
-
|
|
- if (buffer[0] & CONTROL_BIT) {
|
|
- dlen -= packetlength;
|
|
- continue;
|
|
- }
|
|
-
|
|
- switch(packetlength)
|
|
- {
|
|
- case ISDV4_PKGLEN_TPCPEN:
|
|
- if (parse_pen_packet(buffer))
|
|
- garbage = 1;
|
|
- break;
|
|
- default: /* all others */
|
|
- if (parse_touch_packet(buffer, packetlength))
|
|
- garbage = 1;
|
|
- }
|
|
-
|
|
- if (garbage) {
|
|
- int bytes;
|
|
- bytes = skip_garbage(buffer, packetlength);
|
|
- if (bytes > 0) {
|
|
- dlen -= bytes;
|
|
- memmove(buffer, &buffer[bytes], sizeof(buffer) - bytes);
|
|
- }
|
|
- garbage = 0;
|
|
- } else {
|
|
- memmove(buffer, &buffer[packetlength], sizeof(buffer) - packetlength);
|
|
- dlen -= packetlength;
|
|
- }
|
|
- }
|
|
-
|
|
-
|
|
- return 0;
|
|
-out:
|
|
- return 1;
|
|
-}
|
|
-
|
|
int main (int argc, char **argv)
|
|
{
|
|
int fd;
|
|
diff --git a/tools/tools-shared.c b/tools/tools-shared.c
|
|
new file mode 100644
|
|
index 0000000..4d22cdf
|
|
--- /dev/null
|
|
+++ b/tools/tools-shared.c
|
|
@@ -0,0 +1,487 @@
|
|
+/*
|
|
+ * Copyright 2014 by Red Hat, Inc.
|
|
+ *
|
|
+ * 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.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#define WACOM_TOOLS
|
|
+#include "config.h"
|
|
+#endif
|
|
+
|
|
+#include <errno.h>
|
|
+#include <fcntl.h>
|
|
+#include <linux/serial.h>
|
|
+#include <getopt.h>
|
|
+#include <poll.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdint.h>
|
|
+#include <string.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <time.h>
|
|
+#include <termios.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#include "isdv4.h"
|
|
+#include "tools-shared.h"
|
|
+
|
|
+extern int verbose;
|
|
+
|
|
+void version(void)
|
|
+{
|
|
+ printf("%d.%d.%d\n", PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR,
|
|
+ PACKAGE_VERSION_PATCHLEVEL);
|
|
+}
|
|
+
|
|
+int open_device(const char *path)
|
|
+{
|
|
+ int fd;
|
|
+ struct serial_struct ser;
|
|
+
|
|
+ TRACE("Opening device '%s'.\n", path);
|
|
+ fd = open(path, O_RDWR | O_NOCTTY);
|
|
+
|
|
+ if (fd < 1)
|
|
+ perror("Failed to open device file");
|
|
+
|
|
+ if (ioctl(fd, TIOCGSERIAL, &ser) == -1)
|
|
+ {
|
|
+ perror("Not a serial device?");
|
|
+ close(fd);
|
|
+ fd = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ return fd;
|
|
+}
|
|
+
|
|
+int set_serial_attr(int fd, unsigned int baud)
|
|
+{
|
|
+ struct termios t;
|
|
+
|
|
+ if (tcgetattr(fd, &t) == -1)
|
|
+ memset(&t, 0, sizeof(t));
|
|
+
|
|
+ /* defaults from xf86OpenSerial */
|
|
+ t.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
|
+ t.c_oflag &= ~OPOST;
|
|
+ t.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
|
+ t.c_cflag &= ~(CSIZE|PARENB);
|
|
+ t.c_cflag |= CS8|CLOCAL;
|
|
+
|
|
+ /* wacom-specific */
|
|
+ t.c_cflag &= ~(CSTOPB); /* stopbits 1 */
|
|
+ t.c_cflag &= ~(CSIZE); /* databits 8 */
|
|
+ t.c_cflag |= (CS8); /* databits 8 */
|
|
+ t.c_cflag &= ~(PARENB); /* parity none */
|
|
+ t.c_cc[VMIN] = 1; /* vmin 1 */
|
|
+ t.c_cc[VTIME] = 10; /* vtime 10 */
|
|
+ t.c_iflag |= IXOFF; /* flow controll xoff */
|
|
+
|
|
+ TRACE("Baud rate is %d\n", baud);
|
|
+
|
|
+ switch(baud)
|
|
+ {
|
|
+ case 19200: baud = B19200; break;
|
|
+ case 38400: baud = B38400; break;
|
|
+ default:
|
|
+ fprintf(stderr, "Unsupported baud rate.\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ cfsetispeed(&t, baud);
|
|
+ cfsetospeed(&t, baud);
|
|
+
|
|
+ return tcsetattr(fd, TCSANOW, &t);
|
|
+
|
|
+}
|
|
+
|
|
+int write_to_tablet(int fd, char *command)
|
|
+{
|
|
+ int len = 0;
|
|
+
|
|
+ do {
|
|
+ int l;
|
|
+ l = write(fd, &command[len], strlen(command) - len);
|
|
+
|
|
+ TRACE("Written '%s'.\n", command);
|
|
+
|
|
+ if (l == -1 && errno != EAGAIN)
|
|
+ {
|
|
+ perror("not written.\n");
|
|
+ break;
|
|
+ }
|
|
+ len += l;
|
|
+ } while (errno == EAGAIN && len < strlen(command));
|
|
+
|
|
+ return !(len == strlen(command));
|
|
+}
|
|
+
|
|
+int stop_tablet(int fd)
|
|
+{
|
|
+ int rc;
|
|
+ char buffer[10];
|
|
+ int fd_flags;
|
|
+
|
|
+ TRACE("Writing STOP command.\n");
|
|
+ rc = write_to_tablet(fd, ISDV4_STOP);
|
|
+
|
|
+ usleep(250000);
|
|
+
|
|
+ /* flush the line */
|
|
+ fd_flags = fcntl(fd, F_GETFL);
|
|
+ if (fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK) == 0)
|
|
+ {
|
|
+ while (read(fd, buffer, sizeof(buffer)) > 0)
|
|
+ TRACE("garbage flushed\n");
|
|
+ fcntl(fd, F_SETFL, fd_flags);
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int start_tablet(int fd)
|
|
+{
|
|
+ TRACE("Writing SAMPLING command.\n");
|
|
+ return write_to_tablet(fd, ISDV4_SAMPLING);
|
|
+}
|
|
+
|
|
+int wait_for_tablet(int fd)
|
|
+{
|
|
+#if 0
|
|
+ struct pollfd pfd = { fd, POLLIN, 0 };
|
|
+ int rc;
|
|
+
|
|
+ TRACE("Waiting for tablet...");
|
|
+ rc = poll(&pfd, 1, 1000);
|
|
+ if (rc < 0) {
|
|
+ perror("poll failed.");
|
|
+ return -1;
|
|
+ } else if (rc == 0) {
|
|
+ fprintf(stderr, "timeout.\n");
|
|
+ return -1;
|
|
+ } else if (pfd.revents & POLLIN)
|
|
+ TRACE("data available.\n");
|
|
+
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void memdump(const unsigned char *buffer, int len)
|
|
+{
|
|
+ int n = 0;
|
|
+ if (!len)
|
|
+ return;
|
|
+
|
|
+ while(len-- && ++n) {
|
|
+ TRACE("%#hhx ", *buffer++);
|
|
+ if (n % 8 == 0)
|
|
+ TRACE("\n");
|
|
+ }
|
|
+
|
|
+ TRACE("\n");
|
|
+}
|
|
+
|
|
+int skip_garbage(unsigned char *buffer, size_t len)
|
|
+{
|
|
+ int i;
|
|
+ for (i = 0; i < len; i++)
|
|
+ if (buffer[i] & HEADER_BIT)
|
|
+ break;
|
|
+
|
|
+ if (i != 0)
|
|
+ TRACE("skipping over %d bytes.\n", (i < len) ? i : -1);
|
|
+
|
|
+ return (i < len) ? i : -1;
|
|
+}
|
|
+
|
|
+int read_data(int fd, unsigned char* buffer, int min_len)
|
|
+{
|
|
+ int len = 0;
|
|
+ int attempts = 10;
|
|
+ int skip;
|
|
+
|
|
+ TRACE("Reading %d bytes from device.\n", min_len);
|
|
+redo:
|
|
+ do {
|
|
+ int l = read(fd, &buffer[len], min_len);
|
|
+
|
|
+ if (l == -1) {
|
|
+ if (errno != EAGAIN) {
|
|
+ perror("Error reading data.");
|
|
+ return -1;
|
|
+ }
|
|
+ wait_for_tablet(fd);
|
|
+ attempts--;
|
|
+ continue;
|
|
+ } else {
|
|
+ TRACE("read %d bytes in one chunk.\n", l);
|
|
+ len += l;
|
|
+ }
|
|
+
|
|
+ } while (len < min_len && attempts);
|
|
+
|
|
+ if (!attempts) {
|
|
+ fprintf(stderr, "Only able to read %d bytes.\n", len);
|
|
+ memdump(buffer, len);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ TRACE("Read %d bytes.\n", len);
|
|
+
|
|
+ skip = skip_garbage(buffer, len);
|
|
+ if (skip > 0) {
|
|
+ TRACE("%d bytes garbage.\n", skip);
|
|
+ len -= skip;
|
|
+ memmove(buffer, &buffer[skip], len);
|
|
+ goto redo;
|
|
+ }
|
|
+
|
|
+ if (len > min_len)
|
|
+ {
|
|
+ TRACE("%d bytes unexpected data.\n", (len - min_len));
|
|
+ memdump(&buffer[min_len], len - min_len);
|
|
+ }
|
|
+
|
|
+
|
|
+ return len;
|
|
+}
|
|
+
|
|
+int query_tablet(int fd)
|
|
+{
|
|
+ ISDV4QueryReply reply;
|
|
+ ISDV4TouchQueryReply touch;
|
|
+
|
|
+ unsigned char buffer[ISDV4_PKGLEN_TPCCTL];
|
|
+ int len, rc;
|
|
+
|
|
+ TRACE("Querying tablet.\n");
|
|
+
|
|
+ if (stop_tablet(fd)) goto out;
|
|
+ if (write_to_tablet(fd, ISDV4_QUERY)) goto out;
|
|
+ if (wait_for_tablet(fd)) goto out;
|
|
+
|
|
+ len = read_data(fd, buffer, ISDV4_PKGLEN_TPCCTL);
|
|
+ if (len < 1)
|
|
+ goto out;
|
|
+
|
|
+ if (!(buffer[0] & CONTROL_BIT))
|
|
+ {
|
|
+ TRACE("+++ out of cheese error +++ redo from start +++\n");
|
|
+ /* X driver claims that the first read may fail ??? */
|
|
+ len = read_data(fd, buffer, ISDV4_PKGLEN_TPCCTL);
|
|
+ }
|
|
+
|
|
+ TRACE("Parsing query reply.\n");
|
|
+ rc = isdv4ParseQuery(buffer, len, &reply);
|
|
+ if (rc < 0)
|
|
+ {
|
|
+ fprintf(stderr, "parsing error code %d\n", rc);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ printf("TABLET: version: %d\n", reply.version);
|
|
+ printf("TABLET: x max: %d y max %d\n", reply.x_max, reply.y_max);
|
|
+ printf("TABLET: tilt_x max: %d tilt_y max %d\n", reply.tilt_x_max, reply.tilt_y_max);
|
|
+ printf("TABLET: pressure max: %d\n", reply.pressure_max);
|
|
+
|
|
+ /* check for touch capabilities */
|
|
+ TRACE("Trying touch query\n");
|
|
+ if (stop_tablet(fd)) goto out;
|
|
+ if (write_to_tablet(fd, ISDV4_TOUCH_QUERY)) goto out;
|
|
+ if (wait_for_tablet(fd)) goto out;
|
|
+
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+ len = read_data(fd, buffer, ISDV4_PKGLEN_TPCCTL);
|
|
+ if (len < 1 && errno != EAGAIN)
|
|
+ goto out;
|
|
+
|
|
+ TRACE("Parsing touch query reply.\n");
|
|
+ rc = isdv4ParseTouchQuery(buffer, len, &touch);
|
|
+ if (rc < 0)
|
|
+ {
|
|
+ fprintf(stderr, "touch parsing error code %d\n", rc);
|
|
+ /* failure to parse touch query is not fatal */
|
|
+ } else {
|
|
+ printf("TOUCH version: %d\n", touch.version);
|
|
+ printf("TOUCH x max: %d y max %d\n", touch.x_max, touch.y_max);
|
|
+ printf("TOUCH panel resolution: %d\n", touch.panel_resolution);
|
|
+ printf("TOUCH capacity resolution: %d\n", touch.capacity_resolution);
|
|
+ printf("TOUCH sensor id: %d\n", touch.sensor_id);
|
|
+ }
|
|
+
|
|
+ return touch.sensor_id;
|
|
+
|
|
+out:
|
|
+ fprintf(stderr, "error during query.\n");
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int reset_tablet(int fd)
|
|
+{
|
|
+ char buffer[10];
|
|
+ TRACE("Reset requested, resetting tablet\n");
|
|
+
|
|
+ if (stop_tablet(fd)) goto out;
|
|
+ if (write_to_tablet(fd, ISDV4_RESET)) goto out;
|
|
+ if (wait_for_tablet(fd)) goto out;
|
|
+
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+ if (read(fd, buffer, sizeof(buffer)) < 1 && errno != EAGAIN)
|
|
+ goto out;
|
|
+
|
|
+ if (buffer[0] == '&')
|
|
+ return 0;
|
|
+
|
|
+out:
|
|
+ fprintf(stderr, "failed to reset tablet.\n");
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int parse_pen_packet(unsigned char* buffer)
|
|
+{
|
|
+ int rc;
|
|
+ ISDV4CoordinateData coord;
|
|
+
|
|
+ TRACE("Parsing coordinate data.\n");
|
|
+ rc = isdv4ParseCoordinateData(buffer, ISDV4_PKGLEN_TPCPEN, &coord);
|
|
+ if (rc == -1) {
|
|
+ fprintf(stderr, "failed to parse coordinate data.\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ printf("PEN ");
|
|
+ printf("%ld:", time(NULL));
|
|
+ printf("%5d/%5d | pressure: %3d | ", coord.x, coord.y, coord.pressure);
|
|
+ printf(" %3d/%3d |", coord.tilt_x, coord.tilt_y);
|
|
+ printf("%1s %1s %1s %1s |\n", coord.proximity ? "p" : "",
|
|
+ coord.tip ? "t" : "",
|
|
+ coord.side ? "s" : "",
|
|
+ coord.eraser ? "e" : "");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int parse_touch_packet(unsigned char* buffer, int packetlength)
|
|
+{
|
|
+ ISDV4TouchData touchdata;
|
|
+ int rc;
|
|
+
|
|
+ rc = isdv4ParseTouchData(buffer, packetlength, packetlength, &touchdata);
|
|
+ if (rc == -1) {
|
|
+ fprintf(stderr, "failed to parse touch data.\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ printf("TOUCH ");
|
|
+ printf("%ld:", time(NULL));
|
|
+ printf("%5d/%5d | capacity: %3d | ", touchdata.x, touchdata.y, touchdata.capacity);
|
|
+ printf("%d | ", touchdata.status);
|
|
+
|
|
+ if (packetlength == ISDV4_PKGLEN_TOUCH2FG)
|
|
+ printf("%d | %d/%d |", touchdata.finger2.status, touchdata.finger2.x, touchdata.finger2.y);
|
|
+
|
|
+ printf("\n");
|
|
+
|
|
+ return 0;
|
|
+
|
|
+}
|
|
+
|
|
+int event_loop(int fd, int sensor_id)
|
|
+{
|
|
+ unsigned char buffer[256];
|
|
+ int dlen = 0;
|
|
+ int packetlength = ISDV4_PKGLEN_TPCPEN;
|
|
+
|
|
+ TRACE("Waiting for events\n");
|
|
+
|
|
+ if (fcntl(fd, F_SETFD, O_NONBLOCK) == -1)
|
|
+ perror("Nonblock failed.");
|
|
+
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+
|
|
+ while (1) {
|
|
+ int r, garbage = 0;
|
|
+ r = read(fd, &buffer[dlen], sizeof(buffer) - dlen);
|
|
+
|
|
+ if (r == -1) {
|
|
+ if (errno == EAGAIN)
|
|
+ continue;
|
|
+ else {
|
|
+ perror("Error during read.");
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ dlen += r;
|
|
+
|
|
+ if (buffer[0] & HEADER_BIT)
|
|
+ {
|
|
+ packetlength = ISDV4_PKGLEN_TPCPEN;
|
|
+ if (buffer[0] & TOUCH_CONTROL_BIT)
|
|
+ packetlength = ISDV4PacketLengths[sensor_id];
|
|
+ } else {
|
|
+ int bytes = skip_garbage(buffer, dlen);
|
|
+ if (bytes > 0) {
|
|
+ dlen -= bytes;
|
|
+ memmove(buffer, &buffer[bytes], sizeof(buffer) - bytes);
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+
|
|
+ if (dlen < packetlength)
|
|
+ continue;
|
|
+ TRACE("Expecting packet sized %d\n", packetlength);
|
|
+
|
|
+ if (buffer[0] & CONTROL_BIT) {
|
|
+ dlen -= packetlength;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ switch(packetlength)
|
|
+ {
|
|
+ case ISDV4_PKGLEN_TPCPEN:
|
|
+ if (parse_pen_packet(buffer))
|
|
+ garbage = 1;
|
|
+ break;
|
|
+ default: /* all others */
|
|
+ if (parse_touch_packet(buffer, packetlength))
|
|
+ garbage = 1;
|
|
+ }
|
|
+
|
|
+ if (garbage) {
|
|
+ int bytes;
|
|
+ bytes = skip_garbage(buffer, packetlength);
|
|
+ if (bytes > 0) {
|
|
+ dlen -= bytes;
|
|
+ memmove(buffer, &buffer[bytes], sizeof(buffer) - bytes);
|
|
+ }
|
|
+ garbage = 0;
|
|
+ } else {
|
|
+ memmove(buffer, &buffer[packetlength], sizeof(buffer) - packetlength);
|
|
+ dlen -= packetlength;
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
+ return 0;
|
|
+out:
|
|
+ return 1;
|
|
+}
|
|
+
|
|
diff --git a/tools/tools-shared.h b/tools/tools-shared.h
|
|
new file mode 100644
|
|
index 0000000..0a1e41f
|
|
--- /dev/null
|
|
+++ b/tools/tools-shared.h
|
|
@@ -0,0 +1,41 @@
|
|
+/*
|
|
+ * Copyright 2014 by Red Hat, Inc.
|
|
+ *
|
|
+ * 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.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+#ifndef TOOLS_SHARED_H_
|
|
+#define TOOLS_SHARED_H_
|
|
+
|
|
+void version(void);
|
|
+int open_device(const char *path);
|
|
+int set_serial_attr(int fd, unsigned int baud);
|
|
+int write_to_tablet(int fd, char *command);
|
|
+int stop_tablet(int fd);
|
|
+int start_tablet(int fd);
|
|
+int wait_for_tablet(int fd);
|
|
+void memdump(const unsigned char *buffer, int len);
|
|
+int skip_garbage(unsigned char *buffer, size_t len);
|
|
+int read_data(int fd, unsigned char* buffer, int min_len);
|
|
+int query_tablet(int fd);
|
|
+int reset_tablet(int fd);
|
|
+int parse_pen_packet(unsigned char* buffer);
|
|
+int parse_touch_packet(unsigned char* buffer, int packetlength);
|
|
+int event_loop(int fd, int sensor_id);
|
|
+
|
|
+#define TRACE(...) \
|
|
+ do { if (verbose) printf("... " __VA_ARGS__); } while(0)
|
|
+
|
|
+#endif /* TOOLS_SHARED_H_ */
|
|
--
|
|
1.8.5.3
|
|
|