4 * Copyright (C) 2010 Richard Nauber <Richard.Nauber@gmail.com>
6 * This tool is based on the excellent work of:
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 ****************************************************************************/
29 - calculate acceleration
30 - make TUIO port and address configurable
31 - implement pressure event(?)
32 - add a ctrl-c handler
37 #include <mtdev-mapping.h>
50 #define DBG(x) printf x
56 #define DBGV(x) printf x
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
;
77 /* previous samples */
88 /* address of out tuio client*/
91 /* per slot information */
92 struct slotdata_t sldata
[MAXSLOTS
];
97 /*normalisation values */
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
)
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
,
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
;
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
));
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
)
157 if (ev
->type
== EV_ABS
&& ev
->code
== ABS_MT_SLOT
)
160 DBGV(("%02d %01d %04x %d\n", s
->cs
, ev
->type
, ev
->code
, ev
->value
));
162 if (ev
->type
== EV_ABS
) {
165 case ABS_MT_TRACKING_ID
:
166 s
->sldata
[s
->cs
].id
= ev
->value
;
169 case ABS_MT_POSITION_X
:
170 s
->sldata
[s
->cs
].x_1
= 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
;
182 case ABS_MT_POSITION_Y
:
184 s
->sldata
[s
->cs
].y_1
= 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
);
203 if (ev
->type
== EV_SYN
&& ev
->code
== SYN_REPORT
) {
204 /* send "alive" message for all active slots */
211 static void init_state(struct mtdev
*dev
, struct state_t
*s
)
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
;
221 1.0f
/ (dev
->caps
.abs
[MTDEV_POSITION_X
].maximum
-
222 dev
->caps
.abs
[MTDEV_POSITION_X
].minimum
);
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;
241 int main(int argc
, char *argv
[])
245 struct state_t state
;
246 struct input_event ev
;
249 fprintf(stderr
, "Usage: mtdev2tuio <device>\n");
252 fd
= open(argv
[1], O_RDONLY
| O_NONBLOCK
);
254 fprintf(stderr
, "error: could not open device\n");
257 if (ioctl(fd
, EVIOCGRAB
, 1)) {
258 fprintf(stderr
, "error: could not grab the device\n");
262 if (mtdev_open(&dev
, fd
)) {
263 fprintf(stderr
, "error: could not open device!\n");
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 */
276 while (mtdev_get(&dev
, fd
, &ev
, 1) > 0) {
277 process_event(&state
, &ev
);
281 /* this is not executed yet ! */
284 ioctl(fd
, EVIOCGRAB
, 0);