diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ginput/mouse.c | 1140 | ||||
-rw-r--r-- | src/tdisp/tdisp.c | 2 |
2 files changed, 571 insertions, 571 deletions
diff --git a/src/ginput/mouse.c b/src/ginput/mouse.c index 82f54cae..7320cf2d 100644 --- a/src/ginput/mouse.c +++ b/src/ginput/mouse.c @@ -4,573 +4,573 @@ * * http://chibios-gfx.com/license.html */ -
-/**
- * @file src/ginput/mouse.c
- * @brief GINPUT mouse/touch code.
- *
- * @defgroup Mouse Mouse
- * @ingroup GINPUT
- * @{
- */
-#include "ch.h"
-#include "hal.h"
-#include "gfx.h"
-
-#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) || defined(__DOXYGEN__)
-
-#include "ginput/lld/mouse.h"
-
-#if GINPUT_MOUSE_NEED_CALIBRATION
- #if !defined(GFX_USE_GDISP) || !GFX_USE_GDISP
- #error "GINPUT: GFX_USE_GDISP must be defined when mouse or touch calibration is required"
- #endif
-
- #define GINPUT_MOUSE_CALIBRATION_FONT "* Double"
- #define GINPUT_MOUSE_CALIBRATION_FONT2 "* Narrow"
- #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
- #else
- #define GINPUT_MOUSE_CALIBRATION_POINTS 4
- #endif
-
- typedef struct Calibration_t {
- float ax;
- float bx;
- float cx;
- float ay;
- float by;
- float cy;
- } Calibration;
-#endif
-
-typedef struct MousePoint_t {
- coord_t x, y;
- } MousePoint;
-
-static GTIMER_DECL(MouseTimer);
-
-static struct MouseConfig_t {
- MouseReading t;
- MousePoint movepos;
- MousePoint clickpos;
- systime_t clicktime;
- uint16_t last_buttons;
- uint16_t flags;
- #define FLG_INIT_DONE 0x8000
- #define FLG_CLICK_TIMER 0x0001
- #define FLG_IN_CAL 0x0010
- #define FLG_CAL_OK 0x0020
- #define FLG_CAL_SAVED 0x0040
- #define FLG_CAL_FREE 0x0080
- #if GINPUT_MOUSE_NEED_CALIBRATION
- GMouseCalibrationSaveRoutine fnsavecal;
- GMouseCalibrationLoadRoutine fnloadcal;
- Calibration caldata;
- #endif
- } MouseConfig;
-
-#if GINPUT_MOUSE_NEED_CALIBRATION
- static inline void _tsDrawCross(const MousePoint *pp) {
- gdispDrawLine(pp->x-15, pp->y, pp->x-2, pp->y, White);
- gdispDrawLine(pp->x+2, pp->y, pp->x+15, pp->y, White);
- gdispDrawLine(pp->x, pp->y-15, pp->x, pp->y-2, White);
- gdispDrawLine(pp->x, pp->y+2, pp->x, pp->y+15, White);
-
- gdispDrawLine(pp->x-15, pp->y+15, pp->x-7, pp->y+15, RGB2COLOR(184,158,131));
- gdispDrawLine(pp->x-15, pp->y+7, pp->x-15, pp->y+15, RGB2COLOR(184,158,131));
-
- gdispDrawLine(pp->x-15, pp->y-15, pp->x-7, pp->y-15, RGB2COLOR(184,158,131));
- gdispDrawLine(pp->x-15, pp->y-7, pp->x-15, pp->y-15, RGB2COLOR(184,158,131));
-
- gdispDrawLine(pp->x+7, pp->y+15, pp->x+15, pp->y+15, RGB2COLOR(184,158,131));
- gdispDrawLine(pp->x+15, pp->y+7, pp->x+15, pp->y+15, RGB2COLOR(184,158,131));
-
- gdispDrawLine(pp->x+7, pp->y-15, pp->x+15, pp->y-15, RGB2COLOR(184,158,131));
- gdispDrawLine(pp->x+15, pp->y-15, pp->x+15, pp->y-7, RGB2COLOR(184,158,131));
- }
-
- static inline void _tsClearCross(const MousePoint *pp) {
- gdispFillArea(pp->x - 15, pp->y - 15, 42, 42, Blue);
- }
-
- static inline void _tsTransform(MouseReading *pt, const Calibration *c) {
- pt->x = (coord_t) (c->ax * pt->x + c->bx * pt->y + c->cx);
- pt->y = (coord_t) (c->ay * pt->x + c->by * pt->y + c->cy);
- }
-
- static inline void _tsDo3PointCalibration(const MousePoint *cross, const MousePoint *points, Calibration *c) {
- float dx, dx0, dx1, dx2, dy0, dy1, dy2;
-
- /* Compute all the required determinants */
- dx = ((float)(points[0].x - points[2].x)) * ((float)(points[1].y - points[2].y))
- - ((float)(points[1].x - points[2].x)) * ((float)(points[0].y - points[2].y));
-
- dx0 = ((float)(cross[0].x - cross[2].x)) * ((float)(points[1].y - points[2].y))
- - ((float)(cross[1].x - cross[2].x)) * ((float)(points[0].y - points[2].y));
-
- dx1 = ((float)(cross[1].x - cross[2].x)) * ((float)(points[0].x - points[2].x))
- - ((float)(cross[0].x - cross[2].x)) * ((float)(points[1].x - points[2].x));
-
- dx2 = cross[0].x * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) -
- cross[1].x * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) +
- cross[2].x * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y);
-
- dy0 = ((float)(cross[0].y - cross[2].y)) * ((float)(points[1].y - points[2].y))
- - ((float)(cross[1].y - cross[2].y)) * ((float)(points[0].y - points[2].y));
-
- dy1 = ((float)(cross[1].y - cross[2].y)) * ((float)(points[0].x - points[2].x))
- - ((float)(cross[0].y - cross[2].y)) * ((float)(points[1].x - points[2].x));
-
- dy2 = cross[0].y * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) -
- cross[1].y * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) +
- cross[2].y * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y);
-
- /* Now, calculate all the required coefficients */
- c->ax = dx0 / dx;
- c->bx = dx1 / dx;
- c->cx = dx2 / dx;
-
- c->ay = dy0 / dx;
- c->by = dy1 / dx;
- c->cy = dy2 / dx;
- }
-#endif
-
-#if GINPUT_MOUSE_READ_CYCLES > 1
- static void get_raw_reading(MouseReading *pt) {
- int32_t x, y, z;
- unsigned i;
-
- x = y = z = 0;
- for(i = 0; i < GINPUT_MOUSE_READ_CYCLES; i++) {
- ginput_lld_mouse_get_reading(pt);
- x += pt->x;
- y += pt->y;
- z += pt->z;
- }
-
- /* Take the average of the readings */
- pt->x = x / GINPUT_MOUSE_READ_CYCLES;
- pt->y = y / GINPUT_MOUSE_READ_CYCLES;
- pt->z = z / GINPUT_MOUSE_READ_CYCLES;
- }
-#else
- #define get_raw_reading(pt) ginput_lld_mouse_get_reading(pt)
-#endif
-
-static void get_calibrated_reading(MouseReading *pt) {
- #if GINPUT_MOUSE_NEED_CALIBRATION || GDISP_NEED_CONTROL
- coord_t w, h;
- #endif
-
- get_raw_reading(pt);
-
- #if GINPUT_MOUSE_NEED_CALIBRATION || GDISP_NEED_CONTROL
- w = gdispGetWidth();
- h = gdispGetHeight();
- #endif
-
- #if GINPUT_MOUSE_NEED_CALIBRATION
- _tsTransform(pt, &MouseConfig.caldata);
- #endif
-
- #if GDISP_NEED_CONTROL
- switch(gdispGetOrientation()) {
- case GDISP_ROTATE_0:
- break;
- case GDISP_ROTATE_90:
- {
- coord_t t = pt->y;
- pt->y = h - 1 - pt->x;
- pt->x = t;
- }
- break;
- case GDISP_ROTATE_180:
- pt->x = w - 1 - pt->x;
- pt->y = h - 1 - pt->y;
- break;
- case GDISP_ROTATE_270:
- {
- coord_t t = pt->x;
- pt->x = w - 1 - pt->y;
- pt->y = t;
- }
- break;
- }
- #endif
-
- #if GINPUT_MOUSE_NEED_CALIBRATION
- if (pt->x < 0) pt->x = 0;
- else if (pt->x >= w) pt->x = w-1;
- if (pt->y < 0) pt->y = 0;
- else if (pt->y >= h) pt->y = h-1;
- #endif
-}
-
-static void MousePoll(void *param) {
- (void) param;
- GSourceListener *psl;
- GEventMouse *pe;
- unsigned meta;
- uint16_t tbtns;
- uint32_t cdiff;
- uint32_t mdiff;
-
- // Save the last mouse state
- MouseConfig.last_buttons = MouseConfig.t.buttons;
-
- // Get the new mouse reading
- get_calibrated_reading(&MouseConfig.t);
-
- // Calculate out new event meta value and handle CLICK and CXTCLICK
- meta = GMETA_NONE;
-
- // Calculate the position difference from our movement reference (update the reference if out of range)
- mdiff = (MouseConfig.t.x - MouseConfig.movepos.x) * (MouseConfig.t.x - MouseConfig.movepos.x) +
- (MouseConfig.t.y - MouseConfig.movepos.y) * (MouseConfig.t.y - MouseConfig.movepos.y);
- if (mdiff > GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER) {
- MouseConfig.movepos.x = MouseConfig.t.x;
- MouseConfig.movepos.y = MouseConfig.t.y;
- }
-
- // Check if the click has moved outside the click area and if so cancel the click
- if ((MouseConfig.flags & FLG_CLICK_TIMER)) {
- cdiff = (MouseConfig.t.x - MouseConfig.clickpos.x) * (MouseConfig.t.x - MouseConfig.clickpos.x) +
- (MouseConfig.t.y - MouseConfig.clickpos.y) * (MouseConfig.t.y - MouseConfig.clickpos.y);
- if (cdiff > GINPUT_MOUSE_MAX_CLICK_JITTER * GINPUT_MOUSE_MAX_CLICK_JITTER)
- MouseConfig.flags &= ~FLG_CLICK_TIMER;
- }
-
- // Mouse down
- tbtns = MouseConfig.t.buttons & ~MouseConfig.last_buttons;
- if ((tbtns & GINPUT_MOUSE_BTN_LEFT))
- meta |= GMETA_MOUSE_DOWN;
- if ((tbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) {
- MouseConfig.clickpos.x = MouseConfig.t.x;
- MouseConfig.clickpos.y = MouseConfig.t.y;
- MouseConfig.clicktime = chTimeNow();
- MouseConfig.flags |= FLG_CLICK_TIMER;
- }
-
- // Mouse up
- tbtns = ~MouseConfig.t.buttons & MouseConfig.last_buttons;
- if ((tbtns & GINPUT_MOUSE_BTN_LEFT))
- meta |= GMETA_MOUSE_UP;
- if ((tbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) {
- if ((MouseConfig.flags & FLG_CLICK_TIMER)) {
- if ((tbtns & GINPUT_MOUSE_BTN_LEFT)
- #if GINPUT_MOUSE_CLICK_TIME != TIME_INFINITE
- && chTimeNow() - MouseConfig.clicktime < MS2ST(GINPUT_MOUSE_CLICK_TIME)
- #endif
- )
- meta |= GMETA_MOUSE_CLICK;
- else
- meta |= GMETA_MOUSE_CXTCLICK;
- MouseConfig.flags &= ~FLG_CLICK_TIMER;
- }
- }
-
- // Send the event to the listeners that are interested.
- psl = 0;
- while ((psl = geventGetSourceListener((GSourceHandle)(&MouseConfig), psl))) {
- if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) {
- // This listener is missing - save the meta events that have happened
- psl->srcflags |= meta;
- continue;
- }
-
- // If we haven't really moved (and there are no meta events) don't bother sending the event
- if (mdiff <= GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER && !psl->srcflags && !meta && !(psl->listenflags & GLISTEN_MOUSENOFILTER))
- continue;
-
- // Send the event if we are listening for it
- if (((MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEDOWNMOVES))
- || (!(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEUPMOVES))
- || (meta && (psl->listenflags & GLISTEN_MOUSEMETA))) {
- pe->type = GINPUT_MOUSE_EVENT_TYPE;
- pe->instance = 0;
- pe->x = MouseConfig.t.x;
- pe->y = MouseConfig.t.y;
- pe->z = MouseConfig.t.z;
- pe->current_buttons = MouseConfig.t.buttons;
- pe->last_buttons = MouseConfig.last_buttons;
- pe->meta = meta;
- if (psl->srcflags) {
- pe->current_buttons |= GINPUT_MISSED_MOUSE_EVENT;
- pe->meta |= psl->srcflags;
- psl->srcflags = 0;
- }
- geventSendEvent(psl);
- }
- }
-}
-
-GSourceHandle ginputGetMouse(uint16_t instance) {
- #if GINPUT_MOUSE_NEED_CALIBRATION
- Calibration *pc;
- #endif
-
- // We only support a single mouse instance currently
- // 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?
- if (!(MouseConfig.flags & FLG_INIT_DONE)) {
- ginput_lld_mouse_init();
-
- #if GINPUT_MOUSE_NEED_CALIBRATION
- #if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE
- if (!MouseConfig.fnloadcal) {
- MouseConfig.fnloadcal = ginput_lld_mouse_calibration_load;
- MouseConfig.flags &= ~FLG_CAL_FREE;
- }
- if (!MouseConfig.fnsavecal)
- MouseConfig.fnsavecal = ginput_lld_mouse_calibration_save;
- #endif
- if (MouseConfig.fnloadcal && (pc = (Calibration *)MouseConfig.fnloadcal(instance))) {
- MouseConfig.caldata = pc[0];
- 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
-
- // Get the first reading
- MouseConfig.last_buttons = 0;
- get_calibrated_reading(&MouseConfig.t);
-
- // Mark init as done and start the Poll timer
- MouseConfig.flags |= FLG_INIT_DONE;
- gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD);
- }
-
- // Return our structure as the handle
- return (GSourceHandle)&MouseConfig;
-}
-
-bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pe) {
- // Win32 threads don't seem to recognise priority and/or pre-emption
- // so we add a sleep here to prevent 100% polled applications from locking up.
- chThdSleepMilliseconds(1);
-
- if (instance || (MouseConfig.flags & (FLG_INIT_DONE|FLG_IN_CAL)) != FLG_INIT_DONE)
- return FALSE;
-
- pe->type = GINPUT_MOUSE_EVENT_TYPE;
- pe->instance = instance;
- pe->x = MouseConfig.t.x;
- pe->y = MouseConfig.t.y;
- pe->z = MouseConfig.t.z;
- pe->current_buttons = MouseConfig.t.buttons;
- pe->last_buttons = MouseConfig.last_buttons;
- if (pe->current_buttons & ~pe->last_buttons & GINPUT_MOUSE_BTN_LEFT)
- pe->meta = GMETA_MOUSE_DOWN;
- else if (~pe->current_buttons & pe->last_buttons & GINPUT_MOUSE_BTN_LEFT)
- pe->meta = GMETA_MOUSE_UP;
- else
- pe->meta = GMETA_NONE;
- return TRUE;
-}
-
-bool_t ginputCalibrateMouse(uint16_t instance) {
- #if !GINPUT_MOUSE_NEED_CALIBRATION
- (void) instance;
-
- return FALSE;
- #else
-
- const coord_t height = gdispGetHeight();
- const coord_t width = gdispGetWidth();
- const MousePoint cross[] = {{(width / 4), (height / 4)},
- {(width - (width / 4)) , (height / 4)},
- {(width - (width / 4)) , (height - (height / 4))},
- {(width / 2), (height / 2)}}; /* Check point */
- MousePoint points[GINPUT_MOUSE_CALIBRATION_POINTS];
- const MousePoint *pc;
- MousePoint *pt;
- int32_t px, py;
- unsigned i, j;
- font_t font1, font2;
- #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0
- unsigned err;
- #endif
-
- if (instance || (MouseConfig.flags & FLG_IN_CAL))
- return FALSE;
-
- font1 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT);
- font2 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT2);
-
- MouseConfig.flags |= FLG_IN_CAL;
- gtimerStop(&MouseTimer);
- MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED);
-
- #if GDISP_NEED_CONTROL
- 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, font1, White, Blue, justifyCenter);
-
- for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) {
- _tsDrawCross(pc);
-
- do {
-
- /* Wait for the mouse to be pressed */
- while(get_raw_reading(&MouseConfig.t), !(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT))
- chThdSleepMilliseconds(20);
-
- /* Average all the samples while the mouse is down */
- for(px = py = 0, j = 0;
- chThdSleepMilliseconds(20), /* Settling time between readings */
- get_raw_reading(&MouseConfig.t),
- (MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT);
- j++) {
- px += MouseConfig.t.x;
- py += MouseConfig.t.y;
- }
-
- } while(!j);
-
- pt->x = px / j;
- 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, font2, Red, Yellow, justifyCenter);
- chThdSleepMilliseconds(5000);
- gdispFillArea(0, 35, width, 40, Blue);
- }
-
- }
-
- /* Apply 3 point calibration algorithm */
- _tsDo3PointCalibration(cross, points, &MouseConfig.caldata);
-
- /* Verification of correctness of calibration (optional) :
- * See if the 4th point (Middle of the screen) coincides with the calibrated
- * result. If point is within +/- Squareroot(ERROR) pixel margin, then successful calibration
- * Else, start from the beginning.
- */
- #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0
- /* Transform the co-ordinates */
- MouseConfig.t.x = points[3].x;
- MouseConfig.t.y = points[3].y;
- _tsTransform(&MouseConfig.t, &MouseConfig.caldata);
-
- /* Calculate the delta */
- 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);
-
- if (err <= GINPUT_MOUSE_MAX_CALIBRATION_ERROR * GINPUT_MOUSE_MAX_CALIBRATION_ERROR)
- break;
-
- gdispFillStringBox(0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter);
- chThdSleepMilliseconds(5000);
- }
- #endif
-
- // Restart everything
- gdispCloseFont(font1);
- gdispCloseFont(font2);
- MouseConfig.flags |= FLG_CAL_OK;
- MouseConfig.last_buttons = 0;
- get_calibrated_reading(&MouseConfig.t);
- MouseConfig.flags &= ~FLG_IN_CAL;
- if ((MouseConfig.flags & FLG_INIT_DONE))
- gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD);
-
- // Save the calibration data (if possible)
- if (MouseConfig.fnsavecal) {
- MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata));
- MouseConfig.flags |= FLG_CAL_SAVED;
- }
-
- return TRUE;
- #endif
-}
-
-/* Set the routines to save and fetch calibration data.
- * This function should be called before first calling ginputGetMouse() for a particular instance
- * as the gdispGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it.
- * If this is called after gdispGetMouse() has been called and the driver requires calibration storage, it will immediately save the data is has already obtained.
- * The 'requireFree' parameter indicates if the fetch buffer must be free()'d to deallocate the buffer provided by the Fetch routine.
- */
-void ginputSetMouseCalibrationRoutines(uint16_t instance, GMouseCalibrationSaveRoutine fnsave, GMouseCalibrationLoadRoutine fnload, bool_t requireFree) {
- #if GINPUT_MOUSE_NEED_CALIBRATION
- if (instance)
- return;
-
- MouseConfig.fnloadcal = fnload;
- MouseConfig.fnsavecal = fnsave;
- if (requireFree)
- MouseConfig.flags |= FLG_CAL_FREE;
- else
- MouseConfig.flags &= ~FLG_CAL_FREE;
- #if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE
- if (!MouseConfig.fnloadcal) {
- MouseConfig.fnloadcal = ginput_lld_mouse_calibration_load;
- MouseConfig.flags &= ~FLG_CAL_FREE;
- }
- if (!MouseConfig.fnsavecal)
- MouseConfig.fnsavecal = ginput_lld_mouse_calibration_save;
- #endif
- if (MouseConfig.fnsavecal && (MouseConfig.flags & (FLG_CAL_OK|FLG_CAL_SAVED)) == FLG_CAL_OK) {
- MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata));
- MouseConfig.flags |= FLG_CAL_SAVED;
- }
- #else
- (void)instance, (void)fnsave, (void)fnload, (void)requireFree;
- #endif
-}
-
-/* Test if a particular mouse instance requires routines to save its calibration data. */
-bool_t ginputRequireMouseCalibrationStorage(uint16_t instance) {
- if (instance)
- return FALSE;
-
- #if GINPUT_MOUSE_NEED_CALIBRATION && !GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE
- return TRUE;
- #else
- return FALSE;
- #endif
-}
-
-/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */
-void ginputMouseWakeup(void) {
- gtimerJab(&MouseTimer);
-}
-
-/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */
-void ginputMouseWakeupI(void) {
- gtimerJabI(&MouseTimer);
-}
-
-#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */
-/** @} */
+ +/** + * @file src/ginput/mouse.c + * @brief GINPUT mouse/touch code. + * + * @defgroup Mouse Mouse + * @ingroup GINPUT + * @{ + */ +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) || defined(__DOXYGEN__) + +#include "ginput/lld/mouse.h" + +#if GINPUT_MOUSE_NEED_CALIBRATION + #if !defined(GFX_USE_GDISP) || !GFX_USE_GDISP + #error "GINPUT: GFX_USE_GDISP must be defined when mouse or touch calibration is required" + #endif + + #define GINPUT_MOUSE_CALIBRATION_FONT "* Double" + #define GINPUT_MOUSE_CALIBRATION_FONT2 "* Narrow" + #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 + #else + #define GINPUT_MOUSE_CALIBRATION_POINTS 4 + #endif + + typedef struct Calibration_t { + float ax; + float bx; + float cx; + float ay; + float by; + float cy; + } Calibration; +#endif + +typedef struct MousePoint_t { + coord_t x, y; + } MousePoint; + +static GTIMER_DECL(MouseTimer); + +static struct MouseConfig_t { + MouseReading t; + MousePoint movepos; + MousePoint clickpos; + systime_t clicktime; + uint16_t last_buttons; + uint16_t flags; + #define FLG_INIT_DONE 0x8000 + #define FLG_CLICK_TIMER 0x0001 + #define FLG_IN_CAL 0x0010 + #define FLG_CAL_OK 0x0020 + #define FLG_CAL_SAVED 0x0040 + #define FLG_CAL_FREE 0x0080 + #if GINPUT_MOUSE_NEED_CALIBRATION + GMouseCalibrationSaveRoutine fnsavecal; + GMouseCalibrationLoadRoutine fnloadcal; + Calibration caldata; + #endif + } MouseConfig; + +#if GINPUT_MOUSE_NEED_CALIBRATION + static inline void _tsDrawCross(const MousePoint *pp) { + gdispDrawLine(pp->x-15, pp->y, pp->x-2, pp->y, White); + gdispDrawLine(pp->x+2, pp->y, pp->x+15, pp->y, White); + gdispDrawLine(pp->x, pp->y-15, pp->x, pp->y-2, White); + gdispDrawLine(pp->x, pp->y+2, pp->x, pp->y+15, White); + + gdispDrawLine(pp->x-15, pp->y+15, pp->x-7, pp->y+15, RGB2COLOR(184,158,131)); + gdispDrawLine(pp->x-15, pp->y+7, pp->x-15, pp->y+15, RGB2COLOR(184,158,131)); + + gdispDrawLine(pp->x-15, pp->y-15, pp->x-7, pp->y-15, RGB2COLOR(184,158,131)); + gdispDrawLine(pp->x-15, pp->y-7, pp->x-15, pp->y-15, RGB2COLOR(184,158,131)); + + gdispDrawLine(pp->x+7, pp->y+15, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); + gdispDrawLine(pp->x+15, pp->y+7, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); + + gdispDrawLine(pp->x+7, pp->y-15, pp->x+15, pp->y-15, RGB2COLOR(184,158,131)); + gdispDrawLine(pp->x+15, pp->y-15, pp->x+15, pp->y-7, RGB2COLOR(184,158,131)); + } + + static inline void _tsClearCross(const MousePoint *pp) { + gdispFillArea(pp->x - 15, pp->y - 15, 42, 42, Blue); + } + + static inline void _tsTransform(MouseReading *pt, const Calibration *c) { + pt->x = (coord_t) (c->ax * pt->x + c->bx * pt->y + c->cx); + pt->y = (coord_t) (c->ay * pt->x + c->by * pt->y + c->cy); + } + + static inline void _tsDo3PointCalibration(const MousePoint *cross, const MousePoint *points, Calibration *c) { + float dx, dx0, dx1, dx2, dy0, dy1, dy2; + + /* Compute all the required determinants */ + dx = ((float)(points[0].x - points[2].x)) * ((float)(points[1].y - points[2].y)) + - ((float)(points[1].x - points[2].x)) * ((float)(points[0].y - points[2].y)); + + dx0 = ((float)(cross[0].x - cross[2].x)) * ((float)(points[1].y - points[2].y)) + - ((float)(cross[1].x - cross[2].x)) * ((float)(points[0].y - points[2].y)); + + dx1 = ((float)(cross[1].x - cross[2].x)) * ((float)(points[0].x - points[2].x)) + - ((float)(cross[0].x - cross[2].x)) * ((float)(points[1].x - points[2].x)); + + dx2 = cross[0].x * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - + cross[1].x * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) + + cross[2].x * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y); + + dy0 = ((float)(cross[0].y - cross[2].y)) * ((float)(points[1].y - points[2].y)) + - ((float)(cross[1].y - cross[2].y)) * ((float)(points[0].y - points[2].y)); + + dy1 = ((float)(cross[1].y - cross[2].y)) * ((float)(points[0].x - points[2].x)) + - ((float)(cross[0].y - cross[2].y)) * ((float)(points[1].x - points[2].x)); + + dy2 = cross[0].y * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - + cross[1].y * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) + + cross[2].y * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y); + + /* Now, calculate all the required coefficients */ + c->ax = dx0 / dx; + c->bx = dx1 / dx; + c->cx = dx2 / dx; + + c->ay = dy0 / dx; + c->by = dy1 / dx; + c->cy = dy2 / dx; + } +#endif + +#if GINPUT_MOUSE_READ_CYCLES > 1 + static void get_raw_reading(MouseReading *pt) { + int32_t x, y, z; + unsigned i; + + x = y = z = 0; + for(i = 0; i < GINPUT_MOUSE_READ_CYCLES; i++) { + ginput_lld_mouse_get_reading(pt); + x += pt->x; + y += pt->y; + z += pt->z; + } + + /* Take the average of the readings */ + pt->x = x / GINPUT_MOUSE_READ_CYCLES; + pt->y = y / GINPUT_MOUSE_READ_CYCLES; + pt->z = z / GINPUT_MOUSE_READ_CYCLES; + } +#else + #define get_raw_reading(pt) ginput_lld_mouse_get_reading(pt) +#endif + +static void get_calibrated_reading(MouseReading *pt) { + #if GINPUT_MOUSE_NEED_CALIBRATION || GDISP_NEED_CONTROL + coord_t w, h; + #endif + + get_raw_reading(pt); + + #if GINPUT_MOUSE_NEED_CALIBRATION || GDISP_NEED_CONTROL + w = gdispGetWidth(); + h = gdispGetHeight(); + #endif + + #if GINPUT_MOUSE_NEED_CALIBRATION + _tsTransform(pt, &MouseConfig.caldata); + #endif + + #if GDISP_NEED_CONTROL + switch(gdispGetOrientation()) { + case GDISP_ROTATE_0: + break; + case GDISP_ROTATE_90: + { + coord_t t = pt->y; + pt->y = h - 1 - pt->x; + pt->x = t; + } + break; + case GDISP_ROTATE_180: + pt->x = w - 1 - pt->x; + pt->y = h - 1 - pt->y; + break; + case GDISP_ROTATE_270: + { + coord_t t = pt->x; + pt->x = w - 1 - pt->y; + pt->y = t; + } + break; + } + #endif + + #if GINPUT_MOUSE_NEED_CALIBRATION + if (pt->x < 0) pt->x = 0; + else if (pt->x >= w) pt->x = w-1; + if (pt->y < 0) pt->y = 0; + else if (pt->y >= h) pt->y = h-1; + #endif +} + +static void MousePoll(void *param) { + (void) param; + GSourceListener *psl; + GEventMouse *pe; + unsigned meta; + uint16_t tbtns; + uint32_t cdiff; + uint32_t mdiff; + + // Save the last mouse state + MouseConfig.last_buttons = MouseConfig.t.buttons; + + // Get the new mouse reading + get_calibrated_reading(&MouseConfig.t); + + // Calculate out new event meta value and handle CLICK and CXTCLICK + meta = GMETA_NONE; + + // Calculate the position difference from our movement reference (update the reference if out of range) + mdiff = (MouseConfig.t.x - MouseConfig.movepos.x) * (MouseConfig.t.x - MouseConfig.movepos.x) + + (MouseConfig.t.y - MouseConfig.movepos.y) * (MouseConfig.t.y - MouseConfig.movepos.y); + if (mdiff > GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER) { + MouseConfig.movepos.x = MouseConfig.t.x; + MouseConfig.movepos.y = MouseConfig.t.y; + } + + // Check if the click has moved outside the click area and if so cancel the click + if ((MouseConfig.flags & FLG_CLICK_TIMER)) { + cdiff = (MouseConfig.t.x - MouseConfig.clickpos.x) * (MouseConfig.t.x - MouseConfig.clickpos.x) + + (MouseConfig.t.y - MouseConfig.clickpos.y) * (MouseConfig.t.y - MouseConfig.clickpos.y); + if (cdiff > GINPUT_MOUSE_MAX_CLICK_JITTER * GINPUT_MOUSE_MAX_CLICK_JITTER) + MouseConfig.flags &= ~FLG_CLICK_TIMER; + } + + // Mouse down + tbtns = MouseConfig.t.buttons & ~MouseConfig.last_buttons; + if ((tbtns & GINPUT_MOUSE_BTN_LEFT)) + meta |= GMETA_MOUSE_DOWN; + if ((tbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) { + MouseConfig.clickpos.x = MouseConfig.t.x; + MouseConfig.clickpos.y = MouseConfig.t.y; + MouseConfig.clicktime = chTimeNow(); + MouseConfig.flags |= FLG_CLICK_TIMER; + } + + // Mouse up + tbtns = ~MouseConfig.t.buttons & MouseConfig.last_buttons; + if ((tbtns & GINPUT_MOUSE_BTN_LEFT)) + meta |= GMETA_MOUSE_UP; + if ((tbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) { + if ((MouseConfig.flags & FLG_CLICK_TIMER)) { + if ((tbtns & GINPUT_MOUSE_BTN_LEFT) + #if GINPUT_MOUSE_CLICK_TIME != TIME_INFINITE + && chTimeNow() - MouseConfig.clicktime < MS2ST(GINPUT_MOUSE_CLICK_TIME) + #endif + ) + meta |= GMETA_MOUSE_CLICK; + else + meta |= GMETA_MOUSE_CXTCLICK; + MouseConfig.flags &= ~FLG_CLICK_TIMER; + } + } + + // Send the event to the listeners that are interested. + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)(&MouseConfig), psl))) { + if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) { + // This listener is missing - save the meta events that have happened + psl->srcflags |= meta; + continue; + } + + // If we haven't really moved (and there are no meta events) don't bother sending the event + if (mdiff <= GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER && !psl->srcflags && !meta && !(psl->listenflags & GLISTEN_MOUSENOFILTER)) + continue; + + // Send the event if we are listening for it + if (((MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEDOWNMOVES)) + || (!(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEUPMOVES)) + || (meta && (psl->listenflags & GLISTEN_MOUSEMETA))) { + pe->type = GINPUT_MOUSE_EVENT_TYPE; + pe->instance = 0; + pe->x = MouseConfig.t.x; + pe->y = MouseConfig.t.y; + pe->z = MouseConfig.t.z; + pe->current_buttons = MouseConfig.t.buttons; + pe->last_buttons = MouseConfig.last_buttons; + pe->meta = meta; + if (psl->srcflags) { + pe->current_buttons |= GINPUT_MISSED_MOUSE_EVENT; + pe->meta |= psl->srcflags; + psl->srcflags = 0; + } + geventSendEvent(psl); + } + } +} + +GSourceHandle ginputGetMouse(uint16_t instance) { + #if GINPUT_MOUSE_NEED_CALIBRATION + Calibration *pc; + #endif + + // We only support a single mouse instance currently + // 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? + if (!(MouseConfig.flags & FLG_INIT_DONE)) { + ginput_lld_mouse_init(); + + #if GINPUT_MOUSE_NEED_CALIBRATION + #if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE + if (!MouseConfig.fnloadcal) { + MouseConfig.fnloadcal = ginput_lld_mouse_calibration_load; + MouseConfig.flags &= ~FLG_CAL_FREE; + } + if (!MouseConfig.fnsavecal) + MouseConfig.fnsavecal = ginput_lld_mouse_calibration_save; + #endif + if (MouseConfig.fnloadcal && (pc = (Calibration *)MouseConfig.fnloadcal(instance))) { + MouseConfig.caldata = pc[0]; + 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 + + // Get the first reading + MouseConfig.last_buttons = 0; + get_calibrated_reading(&MouseConfig.t); + + // Mark init as done and start the Poll timer + MouseConfig.flags |= FLG_INIT_DONE; + gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); + } + + // Return our structure as the handle + return (GSourceHandle)&MouseConfig; +} + +bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pe) { + // Win32 threads don't seem to recognise priority and/or pre-emption + // so we add a sleep here to prevent 100% polled applications from locking up. + chThdSleepMilliseconds(1); + + if (instance || (MouseConfig.flags & (FLG_INIT_DONE|FLG_IN_CAL)) != FLG_INIT_DONE) + return FALSE; + + pe->type = GINPUT_MOUSE_EVENT_TYPE; + pe->instance = instance; + pe->x = MouseConfig.t.x; + pe->y = MouseConfig.t.y; + pe->z = MouseConfig.t.z; + pe->current_buttons = MouseConfig.t.buttons; + pe->last_buttons = MouseConfig.last_buttons; + if (pe->current_buttons & ~pe->last_buttons & GINPUT_MOUSE_BTN_LEFT) + pe->meta = GMETA_MOUSE_DOWN; + else if (~pe->current_buttons & pe->last_buttons & GINPUT_MOUSE_BTN_LEFT) + pe->meta = GMETA_MOUSE_UP; + else + pe->meta = GMETA_NONE; + return TRUE; +} + +bool_t ginputCalibrateMouse(uint16_t instance) { + #if !GINPUT_MOUSE_NEED_CALIBRATION + (void) instance; + + return FALSE; + #else + + const coord_t height = gdispGetHeight(); + const coord_t width = gdispGetWidth(); + const MousePoint cross[] = {{(width / 4), (height / 4)}, + {(width - (width / 4)) , (height / 4)}, + {(width - (width / 4)) , (height - (height / 4))}, + {(width / 2), (height / 2)}}; /* Check point */ + MousePoint points[GINPUT_MOUSE_CALIBRATION_POINTS]; + const MousePoint *pc; + MousePoint *pt; + int32_t px, py; + unsigned i, j; + font_t font1, font2; + #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 + unsigned err; + #endif + + if (instance || (MouseConfig.flags & FLG_IN_CAL)) + return FALSE; + + font1 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT); + font2 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT2); + + MouseConfig.flags |= FLG_IN_CAL; + gtimerStop(&MouseTimer); + MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED); + + #if GDISP_NEED_CONTROL + 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, font1, White, Blue, justifyCenter); + + for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) { + _tsDrawCross(pc); + + do { + + /* Wait for the mouse to be pressed */ + while(get_raw_reading(&MouseConfig.t), !(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT)) + chThdSleepMilliseconds(20); + + /* Average all the samples while the mouse is down */ + for(px = py = 0, j = 0; + chThdSleepMilliseconds(20), /* Settling time between readings */ + get_raw_reading(&MouseConfig.t), + (MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT); + j++) { + px += MouseConfig.t.x; + py += MouseConfig.t.y; + } + + } while(!j); + + pt->x = px / j; + 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, font2, Red, Yellow, justifyCenter); + chThdSleepMilliseconds(5000); + gdispFillArea(0, 35, width, 40, Blue); + } + + } + + /* Apply 3 point calibration algorithm */ + _tsDo3PointCalibration(cross, points, &MouseConfig.caldata); + + /* Verification of correctness of calibration (optional) : + * See if the 4th point (Middle of the screen) coincides with the calibrated + * result. If point is within +/- Squareroot(ERROR) pixel margin, then successful calibration + * Else, start from the beginning. + */ + #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 + /* Transform the co-ordinates */ + MouseConfig.t.x = points[3].x; + MouseConfig.t.y = points[3].y; + _tsTransform(&MouseConfig.t, &MouseConfig.caldata); + + /* Calculate the delta */ + 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); + + if (err <= GINPUT_MOUSE_MAX_CALIBRATION_ERROR * GINPUT_MOUSE_MAX_CALIBRATION_ERROR) + break; + + gdispFillStringBox(0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); + chThdSleepMilliseconds(5000); + } + #endif + + // Restart everything + gdispCloseFont(font1); + gdispCloseFont(font2); + MouseConfig.flags |= FLG_CAL_OK; + MouseConfig.last_buttons = 0; + get_calibrated_reading(&MouseConfig.t); + MouseConfig.flags &= ~FLG_IN_CAL; + if ((MouseConfig.flags & FLG_INIT_DONE)) + gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); + + // Save the calibration data (if possible) + if (MouseConfig.fnsavecal) { + MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata)); + MouseConfig.flags |= FLG_CAL_SAVED; + } + + return TRUE; + #endif +} + +/* Set the routines to save and fetch calibration data. + * This function should be called before first calling ginputGetMouse() for a particular instance + * as the gdispGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it. + * If this is called after gdispGetMouse() has been called and the driver requires calibration storage, it will immediately save the data is has already obtained. + * The 'requireFree' parameter indicates if the fetch buffer must be free()'d to deallocate the buffer provided by the Fetch routine. + */ +void ginputSetMouseCalibrationRoutines(uint16_t instance, GMouseCalibrationSaveRoutine fnsave, GMouseCalibrationLoadRoutine fnload, bool_t requireFree) { + #if GINPUT_MOUSE_NEED_CALIBRATION + if (instance) + return; + + MouseConfig.fnloadcal = fnload; + MouseConfig.fnsavecal = fnsave; + if (requireFree) + MouseConfig.flags |= FLG_CAL_FREE; + else + MouseConfig.flags &= ~FLG_CAL_FREE; + #if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE + if (!MouseConfig.fnloadcal) { + MouseConfig.fnloadcal = ginput_lld_mouse_calibration_load; + MouseConfig.flags &= ~FLG_CAL_FREE; + } + if (!MouseConfig.fnsavecal) + MouseConfig.fnsavecal = ginput_lld_mouse_calibration_save; + #endif + if (MouseConfig.fnsavecal && (MouseConfig.flags & (FLG_CAL_OK|FLG_CAL_SAVED)) == FLG_CAL_OK) { + MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata)); + MouseConfig.flags |= FLG_CAL_SAVED; + } + #else + (void)instance, (void)fnsave, (void)fnload, (void)requireFree; + #endif +} + +/* Test if a particular mouse instance requires routines to save its calibration data. */ +bool_t ginputRequireMouseCalibrationStorage(uint16_t instance) { + if (instance) + return FALSE; + + #if GINPUT_MOUSE_NEED_CALIBRATION && !GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE + return TRUE; + #else + return FALSE; + #endif +} + +/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ +void ginputMouseWakeup(void) { + gtimerJab(&MouseTimer); +} + +/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ +void ginputMouseWakeupI(void) { + gtimerJabI(&MouseTimer); +} + +#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ +/** @} */ diff --git a/src/tdisp/tdisp.c b/src/tdisp/tdisp.c index a5608acf..42b22cd5 100644 --- a/src/tdisp/tdisp.c +++ b/src/tdisp/tdisp.c @@ -72,7 +72,7 @@ void tdispSetCursor(coord_t col, coord_t row) { MUTEX_LEAVE(); } -void tdispCreateChar(uint8_t address, uint8_t *charmap) { +void tdispCreateChar(uint8_t address, char *charmap) { /* make sure we don't write somewhere we're not supposed to */ if (address < TDISP.maxCustomChars) { MUTEX_ENTER(); |