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