From: Drew Fisher <drew.m.fisher@gmail.com>
Date: Fri, 11 Nov 2011 23:25:18 +0000 (-0800)
Subject: Reorganize directory tree, add a Qt graphical demo.
X-Git-Url: http://git.zarvox.org/shortlog/%7Bdate%7D?a=commitdiff_plain;h=d7480309d9bc12520cb73dd564beba8244ae2aca;p=libtouchmouse.git

Reorganize directory tree, add a Qt graphical demo.

I'll probably have to redo some more CMake stuff to make the Qt demo
optional.

Signed-off-by: Drew Fisher <drew.m.fisher@gmail.com>
---

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a799fe4..570592f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,13 +35,10 @@ set(CMAKE_C_FLAGS "-Wall -ggdb")
 # Build library
 add_library(touchmouse SHARED ${LIBSRC})
 
-# Build demo
-add_executable(consoledemo examples/consoledemo.c)
 if(WIN32)
 	target_link_libraries(touchmouse setupapi)
-	target_link_libraries(consoledemo touchmouse setupapi)
-elseif(NOT APPLE)
-	target_link_libraries(consoledemo touchmouse usb-1.0 pthread rt)
-else()
-	target_link_libraries(consoledemo touchmouse)
 endif()
+
+# Build examples
+add_subdirectory(examples)
+
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..df42089
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,4 @@
+
+add_subdirectory(consoledemo)
+add_subdirectory(qtview)
+
diff --git a/examples/consoledemo/CMakeLists.txt b/examples/consoledemo/CMakeLists.txt
new file mode 100644
index 0000000..cebf5d1
--- /dev/null
+++ b/examples/consoledemo/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+add_executable(consoledemo consoledemo.c)
+if(WIN32)
+	target_link_libraries(consoledemo touchmouse setupapi)
+elseif(NOT APPLE)
+	target_link_libraries(consoledemo touchmouse usb-1.0 pthread rt)
+else()
+	target_link_libraries(consoledemo touchmouse)
+endif()
+
diff --git a/examples/consoledemo.c b/examples/consoledemo/consoledemo.c
similarity index 99%
rename from examples/consoledemo.c
rename to examples/consoledemo/consoledemo.c
index 78fc0dc..2202570 100644
--- a/examples/consoledemo.c
+++ b/examples/consoledemo/consoledemo.c
@@ -81,7 +81,7 @@ int main(void) {
 	}
 
 	// Poll device for image updates.
