/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2008 by Maurus Cuelenaere * * This program 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 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "config.h" #include "button.h" #include "button-target.h" #include "touchscreen.h" #include "string.h" #include "logf.h" #include "lcd.h" /* Size of the 'dead zone' around each 3x3 button */ #define BUTTON_MARGIN_X (int)(LCD_WIDTH * 0.03) #define BUTTON_MARGIN_Y (int)(LCD_HEIGHT * 0.03) static bool touch_enabled = true; static enum touchscreen_mode current_mode = TOUCHSCREEN_POINT; static const int touchscreen_buttons[3][3] = { {BUTTON_TOPLEFT, BUTTON_TOPMIDDLE, BUTTON_TOPRIGHT}, {BUTTON_MIDLEFT, BUTTON_CENTER, BUTTON_MIDRIGHT}, {BUTTON_BOTTOMLEFT, BUTTON_BOTTOMMIDDLE, BUTTON_BOTTOMRIGHT} }; #ifndef DEFAULT_TOUCHSCREEN_CALIBRATION #define DEFAULT_TOUCHSCREEN_CALIBRATION { .A=1, .B=0, .C=0, \ .D=0, .E=1, .F=0, \ .divider=1 } #endif struct touchscreen_parameter calibration_parameters = DEFAULT_TOUCHSCREEN_CALIBRATION; const struct touchscreen_parameter default_calibration_parameters = DEFAULT_TOUCHSCREEN_CALIBRATION; void touchscreen_disable_mapping(void) { #define C(x) calibration_parameters.x C(A) = C(E) = 1; C(B) = C(C) = C(D) = C(F) = 0; C(divider) = 1; #undef C } void touchscreen_reset_mapping(void) { memcpy(&calibration_parameters, &default_calibration_parameters, sizeof(struct touchscreen_parameter)); } int touchscreen_calibrate(struct touchscreen_calibration *cal) { #define C(x) calibration_parameters.x /* Calibration */ #define S(i,j) cal->i[j][0] /* Screen */ #define D(i,j) cal->i[j][1] /* Display */ long divider = (S(x,0) - S(x,2)) * (S(y,1) - S(y,2)) - (S(x,1) - S(x,2)) * (S(y,0) - S(y,2)); if(divider == 0) return -1; else C(divider) = divider; C(A) = (D(x,0) - D(x,2)) * (S(y,1) - S(y,2)) - (D(x,1) - D(x,2)) * (S(y,0) - S(y,2)); C(B) = (S(x,0) - S(x,2)) * (D(x,1) - D(x,2)) - (D(x,0) - D(x,2)) * (S(x,1) - S(x,2)); C(C) = S(y,0) * (S(x,2) * D(x,1) - S(x,1) * D(x,2)) + S(y,1) * (S(x,0) * D(x,2) - S(x,2) * D(x,0)) + S(y,2) * (S(x,1) * D(x,0) - S(x,0) * D(x,1)); C(D) = (D(y,0) - D(y,2)) * (S(y,1) - S(y,2)) - (D(y,1) - D(y,2)) * (S(y,0) - S(y,2)); C(E) = (S(x,0) - S(x,2)) * (D(y,1) - D(y,2)) - (D(y,0) - D(y,2)) * (S(x,1) - S(x,2)); C(F) = S(y,0) * (S(x,2) * D(y,1) - S(x,1) * D(y,2)) + S(y,1) * (S(x,0) * D(y,2) - S(x,2) * D(y,0)) + S(y,2) * (S(x,1) * D(y,0) - S(x,0) * D(y,1)); logf("A: %lX B: %lX C: %lX", C(A), C(B), C(C)); logf("D: %lX E: %lX F: %lX", C(D), C(E), C(F)); logf("divider: %lX", C(divider)); return 0; #undef C #undef S #undef D } static void map_pixels(int *x, int *y) { #define C(x) calibration_parameters.x int _x = *x, _y = *y; *x = (C(A) * _x + C(B) * _y + C(C)) / C(divider); *y = (C(D) * _x + C(E) * _y + C(F)) / C(divider); #undef C } /* TODO: add jitter (and others) filter */ int touchscreen_to_pixels(int x, int y, int *data) { if(!touch_enabled) return 0; x &= 0xFFFF; y &= 0xFFFF; map_pixels(&x, &y); if (current_mode == TOUCHSCREEN_BUTTON) { int column = 0, row = 0; if (x < LCD_WIDTH/3 - BUTTON_MARGIN_X) column = 0; else if (x > LCD_WIDTH/3 + BUTTON_MARGIN_X && x < 2*LCD_WIDTH/3 - BUTTON_MARGIN_X) column = 1; else if (x > 2*LCD_WIDTH/3 + BUTTON_MARGIN_X) column = 2; else return BUTTON_NONE; if (y < LCD_HEIGHT/3 - BUTTON_MARGIN_Y) row = 0; else if (y > LCD_HEIGHT/3 + BUTTON_MARGIN_Y && y < 2*LCD_HEIGHT/3 - BUTTON_MARGIN_Y) row = 1; else if (y > 2*LCD_HEIGHT/3 + BUTTON_MARGIN_Y) row = 2; else return BUTTON_NONE; return touchscreen_buttons[row][column]; } else { *data = (x << 16 | y); return BUTTON_TOUCHSCREEN; } } void touchscreen_set_mode(enum touchscreen_mode mode) { current_mode = mode; } enum touchscreen_mode touchscreen_get_mode(void) { return current_mode; } #ifndef HAS_BUTTON_HOLD void touchscreen_enable(bool en) { if(en != touch_enabled) { touch_enabled = en; touchscreen_enable_device(en); } } bool touchscreen_is_enabled(void) { return touch_enabled; } #endif #if ((CONFIG_PLATFORM & PLATFORM_ANDROID) == 0) /* android has an API for this */ #define TOUCH_SLOP 16u #define REFERENCE_DPI 160 int touchscreen_get_scroll_threshold(void) { #ifdef LCD_DPI const int dpi = LCD_DPI; #else const int dpi = lcd_get_dpi(); #endif /* Inspired by Android calculation * * float density = real dpi / reference dpi (=160) * int threshold = (int) (density * TOUCH_SLOP + 0.5f);(original calculation) * * + 0.5f is for rounding, we use fixed point math to achieve that */ int result = dpi * (TOUCH_SLOP<<1) / REFERENCE_DPI; result += result & 1; /* round up if needed */ return result>>1; } #endif