Initial commit for mtdev2tuio.
[mtdev2tuio.git] / mtdev2tuio.c
bloba094830b877823f9719d46064cf00b869d238d92
1 /*
2 * mtdev2tuio
4 * Copyright (C) 2010 Richard Nauber <Richard.Nauber@gmail.com>
6 * This tool is based on the excellent work of:
7 * liblo
8 * Copyright (C) 2004 Steve Harris, Uwe Koloska (LGPL)
9 * mtdev - Multitouch Protocol Translation Library (MIT license)
10 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
11 * Copyright (C) 2010 Canonical Ltd.
13 * This program is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 ****************************************************************************/
28 /* TODO:
29 - calculate acceleration
30 - make TUIO port and address configurable
31 - implement pressure event(?)
32 - add a ctrl-c handler
35 #include "lo/lo.h"
36 #include <mtdev.h>
37 #include <mtdev-mapping.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <stdlib.h>
44 #define MAXSLOTS 8
46 #define DEBUG
47 //#define DEBUGV
49 #ifdef DEBUG
50 #define DBG(x) printf x
51 #else
52 #define DBG(x)
53 #endif
55 #ifdef DEBUGV
56 #define DBGV(x) printf x
57 #else
58 #define DBGV(x)
59 #endif
61 #define NSEC_PER_USEC 1000L
62 #define NSEC_PER_SEC 1000000000L
64 static inline __u64 timeval_to_ns(const struct timeval *tv)
66 return ((__u64) tv->tv_sec * NSEC_PER_SEC) +
67 tv->tv_usec * NSEC_PER_USEC;
70 typedef __u64 nstime;
72 struct slotdata_t {
73 /* current sample */
74 float x, y;
75 float dx, dy;
77 /* previous samples */
78 float x_1, y_1;
79 nstime tx_1, ty_1;
81 int id;
84 struct state_t {
85 /* frame id */
86 unsigned int fid;
88 /* address of out tuio client*/
89 lo_address tuioaddr;
91 /* per slot information */
92 struct slotdata_t sldata[MAXSLOTS];
94 /* current slot */
95 int cs;
97 /*normalisation values */
98 int x_ofs, y_ofs;
99 float x_scale, y_scale;
102 static float calc_speed(float s, float s_1, nstime t, nstime t_1)
104 return ((s - s_1) * (float)NSEC_PER_SEC / (t - t_1));
107 static void send_msg_set(struct state_t *s, int slot)
110 if (lo_send
111 (s->tuioaddr, "/tuio/2Dcur", "sifffff", "set",
112 s->sldata[slot].id, s->sldata[slot].x,
113 s->sldata[slot].y, s->sldata[slot].dx, s->sldata[slot].dy,
114 0.0) == -1) {
115 printf("OSC error %d: %s\n", lo_address_errno(s->tuioaddr),
116 lo_address_errstr(s->tuioaddr));
119 DBG((" set %i: x=%f y=%f dx=%f dy=%f\n", s->sldata[s->cs].id,
120 s->sldata[slot].x, s->sldata[slot].y, s->sldata[slot].dx,
121 s->sldata[slot].dy));
124 static void send_msg_alive(struct state_t *s)
126 lo_message msg_alive;
127 int i;
129 msg_alive = lo_message_new();
130 lo_message_add_string(msg_alive, "alive");
132 for (i = 0; i < MAXSLOTS; i++) {
133 if (s->sldata[i].id != -1) {
134 lo_message_add_int32(msg_alive, s->sldata[i].id);
135 DBGV((" id=%i ", s->sldata[i].id));
139 DBGV(("\n"));
141 lo_send_message(s->tuioaddr, "/tuio/2Dcur", msg_alive);
142 lo_message_free(msg_alive);
144 if (lo_send(s->tuioaddr, "/tuio/2Dcur", "si", "fseq", s->fid++) == -1) {
145 printf("OSC error %d: %s\n",
146 lo_address_errno(s->tuioaddr),
147 lo_address_errstr(s->tuioaddr));
152 static void process_event(struct state_t *s, const struct input_event *ev)
154 unsigned int i;
155 nstime time;
157 if (ev->type == EV_ABS && ev->code == ABS_MT_SLOT)
158 s->cs = ev->value;
160 DBGV(("%02d %01d %04x %d\n", s->cs, ev->type, ev->code, ev->value));
162 if (ev->type == EV_ABS) {
164 switch (ev->code) {
165 case ABS_MT_TRACKING_ID:
166 s->sldata[s->cs].id = ev->value;
167 break;
169 case ABS_MT_POSITION_X:
170 s->sldata[s->cs].x_1 = s->sldata[s->cs].x;
171 s->sldata[s->cs].x =
172 (ev->value - s->x_ofs) * s->x_scale;
173 time = timeval_to_ns(&ev->time);
175 s->sldata[s->cs].dx =
176 calc_speed(s->sldata[s->cs].x, s->sldata[s->cs].x_1,
177 time, s->sldata[s->cs].tx_1);
178 s->sldata[s->cs].tx_1 = time;
180 break;
182 case ABS_MT_POSITION_Y:
184 s->sldata[s->cs].y_1 = s->sldata[s->cs].y;
185 s->sldata[s->cs].y =
186 (ev->value - s->y_ofs) * s->y_scale;
187 time = timeval_to_ns(&ev->time);
189 s->sldata[s->cs].dy =
190 calc_speed(s->sldata[s->cs].y, s->sldata[s->cs].y_1,
191 time, s->sldata[s->cs].ty_1);
192 s->sldata[s->cs].ty_1 = time;
194 /* send "set" message for the current slot */
195 send_msg_set(s, s->cs);
196 break;
198 default:
199 break;
203 if (ev->type == EV_SYN && ev->code == SYN_REPORT) {
204 /* send "alive" message for all active slots */
205 send_msg_alive(s);
211 static void init_state(struct mtdev *dev, struct state_t *s)
213 unsigned int i;
215 /* calculate scale factors */
217 s->x_ofs = dev->caps.abs[MTDEV_POSITION_X].minimum;
218 s->y_ofs = dev->caps.abs[MTDEV_POSITION_Y].minimum;
220 s->x_scale =
221 1.0f / (dev->caps.abs[MTDEV_POSITION_X].maximum -
222 dev->caps.abs[MTDEV_POSITION_X].minimum);
223 s->y_scale =
224 1.0f / (dev->caps.abs[MTDEV_POSITION_Y].maximum -
225 dev->caps.abs[MTDEV_POSITION_Y].minimum);
227 DBG(("x=%i-%i y=%i-%i\n", dev->caps.abs[MTDEV_POSITION_X].minimum,
228 dev->caps.abs[MTDEV_POSITION_X].maximum,
229 dev->caps.abs[MTDEV_POSITION_Y].minimum,
230 dev->caps.abs[MTDEV_POSITION_Y].maximum));
232 /* mark all slots as unused */
233 for (i = 0; i < MAXSLOTS; i++) {
234 s->sldata[i].id = -1;
237 s->cs = 0;
241 int main(int argc, char *argv[])
243 int fd;
244 struct mtdev dev;
245 struct state_t state;
246 struct input_event ev;
248 if (argc < 2) {
249 fprintf(stderr, "Usage: mtdev2tuio <device>\n");
250 return -1;
252 fd = open(argv[1], O_RDONLY | O_NONBLOCK);
253 if (fd < 0) {
254 fprintf(stderr, "error: could not open device\n");
255 return -1;
257 if (ioctl(fd, EVIOCGRAB, 1)) {
258 fprintf(stderr, "error: could not grab the device\n");
259 return -1;
262 if (mtdev_open(&dev, fd)) {
263 fprintf(stderr, "error: could not open device!\n");
264 return;
267 /* initialize */
268 init_state(&dev, &state);
270 /* set the tuio address */
271 // tuioaddr = lo_address_new_from_url( "osc.unix://localhost/tmp/mysocket" );
272 state.tuioaddr = lo_address_new(NULL, "3333");
274 /* process all available events */
275 while (1) {
276 while (mtdev_get(&dev, fd, &ev, 1) > 0) {
277 process_event(&state, &ev);
281 /* this is not executed yet ! */
282 mtdev_close(&dev);
284 ioctl(fd, EVIOCGRAB, 0);
285 close(fd);
286 return 0;