1 2 /* 3 * Copyright (C) 2010 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include <errno.h> 19 #include <malloc.h> 20 #include <semaphore.h> 21 #include <ScopedLocalRef.h> 22 23 #include "com_android_nfc.h" 24 25 extern uint8_t device_connected_flag; 26 27 namespace android { 28 29 extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); 30 31 /* 32 * Callbacks 33 */ 34 static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) 35 { 36 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 37 LOG_CALLBACK("nfc_jni_presence_check_callback", status); 38 39 /* Report the callback status and wake up the caller */ 40 pCallbackData->status = status; 41 sem_post(&pCallbackData->sem); 42 } 43 44 static void nfc_jni_connect_callback(void *pContext, 45 phLibNfc_Handle /*hRemoteDev*/, 46 phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) 47 { 48 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 49 phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; 50 LOG_CALLBACK("nfc_jni_connect_callback", status); 51 52 if(status == NFCSTATUS_SUCCESS) 53 { 54 psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; 55 psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); 56 psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; 57 } 58 59 /* Report the callback status and wake up the caller */ 60 pCallbackData->status = status; 61 sem_post(&pCallbackData->sem); 62 } 63 64 static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle /*hRemoteDev*/, NFCSTATUS status) 65 { 66 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 67 LOG_CALLBACK("nfc_jni_disconnect_callback", status); 68 69 /* Report the callback status and wake up the caller */ 70 pCallbackData->status = status; 71 sem_post(&pCallbackData->sem); 72 } 73 74 static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) 75 { 76 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 77 phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; 78 LOG_CALLBACK("nfc_jni_receive_callback", status); 79 80 if(status == NFCSTATUS_SUCCESS) 81 { 82 *ptr = data; 83 } 84 else 85 { 86 *ptr = NULL; 87 } 88 89 /* Report the callback status and wake up the caller */ 90 pCallbackData->status = status; 91 sem_post(&pCallbackData->sem); 92 } 93 94 static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) 95 { 96 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 97 LOG_CALLBACK("nfc_jni_send_callback", status); 98 99 /* Report the callback status and wake up the caller */ 100 pCallbackData->status = status; 101 sem_post(&pCallbackData->sem); 102 } 103 104 /* 105 * Functions 106 */ 107 108 static void nfc_jni_transceive_callback(void *pContext, 109 phLibNfc_Handle /*handle*/, phNfc_sData_t *pResBuffer, NFCSTATUS status) 110 { 111 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; 112 LOG_CALLBACK("nfc_jni_transceive_callback", status); 113 114 /* Report the callback data and wake up the caller */ 115 pCallbackData->pContext = pResBuffer; 116 pCallbackData->status = status; 117 sem_post(&pCallbackData->sem); 118 } 119 120 static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) 121 { 122 phLibNfc_Handle handle = 0; 123 NFCSTATUS status; 124 jboolean result = JNI_FALSE; 125 struct nfc_jni_callback_data cb_data; 126 127 ScopedLocalRef<jclass> target_cls(e, NULL); 128 jobject tag; 129 jmethodID ctor; 130 jfieldID f; 131 jbyteArray generalBytes = NULL; 132 phNfc_sData_t sGeneralBytes; 133 unsigned int i; 134 135 CONCURRENCY_LOCK(); 136 137 handle = nfc_jni_get_p2p_device_handle(e, o); 138 139 /* Create the local semaphore */ 140 if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) 141 { 142 goto clean_and_return; 143 } 144 145 TRACE("phLibNfc_RemoteDev_Connect(P2P)"); 146 REENTRANCE_LOCK(); 147 status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); 148 REENTRANCE_UNLOCK(); 149 if(status != NFCSTATUS_PENDING) 150 { 151 ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 152 goto clean_and_return; 153 } 154 TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 155 156 /* Wait for callback response */ 157 if(sem_wait(&cb_data.sem)) 158 { 159 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); 160 goto clean_and_return; 161 } 162 163 if(cb_data.status != NFCSTATUS_SUCCESS) 164 { 165 goto clean_and_return; 166 } 167 168 /* Set General Bytes */ 169 target_cls.reset(e->GetObjectClass(o)); 170 171 f = e->GetFieldID(target_cls.get(), "mGeneralBytes", "[B"); 172 173 TRACE("General Bytes Length = %d", sGeneralBytes.length); 174 TRACE("General Bytes ="); 175 for(i=0;i<sGeneralBytes.length;i++) 176 { 177 TRACE("0x%02x ", sGeneralBytes.buffer[i]); 178 } 179 180 generalBytes = e->NewByteArray(sGeneralBytes.length); 181 182 e->SetByteArrayRegion(generalBytes, 0, 183 sGeneralBytes.length, 184 (jbyte *)sGeneralBytes.buffer); 185 186 e->SetObjectField(o, f, generalBytes); 187 188 result = JNI_TRUE; 189 190 clean_and_return: 191 if (result != JNI_TRUE) 192 { 193 /* Restart the polling loop if the connection failed */ 194 nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); 195 } 196 nfc_cb_data_deinit(&cb_data); 197 CONCURRENCY_UNLOCK(); 198 return result; 199 } 200 201 static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) 202 { 203 phLibNfc_Handle handle = 0; 204 jboolean result = JNI_FALSE; 205 NFCSTATUS status; 206 struct nfc_jni_callback_data cb_data; 207 208 CONCURRENCY_LOCK(); 209 210 handle = nfc_jni_get_p2p_device_handle(e, o); 211 212 /* Create the local semaphore */ 213 if (!nfc_cb_data_init(&cb_data, NULL)) 214 { 215 goto clean_and_return; 216 } 217 218 /* Disconnect */ 219 TRACE("Disconnecting from target (handle = 0x%x)", handle); 220 221 /* NativeNfcTag waits for tag to leave the field here with presence check. 222 * We do not in P2P path because presence check is not safe while transceive may be 223 * in progress. 224 */ 225 226 TRACE("phLibNfc_RemoteDev_Disconnect()"); 227 REENTRANCE_LOCK(); 228 status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); 229 REENTRANCE_UNLOCK(); 230 if(status != NFCSTATUS_PENDING) 231 { 232 ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 233 if(status == NFCSTATUS_TARGET_NOT_CONNECTED) 234 { 235 ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); 236 } 237 else 238 { 239 ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); 240 nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); 241 } 242 243 goto clean_and_return; 244 } 245 TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 246 247 /* Wait for callback response */ 248 if(sem_wait(&cb_data.sem)) 249 { 250 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); 251 goto clean_and_return; 252 } 253 254 /* Disconnect Status */ 255 if(cb_data.status != NFCSTATUS_SUCCESS) 256 { 257 goto clean_and_return; 258 } 259 260 result = JNI_TRUE; 261 262 clean_and_return: 263 /* Reset device connected flag */ 264 device_connected_flag = 0; 265 nfc_cb_data_deinit(&cb_data); 266 CONCURRENCY_UNLOCK(); 267 return result; 268 } 269 270 static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, 271 jobject o, jbyteArray data) 272 { 273 NFCSTATUS status; 274 uint8_t offset = 2; 275 uint8_t *buf; 276 uint32_t buflen; 277 phLibNfc_sTransceiveInfo_t transceive_info; 278 jbyteArray result = NULL; 279 phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); 280 phNfc_sData_t * receive_buffer = NULL; 281 struct nfc_jni_callback_data cb_data; 282 283 CONCURRENCY_LOCK(); 284 285 /* Create the local semaphore */ 286 if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) 287 { 288 goto clean_and_return; 289 } 290 291 /* Transceive*/ 292 TRACE("Transceive data to target (handle = 0x%x)", handle); 293 294 buf = (uint8_t *)e->GetByteArrayElements(data, NULL); 295 buflen = (uint32_t)e->GetArrayLength(data); 296 297 TRACE("Buffer Length = %d\n", buflen); 298 299 transceive_info.sSendData.buffer = buf; //+ offset; 300 transceive_info.sSendData.length = buflen; //- offset; 301 transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); 302 transceive_info.sRecvData.length = 1024; 303 304 if(transceive_info.sRecvData.buffer == NULL) 305 { 306 goto clean_and_return; 307 } 308 309 TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); 310 REENTRANCE_LOCK(); 311 status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); 312 REENTRANCE_UNLOCK(); 313 if(status != NFCSTATUS_PENDING) 314 { 315 ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 316 goto clean_and_return; 317 } 318 TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 319 320 /* Wait for callback response */ 321 if(sem_wait(&cb_data.sem)) 322 { 323 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); 324 goto clean_and_return; 325 } 326 327 if(cb_data.status != NFCSTATUS_SUCCESS) 328 { 329 goto clean_and_return; 330 } 331 332 /* Copy results back to Java */ 333 result = e->NewByteArray(receive_buffer->length); 334 if(result != NULL) 335 e->SetByteArrayRegion(result, 0, 336 receive_buffer->length, 337 (jbyte *)receive_buffer->buffer); 338 339 clean_and_return: 340 if(transceive_info.sRecvData.buffer != NULL) 341 { 342 free(transceive_info.sRecvData.buffer); 343 } 344 345 e->ReleaseByteArrayElements(data, 346 (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); 347 348 nfc_cb_data_deinit(&cb_data); 349 350 CONCURRENCY_UNLOCK(); 351 352 return result; 353 } 354 355 356 static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( 357 JNIEnv *e, jobject o) 358 { 359 NFCSTATUS status; 360 struct timespec ts; 361 phLibNfc_Handle handle; 362 jbyteArray buf = NULL; 363 static phNfc_sData_t *data; 364 struct nfc_jni_callback_data cb_data; 365 366 CONCURRENCY_LOCK(); 367 368 handle = nfc_jni_get_p2p_device_handle(e, o); 369 370 /* Create the local semaphore */ 371 if (!nfc_cb_data_init(&cb_data, (void*)data)) 372 { 373 goto clean_and_return; 374 } 375 376 /* Receive */ 377 TRACE("phLibNfc_RemoteDev_Receive()"); 378 REENTRANCE_LOCK(); 379 status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); 380 REENTRANCE_UNLOCK(); 381 if(status != NFCSTATUS_PENDING) 382 { 383 ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 384 goto clean_and_return; 385 } 386 TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 387 388 /* Wait for callback response */ 389 if(sem_wait(&cb_data.sem)) 390 { 391 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); 392 goto clean_and_return; 393 } 394 395 if(data == NULL) 396 { 397 goto clean_and_return; 398 } 399 400 buf = e->NewByteArray(data->length); 401 e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); 402 403 clean_and_return: 404 nfc_cb_data_deinit(&cb_data); 405 CONCURRENCY_UNLOCK(); 406 return buf; 407 } 408 409 static jboolean com_android_nfc_NativeP2pDevice_doSend( 410 JNIEnv *e, jobject o, jbyteArray buf) 411 { 412 NFCSTATUS status; 413 phNfc_sData_t data; 414 jboolean result = JNI_FALSE; 415 struct nfc_jni_callback_data cb_data; 416 417 phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); 418 419 CONCURRENCY_LOCK(); 420 421 /* Create the local semaphore */ 422 if (!nfc_cb_data_init(&cb_data, NULL)) 423 { 424 goto clean_and_return; 425 } 426 427 /* Send */ 428 TRACE("Send data to the Initiator (handle = 0x%x)", handle); 429 430 data.length = (uint32_t)e->GetArrayLength(buf); 431 data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); 432 433 TRACE("phLibNfc_RemoteDev_Send()"); 434 REENTRANCE_LOCK(); 435 status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); 436 REENTRANCE_UNLOCK(); 437 if(status != NFCSTATUS_PENDING) 438 { 439 ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 440 goto clean_and_return; 441 } 442 TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); 443 444 /* Wait for callback response */ 445 if(sem_wait(&cb_data.sem)) 446 { 447 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); 448 goto clean_and_return; 449 } 450 451 if(cb_data.status != NFCSTATUS_SUCCESS) 452 { 453 goto clean_and_return; 454 } 455 456 result = JNI_TRUE; 457 458 clean_and_return: 459 if (result != JNI_TRUE) 460 { 461 e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); 462 } 463 nfc_cb_data_deinit(&cb_data); 464 CONCURRENCY_UNLOCK(); 465 return result; 466 } 467 468 /* 469 * JNI registration. 470 */ 471 static JNINativeMethod gMethods[] = 472 { 473 {"doConnect", "()Z", 474 (void *)com_android_nfc_NativeP2pDevice_doConnect}, 475 {"doDisconnect", "()Z", 476 (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, 477 {"doTransceive", "([B)[B", 478 (void *)com_android_nfc_NativeP2pDevice_doTransceive}, 479 {"doReceive", "()[B", 480 (void *)com_android_nfc_NativeP2pDevice_doReceive}, 481 {"doSend", "([B)Z", 482 (void *)com_android_nfc_NativeP2pDevice_doSend}, 483 }; 484 485 int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) 486 { 487 return jniRegisterNativeMethods(e, 488 "com/android/nfc/dhimpl/NativeP2pDevice", 489 gMethods, NELEM(gMethods)); 490 } 491 492 } // namepspace android 493