A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Maurus Cuelenaere
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "button.h"
24#include "button-target.h"
25#include "touchscreen.h"
26#include "string.h"
27#include "logf.h"
28#include "lcd.h"
29
30/* Size of the 'dead zone' around each 3x3 button */
31#define BUTTON_MARGIN_X (int)(LCD_WIDTH * 0.03)
32#define BUTTON_MARGIN_Y (int)(LCD_HEIGHT * 0.03)
33
34static bool touch_enabled = true;
35static enum touchscreen_mode current_mode = TOUCHSCREEN_POINT;
36static const int touchscreen_buttons[3][3] =
37{
38 {BUTTON_TOPLEFT, BUTTON_TOPMIDDLE, BUTTON_TOPRIGHT},
39 {BUTTON_MIDLEFT, BUTTON_CENTER, BUTTON_MIDRIGHT},
40 {BUTTON_BOTTOMLEFT, BUTTON_BOTTOMMIDDLE, BUTTON_BOTTOMRIGHT}
41};
42
43#ifndef DEFAULT_TOUCHSCREEN_CALIBRATION
44#define DEFAULT_TOUCHSCREEN_CALIBRATION { .A=1, .B=0, .C=0, \
45 .D=0, .E=1, .F=0, \
46 .divider=1 }
47#endif
48
49struct touchscreen_parameter calibration_parameters
50 = DEFAULT_TOUCHSCREEN_CALIBRATION;
51const struct touchscreen_parameter default_calibration_parameters
52 = DEFAULT_TOUCHSCREEN_CALIBRATION;
53
54void touchscreen_disable_mapping(void)
55{
56#define C(x) calibration_parameters.x
57 C(A) = C(E) = 1;
58 C(B) = C(C) = C(D) = C(F) = 0;
59 C(divider) = 1;
60#undef C
61}
62
63void touchscreen_reset_mapping(void)
64{
65 memcpy(&calibration_parameters, &default_calibration_parameters,
66 sizeof(struct touchscreen_parameter));
67}
68
69int touchscreen_calibrate(struct touchscreen_calibration *cal)
70{
71#define C(x) calibration_parameters.x /* Calibration */
72#define S(i,j) cal->i[j][0] /* Screen */
73#define D(i,j) cal->i[j][1] /* Display */
74 long divider = (S(x,0) - S(x,2)) * (S(y,1) - S(y,2)) -
75 (S(x,1) - S(x,2)) * (S(y,0) - S(y,2));
76
77 if(divider == 0)
78 return -1;
79 else
80 C(divider) = divider;
81
82 C(A) = (D(x,0) - D(x,2)) * (S(y,1) - S(y,2)) -
83 (D(x,1) - D(x,2)) * (S(y,0) - S(y,2));
84
85 C(B) = (S(x,0) - S(x,2)) * (D(x,1) - D(x,2)) -
86 (D(x,0) - D(x,2)) * (S(x,1) - S(x,2));
87
88 C(C) = S(y,0) * (S(x,2) * D(x,1) - S(x,1) * D(x,2)) +
89 S(y,1) * (S(x,0) * D(x,2) - S(x,2) * D(x,0)) +
90 S(y,2) * (S(x,1) * D(x,0) - S(x,0) * D(x,1));
91
92 C(D) = (D(y,0) - D(y,2)) * (S(y,1) - S(y,2)) -
93 (D(y,1) - D(y,2)) * (S(y,0) - S(y,2));
94
95 C(E) = (S(x,0) - S(x,2)) * (D(y,1) - D(y,2)) -
96 (D(y,0) - D(y,2)) * (S(x,1) - S(x,2));
97
98 C(F) = S(y,0) * (S(x,2) * D(y,1) - S(x,1) * D(y,2)) +
99 S(y,1) * (S(x,0) * D(y,2) - S(x,2) * D(y,0)) +
100 S(y,2) * (S(x,1) * D(y,0) - S(x,0) * D(y,1));
101
102 logf("A: %lX B: %lX C: %lX", C(A), C(B), C(C));
103 logf("D: %lX E: %lX F: %lX", C(D), C(E), C(F));
104 logf("divider: %lX", C(divider));
105
106 return 0;
107#undef C
108#undef S
109#undef D
110}
111
112static void map_pixels(int *x, int *y)
113{
114#define C(x) calibration_parameters.x
115 int _x = *x, _y = *y;
116
117 *x = (C(A) * _x + C(B) * _y + C(C)) / C(divider);
118 *y = (C(D) * _x + C(E) * _y + C(F)) / C(divider);
119#undef C
120}
121
122/* TODO: add jitter (and others) filter */
123int touchscreen_to_pixels(int x, int y, int *data)
124{
125 if(!touch_enabled)
126 return 0;
127 x &= 0xFFFF;
128 y &= 0xFFFF;
129
130 map_pixels(&x, &y);
131
132 if (current_mode == TOUCHSCREEN_BUTTON)
133 {
134 int column = 0, row = 0;
135
136 if (x < LCD_WIDTH/3 - BUTTON_MARGIN_X)
137 column = 0;
138 else if (x > LCD_WIDTH/3 + BUTTON_MARGIN_X &&
139 x < 2*LCD_WIDTH/3 - BUTTON_MARGIN_X)
140 column = 1;
141 else if (x > 2*LCD_WIDTH/3 + BUTTON_MARGIN_X)
142 column = 2;
143 else
144 return BUTTON_NONE;
145
146 if (y < LCD_HEIGHT/3 - BUTTON_MARGIN_Y)
147 row = 0;
148 else if (y > LCD_HEIGHT/3 + BUTTON_MARGIN_Y &&
149 y < 2*LCD_HEIGHT/3 - BUTTON_MARGIN_Y)
150 row = 1;
151 else if (y > 2*LCD_HEIGHT/3 + BUTTON_MARGIN_Y)
152 row = 2;
153 else
154 return BUTTON_NONE;
155
156 return touchscreen_buttons[row][column];
157 }
158 else
159 {
160 *data = (x << 16 | y);
161 return BUTTON_TOUCHSCREEN;
162 }
163}
164
165void touchscreen_set_mode(enum touchscreen_mode mode)
166{
167 current_mode = mode;
168}
169
170enum touchscreen_mode touchscreen_get_mode(void)
171{
172 return current_mode;
173}
174
175#ifndef HAS_BUTTON_HOLD
176void touchscreen_enable(bool en)
177{
178 if(en != touch_enabled)
179 {
180 touch_enabled = en;
181 touchscreen_enable_device(en);
182 }
183}
184
185bool touchscreen_is_enabled(void)
186{
187 return touch_enabled;
188}
189#endif
190
191#if ((CONFIG_PLATFORM & PLATFORM_ANDROID) == 0) || defined(DX50) || defined(DX90)
192/* android has an API for this */
193
194#define TOUCH_SLOP 16u
195#define REFERENCE_DPI 160
196
197int touchscreen_get_scroll_threshold(void)
198{
199#ifdef LCD_DPI
200 const int dpi = LCD_DPI;
201#else
202 const int dpi = lcd_get_dpi();
203#endif
204
205 /* Inspired by Android calculation
206 *
207 * float density = real dpi / reference dpi (=160)
208 * int threshold = (int) (density * TOUCH_SLOP + 0.5f);(original calculation)
209 *
210 * + 0.5f is for rounding, we use fixed point math to achieve that
211 */
212
213 int result = dpi * (TOUCH_SLOP<<1) / REFERENCE_DPI;
214 result += result & 1; /* round up if needed */
215 return result>>1;
216}
217
218#endif