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