From f0aba58c91933a4702a7cc74f7daf4192868f570 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Thu, 30 Dec 2010 17:58:01 +0100 Subject: Initial load of utouch-frame Compiles and runs on mtdev. ABI proof. Signed-off-by: Henrik Rydberg --- src/Makefile.am | 21 ++++ src/frame-impl.h | 18 ++++ src/frame-mtdev.c | 189 ++++++++++++++++++++++++++++++++++ src/frame.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 531 insertions(+) create mode 100644 src/Makefile.am create mode 100644 src/frame-impl.h create mode 100644 src/frame-mtdev.c create mode 100644 src/frame.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..aa11733 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,21 @@ +lib_LTLIBRARIES = libutouch-frame.la + +libutouch_frame_la_LDFLAGS = \ + -version-info @LIB_VERSION@ \ + -lm \ + $(EVEMU_LIBS) + $(MTDEV_LIBS) + +libutouch_frame_la_SOURCES = \ + frame-impl.h \ + frame.c \ + frame-mtdev.c + +AM_CFLAGS = $(CWARNFLAGS) + +INCLUDES = -I$(top_srcdir)/include/ + +libutouch_frameincludedir = $(includedir)/utouch +libutouch_frameinclude_HEADERS = \ + $(top_srcdir)/include/utouch/frame.h \ + $(top_srcdir)/include/utouch/frame-mtdev.h diff --git a/src/frame-impl.h b/src/frame-impl.h new file mode 100644 index 0000000..c31f7da --- /dev/null +++ b/src/frame-impl.h @@ -0,0 +1,18 @@ +#ifndef _FRAME_IMPL_H +#define _FRAME_IMPL_H + +#include + +struct utouch_frame_engine { + int num_frames; + int num_slots; + int hold_ms; + int frame; + int slot; + float max_orient; + struct utouch_surface *surface; + struct utouch_frame **frames; + struct utouch_frame *next; +}; + +#endif diff --git a/src/frame-mtdev.c b/src/frame-mtdev.c new file mode 100644 index 0000000..ed5dc9e --- /dev/null +++ b/src/frame-mtdev.c @@ -0,0 +1,189 @@ +/***************************************************************************** + * + * utouch-frame - Touch Frame Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + ****************************************************************************/ + +#include +#include "frame-impl.h" +#include +#include +#include + +int utouch_frame_is_supported_mtdev(const struct evemu_device *dev) +{ + + /* only support pure absolute devices at this time */ + if (evemu_has_event(dev, EV_REL, REL_X) || + evemu_has_event(dev, EV_REL, REL_Y)) + return 0; + + if (evemu_has_event(dev, EV_ABS, ABS_MT_POSITION_X) && + evemu_has_event(dev, EV_ABS, ABS_MT_POSITION_Y)) + return 1; + + return evemu_has_event(dev, EV_ABS, ABS_X) && + evemu_has_event(dev, EV_ABS, ABS_Y) && + evemu_has_event(dev, EV_KEY, BTN_TOUCH) && + evemu_has_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP); +} + +int utouch_frame_init_mtdev(utouch_frame_handle fh, + const struct evemu_device *dev) +{ + struct utouch_surface *s = fh->surface; + float tmp; + + if (!utouch_frame_is_supported_mtdev(dev)) + return -ENODEV; + +#ifdef INPUT_PROP_POINTER + s->needs_pointer = evemu_has_prop(dev, INPUT_PROP_POINTER); + s->is_direct = evemu_has_prop(dev, INPUT_PROP_DIRECT); + s->is_buttonpad = evemu_has_prop(dev, INPUT_PROP_BUTTONPAD); + s->is_semi_mt = evemu_has_prop(dev, INPUT_PROP_SEMI_MT); +#endif + s->use_touch_major = evemu_has_event(dev, EV_ABS, ABS_MT_TOUCH_MAJOR); + s->use_touch_minor = evemu_has_event(dev, EV_ABS, ABS_MT_TOUCH_MINOR); + s->use_width_major = evemu_has_event(dev, EV_ABS, ABS_MT_WIDTH_MAJOR); + s->use_width_minor = evemu_has_event(dev, EV_ABS, ABS_MT_WIDTH_MINOR); + s->use_orientation = evemu_has_event(dev, EV_ABS, ABS_MT_ORIENTATION); + s->use_pressure = evemu_has_event(dev, EV_ABS, ABS_MT_PRESSURE); +#ifdef ABS_MT_DISTANCE + s->use_distance = evemu_has_event(dev, EV_ABS, ABS_MT_DISTANCE); +#endif + + + s->min_x = evemu_get_abs_minimum(dev, ABS_MT_POSITION_X); + s->min_y = evemu_get_abs_minimum(dev, ABS_MT_POSITION_Y); + s->max_x = evemu_get_abs_maximum(dev, ABS_MT_POSITION_X); + s->max_y = evemu_get_abs_maximum(dev, ABS_MT_POSITION_Y); + if (s->min_x == s->max_x) { + s->min_x = 0; + s->max_x = 1024; + } + if (s->min_y == s->max_y) { + s->min_y = 0; + s->max_y = 768; + } + + s->max_pressure = evemu_get_abs_maximum(dev, ABS_MT_PRESSURE); + if (s->use_pressure && s->max_pressure == 0) + s->max_pressure = 256; + + fh->max_orient = evemu_get_abs_maximum(dev, ABS_MT_ORIENTATION); + if (s->use_orientation && fh->max_orient == 0) + fh->max_orient = 1; + + tmp = evemu_get_abs_resolution(dev, ABS_MT_POSITION_X); + if (tmp > 0) + s->phys_width = (s->max_x - s->min_x) / tmp; + else if (s->needs_pointer) + s->phys_width = 100; + else + s->phys_width = 250; + + tmp = evemu_get_abs_resolution(dev, ABS_MT_POSITION_Y); + if (tmp > 0) + s->phys_height = (s->max_y - s->min_y) / tmp; + else if (s->needs_pointer) + s->phys_height = 65; + else + s->phys_height = 160; + + tmp = evemu_get_abs_resolution(dev, ABS_MT_PRESSURE); + if (tmp > 0) + s->phys_pressure = s->max_pressure / tmp; + else + s->phys_pressure = 10; + + return 0; +} + +static float touch_angle(utouch_frame_handle fh, int orient) +{ + return orient / fh->max_orient * M_PI_2; +} + +static int handle_abs_event(utouch_frame_handle fh, + const struct input_event *ev) +{ + struct utouch_contact *t = utouch_frame_get_current_slot(fh); + + switch (ev->code) { + case ABS_MT_SLOT: + utouch_frame_set_current_slot(fh, ev->value); + return 1; + case ABS_MT_POSITION_X: + t->x = ev->value; + return 1; + case ABS_MT_POSITION_Y: + t->y = ev->value; + return 1; + case ABS_MT_TOUCH_MAJOR: + t->touch_major = ev->value; + return 1; + case ABS_MT_TOUCH_MINOR: + t->touch_minor = ev->value; + return 1; + case ABS_MT_WIDTH_MAJOR: + t->width_major = ev->value; + return 1; + case ABS_MT_WIDTH_MINOR: + t->width_minor = ev->value; + return 1; + case ABS_MT_ORIENTATION: + t->orientation = touch_angle(fh, ev->value); + return 1; + case ABS_MT_PRESSURE: + t->pressure = ev->value; + return 1; +#ifdef ABS_MT_DISTANCE + case ABS_MT_DISTANCE: + t->distance = ev->value; + return 1; +#endif + case ABS_MT_TOOL_TYPE: + t->tool_type = ev->value; + return 1; + case ABS_MT_TRACKING_ID: + t->id = ev->value; + return 1; + default: + return 0; + } +} + +static utouch_frame_time_t get_evtime_ms(const struct input_event *syn) +{ + static const utouch_frame_time_t ms = 1000; + return syn->time.tv_usec / ms + syn->time.tv_sec * ms; +} + +const struct utouch_frame * +utouch_frame_pump_mtdev(utouch_frame_handle fh, const struct input_event *ev) +{ + const struct utouch_frame *f = 0; + + if (ev->type == EV_SYN && ev->code == SYN_REPORT) + f = utouch_frame_sync(fh, get_evtime_ms(ev)); + else if (ev->type == EV_ABS) + handle_abs_event(fh, ev); + + return f; +} diff --git a/src/frame.c b/src/frame.c new file mode 100644 index 0000000..9c4be97 --- /dev/null +++ b/src/frame.c @@ -0,0 +1,303 @@ +/***************************************************************************** + * + * utouch-frame - Touch Frame Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + ****************************************************************************/ + +#include "frame-impl.h" +#include +#include +#include +#include +#include + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +unsigned int utouch_frame_get_version(void) +{ + return UTOUCH_FRAME_VERSION; +} + +static void destroy_slots(struct utouch_contact **slots, int nslot) +{ + int i; + + if (slots) { + for (i = nslot - 1; i >= 0; i--) + free(slots[i]); + free(slots); + } +} + +static void destroy_frame(struct utouch_frame *frame, int nslot) +{ + if (frame) { + destroy_slots(frame->slots, nslot); + free(frame->active); + free(frame); + } +} + +static void destroy_frames(struct utouch_frame **frames, int nframe, int nslot) +{ + int i; + + if (frames) { + for (i = nframe - 1; i >= 0; i--) + destroy_frame(frames[i], nslot); + free(frames); + } +} + +static struct utouch_contact **create_slots(int nslot, int size) +{ + struct utouch_contact **slots; + struct utouch_contact *s; + int i; + + slots = calloc(nslot, sizeof(slots[0])); + if (!slots) + return 0; + + for (i = 0; i < nslot; i++) { + s = calloc(1, size); + if (!s) + goto out; + slots[i] = s; + s->slot = i; + s->id = -1; + } + + return slots; +out: + destroy_slots(slots, nslot); + return 0; +} + +static struct utouch_frame *create_frame(int nslot, + int frame_size, int slot_size) +{ + struct utouch_frame *frame; + int i; + + frame = calloc(1, frame_size); + if (!frame) + return 0; + + frame->active = calloc(nslot, sizeof(frame->active[0])); + frame->slots = create_slots(nslot, slot_size); + if (!frame->active || !frame->slots) + goto out; + + return frame; +out: + destroy_frame(frame, nslot); + return 0; +} + +static struct utouch_frame **create_frames(int nframe, int nslot, + int frame_size, int slot_size) +{ + struct utouch_frame **frames; + struct utouch_frame *f; + int i; + + frames = calloc(nframe, sizeof(frames[0])); + if (!frames) + return 0; + + for (i = 0; i < nframe; i++) { + f = create_frame(nslot, frame_size, slot_size); + if (!f) + goto out; + frames[i] = f; + } + + return frames; +out: + destroy_frames(frames, nframe, nslot); + return 0; +} + +utouch_frame_handle utouch_frame_new_engine_raw(unsigned int nframe, + unsigned int nslot, + unsigned int rate, + unsigned int version, + unsigned int surface_size, + unsigned int frame_size, + unsigned int slot_size) +{ + struct utouch_frame *f, *pf; + utouch_frame_handle fh; + int i, j; + + fh = calloc(1, sizeof(struct utouch_frame_engine)); + if (!fh) + return 0; + + fh->num_frames = nframe; + fh->num_slots = nslot; + fh->hold_ms = 1000 / rate; + + surface_size = MAX(surface_size, sizeof(struct utouch_surface)); + frame_size = MAX(frame_size, sizeof(struct utouch_frame)); + slot_size = MAX(slot_size, sizeof(struct utouch_contact)); + + fh->surface = calloc(1, surface_size); + fh->frames = create_frames(nframe, nslot, frame_size, slot_size); + fh->next = create_frame(nslot, frame_size, slot_size); + if (!fh->surface || !fh->frames || !fh->next) + goto out; + + pf = fh->frames[nframe - 1]; + for (i = 0; i < nframe; i++) { + f = fh->frames[i]; + for (j = 0; j < nslot; j++) + f->slots[j]->prev = pf->slots[j]; + f->prev = pf; + pf = f; + } + + return fh; +out: + utouch_frame_delete_engine(fh); + return 0; +} + +void utouch_frame_delete_engine(utouch_frame_handle fh) +{ + destroy_frame(fh->next, fh->num_slots); + destroy_frames(fh->frames, fh->num_frames, fh->num_slots); + free(fh->surface); + free(fh); +} + +struct utouch_surface *utouch_frame_get_surface(utouch_frame_handle fh) +{ + return fh->surface; +} + +struct utouch_contact *utouch_frame_get_current_slot(utouch_frame_handle fh) +{ + return fh->next->slots[fh->slot]; +} + +int utouch_frame_set_current_slot(utouch_frame_handle fh, int slot) +{ + if (slot < 0 || slot >= fh->num_slots) + return -EINVAL; + fh->slot = slot; + return 0; +} + +static void copy_contact(utouch_frame_handle fh, + struct utouch_contact *a, + const struct utouch_contact *b) +{ + struct utouch_surface *s = fh->surface; + + a->active = b->id != -1; + a->id = b->id; + a->tool_type = b->tool_type; + a->x = b->x; + a->y = b->y; + a->touch_major = b->touch_major; + a->touch_minor = s->use_touch_minor && b->touch_minor > 0 ? + b->touch_minor : b->touch_major; + a->width_major = b->width_major; + a->width_minor = s->use_width_minor && b->width_minor > 0 ? + b->width_minor : b->width_major; + a->orientation = b->orientation; + a->pressure = b->pressure; + a->distance = b->distance; +} + +static int detect_addrem(const struct utouch_contact *a, + const struct utouch_contact *b) +{ + return a->id != b->id || a->tool_type != b->tool_type; +} + +static int detect_mod(const struct utouch_contact *a, + const struct utouch_contact *b) +{ + return a->x != b->x || a->y != b->y || + a->touch_major != b->touch_major || + a->touch_minor != b->touch_minor || + a->width_major != b->width_major || + a->width_minor != b->width_minor || + a->orientation != b->orientation || + a->pressure != b->pressure || + a->distance != b->distance; +} + +static utouch_frame_time_t get_time_ms() +{ + static const utouch_frame_time_t ms = 1000; + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_usec / ms + tv.tv_sec * ms; +} + +const struct utouch_frame *utouch_frame_sync(utouch_frame_handle fh, + utouch_frame_time_t time) +{ + struct utouch_frame *frame = fh->frames[fh->frame]; + const struct utouch_frame *prev = frame->prev; + struct utouch_frame *next = fh->next; + int naddrem = 0, nmod = 0; + int i; + + frame->num_active = 0; + for (i = 0; i < fh->num_slots; i++) { + struct utouch_contact *p = frame->slots[i]; + const struct utouch_contact *q = next->slots[i]; + + copy_contact(fh, p, q); + if (p->active) + frame->active[frame->num_active++] = p; + + naddrem += detect_addrem(p->prev, p); + nmod += detect_mod(p->prev, p); + } + if (naddrem + nmod == 0) + return 0; + + frame->time = time ? time : get_time_ms(); + if (naddrem == 0 && frame->time < prev->time + fh->hold_ms) + return 0; + + if (frame->num_active != prev->num_active) { + next->mod_time = frame->time; + next->revision++; + } + if (naddrem) { + next->slot_mod_time = frame->time; + next->slot_revision++; + } + + frame->revision = next->revision; + frame->slot_revision = next->slot_revision; + frame->mod_time = next->mod_time; + frame->slot_mod_time = next->slot_mod_time; + frame->sequence_id = next->sequence_id++; + + fh->frame = (fh->frame + 1) % fh->num_frames; + + return frame; +} -- cgit v1.2.3