| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <semaphore.h> |
| #include <errno.h> |
| |
| #include "com_android_nfc.h" |
| |
| namespace android { |
| |
| /* |
| * Callbacks |
| */ |
| |
| static void nfc_jni_disconnect_callback(void* pContext, |
| NFCSTATUS status) |
| { |
| struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; |
| LOG_CALLBACK("nfc_jni_disconnect_callback", status); |
| |
| /* Report the callback status and wake up the caller */ |
| pCallbackData->status = status; |
| sem_post(&pCallbackData->sem); |
| } |
| |
| |
| static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) |
| { |
| struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; |
| LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); |
| |
| if(status == NFCSTATUS_SUCCESS) |
| { |
| TRACE("Socket connected\n"); |
| } |
| else |
| { |
| ALOGD("Socket not connected:"); |
| switch(nErrCode) |
| { |
| case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: |
| { |
| ALOGD("> SAP NOT ACTIVE\n"); |
| }break; |
| |
| case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: |
| { |
| ALOGD("> SAP NOT FOUND\n"); |
| }break; |
| |
| case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: |
| { |
| ALOGD("> CONNECT REJECTED\n"); |
| }break; |
| |
| case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: |
| { |
| ALOGD("> CONNECT NOT ACCEPTED\n"); |
| }break; |
| |
| case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: |
| { |
| ALOGD("> SOCKET NOT AVAILABLE\n"); |
| }break; |
| } |
| } |
| |
| /* Report the callback status and wake up the caller */ |
| pCallbackData->status = status; |
| sem_post(&pCallbackData->sem); |
| } |
| |
| |
| |
| |
| static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) |
| { |
| struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; |
| LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); |
| |
| /* Report the callback status and wake up the caller */ |
| pCallbackData->status = status; |
| sem_post(&pCallbackData->sem); |
| } |
| |
| static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) |
| { |
| struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; |
| LOG_CALLBACK("nfc_jni_llcp_send_callback", status); |
| |
| /* Report the callback status and wake up the caller */ |
| pCallbackData->status = status; |
| sem_post(&pCallbackData->sem); |
| } |
| |
| /* |
| * Methods |
| */ |
| static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) |
| { |
| NFCSTATUS ret; |
| struct timespec ts; |
| phLibNfc_Handle hRemoteDevice; |
| phLibNfc_Handle hLlcpSocket; |
| struct nfc_jni_callback_data cb_data; |
| jboolean result = JNI_FALSE; |
| |
| /* Retrieve handles */ |
| hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); |
| hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); |
| |
| /* Create the local semaphore */ |
| if (!nfc_cb_data_init(&cb_data, NULL)) |
| { |
| goto clean_and_return; |
| } |
| |
| TRACE("phLibNfc_Llcp_Connect(%d)",nSap); |
| REENTRANCE_LOCK(); |
| ret = phLibNfc_Llcp_Connect(hRemoteDevice, |
| hLlcpSocket, |
| nSap, |
| nfc_jni_connect_callback, |
| (void*)&cb_data); |
| REENTRANCE_UNLOCK(); |
| if(ret != NFCSTATUS_PENDING) |
| { |
| ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); |
| goto clean_and_return; |
| } |
| TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); |
| |
| /* Wait for callback response */ |
| if(sem_wait(&cb_data.sem)) |
| { |
| ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); |
| goto clean_and_return; |
| } |
| |
| if(cb_data.status != NFCSTATUS_SUCCESS) |
| { |
| ALOGW("LLCP Connect request failed"); |
| goto clean_and_return; |
| } |
| |
| result = JNI_TRUE; |
| |
| clean_and_return: |
| nfc_cb_data_deinit(&cb_data); |
| return result; |
| } |
| |
| static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) |
| { |
| NFCSTATUS ret; |
| struct timespec ts; |
| phNfc_sData_t serviceName = {0}; |
| phLibNfc_Handle hRemoteDevice; |
| phLibNfc_Handle hLlcpSocket; |
| struct nfc_jni_callback_data cb_data; |
| jboolean result = JNI_FALSE; |
| |
| /* Retrieve handles */ |
| hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); |
| hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); |
| |
| /* Create the local semaphore */ |
| if (!nfc_cb_data_init(&cb_data, NULL)) |
| { |
| goto clean_and_return; |
| } |
| |
| /* Service socket */ |
| serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); |
| serviceName.length = (uint32_t)e->GetStringUTFLength(sn); |
| |
| TRACE("phLibNfc_Llcp_ConnectByUri()"); |
| REENTRANCE_LOCK(); |
| ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, |
| hLlcpSocket, |
| &serviceName, |
| nfc_jni_connect_callback, |
| (void*)&cb_data); |
| REENTRANCE_UNLOCK(); |
| if(ret != NFCSTATUS_PENDING) |
| { |
| ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| goto clean_and_return; |
| } |
| TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| |
| /* Wait for callback response */ |
| if(sem_wait(&cb_data.sem)) |
| { |
| ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); |
| goto clean_and_return; |
| } |
| |
| if(cb_data.status != NFCSTATUS_SUCCESS) |
| { |
| goto clean_and_return; |
| } |
| |
| result = JNI_TRUE; |
| |
| clean_and_return: |
| if (serviceName.buffer != NULL) { |
| e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); |
| } |
| nfc_cb_data_deinit(&cb_data); |
| return result; |
| } |
| |
| static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) |
| { |
| NFCSTATUS ret; |
| phLibNfc_Handle hLlcpSocket; |
| |
| /* Retrieve socket handle */ |
| hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); |
| |
| TRACE("phLibNfc_Llcp_Close()"); |
| REENTRANCE_LOCK(); |
| ret = phLibNfc_Llcp_Close(hLlcpSocket); |
| REENTRANCE_UNLOCK(); |
| if(ret != NFCSTATUS_SUCCESS) |
| { |
| ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| return FALSE; |
| } |
| TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| return TRUE; |
| } |
| |
| static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) |
| { |
| NFCSTATUS ret; |
| struct timespec ts; |
| phLibNfc_Handle hRemoteDevice; |
| phLibNfc_Handle hLlcpSocket; |
| phNfc_sData_t sSendBuffer = {NULL, 0}; |
| struct nfc_jni_callback_data cb_data; |
| jboolean result = JNI_FALSE; |
| |
| /* Retrieve handles */ |
| hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); |
| hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); |
| |
| /* Create the local semaphore */ |
| if (!nfc_cb_data_init(&cb_data, NULL)) |
| { |
| goto clean_and_return; |
| } |
| |
| sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); |
| sSendBuffer.length = (uint32_t)e->GetArrayLength(data); |
| |
| TRACE("phLibNfc_Llcp_Send()"); |
| REENTRANCE_LOCK(); |
| ret = phLibNfc_Llcp_Send(hRemoteDevice, |
| hLlcpSocket, |
| &sSendBuffer, |
| nfc_jni_send_callback, |
| (void*)&cb_data); |
| REENTRANCE_UNLOCK(); |
| if(ret != NFCSTATUS_PENDING) |
| { |
| ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| goto clean_and_return; |
| } |
| TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| |
| /* Wait for callback response */ |
| if(sem_wait(&cb_data.sem)) |
| { |
| ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); |
| goto clean_and_return; |
| } |
| |
| if(cb_data.status != NFCSTATUS_SUCCESS) |
| { |
| goto clean_and_return; |
| } |
| |
| result = JNI_TRUE; |
| |
| clean_and_return: |
| if (sSendBuffer.buffer != NULL) |
| { |
| e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); |
| } |
| nfc_cb_data_deinit(&cb_data); |
| return result; |
| } |
| |
| static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) |
| { |
| NFCSTATUS ret; |
| struct timespec ts; |
| phLibNfc_Handle hRemoteDevice; |
| phLibNfc_Handle hLlcpSocket; |
| phNfc_sData_t sReceiveBuffer = {NULL, 0}; |
| struct nfc_jni_callback_data cb_data; |
| jint result = -1; |
| |
| /* Retrieve handles */ |
| hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); |
| hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); |
| |
| /* Create the local semaphore */ |
| if (!nfc_cb_data_init(&cb_data, NULL)) |
| { |
| goto clean_and_return; |
| } |
| |
| sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); |
| sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); |
| |
| TRACE("phLibNfc_Llcp_Recv()"); |
| REENTRANCE_LOCK(); |
| ret = phLibNfc_Llcp_Recv(hRemoteDevice, |
| hLlcpSocket, |
| &sReceiveBuffer, |
| nfc_jni_receive_callback, |
| (void*)&cb_data); |
| REENTRANCE_UNLOCK(); |
| if(ret == NFCSTATUS_PENDING) |
| { |
| /* Wait for callback response */ |
| if(sem_wait(&cb_data.sem)) |
| { |
| ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); |
| goto clean_and_return; |
| } |
| |
| if(cb_data.status == NFCSTATUS_SUCCESS) |
| { |
| result = sReceiveBuffer.length; |
| } |
| } |
| else if (ret == NFCSTATUS_SUCCESS) |
| { |
| result = sReceiveBuffer.length; |
| } |
| else |
| { |
| /* Return status should be either SUCCESS or PENDING */ |
| ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| goto clean_and_return; |
| } |
| TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| |
| clean_and_return: |
| if (sReceiveBuffer.buffer != NULL) |
| { |
| e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); |
| } |
| nfc_cb_data_deinit(&cb_data); |
| return result; |
| } |
| |
| static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) |
| { |
| NFCSTATUS ret; |
| phLibNfc_Handle hRemoteDevice; |
| phLibNfc_Handle hLlcpSocket; |
| phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; |
| |
| /* Retrieve handles */ |
| hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); |
| hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); |
| |
| TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); |
| REENTRANCE_LOCK(); |
| ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, |
| hLlcpSocket, |
| &remoteSocketOption); |
| REENTRANCE_UNLOCK(); |
| if(ret == NFCSTATUS_SUCCESS) |
| { |
| TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| return remoteSocketOption.miu; |
| } |
| else |
| { |
| ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| return 0; |
| } |
| } |
| |
| static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) |
| { |
| NFCSTATUS ret; |
| phLibNfc_Handle hRemoteDevice; |
| phLibNfc_Handle hLlcpSocket; |
| phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; |
| |
| /* Retrieve handles */ |
| hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); |
| hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); |
| |
| TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); |
| REENTRANCE_LOCK(); |
| ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, |
| hLlcpSocket, |
| &remoteSocketOption); |
| REENTRANCE_UNLOCK(); |
| if(ret == NFCSTATUS_SUCCESS) |
| { |
| TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| return remoteSocketOption.rw; |
| } |
| else |
| { |
| ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); |
| return 0; |
| } |
| } |
| |
| |
| /* |
| * JNI registration. |
| */ |
| static JNINativeMethod gMethods[] = |
| { |
| {"doConnect", "(I)Z", |
| (void *)com_android_nfc_NativeLlcpSocket_doConnect}, |
| |
| {"doConnectBy", "(Ljava/lang/String;)Z", |
| (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, |
| |
| {"doClose", "()Z", |
| (void *)com_android_nfc_NativeLlcpSocket_doClose}, |
| |
| {"doSend", "([B)Z", |
| (void *)com_android_nfc_NativeLlcpSocket_doSend}, |
| |
| {"doReceive", "([B)I", |
| (void *)com_android_nfc_NativeLlcpSocket_doReceive}, |
| |
| {"doGetRemoteSocketMiu", "()I", |
| (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, |
| |
| {"doGetRemoteSocketRw", "()I", |
| (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, |
| }; |
| |
| |
| int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) |
| { |
| return jniRegisterNativeMethods(e, |
| "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); |
| } |
| |
| } // namespace android |