2 * Copyright (c) 2012 Martin Sucha
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <char_dev_iface.h>
39 #define START_OF_PACKET 128
40 #define CONTROL_PACKET 64
41 #define TOUCH_EVENT 16
51 #define CMD_QUERY_STYLUS '*'
52 #define CMD_QUERY_TOUCH '%'
54 /* packet_consumer_fn(uint8_t *packet, size_t size, isdv4_state_t *state,
56 return true if reading of packets should continue */
57 typedef bool (*packet_consumer_fn
)(uint8_t *, size_t, isdv4_state_t
*);
59 static void isdv4_event_init(isdv4_event_t
*event
)
61 memset(event
, 0, sizeof(isdv4_event_t
));
65 * Parse event packet and emit events
66 * @return true if reading of packets should continue
68 static bool parse_event(uint8_t *packet
, size_t size
, isdv4_state_t
*state
)
73 bool control_packet
= ((packet
[0] & CONTROL_PACKET
) > 0);
77 /* This is an event initiated by the device */
79 isdv4_event_init(&event
);
81 if (packet
[0] & TOUCH_EVENT
) {
85 /* This is a touch event */
86 bool finger1
= (packet
[0] & FINGER1
) > 0;
87 event
.x
= ((packet
[1] & 127) << 7) | (packet
[2] & 127);
88 event
.y
= ((packet
[3] & 127) << 7) | (packet
[4] & 127);
91 if (!state
->stylus_in_proximity
) {
92 if (!finger1
&& state
->finger1_pressed
) {
93 state
->finger1_pressed
= false;
97 state
->emit_event_fn(&event
);
99 else if (finger1
&& !state
->finger1_pressed
) {
100 state
->finger1_pressed
= true;
104 state
->emit_event_fn(&event
);
109 state
->emit_event_fn(&event
);
117 /* This is a stylus event */
118 bool tip
= packet
[0] & TIP
;
119 bool button1
= packet
[0] & BUTTON1
;
120 bool button2
= packet
[0] & BUTTON2
;
121 bool proximity
= packet
[0] & PROXIMITY
;
122 event
.x
= ((packet
[1] & 127) << 7) | (packet
[2] & 124) | ((packet
[6] >> 5) & 3);
123 event
.y
= ((packet
[3] & 127) << 7) | (packet
[4] & 124) | ((packet
[6] >> 3) & 3);
124 event
.pressure
= (packet
[5] & 127) | ((packet
[6] & 7) << 7);
126 if (proximity
&& !state
->stylus_in_proximity
) {
127 /* Stylus came into proximity */
128 state
->stylus_in_proximity
= true;
129 state
->stylus_is_eraser
= !tip
&& button2
;
130 event
.source
= (state
->stylus_is_eraser
? STYLUS_ERASER
: STYLUS_TIP
);
131 event
.type
= PROXIMITY_IN
;
132 state
->emit_event_fn(&event
);
134 else if (!proximity
&& state
->stylus_in_proximity
) {
135 /* Stylus came out of proximity */
136 state
->stylus_in_proximity
= false;
137 event
.source
= (state
->stylus_is_eraser
? STYLUS_ERASER
: STYLUS_TIP
);
138 event
.type
= PROXIMITY_OUT
;
139 state
->emit_event_fn(&event
);
142 /* Proximity state didn't change, but we need to check if it is still eraser */
143 if (state
->stylus_is_eraser
&& !button2
) {
144 event
.type
= PROXIMITY_OUT
;
145 event
.source
= STYLUS_ERASER
;
146 state
->emit_event_fn(&event
);
147 event
.type
= PROXIMITY_IN
;
148 event
.source
= STYLUS_TIP
;
149 state
->emit_event_fn(&event
);
150 state
->stylus_is_eraser
= false;
152 else if (!state
->stylus_is_eraser
&& !tip
&& button2
) {
153 event
.type
= PROXIMITY_OUT
;
154 event
.source
= STYLUS_TIP
;
155 state
->emit_event_fn(&event
);
156 event
.type
= PROXIMITY_IN
;
157 event
.source
= STYLUS_ERASER
;
158 state
->emit_event_fn(&event
);
159 state
->stylus_is_eraser
= true;
163 if (!state
->stylus_is_eraser
) {
164 if (tip
&& !state
->tip_pressed
) {
165 state
->tip_pressed
= true;
167 event
.source
= STYLUS_TIP
;
169 state
->emit_event_fn(&event
);
171 else if (!tip
&& state
->tip_pressed
) {
172 state
->tip_pressed
= false;
173 event
.type
= RELEASE
;
174 event
.source
= STYLUS_TIP
;
176 state
->emit_event_fn(&event
);
178 if (button1
&& !state
->button1_pressed
) {
179 state
->button1_pressed
= true;
181 event
.source
= STYLUS_TIP
;
183 state
->emit_event_fn(&event
);
185 else if (!button1
&& state
->button1_pressed
) {
186 state
->button1_pressed
= false;
187 event
.type
= RELEASE
;
188 event
.source
= STYLUS_TIP
;
190 state
->emit_event_fn(&event
);
192 if (button2
&& !state
->button2_pressed
) {
193 state
->button2_pressed
= true;
195 event
.source
= STYLUS_TIP
;
197 state
->emit_event_fn(&event
);
199 else if (!button2
&& state
->button2_pressed
) {
200 state
->button2_pressed
= false;
201 event
.type
= RELEASE
;
202 event
.source
= STYLUS_TIP
;
204 state
->emit_event_fn(&event
);
207 event
.source
= STYLUS_TIP
;
209 state
->emit_event_fn(&event
);
212 if (tip
&& !state
->tip_pressed
) {
213 state
->tip_pressed
= true;
215 event
.source
= STYLUS_ERASER
;
217 state
->emit_event_fn(&event
);
219 else if (!tip
&& state
->tip_pressed
) {
220 state
->tip_pressed
= false;
221 event
.type
= RELEASE
;
222 event
.source
= STYLUS_ERASER
;
224 state
->emit_event_fn(&event
);
227 event
.source
= STYLUS_ERASER
;
229 state
->emit_event_fn(&event
);
236 static bool parse_response_stylus(uint8_t *packet
, size_t size
,
237 isdv4_state_t
*state
)
242 bool control_packet
= ((packet
[0] & CONTROL_PACKET
) > 0);
249 state
->stylus_max_x
= ((packet
[1] & 127) << 7) | (packet
[2] & 124) |
250 ((packet
[6] >> 5) & 3);
251 state
->stylus_max_y
= ((packet
[3] & 127) << 7) | (packet
[4] & 124) |
252 ((packet
[6] >> 3) & 3);
253 state
->stylus_max_pressure
= (packet
[5] & 63) | ((packet
[6] & 7) << 7);
254 state
->stylus_max_xtilt
= packet
[8] & 127;
255 state
->stylus_max_ytilt
= packet
[7] & 127;
256 state
->stylus_tilt_supported
= (state
->stylus_max_xtilt
&&
257 state
->stylus_max_ytilt
);
262 static bool parse_response_touch(uint8_t *packet
, size_t size
,
263 isdv4_state_t
*state
)
268 bool control_packet
= ((packet
[0] & CONTROL_PACKET
) > 0);
275 state
->touch_type
= (packet
[0] & 63);
277 unsigned int touch_resolution
= packet
[1] & 127;
278 state
->touch_max_x
= ((packet
[2] >> 5) & 3) | ((packet
[3] & 127) << 7) |
280 state
->touch_max_y
= ((packet
[2] >> 3) & 3) | ((packet
[5] & 127) << 7) |
283 if (touch_resolution
== 0)
284 touch_resolution
= 10;
286 if (state
->touch_max_x
== 0 || state
->touch_max_y
== 0) {
287 state
->touch_max_x
= (1 << touch_resolution
);
288 state
->touch_max_y
= (1 << touch_resolution
);
294 static int read_packets(isdv4_state_t
*state
, packet_consumer_fn consumer
)
298 ssize_t read
= char_dev_read(state
->sess
, state
->buf
+ state
->buf_end
,
299 state
->buf_size
- state
->buf_end
);
302 state
->buf_end
+= read
;
306 /* Skip data until a start of packet is found */
307 while (i
< state
->buf_end
&& (state
->buf
[i
] & START_OF_PACKET
) == 0) i
++;
311 size_t processed_end
= i
;
313 /* Process packets one by one */
314 while (reading
&& i
< state
->buf_end
) {
315 /* Determine the packet length */
316 size_t packet_remaining
;
317 if (state
->buf
[i
] & CONTROL_PACKET
) {
318 packet_remaining
= 11;
320 else if (state
->buf
[i
] & TOUCH_EVENT
) {
321 packet_remaining
= 5;
324 packet_remaining
= 9;
327 /* Find the end of the packet */
328 i
++; /* We need to skip the first byte with START_OF_PACKET set */
330 while (packet_remaining
> 0 && i
< state
->buf_end
&&
331 (state
->buf
[i
] & START_OF_PACKET
) == 0) {
337 /* If we have whole packet, process it */
338 if (end
> start
&& packet_remaining
== 0) {
339 reading
= consumer(state
->buf
+ start
, end
- start
, state
);
345 if (processed_end
== 0 && state
->buf_end
== state
->buf_size
) {
346 /* Packet too large, throw it away */
350 /* Shift the buffer contents to the left */
351 size_t unprocessed_len
= state
->buf_end
- processed_end
;
352 memcpy(state
->buf
, state
->buf
+ processed_end
, unprocessed_len
);
353 state
->buf_end
= unprocessed_len
;
357 static bool write_command(async_sess_t
*sess
, uint8_t command
)
359 return char_dev_write(sess
, &command
, 1) == 1;
362 int isdv4_init(isdv4_state_t
*state
, async_sess_t
*sess
,
363 isdv4_event_fn event_fn
)
365 memset(state
, 0, sizeof(isdv4_state_t
));
367 state
->buf
= malloc(BUF_SIZE
);
368 if (state
->buf
== NULL
)
370 state
->buf_size
= BUF_SIZE
;
371 state
->emit_event_fn
= event_fn
;
375 int isdv4_init_tablet(isdv4_state_t
*state
)
377 if (!write_command(state
->sess
, CMD_STOP
))
380 thread_usleep(250000); /* 250 ms */
382 // FIXME: Read all possible garbage before sending commands
383 if (!write_command(state
->sess
, CMD_QUERY_STYLUS
))
386 int rc
= read_packets(state
, parse_response_stylus
);
390 if (!write_command(state
->sess
, CMD_QUERY_TOUCH
))
393 rc
= read_packets(state
, parse_response_touch
);
397 if (!write_command(state
->sess
, CMD_START
))
403 int isdv4_read_events(isdv4_state_t
*state
)
405 return read_packets(state
, parse_event
);
408 void isdv4_fini(isdv4_state_t
*state
)