-	int i;
+	int i = 0;
 	while(i < 100) {
 		res = touchmouse_process_events_timeout(dev, -1); // -1 means infinite timeout
 		i++;
diff --git a/examples/qtview/CMakeLists.txt b/examples/qtview/CMakeLists.txt
new file mode 100644
index 0000000..8e7a2f4
--- /dev/null
+++ b/examples/qtview/CMakeLists.txt
@@ -0,0 +1,20 @@
+
+find_package(Qt4 REQUIRED QtCore QtGui)
+include(${QT_USE_FILE})
+include_directories(${QT_INCLUDES})
+
+set (QTVIEW_HEADERS mousepoller.h mouseviewer.h)
+set (QTVIEW_SOURCES mousepoller.cpp mouseviewer.cpp main.cpp)
+
+QT4_WRAP_CPP(QTVIEW_MOC_OUTFILES ${QTVIEW_HEADERS} )
+
+add_executable(qtview ${QTVIEW_SOURCES} ${QTVIEW_MOC_OUTFILES})
+if(WIN32)
+	target_link_libraries(qtview touchmouse ${QT_LIBRARIES} setupapi)
+elseif(NOT APPLE)
+	target_link_libraries(qtview touchmouse ${QT_LIBRARIES} usb-1.0 pthread rt)
+else()
+	target_link_libraries(qtview touchmouse ${QT_LIBRARIES})
+endif()
+
+
diff --git a/examples/qtview/main.cpp b/examples/qtview/main.cpp
new file mode 100644
index 0000000..6113a32
--- /dev/null
+++ b/examples/qtview/main.cpp
@@ -0,0 +1,20 @@
+#include <QApplication>
+#include "mousepoller.h"
+#include "mouseviewer.h"
+
+int main(int argc, char** argv) {
+	QApplication* app = new QApplication(argc, argv);
+
+	MousePoller* poller = new MousePoller();
+
+	MouseViewer* viewer = new MouseViewer();
+	QObject::connect(poller, SIGNAL(mouseUpdate(QByteArray,QDateTime)),
+			viewer, SLOT(imageUpdate(QByteArray,QDateTime)));
+	viewer->resize(15 * 12, 13 * 12 );
+	viewer->show();
+	poller->startPolling();
+	
+	int retval = app->exec();
+	poller->stopPolling();
+	return retval;
+}
diff --git a/examples/qtview/mousepoller.cpp b/examples/qtview/mousepoller.cpp
new file mode 100644
index 0000000..12fc9a8
--- /dev/null
+++ b/examples/qtview/mousepoller.cpp
@@ -0,0 +1,110 @@
+#include "mousepoller.h"
+#include <QTimer>
+#include <libtouchmouse/libtouchmouse.h>
+#include <QDebug>
+
+MousePoller::MousePoller(int index, QObject* parent) : QObject(parent) {
+	touchmouse_okay = false;
+	timer = new QTimer(this);
+	timer->setInterval(1);
+	connect(timer, SIGNAL(timeout()),
+			this, SLOT(pollMouse()));
+	int res;
+	res = touchmouse_init();
+	if (res != 0) {
+		qDebug() << "Failed to initialize libtouchmouse";
+	}
+	int devs_found = 0;
+	touchmouse_device_info* devs = touchmouse_enumerate_devices();
+	touchmouse_device_info* d = devs;
+	while(d) {
+		d = d->next;
+		devs_found++;
+	}
+	if (devs_found < index) {
+		qDebug() << "Didn't see enough Touchmouse devices to open device" << index;
+		touchmouse_free_enumeration(devs);
+		return;
+	}
+	dev = NULL;
+	d = devs;
+	for(int i = 0; i < index ; i++) {
+		d = d->next;
+	}
+	res = touchmouse_open(&dev, d);
+	touchmouse_free_enumeration(devs);
+	if (res != 0) {
+		qDebug() << "Failed to open Touchmouse device";
+		return;
+	}
+	res = touchmouse_set_image_update_callback(dev, MousePoller::callback);
+	if (res != 0) {
+		qDebug() << "Failed to set Touchmouse device to full updates mode";
+		return;
+	}
+	res = touchmouse_set_device_userdata(dev, this);
+	if (res != 0) {
+		qDebug() << "Failed to set device userdata";
+		return;
+	}
+	touchmouse_okay = true;
+}
+
+MousePoller::~MousePoller() {
+	touchmouse_close(dev);
+	touchmouse_shutdown();
+}
+
+void MousePoller::callback(touchmouse_callback_info *cbdata) {
+	//qDebug() << "static callback triggered";
+	MousePoller* poller = static_cast<MousePoller*>(cbdata->userdata);
+	poller->memberCallback(cbdata);
+}
+
+void MousePoller::memberCallback(touchmouse_callback_info *cbdata) {
+	QByteArray ba((const char*)cbdata->image, 195);
+	// TODO: aggregate timestamps using mouse clock for precision.
+	QDateTime timestamp = QDateTime::currentDateTime();
+	emit mouseUpdate(ba, timestamp);
+}
+
+void MousePoller::pollMouse() {
+	int res;
+	res = touchmouse_process_events_timeout(dev, 0);
+	if (res < 0) {
+		if (res != -1) // -1 is returned on recoverable errors, -2 is a fatal hid_read failure
+			// TODO: make an error enumeration
+			touchmouse_okay = false;
+	}
+}
+
+void MousePoller::startPolling() {
+	if (touchmouse_okay) {
+		int res;
+		res = touchmouse_set_device_mode(dev, TOUCHMOUSE_RAW_IMAGE);
+		if (res != 0) {
+			qDebug() << "Failed to enable full image updates";
+			touchmouse_okay = false;
+			return;
+		}
+		timer->start();
+	} else {
+		qDebug() << "MousePoller::startPolling() called, but libtouchmouse not okay";
+	}
+}
+
+void MousePoller::stopPolling() {
+	if (touchmouse_okay) {
+		int res;
+		res = touchmouse_set_device_mode(dev, TOUCHMOUSE_DEFAULT);
+		if (res != 0) {
+			qDebug() << "Failed to disable full image updates";
+			touchmouse_okay = false;
+			return;
+		}
+		timer->stop();
+	} else {
+		qDebug() << "MousePoller::stopPolling() called, but libtouchmouse not okay";
+	}
+}
+
diff --git a/examples/qtview/mousepoller.h b/examples/qtview/mousepoller.h
new file mode 100644
index 0000000..9a2a7d4
--- /dev/null
+++ b/examples/qtview/mousepoller.h
@@ -0,0 +1,33 @@
+#ifndef __MOUSEPOLLER_H__
+#define __MOUSEPOLLER_H__
+
+#include <QObject>
+#include <QByteArray>
+#include <QDateTime>
+#include <libtouchmouse/libtouchmouse.h>
+
+class QTimer;
+
+class MousePoller : public QObject {
+	Q_OBJECT
+public:
+	MousePoller(int index = 0, QObject* parent = 0);
+	~MousePoller();
+	static void callback(touchmouse_callback_info *cbdata);
+	void memberCallback(touchmouse_callback_info* cbdata);
+
+public slots:
+	void startPolling();
+	void stopPolling();
+	void pollMouse();
+
+signals:
+	void mouseUpdate(QByteArray image, QDateTime timestamp);
+
+private:
+	QTimer* timer;
+	touchmouse_device *dev;
+	bool touchmouse_okay;
+};
+
+#endif // __MOUSEPOLLER_H__
diff --git a/examples/qtview/mousethread.cpp b/examples/qtview/mousethread.cpp
new file mode 100644
index 0000000..1e4425d
--- /dev/null
+++ b/examples/qtview/mousethread.cpp
@@ -0,0 +1,8 @@
+#include "mousethread.h"
+
+MouseThread::MouseThread(QObject* parent) : QThread(parent) {
+	shutdownRequested = false;
+	moveToThread(this);
+}
+
+
diff --git a/examples/qtview/mousethread.h b/examples/qtview/mousethread.h
new file mode 100644
index 0000000..342f10a
--- /dev/null
+++ b/examples/qtview/mousethread.h
@@ -0,0 +1,20 @@
+#ifndef __MOUSETHREAD_H__
+#define __MOUSETHREAD_H__
+
+#include <QThread>
+
+class MouseThread : public QThread {
+	Q_OBJECT
+public:
+	MouseThread(QObject* parent = 0);
+	~MouseThread();
+
+	void run();
+public slots:
+	void shutdown();
+private:
+	bool shutdownRequested;
+};
+
+#endif // __MOUSETHREAD_H__
+
diff --git a/examples/qtview/mouseviewer.cpp b/examples/qtview/mouseviewer.cpp
new file mode 100644
index 0000000..d91c79d
--- /dev/null
+++ b/examples/qtview/mouseviewer.cpp
@@ -0,0 +1,39 @@
+#include "mouseviewer.h"
+#include <QPainter>
+#include <QPaintEvent>
+#include <QDebug>
+
+MouseViewer::MouseViewer(QWidget* parent) : QWidget(parent) {
+	lastImage.resize(195);
+	// Blank initial image
+	for(int i = 0 ; i < 195; i++) {
+		lastImage[i] = 0;
+	}
+}
+
+MouseViewer::~MouseViewer() {
+
+}
+
+void MouseViewer::paintEvent(QPaintEvent* e) {
+	Q_UNUSED(e)
+	QPainter p(this);
+	if (lastImage.size() == 195) {
+		for(int row = 0; row < 13; row++) {
+			for(int col = 0; col < 15 ; col++) {
+				unsigned char value = uchar(lastImage[row*15 + col]);
+				QColor c(value, value, value);
+				p.setBrush(c);
+				p.drawRect(width() * col / 15, height() * row / 13, width() / 15, height() / 13);
+			}
+		}
+	} else {
+		qDebug() << "paintEvent, but no image yet";
+	}
+}
+
+void MouseViewer::imageUpdate(QByteArray image, QDateTime timestamp) {
+	// Ignoring timestamp, lah de dah
+	lastImage = image;
+	update();
+}
diff --git a/examples/qtview/mouseviewer.h b/examples/qtview/mouseviewer.h
new file mode 100644
index 0000000..16167b7
--- /dev/null
+++ b/examples/qtview/mouseviewer.h
@@ -0,0 +1,22 @@
+#ifndef __MOUSEVIEWER_H__
+#define __MOUSEVIEWER_H__
+
+#include <QWidget>
+#include <QByteArray>
+#include <QDateTime>
+
+class QPaintEvent;
+
+class MouseViewer : public QWidget {
+	Q_OBJECT
+public:
+	MouseViewer(QWidget* parent = 0);
+	~MouseViewer();
+	void paintEvent(QPaintEvent* e);
+public slots:
+	void imageUpdate(QByteArray image, QDateTime timestamp);
+private:
+	QByteArray lastImage;
+};
+
+#endif // __MOUSEVIEWER_H__
diff --git a/libtouchmouse/libtouchmouse.h b/libtouchmouse/libtouchmouse.h
index 1d38ea1..9655e47 100644
--- a/libtouchmouse/libtouchmouse.h
+++ b/libtouchmouse/libtouchmouse.h
@@ -13,6 +13,10 @@
 	#endif
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 // Types:
 struct touchmouse_device_;
 typedef struct touchmouse_device_ touchmouse_device;
@@ -65,4 +69,8 @@ TOUCHMOUSEAPI int touchmouse_set_device_userdata(touchmouse_device *dev, void *u
 // milliseconds > 0 means "fetch data.  Trigger a callback if the data arrives within <arg> milliseconds, otherwise return."
 TOUCHMOUSEAPI int touchmouse_process_events_timeout(touchmouse_device *dev, int milliseconds);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __LIBTOUCHMOUSE_H__ */
diff --git a/src/touchmouse.c b/src/touchmouse.c
index 765802d..8202ce2 100644
--- a/src/touchmouse.c
+++ b/src/touchmouse.c
@@ -341,6 +341,7 @@ int touchmouse_process_events_timeout(touchmouse_device *dev, int milliseconds)
 	uint64_t deadline;
 	if(milliseconds == -1) {
 		deadline = (uint64_t)(-1);
+		printf("Got infinite timeout\n");
 	} else {
 		deadline = mono_timer_nanos() + (milliseconds * 1000000);
 	}
@@ -353,25 +354,25 @@ int touchmouse_process_events_timeout(touchmouse_device *dev, int milliseconds)
 		res = hid_read_timeout(dev->dev, data, 255, (deadline - nanos) / 1000000 );
 		if (res < 0 ) {
 			fprintf(stderr, "hid_read() failed: %d\n", res);
-			return -1;
+			return -2;
 		} else if (res > 0) {
 			// Dump contents of transfer
-			printf("Got reply: %d bytes:", res);
-			int j;
-			for(j = 0; j < res; j++) {
-				printf(" %02X", data[j]);
-			}
-			printf("\n");
+			//printf("Got reply: %d bytes:", res);
+			//int j;
+			//for(j = 0; j < res; j++) {
+			//	printf(" %02X", data[j]);
+			//}
+			//printf("\n");
 			// Interpret contents.
 			report* r = (report*)data;
 			// We only care about report ID 39 (0x27), which should be 32 bytes long
 			if (res == 32 && r->report_id == 0x27) {
-				printf("Timestamp: %02X\t%02X bytes:", r->timestamp, r->length - 1);
+				//printf("Timestamp: %02X\t%02X bytes:", r->timestamp, r->length - 1);
 				int t;
-				for(t = 0; t < r->length - 1; t++) {
-					printf(" %02X", r->data[t]);
-				}
-				printf("\n");
+				//for(t = 0; t < r->length - 1; t++) {
+				//	printf(" %02X", r->data[t]);
+				//}
+				//printf("\n");
 				// Reset the decoder if we've seen one timestamp already from earlier
 				// transfers, and this one doesn't match.
 				if (first_timestamp_read && r->timestamp != last_timestamp) {
@@ -394,7 +395,7 @@ int touchmouse_process_events_timeout(touchmouse_device *dev, int milliseconds)
 						return 0;
 					}
 					if (res == DECODER_ERROR) {
-						fprintf(stderr, "Caught error in decoder, aborting!\n");
+						fprintf(stderr, "Caught error in decoder, aborting decode!\n");
 						reset_decoder(dev);
 						return -1;
 					}
@@ -410,7 +411,7 @@ int touchmouse_process_events_timeout(touchmouse_device *dev, int milliseconds)
 						return 0;
 					}
 					if (res == DECODER_ERROR) {
-						fprintf(stderr, "Caught error in decoder, aborting!\n");
+						fprintf(stderr, "Caught error in decoder, aborting decode!\n");
 						reset_decoder(dev);
 						return -1;
 					}