00001
00039 #include <assert.h>
00040 #include <interrupt.h>
00041 #include <pmic.h>
00042 #include <intc.h>
00043
00044 #include <touch/touch.h>
00045 #include <cpu/touch/resistive/touch.h>
00046
00047 #ifdef CONFIG_SOFTIRQ
00048 # include <softirq.h>
00049 #endif
00050
00062
00063 enum touch_states {
00064 TOUCH_DISABLED,
00065 TOUCH_NOT_TOUCHED,
00066 TOUCH_READING_X,
00067 TOUCH_READING_Y,
00068 TOUCH_PROCESSING,
00069 TOUCH_TOUCHED,
00070 };
00071
00073 static enum touch_states touch_state;
00075 static struct touch_event touch_last_event;
00076
00078 static uint16_t touch_raw_x;
00080 static uint16_t touch_raw_y;
00081
00083 static struct touch_calibration_matrix touch_matrix;
00085 touch_event_handler_t touch_event_handler;
00086
00087 static void touch_priv_port_handler(void *int_data);
00088 static void touch_priv_adc_handler(void *int_data);
00089 static void touch_priv_process_samples(void *int_data);
00090
00095 INTC_DEFINE_HANDLER(CONFIG_TOUCH_PORT_IRQ_ID, touch_priv_port_handler,
00096 CONFIG_TOUCH_PORT_INTLVL);
00097 INTC_DEFINE_HANDLER(CONFIG_TOUCH_ADC_IRQ_ID, touch_priv_adc_handler,
00098 CONFIG_TOUCH_ADC_INTLVL);
00100
00111 void touch_init(void)
00112 {
00113
00114 touch_event_handler = NULL;
00115
00116 touch_priv_adc_init();
00117 touch_priv_port_init();
00118
00119 #ifdef CONFIG_SOFTIRQ
00120
00121 softirq_set_handler(SOFTIRQ_TOUCH_PROCESS, touch_priv_process_samples, NULL);
00122 #endif
00123
00124 touch_state = TOUCH_NOT_TOUCHED;
00125 touch_last_event.type = TOUCH_NO_EVENT;
00126
00127 touch_disable();
00128 }
00129
00130
00137 void touch_enable(void)
00138 {
00139 touch_state = TOUCH_NOT_TOUCHED;
00140 touch_last_event.type = TOUCH_NO_EVENT;
00141
00142 touch_priv_port_set_detection();
00143
00144
00145
00146
00147 touch_priv_adc_clear_int_flag();
00148 touch_priv_adc_enable_int();
00149
00150 touch_priv_port_clear_int_flag();
00151 touch_priv_port_enable_int();
00152 }
00153
00154
00160 void touch_disable(void)
00161 {
00162
00163
00164
00165 irqflags_t irqflags = cpu_irq_save();
00166
00167 touch_priv_port_disable_int();
00168 touch_priv_adc_disable_int();
00169
00170 cpu_irq_restore(irqflags);
00171 }
00172
00173
00179 void touch_get_event(struct touch_event *buffer)
00180 {
00181 assert(buffer != NULL);
00182
00183
00184 irqflags_t irqflags = cpu_irq_save();
00185
00186 *buffer = touch_last_event;
00187
00188 cpu_irq_restore(irqflags);
00189 }
00190
00191
00198 bool touch_is_touched(void)
00199 {
00200 return ((touch_last_event.type == TOUCH_PRESS)
00201 || (touch_last_event.type == TOUCH_MOVE));
00202 }
00203
00204
00210 void touch_set_event_handler(touch_event_handler_t handler)
00211 {
00212
00213 irqflags_t irqflags = cpu_irq_save();
00214
00215 touch_event_handler = handler;
00216
00217 cpu_irq_restore(irqflags);
00218 }
00219
00220
00226 touch_event_handler_t touch_get_event_handler(void)
00227 {
00228 return (touch_event_handler);
00229 }
00230
00231
00237 void touch_set_calibration_matrix(
00238 const struct touch_calibration_matrix *matrix)
00239 {
00240 assert(matrix != NULL);
00241
00242 touch_matrix = *matrix;
00243 }
00244
00250 void touch_get_calibration_matrix(struct touch_calibration_matrix *buffer)
00251 {
00252 assert(buffer != NULL);
00253
00254 *buffer = touch_matrix;
00255 }
00256
00257
00270 void touch_compute_calibration_matrix(
00271 const touch_calibration_points_t points,
00272 struct touch_calibration_matrix *matrix)
00273 {
00274 assert(points != NULL);
00275 assert(matrix != NULL);
00276
00277
00278 int32_t x_r1 = points[0].raw_x;
00279 int32_t y_r1 = points[0].raw_y;
00280
00281 int32_t x_r2 = points[1].raw_x;
00282 int32_t y_r2 = points[1].raw_y;
00283
00284 int32_t x_r3 = points[2].raw_x;
00285 int32_t y_r3 = points[2].raw_y;
00286
00287
00288 int32_t x_p1 = points[0].panel_x;
00289 int32_t y_p1 = points[0].panel_y;
00290
00291 int32_t x_p2 = points[1].panel_x;
00292 int32_t y_p2 = points[1].panel_y;
00293
00294 int32_t x_p3 = points[2].panel_x;
00295 int32_t y_p3 = points[2].panel_y;
00296
00297
00298 matrix->a = ((x_p1 - x_p3) * (y_r2 - y_r3))
00299 - ((x_p2 - x_p3) * (y_r1 - y_r3));
00300 matrix->b = ((x_r1 - x_r3) * (x_p2 - x_p3))
00301 - ((x_p1 - x_p3) * (x_r2 - x_r3));
00302 matrix->c = y_r1 * ((x_r3 * x_p2) - (x_r2 * x_p3))
00303 + y_r2 * ((x_r1 * x_p3) - (x_r3 * x_p1))
00304 + y_r3 * ((x_r2 * x_p1) - (x_r1 * x_p2));
00305
00306
00307 matrix->d = ((y_p1 - y_p3) * (y_r2 - y_r3))
00308 - ((y_p2 - y_p3) * (y_r1 - y_r3));
00309 matrix->e = ((x_r1 - x_r3) * (y_p2 - y_p3))
00310 - ((y_p1 - y_p3) * (x_r2 - x_r3));
00311 matrix->f = y_r1 * ((x_r3 * y_p2) - (x_r2 * y_p3))
00312 + y_r2 * ((x_r1 * y_p3) - (x_r3 * y_p1))
00313 + y_r3 * ((x_r2 * y_p1) - (x_r1 * y_p2));
00314
00315
00316 matrix->k = ((x_r1 - x_r3) * (y_r2 - y_r3))
00317 - ((x_r2 - x_r3) * (y_r1 - y_r3));
00318 }
00319
00330 void touch_priv_process_samples(void *int_data)
00331 {
00332
00333 bool send_event = false;
00334
00335
00336
00337
00338 int32_t temp_k = touch_matrix.k;
00339 if (temp_k == 0) {
00340 temp_k = 1;
00341 }
00342
00343
00344
00345
00346 touch_raw_x >>= CONFIG_TOUCH_OVERSAMPLING;
00347 touch_raw_y >>= CONFIG_TOUCH_OVERSAMPLING;
00348
00349
00350 int32_t panel_x = (touch_matrix.a * touch_raw_x)
00351 + (touch_matrix.b * touch_raw_y)
00352 + touch_matrix.c;
00353 panel_x /= temp_k;
00354
00355
00356 int32_t panel_y = (touch_matrix.d * touch_raw_x)
00357 + (touch_matrix.e * touch_raw_y)
00358 + touch_matrix.f;
00359 panel_y /= temp_k;
00360
00361
00362
00363
00364
00365 touch_priv_port_clear_int_flag();
00366
00367 if (touch_priv_port_is_int_flag_set() == false) {
00368 touch_state = TOUCH_NOT_TOUCHED;
00369
00370
00371
00372
00373 if ((touch_last_event.type == TOUCH_PRESS)
00374 || (touch_last_event.type == TOUCH_MOVE)) {
00375 touch_last_event.type = TOUCH_RELEASE;
00376
00377
00378 if (touch_event_handler != NULL) {
00379 touch_event_handler(&touch_last_event);
00380 }
00381 }
00382 } else {
00383 touch_state = TOUCH_TOUCHED;
00384
00385
00386
00387
00388 if ((touch_last_event.type == TOUCH_NO_EVENT)
00389 || (touch_last_event.type == TOUCH_RELEASE)) {
00390 touch_last_event.type = TOUCH_PRESS;
00391 send_event = true;
00392 }
00393
00394
00395
00396 else if ((touch_last_event.point.panel_x != panel_x)
00397 || (touch_last_event.point.panel_y != panel_y)) {
00398 touch_last_event.type = TOUCH_MOVE;
00399 send_event = true;
00400 }
00401
00402
00403
00404
00405 if (send_event) {
00406 touch_last_event.point.raw_x = touch_raw_x;
00407 touch_last_event.point.raw_y = touch_raw_y;
00408 touch_last_event.point.panel_x = panel_x;
00409 touch_last_event.point.panel_y = panel_y;
00410
00411 if (touch_event_handler != NULL) {
00412 touch_event_handler(&touch_last_event);
00413 }
00414 }
00415 }
00416
00417
00418 touch_priv_port_enable_int();
00419 }
00420
00421
00430 void touch_priv_port_handler(void *int_data)
00431 {
00432 assert((touch_state == TOUCH_NOT_TOUCHED)
00433 || (touch_state == TOUCH_TOUCHED));
00434
00435
00436 touch_priv_port_disable_int();
00437
00438
00439 touch_raw_x = 0;
00440 touch_raw_y = 0;
00441
00442
00443 touch_state = TOUCH_READING_X;
00444 touch_priv_port_set_gradient_x();
00445 touch_priv_adc_set_surface_x();
00446
00447 touch_priv_adc_start();
00448 }
00449
00450
00460 void touch_priv_adc_handler(void *int_data)
00461 {
00462 static uint8_t sample_count = 0;
00463
00464 switch (touch_state) {
00465 case TOUCH_READING_X:
00466
00467 touch_raw_x += touch_priv_adc_get_x();
00468
00469
00470
00471 ++sample_count;
00472
00473 if (sample_count < (1 << CONFIG_TOUCH_OVERSAMPLING)) {
00474 touch_priv_adc_start();
00475 } else {
00476 sample_count = 0;
00477
00478 touch_state = TOUCH_READING_Y;
00479 touch_priv_port_set_gradient_y();
00480 touch_priv_adc_set_surface_y();
00481 touch_priv_adc_start();
00482 }
00483 break;
00484
00485
00486 case TOUCH_READING_Y:
00487
00488 touch_raw_y += touch_priv_adc_get_y();
00489
00490
00491
00492 ++sample_count;
00493
00494 if (sample_count < (1 << CONFIG_TOUCH_OVERSAMPLING)) {
00495 touch_priv_adc_start();
00496 } else {
00497 sample_count = 0;
00498
00499 touch_state = TOUCH_PROCESSING;
00500
00501
00502 touch_priv_port_set_detection();
00503 #ifdef CONFIG_SOFTIRQ
00504 softirq_raise(SOFTIRQ_TOUCH_PROCESS);
00505 #else
00506 touch_priv_process_samples(NULL);
00507 #endif
00508 }
00509 break;
00510
00511 default:
00512 assert(0);
00513 break;
00514 }
00515 }
00516
00518