/** * handle a group of points of a particular type, with potentially * multiple sets delimited by triplicate points. */ void process_multi_group(point_line_t **plta, int count, double tolerance) { int i; point_line_t *plt = NULL; int points = 0; point_line_t *pltg = NULL; int marker = 0; point_line_t *prev_plt = NULL; if (!plta) { printf("WARNING: Unexpected call to process_multi_group with a NULL point array\n"); return; } #if PRINT_ARRAY static int print_counter = 0; if (print_counter == 0) { bu_log("--- BEFORE ---\n"); print_array(plta, count); } #endif /* remove points marked as bogus, 5-identical points in succession */ count = delete_points(plta, count, tolerance); #if PRINT_ARRAY if (print_counter == 0) { print_counter++; bu_log("--- AFTER ---\n"); print_array(plta, count); } #endif /* isolate groups and pass them on to the group processing routine */ for (i = 0; i < count; i++) { plt = &(*plta)[i]; if (!plt || !plt->type) { printf("WARNING: Unexpected NULL encountered while processing a point array (%d of %d)\n", i, count); continue; } /* if this is the first point of a group, allocate and initialize */ if (!prev_plt) { prev_plt = &(*plta)[i]; pltg = (point_line_t *) bu_malloc(sizeof(point_line_t), "begin point_line_t subgroup"); COPY_POINT_LINE_T(*pltg, *prev_plt); marker = 0; continue; } if (marker) { /* gobble up repeats points used as a marker, average new point */ if (DIST_PT_PT(prev_plt->val, plt->val) < tolerance) { prev_plt->val[X] = (prev_plt->val[X] + plt->val[X]) / 2.0; prev_plt->val[Y] = (prev_plt->val[Y] + plt->val[Y]) / 2.0; prev_plt->val[Z] = (prev_plt->val[Z] + plt->val[Z]) / 2.0; INITIALIZE_POINT_LINE_T(*plt); /* poof */ continue; } if (process_group(&pltg, points+1)) { bu_free((genptr_t)pltg, "end subgroup: point_line_t"); pltg = NULL; prev_plt = NULL; points = 0; marker = 0; --i; continue; } else { /* process_group is allowed to return non-zero if there are not enough points -- they get returned to the stack for processing again */ printf("warning, process_group returned 0\n"); } marker = 0; continue; } /* FIXME: shouldn't just average to the average, later points get weighted too much.. */ if (DIST_PT_PT(prev_plt->val, plt->val) < tolerance) { /* printf("%d: CLOSE DISTANCE of %f\n", plt->index, DIST_PT_PT(prev_plt->val, plt->val));*/ marker = points; (pltg[marker]).val[X] = (prev_plt->val[X] + plt->val[X]) / 2.0; (pltg[marker]).val[Y] = (prev_plt->val[Y] + plt->val[Y]) / 2.0; (pltg[marker]).val[Z] = (prev_plt->val[Z] + plt->val[Z]) / 2.0; continue; } if (!pltg) { printf("Blah! Error. Group array is null. Shouldn't be here!\n"); return; } pltg = (point_line_t *) bu_realloc(pltg, sizeof(point_line_t) * (points + 2), "add subgroup: point_line_t"); points++; COPY_POINT_LINE_T(pltg[points], *plt); prev_plt = plt; } printf("i: %d, count: %d", i, count); /* make sure we're not at the end of a list (i.e. no end marker, but we're at the end of this group */ if (points > 0) { if (process_group(&pltg, points+1)) { bu_free((genptr_t)pltg, "end point_line_t subgroup"); pltg = NULL; prev_plt = NULL; points = 0; marker = 0; } else { /* this one shouldn't return zero, we're at the end of a multiblock */ printf("ERROR, process_group returned 0\n"); } } }
/******************************************************* 功能: 触摸屏工作函数 由中断触发,接受1组坐标数据,校验后再分析输出 参数: ts: client私有数据结构体 return: 执行结果码,0表示正常执行 ********************************************************/ static void goodix_ts_work_func(struct work_struct *work) { static uint8_t finger_bit=0; //last time fingers' state struct point_data * p = NULL; uint8_t read_position = 0; uint8_t point_data[READ_BYTES_NUM]={ 0 }; uint8_t finger=0; //record which finger is changed uint8_t check_sum = 0; int ret = -1; int count = 0; struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work); if (ts->use_shutdown && gpio_get_value(ts->gpio_shutdown)) goto NO_ACTION; //The data is invalid. //if i2c-transfer is failed, let it restart less than 10 times. FOR DEBUG. /* if( ts->retry > 9) { if(!ts->use_irq && (ts->timer.state != HRTIMER_STATE_INACTIVE)) hrtimer_cancel(&ts->timer); dev_info(&(ts->client->dev), "Because of transfer error, %s stop working.\n",s3c_ts_name); ts->bad_data = 1; return ; } */ ret=i2c_read_bytes(ts->client, point_data, sizeof(point_data)); if(ret <= 0) { dev_dbg(&(ts->client->dev),"I2C transfer error. ERROR Number:%d\n ", ret); ts->retry++; if(ts->power) { ts->power(ts, 0); ts->power(ts, 1); } else { goodix_init_panel(ts); msleep(260); } goto XFER_ERROR; } //如果能够保证在INT中断后及时的读取坐标数据,可以不进行校验 if(!ts->use_irq) { switch(point_data[1]& 0x1f) { case 0: break; case 1: for(count=1; count<8; count++) check_sum += (int)point_data[count]; read_position = 8; break; case 2: case 3: for(count=1; count<13;count++) check_sum += (int)point_data[count]; read_position = 13; break; default: //(point_data[1]& 0x1f) > 3 for(count=1; count<34;count++) check_sum += (int)point_data[count]; read_position = 34; } if(check_sum != point_data[read_position]) goto XFER_ERROR; } //The bits indicate which fingers pressed down point_data[1]&=0x1f; finger = finger_bit^point_data[1]; if(finger == 0 && point_data[1] == 0) goto NO_ACTION; //no fingers and no action else if(finger == 0) //the same as last time goto BIT_NO_CHANGE; //check which point(s) DOWN or UP analyse_points(&finger_list, finger_bit, finger); if(finger_list.head == NULL) goto NO_ACTION; else dev_dbg(&ts->client->dev, "fingers count:%d\n", finger_list.length); BIT_NO_CHANGE: for(p = finger_list.head; p != NULL; p = p->next) { if(p->state == FLAG_UP) { p->x = p->y = 0; p->pressure = 0; continue; } if(p->id < 3) read_position = p->id*5+3; else read_position = 29; if(p->id != 3) { p->x = (unsigned int) (point_data[read_position]<<8) + (unsigned int)( point_data[read_position+1]); p->y = (unsigned int)(point_data[read_position+2]<<8) + (unsigned int) (point_data[read_position+3]); p->pressure = point_data[read_position+4]; } #if MAX_FINGER_NUM > 3 else { p->x = (unsigned int) (point_data[18]<<8) + (unsigned int)( point_data[25]); p->y = (unsigned int)(point_data[26]<<8) + (unsigned int) (point_data[27]); p->pressure = point_data[28]; } #endif // 将触摸屏的坐标映射到LCD坐标上. 触摸屏短边为X轴,LCD坐标一般长边为X轴,可能需要调整原点位置 p->x = (TOUCH_MAX_WIDTH - p->x)*SCREEN_MAX_WIDTH/TOUCH_MAX_WIDTH;//y if (board_version == 0){ p->y = p->y*SCREEN_MAX_HEIGHT/TOUCH_MAX_HEIGHT;//x } else if (board_version == 1) { p->y = (TOUCH_MAX_HEIGHT - p->y)*SCREEN_MAX_HEIGHT/TOUCH_MAX_HEIGHT;//x } swap(p->x, p->y); } #ifndef GOODIX_MULTI_TOUCH if(finger_list.head->state == FLAG_DOWN) { input_report_abs(ts->input_dev, ABS_X, finger_list.head->x); input_report_abs(ts->input_dev, ABS_Y, finger_list.head.y); } input_report_abs(ts->input_dev, ABS_PRESSURE, finger_list.head->pressure); input_report_key(ts->input_dev, BTN_TOUCH, finger_list.head->state); #else /* ABS_MT_TOUCH_MAJOR is used as ABS_MT_PRESSURE in android. */ for(p = finger_list.head; p != NULL; p = p->next) { if(p->state == FLAG_DOWN) { input_report_abs(ts->input_dev, ABS_MT_POSITION_X, p->x); input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, p->y); } //input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, p->id); input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, p->pressure); input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, p->pressure); //printk("ID:%d.\n", p->id); input_mt_sync(ts->input_dev); } #endif input_sync(ts->input_dev); delete_points(&finger_list); finger_bit = point_data[1]&0x1f; //restore last presse state. XFER_ERROR: NO_ACTION: if(ts->use_irq) enable_irq(ts->client->irq); }