From b8a64a20fe7735d742a767e2c46d5d5930445dfa Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Fri, 30 Nov 2012 00:39:48 +1000 Subject: [PATCH 1/5] Adjust Win32 mouse poll period Adjust Win32 mouse poll period for better performance --- drivers/multiple/Win32/ginput_lld_mouse_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/multiple/Win32/ginput_lld_mouse_config.h b/drivers/multiple/Win32/ginput_lld_mouse_config.h index fc70a4d2..e4c2eb82 100644 --- a/drivers/multiple/Win32/ginput_lld_mouse_config.h +++ b/drivers/multiple/Win32/ginput_lld_mouse_config.h @@ -52,7 +52,7 @@ // This driver supports both an "interrupt" mode, and a polled mode #define GINPUT_MOUSE_POLL_PERIOD TIME_INFINITE // Interrupt driven by the Window thread -//#define GINPUT_MOUSE_POLL_PERIOD 100 // Poll driven +//#define GINPUT_MOUSE_POLL_PERIOD 25 // Poll driven #endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ /** @} */ From bc0ce072984b89a097b0d8de35422452588fac56 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Fri, 30 Nov 2012 00:40:28 +1000 Subject: [PATCH 2/5] Static initialisation fix for a GListener --- include/gevent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gevent.h b/include/gevent.h index fa735452..6467e60d 100644 --- a/include/gevent.h +++ b/include/gevent.h @@ -40,7 +40,7 @@ /** * @brief Data part of a static GListener initializer. */ - #define _GLISTENER_DATA(name) { _SEMAPHORE_DATA(name.waitqueue, 0), _BSEMAPHORE_DATA(name.eventlock, FALSE), {0} } + #define _GLISTENER_DATA(name) { _SEMAPHORE_DATA(name.waitqueue, 0), _BSEMAPHORE_DATA(name.eventlock, FALSE), 0, 0, {0} } /** * @brief Static GListener initializer. */ From e741d6045b16af2143fb325ab416992a8c0c8fd5 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Fri, 30 Nov 2012 00:41:43 +1000 Subject: [PATCH 3/5] GWIN Console Clear Fix When a GWIN Console is cleared, set the cursor back to the top left corner. --- src/gwin.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gwin.c b/src/gwin.c index 87288aa9..e7bbda01 100644 --- a/src/gwin.c +++ b/src/gwin.c @@ -152,6 +152,13 @@ void gwinClear(GHandle gh) { gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + + #if GWIN_NEED_CONSOLE + if (gh->type == GW_CONSOLE) { + ((GConsoleObject *)gh)->cx = 0; + ((GConsoleObject *)gh)->cy = 0; + } + #endif } /** From 64ceade60c4800d5cca284f558c2f2c2f72e9386 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Fri, 30 Nov 2012 00:44:24 +1000 Subject: [PATCH 4/5] GINPUT Touch Calibration Improvements to error detection and displaying that to the user during a calibration. Also introduced a hack to allow initialisation of a touch device without an automatic calibration for when the user application wants to do something with the raw readings first. --- src/ginput/mouse.c | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/ginput/mouse.c b/src/ginput/mouse.c index 35872a6c..ac23e9f1 100644 --- a/src/ginput/mouse.c +++ b/src/ginput/mouse.c @@ -40,7 +40,10 @@ #endif #define GINPUT_MOUSE_CALIBRATION_FONT &fontUI2Double + #define GINPUT_MOUSE_CALIBRATION_FONT2 &fontUI2Narrow #define GINPUT_MOUSE_CALIBRATION_TEXT "Calibration" + #define GINPUT_MOUSE_CALIBRATION_ERROR_TEXT "Failed - Please try again!" + #define GINPUT_MOUSE_CALIBRATION_SAME_TEXT "Error: Same Reading - Check Driver!" #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR < 0 #define GINPUT_MOUSE_CALIBRATION_POINTS 3 @@ -327,7 +330,9 @@ GSourceHandle ginputGetMouse(uint16_t instance) { #endif // We only support a single mouse instance currently - if (instance) + // Instance 9999 is the same as instance 0 except that it installs + // a special "raw" calibration if there isn't one we can load. + if (instance && instance != 9999) return 0; // Do we need to initialise the mouse subsystem? @@ -348,6 +353,14 @@ GSourceHandle ginputGetMouse(uint16_t instance) { MouseConfig.flags |= (FLG_CAL_OK|FLG_CAL_SAVED); if ((MouseConfig.flags & FLG_CAL_FREE)) chHeapFree((void *)pc); + } else if (instance == 9999) { + MouseConfig.caldata.ax = 1; + MouseConfig.caldata.bx = 0; + MouseConfig.caldata.cx = 0; + MouseConfig.caldata.ay = 0; + MouseConfig.caldata.by = 1; + MouseConfig.caldata.cy = 0; + MouseConfig.flags |= (FLG_CAL_OK|FLG_CAL_SAVED); } else ginputCalibrateMouse(instance); #endif @@ -410,6 +423,9 @@ bool_t ginputCalibrateMouse(uint16_t instance) { MousePoint *pt; int32_t px, py; unsigned i, j; + #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 + unsigned err; + #endif if (instance || (MouseConfig.flags & FLG_IN_CAL)) return FALSE; @@ -422,13 +438,17 @@ bool_t ginputCalibrateMouse(uint16_t instance) { gdispSetOrientation(GDISP_ROTATE_0); #endif - gdispClear(Blue); - - gdispFillStringBox(0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, GINPUT_MOUSE_CALIBRATION_FONT, White, Blue, justifyCenter); + #if GDISP_NEED_CLIP + gdispSetClip(0, 0, width, height); + #endif #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 - do { + while(1) { #endif + gdispClear(Blue); + + gdispFillStringBox(0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, GINPUT_MOUSE_CALIBRATION_FONT, White, Blue, justifyCenter); + for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) { _tsDrawCross(pc); @@ -454,6 +474,13 @@ bool_t ginputCalibrateMouse(uint16_t instance) { pt->y = py / j; _tsClearCross(pc); + + if (i >= 1 && pt->x == (pt-1)->x && pt->y == (pt-1)->y) { + gdispFillStringBox(0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, GINPUT_MOUSE_CALIBRATION_FONT2, Red, Yellow, justifyCenter); + chThdSleepMilliseconds(5000); + gdispFillArea(0, 35, width, 40, Blue); + } + } /* Apply 3 point calibration algorithm */ @@ -471,10 +498,15 @@ bool_t ginputCalibrateMouse(uint16_t instance) { _tsTransform(&MouseConfig.t, &MouseConfig.caldata); /* Calculate the delta */ - px = (MouseConfig.t.x - cross[3].x) * (MouseConfig.t.x - cross[3].x) + + err = (MouseConfig.t.x - cross[3].x) * (MouseConfig.t.x - cross[3].x) + (MouseConfig.t.y - cross[3].y) * (MouseConfig.t.y - cross[3].y); - } while (px > GINPUT_MOUSE_MAX_CALIBRATION_ERROR * GINPUT_MOUSE_MAX_CALIBRATION_ERROR); + if (err <= GINPUT_MOUSE_MAX_CALIBRATION_ERROR * GINPUT_MOUSE_MAX_CALIBRATION_ERROR) + break; + + gdispFillStringBox(0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, GINPUT_MOUSE_CALIBRATION_FONT2, Red, Yellow, justifyCenter); + chThdSleepMilliseconds(5000); + } #endif // Restart everything From a123ba7c4e57ff19b557c6402f3d5dc96a0ff2cc Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Fri, 30 Nov 2012 00:46:24 +1000 Subject: [PATCH 5/5] GINPUT touch driver test demo Added demo program to test the driver parameters for a new GINPUT touch driver. It steps through a series of tests to ensure that the driver is configured optimally. --- demos/modules/ginput_touch_driver_test/main.c | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 demos/modules/ginput_touch_driver_test/main.c diff --git a/demos/modules/ginput_touch_driver_test/main.c b/demos/modules/ginput_touch_driver_test/main.c new file mode 100644 index 00000000..d93978cf --- /dev/null +++ b/demos/modules/ginput_touch_driver_test/main.c @@ -0,0 +1,229 @@ +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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, see . +*/ + +#include "ch.h" +#include "hal.h" +#include "chprintf.h" +#include "gdisp.h" +#include "ginput.h" +#include "gwin.h" + +static GConsoleObject gc; +static GListener gl; + +/*------------------------------------------------------------------------* + * GINPUT Touch Driver Calibrator. * + *------------------------------------------------------------------------*/ +int main(void) { + GSourceHandle gs; + GEventMouse *pem; + coord_t swidth, sheight; + GHandle ghc; + BaseSequentialStream *gp; + unsigned testnum; + + halInit(); // Initialise the Hardware + chSysInit(); // Initialize the OS + gdispInit(); // Initialize the display + + // Get the display dimensions + swidth = gdispGetWidth(); + sheight = gdispGetHeight(); + testnum = 0; + + // Create our title + gdispFillStringBox(0, 0, swidth, 20, "Touch Calibration", &fontUI2, Red, White, justifyCenter); + + // Create our main display window + ghc = gwinCreateConsole(&gc, 0, 20, swidth, sheight-20, &fontUI2); + gwinClear(ghc); + gp = gwinGetConsoleStream(ghc); + + // Initialize the mouse in our special no calibration mode. + geventListenerInit(&gl); + gs = ginputGetMouse(9999); + geventAttachSource(&gl, gs, GLISTEN_MOUSEDOWNMOVES|GLISTEN_MOUSEMETA); + + /* + * Test: Device Type + */ + + gwinClear(ghc); + gwinSetColor(ghc, Yellow); + chprintf(gp, "\n%u. DEVICE TYPE\n\n", ++testnum); + + pem = (GEventMouse *)&gl.event; + ginputGetMouseStatus(0, pem); + + gwinSetColor(ghc, White); + chprintf(gp, "This is detected as a %s device\n\n", + pem->type == GEVENT_MOUSE ? "MOUSE" : (pem->type == GEVENT_TOUCH ? "TOUCH" : "UNKNOWN")); + + chprintf(gp, "Press and release your finger (or mouse button) to move on to the next test.\n"); + + do { + pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); + if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check + continue; + + } while (!(pem->meta & GMETA_MOUSE_UP)); + + /* + * Test: Mouse raw reading jitter + */ + + gwinClear(ghc); + gwinSetColor(ghc, Yellow); + chprintf(gp, "\n%u. GINPUT_MOUSE_READ_CYCLES\n\n", ++testnum); + + gwinSetColor(ghc, White); + chprintf(gp, "Press on the surface (or press and hold the mouse button).\n\n"); + chprintf(gp, "Numbers will display in this window.\n" + "Ensure that values don't jump around very much when your finger is stationary.\n\n" + "Increasing GINPUT_MOUSE_READ_CYCLES helps reduce jitter but increases CPU usage.\n\n" + "Releasing your finger (or mouse button) will move on to the next test.\n\n"); + + // For this test turn on ALL mouse movement events + geventAttachSource(&gl, gs, GLISTEN_MOUSEDOWNMOVES|GLISTEN_MOUSEMETA|GLISTEN_MOUSENOFILTER); + + do { + pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); + if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check + continue; + + if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) + chprintf(gp, "%u:%u\n", pem->x, pem->y); + } while (!(pem->meta & GMETA_MOUSE_UP)); + + // Reset to just changed movements. + geventAttachSource(&gl, gs, GLISTEN_MOUSEDOWNMOVES|GLISTEN_MOUSEMETA); + + /* + * Test: Calibration + */ + + gwinClear(ghc); + gwinSetColor(ghc, Yellow); + chprintf(gp, "\n%u. GINPUT_MOUSE_CALIBRATION_ERROR\n\n", ++testnum); + gwinSetColor(ghc, Gray); + chprintf(gp, "Ensure GINPUT_MOUSE_NEED_CALIBRATION = TRUE and GINPUT_MOUSE_CALIBRATION_ERROR is >= 0\n\n"); + gwinSetColor(ghc, White); + chprintf(gp, "When you press and release the surface, calibration will start.\n"); + chprintf(gp, "You will be presented with a number of points to touch.\nPress them in turn.\n\n" + "If the calibration repeatedly fails increase GINPUT_MOUSE_CALIBRATION_ERROR and try again.\n"); + + do { + pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); + if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check + continue; + + } while (!(pem->meta & GMETA_MOUSE_UP)); + + // Calibrate + ginputCalibrateMouse(0); + + // Calibration uses the whole screen - re-establish our title + gdispFillStringBox(0, 0, swidth, 20, "Touch Calibration", &fontUI2, Green, White, justifyCenter); + + /* + * Test: Mouse movement jitter + */ + + gwinClear(ghc); + gwinSetColor(ghc, Yellow); + chprintf(gp, "\n%u. GINPUT_MOUSE_MOVE_JITTER\n\n", ++testnum); + + gwinSetColor(ghc, White); + chprintf(gp, "Press firmly on the surface (or press and hold the mouse button) and move around as if to draw.\n\n"); + chprintf(gp, "Dots will display in this window. Ensure that when you stop moving your finger that " + "new dots stop displaying.\nNew dots should only display when your finger is moving.\n\n" + "Adjust GINPUT_MOUSE_MOVE_JITTER to the smallest value that this reliably works for.\n\n" + "Releasing your finger (or mouse button) will move on to the next test.\n\n"); + + do { + pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); + if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check + continue; + + if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) + chprintf(gp, "."); + } while (!(pem->meta & GMETA_MOUSE_UP)); + + /* + * Test: Polling frequency + */ + + gwinClear(ghc); + gwinSetColor(ghc, Yellow); + chprintf(gp, "\n%u. GINPUT_MOUSE_POLL_PERIOD\n\n", ++testnum); + + gwinSetColor(ghc, White); + chprintf(gp, "Press firmly on the surface (or press and hold the mouse button) and move around as if to draw.\n\n"); + chprintf(gp, "A green line will follow your finger.\n" + "Adjust GINPUT_MOUSE_POLL_PERIOD to the highest value that provides a line without " + "gaps that are too big.\nDecreasing the value increases CPU usage.\n" + "About 25 (millisecs) normally produces good results." + "This test can be ignored for interrupt driven drivers.\n\n" + "Releasing your finger (or mouse button) will move on to the next test.\n"); + + do { + pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); + if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check + continue; + + if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) + gdispDrawPixel(pem->x, pem->y, Green); + } while (!(pem->meta & GMETA_MOUSE_UP)); + + + /* + * Test: Click Jitter + */ + + gwinClear(ghc); + gwinSetColor(ghc, Yellow); + chprintf(gp, "\n%u. GINPUT_MOUSE_MAX_CLICK_JITTER\n\n", ++testnum); + + gwinSetColor(ghc, White); + chprintf(gp, "Press and release the touch surface to \"click\".\nTry both short and long presses.\n"); + chprintf(gp, "For a mouse click with the left and right buttons.\n\n"); + chprintf(gp, "Dots will display in this window. A yellow dash is a left (or short) click. " + "A red x is a right (or long) click.\n\n" + "Adjust GINPUT_MOUSE_CLICK_JITTER to the smallest value that this reliably works for.\n" + "Adjust GINPUT_MOUSE_CLICK_TIME to adjust distinguishing short vs long presses.\n" + "TIME_INFINITE means there are no long presses (although a right mouse button will still work).\n\n" + "Note: moving your finger (mouse) during a click cancels it." + "This test does not end.\n\n"); + + while(1) { + pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); + if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check + continue; + + if ((pem->meta & GMETA_MOUSE_CLICK)) { + gwinSetColor(ghc, Yellow); + chprintf(gp, "-"); + } + if ((pem->meta & GMETA_MOUSE_CXTCLICK)) { + gwinSetColor(ghc, Red); + chprintf(gp, "x"); + } + } +}