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 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 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 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 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 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 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 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 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 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 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 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 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 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 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* 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 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 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 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