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