diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 09cbdbfc09..da09e3c49a 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -12405,7 +12405,7 @@ id: LANG_TOUCHSCREEN_MODE - desc: in Settings -> General -> System menu + desc: in Settings -> General -> Display -> Touchscreen Settings user: core *: none @@ -12422,7 +12422,7 @@ id: LANG_TOUCHSCREEN_GRID - desc: in Settings -> General -> System menu + desc: in Settings -> General -> Display -> Touchscreen Settings user: core *: none @@ -12439,7 +12439,7 @@ id: LANG_TOUCHSCREEN_POINT - desc: in Settings -> General -> System menu + desc: in Settings -> General -> Display -> Touchscreen Settings user: core *: none @@ -12502,3 +12502,54 @@ swcodec: "Speed" + + id: LANG_TOUCHSCREEN_SETTINGS + desc: in Settings -> General -> Display menu + user: core + + *: none + touchscreen: "Touchscreen Settings" + + + *: none + touchscreen: "Touchscreen Settings" + + + *: none + touchscreen: "Touchscreen Settings" + + + + id: LANG_TOUCHSCREEN_CALIBRATE + desc: in Settings -> General -> Display -> Touchscreen Settings + user: core + + *: none + touchscreen: "Calibrate" + + + *: none + touchscreen: "Calibrate" + + + *: none + touchscreen: "Calibrate" + + + + id: LANG_TOUCHSCREEN_RESET_CALIBRATION + desc: in Settings -> General -> Display -> Touchscreen Settings + user: core + + *: none + touchscreen: "Reset Calibration" + + + *: none + touchscreen: "Reset Calibration" + + + *: none + touchscreen: "Reset Calibration" + + diff --git a/apps/lang/nederlands.lang b/apps/lang/nederlands.lang index 2d476d1d14..e73839926f 100644 --- a/apps/lang/nederlands.lang +++ b/apps/lang/nederlands.lang @@ -12335,7 +12335,7 @@ id: LANG_TOUCHSCREEN_MODE - desc: in Settings -> General -> System menu + desc: in Settings -> General -> Display -> Touchscreen Settings user: core *: none @@ -12352,7 +12352,7 @@ id: LANG_TOUCHSCREEN_GRID - desc: in Settings -> General -> System menu + desc: in Settings -> General -> Display -> Touchscreen Settings user: core *: none @@ -12369,7 +12369,7 @@ id: LANG_TOUCHSCREEN_POINT - desc: in Settings -> General -> System menu + desc: in Settings -> General -> Display -> Touchscreen Settings user: core *: none @@ -12432,3 +12432,54 @@ swcodec: "Snelheid" + + id: LANG_TOUCHSCREEN_SETTINGS + desc: in Settings -> General -> Display menu + user: core + + *: none + touchscreen: "Touchscreen Settings" + + + *: none + touchscreen: "Touchscreen instellingen" + + + *: none + touchscreen: "Touchscreen instellingen" + + + + id: LANG_TOUCHSCREEN_CALIBRATE + desc: in Settings -> General -> Display -> Touchscreen Settings + user: core + + *: none + touchscreen: "Calibrate" + + + *: none + touchscreen: "Kalibreer" + + + *: none + touchscreen: "Kalibreer" + + + + id: LANG_TOUCHSCREEN_RESET_CALIBRATION + desc: in Settings -> General -> Display -> Touchscreen Settings + user: core + + *: none + touchscreen: "Reset Calibration" + + + *: none + touchscreen: "Kalibratie terugzetten" + + + *: none + touchscreen: "Kalibratie terugzetten" + + diff --git a/apps/menus/display_menu.c b/apps/menus/display_menu.c index a015be3a23..aee9c1828d 100644 --- a/apps/menus/display_menu.c +++ b/apps/menus/display_menu.c @@ -36,6 +36,9 @@ #include "talk.h" #include "lcd.h" #include "lcd-remote.h" +#ifdef HAVE_TOUCHSCREEN +#include "screens.h" +#endif #ifdef HAVE_BACKLIGHT static int filterfirstkeypress_callback(int action,const struct menu_item_ex *this_item) @@ -496,6 +499,29 @@ MAKE_MENU(peak_meter_menu, ID2P(LANG_PM_MENU), NULL, Icon_NOICON, /***********************************/ +#ifdef HAVE_TOUCHSCREEN +static int touch_mode_callback(int action,const struct menu_item_ex *this_item) +{ + (void)this_item; + switch (action) + { + case ACTION_EXIT_MENUITEM: /* on exit */ + touchscreen_set_mode(global_settings.touch_mode); + break; + } + return action; +} +MENUITEM_SETTING(touch_mode, &global_settings.touch_mode, touch_mode_callback); + +MENUITEM_FUNCTION(touchscreen_menu_calibrate, 0, ID2P(LANG_TOUCHSCREEN_CALIBRATE), calibrate, + NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(touchscreen_menu_reset_calibration, 0, ID2P(LANG_TOUCHSCREEN_RESET_CALIBRATION), reset_mapping, + NULL, NULL, Icon_NOICON); + +MAKE_MENU(touchscreen_menu, ID2P(LANG_TOUCHSCREEN_SETTINGS), NULL, Icon_NOICON, &touch_mode, + &touchscreen_menu_calibrate, &touchscreen_menu_reset_calibration); +#endif + MENUITEM_SETTING(codepage_setting, &global_settings.default_codepage, NULL); @@ -511,4 +537,7 @@ MAKE_MENU(display_menu, ID2P(LANG_DISPLAY), &bars_menu, &peak_meter_menu, #endif &codepage_setting, +#ifdef HAVE_TOUCHSCREEN + &touchscreen_menu, +#endif ); diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index 56a0178000..fdc775877a 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c @@ -265,21 +265,6 @@ MENUITEM_SETTING(buttonlight_brightness, &global_settings.buttonlight_brightness MENUITEM_SETTING(touchpad_sensitivity, &global_settings.touchpad_sensitivity, NULL); #endif -#ifdef HAVE_TOUCHSCREEN -static int touch_mode_callback(int action,const struct menu_item_ex *this_item) -{ - (void)this_item; - switch (action) - { - case ACTION_EXIT_MENUITEM: /* on exit */ - touchscreen_set_mode(global_settings.touch_mode); - break; - } - return action; -} -MENUITEM_SETTING(touch_mode, &global_settings.touch_mode, touch_mode_callback); -#endif - MAKE_MENU(system_menu, ID2P(LANG_SYSTEM), 0, Icon_System_menu, &start_screen, @@ -314,9 +299,6 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM), #endif #ifdef HAVE_TOUCHPAD_SENSITIVITY_SETTING &touchpad_sensitivity, -#endif -#ifdef HAVE_TOUCHSCREEN - &touch_mode, #endif ); diff --git a/apps/screens.c b/apps/screens.c index 096b81411e..829aa191e1 100644 --- a/apps/screens.c +++ b/apps/screens.c @@ -1019,3 +1019,85 @@ bool view_runtime(void) } return false; } + +#ifdef HAVE_TOUCHSCREEN +static int get_sample(struct touchscreen_calibration *cal, int x, int y, int i, + struct screen* screen) +{ + int action; + short ts_x, ts_y; + + /* Draw a cross */ + screen->drawline(x - 10, y, x - 2, y); + screen->drawline(x + 2, y, x + 10, y); + screen->drawline(x, y - 10, x, y - 2); + screen->drawline(x, y + 2, x, y + 10); + screen->update(); + + /* Wait for a touchscreen press */ + while(true) + { + action = get_action(CONTEXT_STD, TIMEOUT_BLOCK); + if(action == ACTION_TOUCHSCREEN) + { + if(action_get_touchscreen_press(&ts_x, &ts_y) == BUTTON_REL) + break; + } + else if(action == ACTION_STD_CANCEL) + return -1; + } + + cal->x[i][0] = ts_x; + cal->y[i][0] = ts_y; + cal->x[i][1] = x; + cal->y[i][1] = y; + + return 0; +} + + +int calibrate(void) +{ + short points[3][2] = { + {LCD_WIDTH/10, LCD_HEIGHT/10}, + {7*LCD_WIDTH/8, LCD_HEIGHT/2}, + {LCD_WIDTH/2, 7*LCD_HEIGHT/8} + }; + struct screen* screen = &screens[SCREEN_MAIN]; + enum touchscreen_mode old_mode = touchscreen_get_mode(); + struct touchscreen_calibration cal; + int i, ret = 0; + bool statusbar = global_settings.statusbar; /* hide the statusbar */ + + global_settings.statusbar = false; + touchscreen_disable_mapping(); /* set raw mode */ + touchscreen_set_mode(TOUCHSCREEN_POINT); + for(i=0; i<3; i++) + { + screen->clear_display(); + + if(get_sample(&cal, points[i][0], points[i][1], i, screen)) + { + ret = -1; + break; + } + } + + if(ret == 0) + touchscreen_calibrate(&cal); + else + touchscreen_reset_mapping(); + memcpy(&global_settings.ts_calibration_data, &calibration_parameters, sizeof(struct touchscreen_parameter)); + touchscreen_set_mode(old_mode); + global_settings.statusbar = statusbar; + + return ret; +} + +int reset_mapping(void) +{ + touchscreen_reset_mapping(); + memcpy(&global_settings.ts_calibration_data, &calibration_parameters, sizeof(struct touchscreen_parameter)); + return 0; +} +#endif diff --git a/apps/screens.h b/apps/screens.h index eb613fc178..38fef14d60 100644 --- a/apps/screens.h +++ b/apps/screens.h @@ -50,5 +50,10 @@ bool shutdown_screen(void); bool browse_id3(void); bool view_runtime(void); +#ifdef HAVE_TOUCHSCREEN +int calibrate(void); +int reset_mapping(void); +#endif + #endif diff --git a/apps/settings.c b/apps/settings.c index 9594bd164e..3219dbbf12 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -966,6 +966,7 @@ void settings_apply(bool read_disk) #ifdef HAVE_TOUCHSCREEN touchscreen_set_mode(global_settings.touch_mode); + memcpy(&calibration_parameters, &global_settings.ts_calibration_data, sizeof(struct touchscreen_parameter)); #endif /* This should stay last */ diff --git a/apps/settings.h b/apps/settings.h index 6ccaeed92e..ef5a62013d 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -730,6 +730,7 @@ struct user_settings #ifdef HAVE_TOUCHSCREEN int touch_mode; + struct touchscreen_parameter ts_calibration_data; #endif /* If values are just added to the end, no need to bump plugin API diff --git a/apps/settings_list.c b/apps/settings_list.c index 74e2cab3cd..dcad718ee5 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -53,6 +53,10 @@ #include "iap.h" #endif #include "statusbar.h" +#ifdef HAVE_TOUCHSCREEN +#include "touchscreen.h" +#include "ctype.h" /* For isspace() */ +#endif #define NVRAM(bytes) (bytes<A, ...); */ + int vals[7], count = 0; + while(*value != 0 && count < 7) + { + if(isspace(*value)) + value++; + else + { + vals[count++] = atoi(value); + while(!isspace(*value)) + value++; + } + } + var->A = vals[0]; + var->B = vals[1]; + var->C = vals[2]; + var->D = vals[3]; + var->E = vals[4]; + var->F = vals[5]; + var->divider = vals[6]; +} + +static char* tsc_write_to_cfg(void* setting, char*buf, int buf_len) +{ + const struct touchscreen_parameter *var = (const struct touchscreen_parameter*) setting; + snprintf(buf, buf_len, "%d %d %d %d %d %d %d", var->A, var->B, var->C, var->D, var->E, var->F, var->divider); + return buf; +} +static bool tsc_is_changed(void* setting, void* defaultval) +{ + return memcmp(setting, defaultval, sizeof(struct touchscreen_parameter)) != 0; +} +static void tsc_set_default(void* setting, void* defaultval) +{ + memcpy(setting, defaultval, sizeof(struct touchscreen_parameter)); +} +#endif const struct settings_list settings[] = { /* sound settings */ SOUND_SETTING(F_NO_WRAP,volume, LANG_VOLUME, "volume", SOUND_VOLUME), @@ -1470,6 +1516,10 @@ const struct settings_list settings[] = { CHOICE_SETTING(0, touch_mode, LANG_TOUCHSCREEN_MODE, TOUCHSCREEN_BUTTON, "touchscreen mode", "point,grid", NULL, 2, ID2P(LANG_TOUCHSCREEN_POINT), ID2P(LANG_TOUCHSCREEN_GRID)), + CUSTOM_SETTING(0, ts_calibration_data, -1, + &default_calibration_parameters, "touchscreen calibration", + tsc_load_from_cfg, tsc_write_to_cfg, + tsc_is_changed, tsc_set_default), #endif OFFON_SETTING(0, prevent_skip, LANG_PREVENT_SKIPPING, false, "prevent track skip", NULL), }; diff --git a/firmware/drivers/touchscreen.c b/firmware/drivers/touchscreen.c index f7b1b09b92..002acf1236 100755 --- a/firmware/drivers/touchscreen.c +++ b/firmware/drivers/touchscreen.c @@ -34,119 +34,93 @@ static const int touchscreen_buttons[3][3] = {BUTTON_BOTTOMLEFT, BUTTON_BOTTOMMIDDLE, BUTTON_BOTTOMRIGHT} }; -/* Based on ftp://ftp.embedded.com/pub/2002/06vidales/calibrate.c - * - * Copyright (c) 2001, Carlos E. Vidales. All rights reserved. - * - * This sample program was written and put in the public domain - * by Carlos E. Vidales. The program is provided "as is" - * without warranty of any kind, either expressed or implied. - * If you choose to use the program within your own products - * you do so at your own risk, and assume the responsibility - * for servicing, repairing or correcting the program should - * it prove defective in any manner. - * You may copy and distribute the program's source code in any - * medium, provided that you also include in each copy an - * appropriate copyright notice and disclaimer of warranty. - * You may also modify this program and distribute copies of - * it provided that you include prominent notices stating - * that you changed the file(s) and the date of any change, - * and that you do not charge any royalties or licenses for - * its use. - */ -struct touchscreen_parameter -{ - long A; - long B; - long C; - long D; - long E; - long F; - long divider; -}; - #ifndef DEFAULT_TOUCHSCREEN_CALIBRATION -#define DEFAULT_TOUCHSCREEN_CALIBRATION {.A=1, .B=0, .C=0, \ - .D=0, .E=1, .F=0, \ - .divider=1} +#define DEFAULT_TOUCHSCREEN_CALIBRATION { .A=1, .B=0, .C=0, \ + .D=0, .E=1, .F=0, \ + .divider=1 } #endif -static struct touchscreen_parameter calibration_parameters +struct touchscreen_parameter calibration_parameters = DEFAULT_TOUCHSCREEN_CALIBRATION; -static const struct touchscreen_parameter default_parameters +const struct touchscreen_parameter default_calibration_parameters = DEFAULT_TOUCHSCREEN_CALIBRATION; void touchscreen_disable_mapping(void) { - calibration_parameters.A = 1; - calibration_parameters.B = 0; - calibration_parameters.C = 0; - calibration_parameters.D = 0; - calibration_parameters.E = 1; - calibration_parameters.F = 0; - calibration_parameters.divider = 1; +#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_parameters, + memcpy(&calibration_parameters, &default_calibration_parameters, sizeof(struct touchscreen_parameter)); } int touchscreen_calibrate(struct touchscreen_calibration *cal) { - calibration_parameters.divider = ((cal->x[0] - cal->x[2]) * (cal->y[1] - cal->y[2])) - - ((cal->x[1] - cal->x[2]) * (cal->y[0] - cal->y[2])) ; +#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(calibration_parameters.divider == 0) + if(divider == 0) return -1; - - calibration_parameters.A = ((cal->xfb[0] - cal->xfb[2]) * (cal->y[1] - cal->y[2])) - - ((cal->xfb[1] - cal->xfb[2]) * (cal->y[0] - cal->y[2])) ; + else + C(divider) = divider; - calibration_parameters.B = ((cal->x[0] - cal->x[2]) * (cal->xfb[1] - cal->xfb[2])) - - ((cal->xfb[0] - cal->xfb[2]) * (cal->x[1] - cal->x[2])) ; + 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)); - calibration_parameters.C = (cal->x[2] * cal->xfb[1] - cal->x[1] * cal->xfb[2]) * cal->y[0] + - (cal->x[0] * cal->xfb[2] - cal->x[2] * cal->xfb[0]) * cal->y[1] + - (cal->x[1] * cal->xfb[0] - cal->x[0] * cal->xfb[1]) * cal->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)); - calibration_parameters.D = ((cal->yfb[0] - cal->yfb[2]) * (cal->y[1] - cal->y[2])) - - ((cal->yfb[1] - cal->yfb[2]) * (cal->y[0] - cal->y[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)); - calibration_parameters.E = ((cal->x[0] - cal->x[2]) * (cal->yfb[1] - cal->yfb[2])) - - ((cal->yfb[0] - cal->yfb[2]) * (cal->x[1] - cal->x[2])) ; + 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)); - calibration_parameters.F = (cal->x[2] * cal->yfb[1] - cal->x[1] * cal->yfb[2]) * cal->y[0] + - (cal->x[0] * cal->yfb[2] - cal->x[2] * cal->yfb[0]) * cal->y[1] + - (cal->x[1] * cal->yfb[0] - cal->x[0] * cal->yfb[1]) * cal->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)); - logf("A: %lX B: %lX C: %lX", calibration_parameters.A, - calibration_parameters.B, calibration_parameters.C); - logf("D: %lX E: %lX F: %lX", calibration_parameters.D, - calibration_parameters.E, calibration_parameters.F); - logf("divider: %lX", calibration_parameters.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 = (calibration_parameters.A*_x + calibration_parameters.B*_y + - calibration_parameters.C) / calibration_parameters.divider; - *y = (calibration_parameters.D*_x + calibration_parameters.E*_y + - calibration_parameters.F) / calibration_parameters.divider; + + *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) { x &= 0xFFFF; y &= 0xFFFF; - + map_pixels(&x, &y); - + if(current_mode == TOUCHSCREEN_BUTTON) return touchscreen_buttons[y / (LCD_HEIGHT/3)] [x / (LCD_WIDTH/3) ]; diff --git a/firmware/export/touchscreen.h b/firmware/export/touchscreen.h index 0d8233a522..7d1eb4ac8a 100755 --- a/firmware/export/touchscreen.h +++ b/firmware/export/touchscreen.h @@ -24,10 +24,14 @@ struct touchscreen_calibration { - int x[3]; - int xfb[3]; - int y[3]; - int yfb[3]; + int x[3][2]; + int y[3][2]; +}; + +struct touchscreen_parameter +{ + int A, B, C, D, E, F; + int divider; }; enum touchscreen_mode @@ -38,6 +42,8 @@ enum touchscreen_mode from button_get_data */ }; +extern struct touchscreen_parameter calibration_parameters; +extern const struct touchscreen_parameter default_calibration_parameters; int touchscreen_calibrate(struct touchscreen_calibration *cal); int touchscreen_to_pixels(int x, int y, int *data); void touchscreen_set_mode(enum touchscreen_mode mode);