2 * tslib/plugins/cy8mrln-palmpre.c
4 * Copyright (C) 2010 Frederik Sdun <frederik.sdun@googlemail.com>
5 * Thomas Zimmermann <ml@vdm-design.de>
8 * This file is placed under the LGPL. Please see the file
9 * COPYING for more details.
12 * Pluging for the cy8mrln touchscreen with the Firmware used on the Palm Pre
17 #include <linux/spi/cy8mrln.h>
22 #include <sys/ioctl.h>
24 #include <sys/types.h>
28 #include "tslib-private.h"
29 #include "tslib-filter.h"
32 #define SCREEN_WIDTH 319
33 #define SCREEN_HEIGHT 527
37 struct cy8mrln_palmpre_input
40 uint16_t field[H_FIELDS * V_FIELDS];
41 uint16_t ffff; //seperator? always ff
42 uint8_t seq_nr1; //incremented if seq_nr0 = scanrate
43 uint16_t seq_nr2; //incremeted if seq_nr1 = 255
45 uint8_t seq_nr0; //incremented. 0- scanrate
47 }__attribute__((packed));
49 struct tslib_cy8mrln_palmpre
51 struct tslib_module_info module;
52 uint16_t nulls[7][11];
55 static int scanrate = 60;
56 static int verbose = 1;
57 static int wot_threshold = 22;
58 static int sleepmode = CY8MRLN_ON_STATE;
59 static int wot_scanrate = WOT_SCANRATE_512HZ;
60 static int timestamp_mode = 1;
63 cy8mrln_palmpre_set_scanrate(struct tsdev* dev, int rate)
65 if(ioctl(dev->fd,CY8MRLN_IOCTL_SET_SCANRATE,&rate) < 0)
72 cy8mrln_palmpre_set_verbose(struct tsdev* dev, int v)
74 if(ioctl(dev->fd,CY8MRLN_IOCTL_SET_VERBOSE_MODE,&v) < 0)
81 cy8mrln_palmpre_set_sleepmode(struct tsdev* dev, int mode)
83 if(ioctl(dev->fd,CY8MRLN_IOCTL_SET_SLEEPMODE,&mode) < 0)
90 cy8mrln_palmpre_set_wot_scanrate(struct tsdev* dev, int rate)
92 if(ioctl(dev->fd,CY8MRLN_IOCTL_SET_WOT_SCANRATE,&rate) < 0)
99 cy8mrln_palmpre_set_wot_threshold(struct tsdev* dev, int v)
101 if(v < WOT_THRESHOLD_MIN || v > WOT_THRESHOLD_MAX)
103 if(ioctl(dev->fd,CY8MRLN_IOCTL_SET_WOT_THRESHOLD,&v) < 0)
110 cy8mrln_palmpre_set_timestamp_mode(struct tsdev* dev, int v)
113 if(ioctl(dev->fd,CY8MRLN_IOCTL_SET_TIMESTAMP_MODE,&v) < 0)
120 parse_scanrate(struct tslib_module_info *info, char *str, void *data)
123 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
124 unsigned long rate = strtoul(str, NULL, 0);
126 if(rate == ULONG_MAX && errno == ERANGE)
129 return cy8mrln_palmpre_set_scanrate(i->module.dev, scanrate);
133 parse_verbose(struct tslib_module_info *info, char *str, void *data)
136 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
137 unsigned long v = strtoul(str, NULL, 0);
139 if(v == ULONG_MAX && errno == ERANGE)
142 return cy8mrln_palmpre_set_verbose(i->module.dev, scanrate);
146 parse_wot_scanrate(struct tslib_module_info *info, char *str, void *data)
149 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
150 unsigned long rate = strtoul(str, NULL, 0);
152 return cy8mrln_palmpre_set_wot_scanrate(i->module.dev, rate);
156 parse_wot_threshold(struct tslib_module_info *info, char *str, void *data)
159 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
160 unsigned long threshold = strtoul(str, NULL, 0);
162 return cy8mrln_palmpre_set_wot_threshold(i->module.dev, threshold);
166 parse_sleepmode(struct tslib_module_info *info, char *str, void *data)
169 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
170 unsigned long sleep = strtoul(str, NULL, 0);
172 return cy8mrln_palmpre_set_sleepmode(i->module.dev, sleep);
177 parse_timestamp_mode(struct tslib_module_info *info, char *str, void *data)
180 struct tslib_cy8mrln_palmpre *i = (struct tslib_cy8mrln_palmpre*) info;
181 unsigned long sleep = strtoul(str, NULL, 0);
183 return cy8mrln_palmpre_set_sleepmode(i->module.dev, sleep);
187 static const struct tslib_vars raw_vars[] =
189 { "scanrate", NULL, parse_scanrate},
190 { "verbose", NULL, parse_verbose},
191 { "wot_scanrate", NULL, parse_wot_scanrate},
192 { "wot_threshold", NULL, parse_wot_threshold},
193 { "sleepmode", NULL, parse_sleepmode},
194 { "timestamp_mode", NULL, parse_timestamp_mode}
197 #define NR_VARS (sizeof(raw_vars) / sizeof(raw_vars[0]))
200 interpolate(uint16_t field[H_FIELDS * V_FIELDS], int i, struct ts_sample *out) {
201 float f11, f12, f13, f21, f22, f23, f31, f32, f33;
202 int x = SCREEN_WIDTH / H_FIELDS * (H_FIELDS - (i % H_FIELDS));
203 int y = SCREEN_HEIGHT / (V_FIELDS - 1) * (i / H_FIELDS);
204 static int dx = SCREEN_WIDTH / H_FIELDS;
205 static int dy = SCREEN_HEIGHT / V_FIELDS;
207 /* caluculate corrections for top, bottom, left and right fields */
208 f12 = (i < (H_FIELDS + 1)) ? 0.0 : 0.5 * field[i - H_FIELDS] / field[i];
209 f32 = (i > (H_FIELDS * (V_FIELDS - 2)))
210 ? 0.0 : 0.5 * field[i + H_FIELDS] / field[i];
211 f21 = (i % H_FIELDS == (H_FIELDS - 1))
212 ? 0.0 : 0.5 * field[i + 1] / field[i];
213 f23 = (i % H_FIELDS == 0) ? 0.0 : 0.5 * field[i - 1] / field[i];
216 correct values for the edges, shift the mesuarment point by half a
217 field diminsion to the outside
224 } else if (i == (H_FIELDS - 1)) {
229 } else if (i % H_FIELDS == (H_FIELDS - 1)) {
232 } else if (i % H_FIELDS == 0) {
235 } else if (i < H_FIELDS) {
238 } else if (i == (H_FIELDS * (V_FIELDS - 2))) {
243 } else if (i == (H_FIELDS * (V_FIELDS - 1) - 1)) {
248 } else if (i > (H_FIELDS * (V_FIELDS - 2))) {
253 /* caluclate corrections for the corners */
255 f11 = (i % H_FIELDS == (H_FIELDS - 1) || i < (H_FIELDS + 1))
256 ? 0.0 : 0.4 * field[i - H_FIELDS + 1] / field[i];
257 f13 = (i % H_FIELDS == 0 || i < (H_FIELDS + 1))
258 ? 0.0 : 0.4 * field[i - H_FIELDS - 1] / field[i];
259 f31 = (i % H_FIELDS == (H_FIELDS - 1)
260 || i > (H_FIELDS * (V_FIELDS - 1) - 1))
261 ? 0.0 : 0.4 * field[i + H_FIELDS + 1] / field[i];
262 f33 = (i % H_FIELDS == 0 || i > (H_FIELDS * (V_FIELDS - 1) - 1))
263 ? 0.0 : 0.4 * field[i + H_FIELDS - 1] / field[i];
266 out->x = x // + (f13 + f33 - f11 - f31) * dx /* use corners too?*/
268 // + (f21 == 0.0) ? ((f23 * 2 + (dx / 2)) * dx) : (f23 * dx)
269 // - (f23 == 0.0) ? ((f21 * 2 + (dx / 2)) * dx) : (f21 * dx)
271 out->y = y // + (f31 + f33 - f11 - f13) * dy /* use corners too?*/
272 + (f32 - f12) * dy + (dy / 2);
274 out->pressure = field[i];
276 printf("RAW--------------------------->f21: %f (%d), f23: %f (%d), f12: %f (%d), f32: %f (%d), ",
277 f21, field[i - 1], f23, field[i + 1], f12,
278 field[i - H_FIELDS], f32, field[i + H_FIELDS]);
283 cy8mrln_palmpre_read(struct tslib_module_info *info, struct ts_sample *samp, int nr)
285 struct tsdev *ts = info->dev;
286 struct cy8mrln_palmpre_input *cy8mrln_evt;
288 cy8mrln_evt = alloca(sizeof(*cy8mrln_evt) * nr);
289 ret = read(ts->fd, cy8mrln_evt, sizeof(*cy8mrln_evt) * nr);
291 int nr = ret / sizeof(*cy8mrln_evt);
294 while(ret >= (int)sizeof(*cy8mrln_evt)) {
295 for (i = 0; i < (H_FIELDS * V_FIELDS); i++) {
296 /* auto calibrate zero values */
297 if (cy8mrln_evt->field[i] > info->nulls[i])
298 info->nulls[i] = cy8mrln_evt->field[i];
300 tmp_value = abs(info->nulls[i] - cy8mrln_evt->field[i]);
302 /* check for the maximum value */
303 if (tmp_value > max_value) {
304 max_value = tmp_value;
308 cy8mrln_evt->field[i] = tmp_value;
310 /* only caluclate events that are not noise */
311 if (max_value > NOISE) {
312 interpolate(cy8mrln_evt->field, max_index, samp);
314 fprintf(stderr,"RAW---------------------------> %d %d %d\n",
315 samp->x, samp->y, samp->pressure);
319 gettimeofday(&samp->tv,NULL);
322 ret -= sizeof(*cy8mrln_evt);
333 cy8mrln_palmpre_fini(struct tslib_module_info *inf)
339 static const struct tslib_ops cy8mrln_palmpre_ops =
341 .read = cy8mrln_palmpre_read,
342 .fini = cy8mrln_palmpre_fini,
345 TSAPI struct tslib_module_info *cy8mrln_palmpre_mod_init(struct tsdev *dev, const char *params)
347 struct tslib_cy8mrln_palmpre *info;
348 struct cy8mrln_palmpre_input input;
350 info = malloc(sizeof(struct tslib_cy8mrln_palmpre));
353 info->module.ops = &cy8mrln_palmpre_ops;
355 cy8mrln_palmpre_set_verbose(dev,verbose);
356 cy8mrln_palmpre_set_scanrate(dev,scanrate);
357 cy8mrln_palmpre_set_timestamp_mode(dev,timestamp_mode);
358 cy8mrln_palmpre_set_sleepmode(dev,sleepmode);
359 cy8mrln_palmpre_set_wot_scanrate(dev,wot_scanrate);
360 cy8mrln_palmpre_set_wot_threshold(dev,wot_threshold);
362 if (tslib_parse_vars(&info->module, raw_vars, NR_VARS, params)) {
367 read(dev->fd, &input, sizeof(input));
369 memcpy(info->nulls, input.values, 7*11*sizeof(uint16_t));
371 return &(info->module);
373 #ifndef TSLIB_STATIC_CY8MRLN_MODULE
374 TSLIB_MODULE_INIT(cy8mrln_palmpre_mod_init);