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