summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-11-20 19:05:16 +0000
committerAidan MacDonald <amachronic@protonmail.com>2021-11-24 18:49:03 -0500
commit44acbc66291da6a8ade8571b73a10e34341a622b (patch)
tree226f9d9f971756f481455da082443f700bcfc786
parentb39acee3abd199d80b84c68ebfa7301b7e7a957e (diff)
downloadrockbox-44acbc66291da6a8ade8571b73a10e34341a622b.tar.gz
rockbox-44acbc66291da6a8ade8571b73a10e34341a622b.zip
Shanling Q1: enable multi-touch reporting
The FT6x06 driver used for the Shanling Q1's touchscreen has been extended to report more than one touch point. It can also return the gesture detected by the controller, but this doesn't seem to report anything useful on the Q1. Multi-touch is only useful in 3x3 grid mode since the Rockbox button API cannot report more than one touch point. The FiiO M3K uses the same driver so it's been updated to the multi-touch API, but functionality is unchanged. Change-Id: I4de42f44808d6eb902e3da212d8f936b7a5042c7
-rw-r--r--firmware/drivers/ft6x06.c64
-rw-r--r--firmware/export/config/fiiom3k.h1
-rw-r--r--firmware/export/config/shanlingq1.h1
-rw-r--r--firmware/export/ft6x06.h23
-rw-r--r--firmware/target/mips/ingenic_x1000/debug-x1000.c6
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c5
-rw-r--r--firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c83
7 files changed, 139 insertions, 44 deletions
diff --git a/firmware/drivers/ft6x06.c b/firmware/drivers/ft6x06.c
index 538ca10480..c605ee0944 100644
--- a/firmware/drivers/ft6x06.c
+++ b/firmware/drivers/ft6x06.c
@@ -24,6 +24,16 @@
24#include "i2c-async.h" 24#include "i2c-async.h"
25#include <string.h> 25#include <string.h>
26 26
27#define BYTES_PER_POINT 6
28
29#ifdef FT6x06_SWAP_AXES
30# define POS_X pos_y
31# define POS_Y pos_x
32#else
33# define POS_X pos_x
34# define POS_Y pos_y
35#endif
36
27struct ft6x06_driver { 37struct ft6x06_driver {
28 /* i2c bus data */ 38 /* i2c bus data */
29 int i2c_cookie; 39 int i2c_cookie;
@@ -33,39 +43,42 @@ struct ft6x06_driver {
33 ft6x06_event_cb event_cb; 43 ft6x06_event_cb event_cb;
34 44
35 /* buffer for I2C transfers */ 45 /* buffer for I2C transfers */
36 uint8_t raw_data[6]; 46 uint8_t raw_data[1 + 2 + BYTES_PER_POINT * FT6x06_NUM_POINTS];
37}; 47};
38 48
39static struct ft6x06_driver ft_drv; 49static struct ft6x06_driver ft_drv;
40struct ft6x06_state ft6x06_state; 50struct ft6x06_state ft6x06_state;
41 51
52static inline void ft6x06_convert_point(const uint8_t* raw,
53 struct ft6x06_point* pt)
54{
55 pt->event = (raw[0] >> 6) & 0x3;
56 pt->touch_id = (raw[2] >> 4) & 0xf;
57 pt->POS_X = ((raw[0] & 0xf) << 8) | raw[1];
58 pt->POS_Y = ((raw[2] & 0xf) << 8) | raw[3];
59 pt->weight = raw[4];
60 pt->area = (raw[5] >> 4) & 0xf;
61}
62
42static void ft6x06_i2c_callback(int status, i2c_descriptor* desc) 63static void ft6x06_i2c_callback(int status, i2c_descriptor* desc)
43{ 64{
44 (void)desc; 65 (void)desc;
45 if(status != I2C_STATUS_OK) 66 if(status != I2C_STATUS_OK)
46 return; 67 return;
47 68
48 int evt = ft_drv.raw_data[1] >> 6; 69 ft6x06_state.gesture = ft_drv.raw_data[1];
49 int tx = ft_drv.raw_data[2] | ((ft_drv.raw_data[1] & 0xf) << 8); 70 ft6x06_state.nr_points = ft_drv.raw_data[2] & 0xf;
50 int ty = ft_drv.raw_data[4] | ((ft_drv.raw_data[3] & 0xf) << 8); 71 for(int i = 0; i < FT6x06_NUM_POINTS; ++i) {
51 72 ft6x06_convert_point(&ft_drv.raw_data[3 + i * BYTES_PER_POINT],
52 ft6x06_state.event = evt; 73 &ft6x06_state.points[i]);
53#ifdef FT6x06_SWAP_AXES 74 }
54 ft6x06_state.pos_x = ty;
55 ft6x06_state.pos_y = tx;
56#else
57 ft6x06_state.pos_x = tx;
58 ft6x06_state.pos_y = ty;
59#endif
60 75
61 ft_drv.event_cb(evt, ft6x06_state.pos_x, ft6x06_state.pos_y); 76 ft_drv.event_cb(&ft6x06_state);
62} 77}
63 78
64static void ft6x06_dummy_event_cb(int evt, int tx, int ty) 79static void ft6x06_dummy_event_cb(struct ft6x06_state* state)
65{ 80{
66 (void)evt; 81 (void)state;
67 (void)tx;
68 (void)ty;
69} 82}
70 83
71void ft6x06_init(void) 84void ft6x06_init(void)
@@ -74,9 +87,10 @@ void ft6x06_init(void)
74 memset(&ft_drv, 0, sizeof(ft_drv)); 87 memset(&ft_drv, 0, sizeof(ft_drv));
75 ft_drv.event_cb = ft6x06_dummy_event_cb; 88 ft_drv.event_cb = ft6x06_dummy_event_cb;
76 89
77 ft6x06_state.event = FT6x06_EVT_NONE; 90 memset(&ft6x06_state, 0, sizeof(struct ft6x06_state));
78 ft6x06_state.pos_x = 0; 91 ft6x06_state.gesture = -1;
79 ft6x06_state.pos_y = 0; 92 for(int i = 0; i < FT6x06_NUM_POINTS; ++i)
93 ft6x06_state.points[i].event = FT6x06_EVT_NONE;
80 94
81 /* Reserve bus management cookie */ 95 /* Reserve bus management cookie */
82 ft_drv.i2c_cookie = i2c_async_reserve_cookies(FT6x06_BUS, 1); 96 ft_drv.i2c_cookie = i2c_async_reserve_cookies(FT6x06_BUS, 1);
@@ -85,16 +99,16 @@ void ft6x06_init(void)
85 ft_drv.i2c_desc.slave_addr = FT6x06_ADDR; 99 ft_drv.i2c_desc.slave_addr = FT6x06_ADDR;
86 ft_drv.i2c_desc.bus_cond = I2C_START | I2C_STOP; 100 ft_drv.i2c_desc.bus_cond = I2C_START | I2C_STOP;
87 ft_drv.i2c_desc.tran_mode = I2C_READ; 101 ft_drv.i2c_desc.tran_mode = I2C_READ;
88 ft_drv.i2c_desc.buffer[0] = &ft_drv.raw_data[5]; 102 ft_drv.i2c_desc.buffer[0] = &ft_drv.raw_data[0];
89 ft_drv.i2c_desc.count[0] = 1; 103 ft_drv.i2c_desc.count[0] = 1;
90 ft_drv.i2c_desc.buffer[1] = &ft_drv.raw_data[0]; 104 ft_drv.i2c_desc.buffer[1] = &ft_drv.raw_data[1];
91 ft_drv.i2c_desc.count[1] = 5; 105 ft_drv.i2c_desc.count[1] = sizeof(ft_drv.raw_data) - 1;
92 ft_drv.i2c_desc.callback = ft6x06_i2c_callback; 106 ft_drv.i2c_desc.callback = ft6x06_i2c_callback;
93 ft_drv.i2c_desc.arg = 0; 107 ft_drv.i2c_desc.arg = 0;
94 ft_drv.i2c_desc.next = NULL; 108 ft_drv.i2c_desc.next = NULL;
95 109
96 /* Set I2C register address */ 110 /* Set I2C register address */
97 ft_drv.raw_data[5] = 0x02; 111 ft_drv.raw_data[0] = 0x01;
98} 112}
99 113
100void ft6x06_set_event_cb(ft6x06_event_cb cb) 114void ft6x06_set_event_cb(ft6x06_event_cb cb)
diff --git a/firmware/export/config/fiiom3k.h b/firmware/export/config/fiiom3k.h
index 29395bd433..61b6123a67 100644
--- a/firmware/export/config/fiiom3k.h
+++ b/firmware/export/config/fiiom3k.h
@@ -24,6 +24,7 @@
24#define HAVE_I2C_ASYNC 24#define HAVE_I2C_ASYNC
25#define HAVE_FT6x06 25#define HAVE_FT6x06
26#define FT6x06_SWAP_AXES 26#define FT6x06_SWAP_AXES
27#define FT6x06_NUM_POINTS 1
27 28
28/* Buffer for plugins and codecs. */ 29/* Buffer for plugins and codecs. */
29#define PLUGIN_BUFFER_SIZE 0x200000 /* 2 MiB */ 30#define PLUGIN_BUFFER_SIZE 0x200000 /* 2 MiB */
diff --git a/firmware/export/config/shanlingq1.h b/firmware/export/config/shanlingq1.h
index 1f1ee79ca7..16ce888958 100644
--- a/firmware/export/config/shanlingq1.h
+++ b/firmware/export/config/shanlingq1.h
@@ -59,6 +59,7 @@
59#define HAVE_TOUCHSCREEN 59#define HAVE_TOUCHSCREEN
60#define HAVE_BUTTON_DATA 60#define HAVE_BUTTON_DATA
61#define HAVE_FT6x06 61#define HAVE_FT6x06
62#define FT6x06_NUM_POINTS 5
62#define HAVE_HEADPHONE_DETECTION 63#define HAVE_HEADPHONE_DETECTION
63 64
64/* Storage defines */ 65/* Storage defines */
diff --git a/firmware/export/ft6x06.h b/firmware/export/ft6x06.h
index de1fdd0979..6596f89272 100644
--- a/firmware/export/ft6x06.h
+++ b/firmware/export/ft6x06.h
@@ -25,23 +25,32 @@
25#include "config.h" 25#include "config.h"
26#include <stdbool.h> 26#include <stdbool.h>
27 27
28typedef void(*ft6x06_event_cb)(int, int, int); 28enum ft6x06_event {
29 FT6x06_EVT_NONE = -1,
30 FT6x06_EVT_PRESS = 0,
31 FT6x06_EVT_RELEASE = 1,
32 FT6x06_EVT_CONTACT = 2,
33};
29 34
30struct ft6x06_state { 35struct ft6x06_point {
31 int event; 36 int event;
37 int touch_id;
32 int pos_x; 38 int pos_x;
33 int pos_y; 39 int pos_y;
40 int weight;
41 int area;
34}; 42};
35 43
36enum ft6x06_event { 44struct ft6x06_state {
37 FT6x06_EVT_NONE = -1, 45 int gesture;
38 FT6x06_EVT_PRESS = 0, 46 int nr_points;
39 FT6x06_EVT_RELEASE = 1, 47 struct ft6x06_point points[FT6x06_NUM_POINTS];
40 FT6x06_EVT_CONTACT = 2,
41}; 48};
42 49
43extern struct ft6x06_state ft6x06_state; 50extern struct ft6x06_state ft6x06_state;
44 51
52typedef void(*ft6x06_event_cb)(struct ft6x06_state* state);
53
45void ft6x06_init(void); 54void ft6x06_init(void);
46void ft6x06_set_event_cb(ft6x06_event_cb fn); 55void ft6x06_set_event_cb(ft6x06_event_cb fn);
47void ft6x06_enable(bool en); 56void ft6x06_enable(bool en);
diff --git a/firmware/target/mips/ingenic_x1000/debug-x1000.c b/firmware/target/mips/ingenic_x1000/debug-x1000.c
index 1965b0b74e..98b8f95fb5 100644
--- a/firmware/target/mips/ingenic_x1000/debug-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/debug-x1000.c
@@ -149,6 +149,9 @@ static bool dbg_cpuidle(void)
149#ifdef FIIO_M3K 149#ifdef FIIO_M3K
150extern bool dbg_fiiom3k_touchpad(void); 150extern bool dbg_fiiom3k_touchpad(void);
151#endif 151#endif
152#ifdef SHANLING_Q1
153extern bool dbg_shanlingq1_touchscreen(void);
154#endif
152#ifdef HAVE_AXP_PMU 155#ifdef HAVE_AXP_PMU
153extern bool axp_debug_menu(void); 156extern bool axp_debug_menu(void);
154#endif 157#endif
@@ -170,6 +173,9 @@ static const struct {
170#ifdef FIIO_M3K 173#ifdef FIIO_M3K
171 {"Touchpad", &dbg_fiiom3k_touchpad}, 174 {"Touchpad", &dbg_fiiom3k_touchpad},
172#endif 175#endif
176#ifdef SHANLING_Q1
177 {"Touchscreen", &dbg_shanlingq1_touchscreen},
178#endif
173#ifdef HAVE_AXP_PMU 179#ifdef HAVE_AXP_PMU
174 {"Power stats", &axp_debug_menu}, 180 {"Power stats", &axp_debug_menu},
175#endif 181#endif
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
index 04e3102d42..24daf2ef69 100644
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
@@ -318,7 +318,7 @@ static void ft_step_state(uint32_t t, int evt, int tx, int ty)
318 } 318 }
319} 319}
320 320
321static void ft_event_cb(int evt, int tx, int ty) 321static void ft_event_cb(struct ft6x06_state* state)
322{ 322{
323 /* TODO: convert the touch positions to linear positions. 323 /* TODO: convert the touch positions to linear positions.
324 * 324 *
@@ -327,7 +327,8 @@ static void ft_event_cb(int evt, int tx, int ty)
327 * the middle of the touchpad than on the edges, so scrolling feels slow 327 * the middle of the touchpad than on the edges, so scrolling feels slow
328 * in the middle and faster near the edge. 328 * in the middle and faster near the edge.
329 */ 329 */
330 ft_step_state(__ost_read32(), evt, tx, ty); 330 struct ft6x06_point* pt = &state->points[0];
331 ft_step_state(__ost_read32(), pt->event, pt->pos_x, pt->pos_y);
331} 332}
332 333
333static void ft_init(void) 334static void ft_init(void)
diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
index 27c49a7bd7..13b0cdd078 100644
--- a/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
+++ b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
@@ -32,6 +32,11 @@
32#include "i2c-x1000.h" 32#include "i2c-x1000.h"
33#include <stdbool.h> 33#include <stdbool.h>
34 34
35#ifndef BOOTLOADER
36# include "lcd.h"
37# include "font.h"
38#endif
39
35/* Volume wheel rotation */ 40/* Volume wheel rotation */
36static volatile int wheel_pos = 0; 41static volatile int wheel_pos = 0;
37 42
@@ -109,6 +114,7 @@ void button_init_device(void)
109 114
110int button_read_device(int* data) 115int button_read_device(int* data)
111{ 116{
117 const struct ft6x06_point* point;
112 int r = 0; 118 int r = 0;
113 119
114 /* Read GPIO buttons, these are all active low */ 120 /* Read GPIO buttons, these are all active low */
@@ -138,16 +144,22 @@ int button_read_device(int* data)
138 reset_poweroff_timer(); 144 reset_poweroff_timer();
139 } 145 }
140 146
141 /* Handle touchscreen 147 if(touchscreen_get_mode() == TOUCHSCREEN_POINT) {
142 * 148 /* Pointing mode can't use multitouch since we can only pass
143 * TODO: Support 2-point multitouch (useful for 3x3 grid mode) 149 * along coordinates for one touch event at a time */
144 * TODO: Support simple gestures by converting them to fake buttons 150 point = &ft6x06_state.points[0];
145 */ 151 int t = touchscreen_to_pixels(point->pos_x, point->pos_y, data);
146 int t = touchscreen_to_pixels(ft6x06_state.pos_x, ft6x06_state.pos_y, data); 152 if(point->event == FT6x06_EVT_PRESS ||
147 if(ft6x06_state.event == FT6x06_EVT_PRESS || 153 point->event == FT6x06_EVT_CONTACT)
148 ft6x06_state.event == FT6x06_EVT_CONTACT) { 154 r |= t;
149 /* Only set the button bit if the screen is being touched. */ 155 } else {
150 r |= t; 156 /* 3x3 mode can have simultaneous 'button' presses via multitouch */
157 for(int i = 0; i < ft6x06_state.nr_points; ++i) {
158 point = &ft6x06_state.points[i];
159 if(point->event == FT6x06_EVT_PRESS ||
160 point->event == FT6x06_EVT_CONTACT)
161 r |= touchscreen_to_pixels(point->pos_x, point->pos_y, NULL);
162 }
151 } 163 }
152 164
153 return r; 165 return r;
@@ -193,3 +205,54 @@ void GPIOD03(void)
193 handle_wheel_irq(); 205 handle_wheel_irq();
194 gpio_flip_edge_irq(GPIO_WHEEL2); 206 gpio_flip_edge_irq(GPIO_WHEEL2);
195} 207}
208
209#ifndef BOOTLOADER
210static int getbtn(void)
211{
212 int btn;
213 do {
214 btn = button_get_w_tmo(1);
215 } while(btn & (BUTTON_REL|BUTTON_REPEAT));
216 return btn;
217}
218
219bool dbg_shanlingq1_touchscreen(void)
220{
221 /* definition of box used to represent the touchpad */
222 const int pad_w = LCD_WIDTH;
223 const int pad_h = LCD_HEIGHT;
224 const int box_h = pad_h - SYSFONT_HEIGHT*5;
225 const int box_w = pad_w * box_h / pad_h;
226 const int box_x = (LCD_WIDTH - box_w) / 2;
227 const int box_y = SYSFONT_HEIGHT * 9 / 2;
228
229 bool draw_border = true;
230
231 do {
232 int line = 0;
233 lcd_clear_display();
234 lcd_putsf(0, line++, "nr_points: %d gesture: %d",
235 ft6x06_state.nr_points, ft6x06_state.gesture);
236
237 /* draw touchpad box borders */
238 if(draw_border)
239 lcd_drawrect(box_x, box_y, box_w, box_h);
240
241 for(int i = 0; i < ft6x06_state.nr_points; ++i) {
242 const struct ft6x06_point* point = &ft6x06_state.points[i];
243 lcd_putsf(0, line++, "pt%d id:%d pos: %d,%d wgt: %d area:%d",
244 i, point->touch_id, point->pos_x, point->pos_y,
245 point->weight, point->area);
246
247 /* draw crosshair */
248 int tx = box_x + point->pos_x * box_w / pad_w;
249 int ty = box_y + point->pos_y * box_h / pad_h;
250 lcd_hline(tx-2, tx+2, ty);
251 lcd_vline(tx, ty-2, ty+2);
252 }
253
254 lcd_update();
255 } while(getbtn() != BUTTON_POWER);
256 return false;
257}
258#endif