Merge pull request #24 from inmarket/master

New GINPUT touch driver test demo + fixes
ugfx_release_2.6
Tectu 2012-11-29 06:55:49 -08:00
commit f2c74cf431
5 changed files with 277 additions and 9 deletions

View File

@ -0,0 +1,229 @@
/*
ChibiOS/GFX - Copyright (C) 2012
Joel Bodenmann aka Tectu <joel@unormal.org>
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 <http://www.gnu.org/licenses/>.
*/
#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");
}
}
}

View File

@ -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 */
/** @} */

View File

@ -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.
*/

View File

@ -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
#if GDISP_NEED_CLIP
gdispSetClip(0, 0, width, height);
#endif
#if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0
while(1) {
#endif
gdispClear(Blue);
gdispFillStringBox(0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, GINPUT_MOUSE_CALIBRATION_FONT, White, Blue, justifyCenter);
#if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0
do {
#endif
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

View File

@ -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
}
/**