From d7480309d9bc12520cb73dd564beba8244ae2aca Mon Sep 17 00:00:00 2001 From: Drew Fisher Date: Fri, 11 Nov 2011 15:25:18 -0800 Subject: [PATCH] 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 --- CMakeLists.txt | 11 +-- examples/CMakeLists.txt | 4 + examples/consoledemo/CMakeLists.txt | 10 +++ examples/{ => consoledemo}/consoledemo.c | 2 +- examples/qtview/CMakeLists.txt | 20 +++++ examples/qtview/main.cpp | 20 +++++ examples/qtview/mousepoller.cpp | 110 +++++++++++++++++++++++ examples/qtview/mousepoller.h | 33 +++++++ examples/qtview/mousethread.cpp | 8 ++ examples/qtview/mousethread.h | 20 +++++ examples/qtview/mouseviewer.cpp | 39 ++++++++ examples/qtview/mouseviewer.h | 22 +++++ libtouchmouse/libtouchmouse.h | 8 ++ src/touchmouse.c | 29 +++--- 14 files changed, 314 insertions(+), 22 deletions(-) create mode 100644 examples/CMakeLists.txt create mode 100644 examples/consoledemo/CMakeLists.txt rename examples/{ => consoledemo}/consoledemo.c (99%) create mode 100644 examples/qtview/CMakeLists.txt create mode 100644 examples/qtview/main.cpp create mode 100644 examples/qtview/mousepoller.cpp create mode 100644 examples/qtview/mousepoller.h create mode 100644 examples/qtview/mousethread.cpp create mode 100644 examples/qtview/mousethread.h create mode 100644 examples/qtview/mouseviewer.cpp create mode 100644 examples/qtview/mouseviewer.h 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 +#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 +#include +#include + +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(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 +#include +#include +#include + +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 + +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 +#include +#include + +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 +#include +#include + +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 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; } -- 2.39.5