• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "qemu-common.h"
18 #include "utils/panic.h"
19 #include "android/hw-events.h"
20 #include "android/charmap.h"
21 #include "android/multitouch-screen.h"
22 #include "android/sdk-controller-socket.h"
23 #include "android/multitouch-port.h"
24 #include "android/globals.h"  /* for android_hw */
25 #include "android/opengles.h"
26 #include "android/utils/misc.h"
27 #include "android/utils/jpeg-compress.h"
28 #include "android/utils/debug.h"
29 
30 #define  E(...)    derror(__VA_ARGS__)
31 #define  W(...)    dwarning(__VA_ARGS__)
32 #define  D(...)    VERBOSE_PRINT(mtport,__VA_ARGS__)
33 #define  D_ACTIVE  VERBOSE_CHECK(mtport)
34 
35 #define TRACE_ON    1
36 
37 #if TRACE_ON
38 #define  T(...)    VERBOSE_PRINT(mtport,__VA_ARGS__)
39 #else
40 #define  T(...)
41 #endif
42 
43 /* Timeout (millisec) to use when communicating with SDK controller. */
44 #define SDKCTL_MT_TIMEOUT      3000
45 
46 /*
47  * Message types used in multi-touch emulation.
48  */
49 
50 /* Pointer move message. */
51 #define SDKCTL_MT_MOVE                  1
52 /* First pointer down message. */
53 #define SDKCTL_MT_FISRT_DOWN            2
54 /* Last pointer up message. */
55 #define SDKCTL_MT_LAST_UP               3
56 /* Pointer down message. */
57 #define SDKCTL_MT_POINTER_DOWN          4
58 /* Pointer up message. */
59 #define SDKCTL_MT_POINTER_UP            5
60 /* Sends framebuffer update. */
61 #define SDKCTL_MT_FB_UPDATE             6
62 /* Framebuffer update has been received. */
63 #define SDKCTL_MT_FB_UPDATE_RECEIVED    7
64 /* Framebuffer update has been handled. */
65 #define SDKCTL_MT_FB_UPDATE_HANDLED     8
66 
67 /* Multi-touch port descriptor. */
68 struct AndroidMTSPort {
69     /* Caller identifier. */
70     void*               opaque;
71     /* Communication socket. */
72     SDKCtlSocket*       sdkctl;
73     /* Initialized JPEG compressor instance. */
74     AJPEGDesc*          jpeg_compressor;
75     /* Direct packet descriptor for framebuffer updates. */
76     SDKCtlDirectPacket* fb_packet;
77 };
78 
79 /* Data sent with SDKCTL_MT_QUERY_START */
80 typedef struct QueryDispData {
81     /* Width of the emulator display. */
82     int     width;
83     /* Height of the emulator display. */
84     int     height;
85 } QueryDispData;
86 
87 /* Multi-touch event structure received from SDK controller port. */
88 typedef struct AndroidMTEvent {
89     /* Pointer identifier. */
90     int     pid;
91     /* Pointer 'x' coordinate. */
92     int     x;
93     /* Pointer 'y' coordinate. */
94     int     y;
95     /* Pointer pressure. */
96     int     pressure;
97 } AndroidMTEvent;
98 
99 /* Multi-touch pointer descriptor received from SDK controller port. */
100 typedef struct AndroidMTPtr {
101     /* Pointer identifier. */
102     int     pid;
103 } AndroidMTPtr;
104 
105 /* Destroys and frees the descriptor. */
106 static void
_mts_port_free(AndroidMTSPort * mtsp)107 _mts_port_free(AndroidMTSPort* mtsp)
108 {
109     if (mtsp != NULL) {
110         if (mtsp->fb_packet != NULL) {
111             sdkctl_direct_packet_release(mtsp->fb_packet);
112         }
113         if (mtsp->jpeg_compressor != NULL) {
114             jpeg_compressor_destroy(mtsp->jpeg_compressor);
115         }
116         if (mtsp->sdkctl != NULL) {
117             sdkctl_socket_release(mtsp->sdkctl);
118         }
119         AFREE(mtsp);
120     }
121 }
122 
123 /********************************************************************************
124  *                          Multi-touch action handlers
125  *******************************************************************************/
126 
127 /*
128  * Although there are a lot of similarities in the way the handlers below are
129  * implemented, for the sake of tracing / debugging it's better to have a
130  * separate handler for each distinctive action.
131  */
132 
133 /* First pointer down event handler. */
134 static void
_on_action_down(int tracking_id,int x,int y,int pressure)135 _on_action_down(int tracking_id, int x, int y, int pressure)
136 {
137     multitouch_update_pointer(MTES_DEVICE, tracking_id, x, y, pressure);
138 }
139 
140 /* Last pointer up event handler. */
141 static void
_on_action_up(int tracking_id)142 _on_action_up(int tracking_id)
143 {
144     multitouch_update_pointer(MTES_DEVICE, tracking_id, 0, 0, 0);
145 }
146 
147 /* Pointer down event handler. */
148 static void
_on_action_pointer_down(int tracking_id,int x,int y,int pressure)149 _on_action_pointer_down(int tracking_id, int x, int y, int pressure)
150 {
151     multitouch_update_pointer(MTES_DEVICE, tracking_id, x, y, pressure);
152 }
153 
154 /* Pointer up event handler. */
155 static void
_on_action_pointer_up(int tracking_id)156 _on_action_pointer_up(int tracking_id)
157 {
158     multitouch_update_pointer(MTES_DEVICE, tracking_id, 0, 0, 0);
159 }
160 
161 /* Pointer move event handler. */
162 static void
_on_action_move(int tracking_id,int x,int y,int pressure)163 _on_action_move(int tracking_id, int x, int y, int pressure)
164 {
165     multitouch_update_pointer(MTES_DEVICE, tracking_id, x, y, pressure);
166 }
167 
168 /********************************************************************************
169  *                          Multi-touch event handlers
170  *******************************************************************************/
171 
172 /* Handles "pointer move" event.
173  * Param:
174  *  param - Array of moving pointers.
175  *  pointers_count - Number of pointers in the array.
176  */
177 static void
_on_move(const AndroidMTEvent * param,int pointers_count)178 _on_move(const AndroidMTEvent* param, int pointers_count)
179 {
180     int n;
181     for (n = 0; n < pointers_count; n++, param++) {
182         T("Multi-touch: MOVE(%d): %d-> %d:%d:%d",
183           n, param->pid, param->x, param->y, param->pressure);
184          _on_action_move(param->pid, param->x, param->y, param->pressure);
185     }
186 }
187 
188 /* Handles "first pointer down" event. */
189 static void
_on_down(const AndroidMTEvent * param)190 _on_down(const AndroidMTEvent* param)
191 {
192     T("Multi-touch: 1-ST DOWN: %d-> %d:%d:%d",
193       param->pid, param->x, param->y, param->pressure);
194     _on_action_down(param->pid, param->x, param->y, param->pressure);
195 }
196 
197 /* Handles "last pointer up" event. */
198 static void
_on_up(const AndroidMTPtr * param)199 _on_up(const AndroidMTPtr* param)
200 {
201     T("Multi-touch: LAST UP: %d", param->pid);
202     _on_action_up(param->pid);
203 }
204 
205 /* Handles "next pointer down" event. */
206 static void
_on_pdown(const AndroidMTEvent * param)207 _on_pdown(const AndroidMTEvent* param)
208 {
209     T("Multi-touch: DOWN: %d-> %d:%d:%d",
210       param->pid, param->x, param->y, param->pressure);
211     _on_action_pointer_down(param->pid, param->x, param->y, param->pressure);
212 }
213 
214 /* Handles "next pointer up" event. */
215 static void
_on_pup(const AndroidMTPtr * param)216 _on_pup(const AndroidMTPtr* param)
217 {
218     T("Multi-touch: UP: %d", param->pid);
219     _on_action_pointer_up(param->pid);
220 }
221 
222 /********************************************************************************
223  *                      Device communication callbacks
224  *******************************************************************************/
225 
226 /* A callback that is invoked on SDK controller socket connection events. */
227 static AsyncIOAction
_on_multitouch_socket_connection(void * opaque,SDKCtlSocket * sdkctl,AsyncIOState status)228 _on_multitouch_socket_connection(void* opaque,
229                                  SDKCtlSocket* sdkctl,
230                                  AsyncIOState status)
231 {
232     if (status == ASIO_STATE_FAILED) {
233         /* Reconnect (after timeout delay) on failures */
234         if (sdkctl_socket_is_handshake_ok(sdkctl)) {
235             sdkctl_socket_reconnect(sdkctl, SDKCTL_DEFAULT_TCP_PORT,
236                                     SDKCTL_MT_TIMEOUT);
237         }
238     }
239     return ASIO_ACTION_DONE;
240 }
241 
242 /* A callback that is invoked on SDK controller port connection events. */
243 static void
_on_multitouch_port_connection(void * opaque,SDKCtlSocket * sdkctl,SdkCtlPortStatus status)244 _on_multitouch_port_connection(void* opaque,
245                                SDKCtlSocket* sdkctl,
246                                SdkCtlPortStatus status)
247 {
248     switch (status) {
249         case SDKCTL_PORT_CONNECTED:
250             D("Multi-touch: SDK Controller is connected");
251             break;
252 
253         case SDKCTL_PORT_DISCONNECTED:
254             D("Multi-touch: SDK Controller is disconnected");
255             // Disable OpenGLES framebuffer updates.
256             if (android_hw->hw_gpu_enabled) {
257                 android_setPostCallback(NULL, NULL);
258             }
259             break;
260 
261         case SDKCTL_PORT_ENABLED:
262             D("Multi-touch: SDK Controller port is enabled.");
263             // Enable OpenGLES framebuffer updates.
264             if (android_hw->hw_gpu_enabled) {
265                 android_setPostCallback(multitouch_opengles_fb_update, NULL);
266             }
267             /* Refresh (possibly stale) device screen. */
268             multitouch_refresh_screen();
269             break;
270 
271         case SDKCTL_PORT_DISABLED:
272             D("Multi-touch: SDK Controller port is disabled.");
273             // Disable OpenGLES framebuffer updates.
274             if (android_hw->hw_gpu_enabled) {
275                 android_setPostCallback(NULL, NULL);
276             }
277             break;
278 
279         case SDKCTL_HANDSHAKE_CONNECTED:
280             D("Multi-touch: Handshake succeeded with connected port.");
281             break;
282 
283         case SDKCTL_HANDSHAKE_NO_PORT:
284             D("Multi-touch: Handshake succeeded with disconnected port.");
285             break;
286 
287         case SDKCTL_HANDSHAKE_DUP:
288             W("Multi-touch: Handshake failed due to port duplication.");
289             sdkctl_socket_disconnect(sdkctl);
290             break;
291 
292         case SDKCTL_HANDSHAKE_UNKNOWN_QUERY:
293             W("Multi-touch: Handshake failed due to unknown query.");
294             sdkctl_socket_disconnect(sdkctl);
295             break;
296 
297         case SDKCTL_HANDSHAKE_UNKNOWN_RESPONSE:
298         default:
299             W("Multi-touch: Handshake failed due to unknown reason.");
300             sdkctl_socket_disconnect(sdkctl);
301             break;
302     }
303 }
304 
305 /* A callback that is invoked when a message is received from the device. */
306 static void
_on_multitouch_message(void * client_opaque,SDKCtlSocket * sdkctl,SDKCtlMessage * message,int msg_type,void * msg_data,int msg_size)307 _on_multitouch_message(void* client_opaque,
308                        SDKCtlSocket* sdkctl,
309                        SDKCtlMessage* message,
310                        int msg_type,
311                        void* msg_data,
312                        int msg_size)
313 {
314     switch (msg_type) {
315         case SDKCTL_MT_MOVE: {
316             assert((msg_size / sizeof(AndroidMTEvent)) && !(msg_size % sizeof(AndroidMTEvent)));
317             _on_move((const AndroidMTEvent*)msg_data, msg_size / sizeof(AndroidMTEvent));
318             break;
319         }
320 
321         case SDKCTL_MT_FISRT_DOWN:
322             assert(msg_size / sizeof(AndroidMTEvent) && !(msg_size % sizeof(AndroidMTEvent)));
323             _on_down((const AndroidMTEvent*)msg_data);
324             break;
325 
326         case SDKCTL_MT_LAST_UP:
327             _on_up((const AndroidMTPtr*)msg_data);
328             break;
329 
330         case SDKCTL_MT_POINTER_DOWN:
331             assert(msg_size / sizeof(AndroidMTEvent) && !(msg_size % sizeof(AndroidMTEvent)));
332             _on_pdown((const AndroidMTEvent*)msg_data);
333             break;
334 
335         case SDKCTL_MT_POINTER_UP:
336             _on_pup((const AndroidMTPtr*)msg_data);
337             break;
338 
339         case SDKCTL_MT_FB_UPDATE_RECEIVED:
340             D("Framebuffer update ACK.");
341             break;
342 
343         case SDKCTL_MT_FB_UPDATE_HANDLED:
344             D("Framebuffer update handled.");
345             multitouch_fb_updated();
346             break;
347 
348         default:
349             W("Multi-touch: Unknown message %d", msg_type);
350             break;
351     }
352 }
353 
354 /********************************************************************************
355  *                          MTS port API
356  *******************************************************************************/
357 
358 AndroidMTSPort*
mts_port_create(void * opaque)359 mts_port_create(void* opaque)
360 {
361     AndroidMTSPort* mtsp;
362 
363     ANEW0(mtsp);
364     mtsp->opaque                = opaque;
365 
366     /* Initialize default MTS descriptor. */
367     multitouch_init(mtsp);
368 
369     /* Create JPEG compressor. Put message header + MTFrameHeader in front of the
370      * compressed data. this way we will have entire query ready to be
371      * transmitted to the device. */
372     mtsp->jpeg_compressor =
373         jpeg_compressor_create(sdkctl_message_get_header_size() + sizeof(MTFrameHeader), 4096);
374 
375     mtsp->sdkctl = sdkctl_socket_new(SDKCTL_MT_TIMEOUT, "multi-touch",
376                                      _on_multitouch_socket_connection,
377                                      _on_multitouch_port_connection,
378                                      _on_multitouch_message, mtsp);
379     sdkctl_init_recycler(mtsp->sdkctl, 64, 8);
380 
381     /* Create a direct packet that will wrap up framebuffer updates. Note that
382      * we need to do this after we have initialized the recycler! */
383     mtsp->fb_packet = sdkctl_direct_packet_new(mtsp->sdkctl);
384 
385     /* Now we can initiate connection witm MT port on the device. */
386     sdkctl_socket_connect(mtsp->sdkctl, SDKCTL_DEFAULT_TCP_PORT,
387                           SDKCTL_MT_TIMEOUT);
388 
389     return mtsp;
390 }
391 
392 void
mts_port_destroy(AndroidMTSPort * mtsp)393 mts_port_destroy(AndroidMTSPort* mtsp)
394 {
395     _mts_port_free(mtsp);
396 }
397 
398 /********************************************************************************
399  *                       Handling framebuffer updates
400  *******************************************************************************/
401 
402 /* Compresses a framebuffer region into JPEG image.
403  * Param:
404  *  mtsp - Multi-touch port descriptor with initialized JPEG compressor.
405  *  fmt Descriptor for framebuffer region to compress.
406  *  fb Beginning of the framebuffer.
407  *  jpeg_quality JPEG compression quality. A number from 1 to 100. Note that
408  *      value 10 provides pretty decent image for the purpose of multi-touch
409  *      emulation.
410  */
411 static void
_fb_compress(const AndroidMTSPort * mtsp,const MTFrameHeader * fmt,const uint8_t * fb,int jpeg_quality,int ydir)412 _fb_compress(const AndroidMTSPort* mtsp,
413              const MTFrameHeader* fmt,
414              const uint8_t* fb,
415              int jpeg_quality,
416              int ydir)
417 {
418     T("Multi-touch: compressing %d bytes frame buffer", fmt->w * fmt->h * fmt->bpp);
419 
420     jpeg_compressor_compress_fb(mtsp->jpeg_compressor, fmt->x, fmt->y, fmt->w,
421                                 fmt->h, fmt->disp_height, fmt->bpp, fmt->bpl,
422                                 fb, jpeg_quality, ydir);
423 }
424 
425 int
mts_port_send_frame(AndroidMTSPort * mtsp,MTFrameHeader * fmt,const uint8_t * fb,on_sdkctl_direct_cb cb,void * cb_opaque,int ydir)426 mts_port_send_frame(AndroidMTSPort* mtsp,
427                     MTFrameHeader* fmt,
428                     const uint8_t* fb,
429                     on_sdkctl_direct_cb cb,
430                     void* cb_opaque,
431                     int ydir)
432 {
433     /* Make sure that port is connected. */
434     if (!sdkctl_socket_is_port_ready(mtsp->sdkctl)) {
435         return -1;
436     }
437 
438     /* Compress framebuffer region. 10% quality seems to be sufficient. */
439     fmt->format = MTFB_JPEG;
440     _fb_compress(mtsp, fmt, fb, 10, ydir);
441 
442     /* Total size of the update data: header + JPEG image. */
443     const int update_size =
444         sizeof(MTFrameHeader) + jpeg_compressor_get_jpeg_size(mtsp->jpeg_compressor);
445 
446     /* Update message starts at the beginning of the buffer allocated by the
447      * compressor's destination manager. */
448     uint8_t* const msg = (uint8_t*)jpeg_compressor_get_buffer(mtsp->jpeg_compressor);
449 
450     /* Initialize message header. */
451     sdkctl_init_message_header(msg, SDKCTL_MT_FB_UPDATE, update_size);
452 
453     /* Copy framebuffer update header to the message. */
454     memcpy(msg + sdkctl_message_get_header_size(), fmt, sizeof(MTFrameHeader));
455 
456     /* Compression rate... */
457     const float comp_rate = ((float)jpeg_compressor_get_jpeg_size(mtsp->jpeg_compressor) / (fmt->w * fmt->h * fmt->bpp)) * 100;
458 
459     /* Zeroing the rectangle in the update header we indicate that it contains
460      * no updates. */
461     fmt->x = fmt->y = fmt->w = fmt->h = 0;
462 
463     /* Send update to the device. */
464     sdkctl_direct_packet_send(mtsp->fb_packet, msg, cb, cb_opaque);
465 
466     T("Multi-touch: Sent %d bytes in framebuffer update. Compression rate is %.2f%%",
467       update_size, comp_rate);
468 
469     return 0;
470 }
471