1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <semaphore.h>
18#include <errno.h>
19
20#include "com_android_nfc.h"
21
22namespace android {
23
24/*
25 * Callbacks
26 */
27
28static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status)
29{
30   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
31   LOG_CALLBACK("nfc_jni_receiveFrom_callback", status);
32
33   if(status == NFCSTATUS_SUCCESS)
34   {
35      pCallbackData->pContext = (void*)ssap;
36      TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap);
37   }
38
39   /* Report the callback status and wake up the caller */
40   pCallbackData->status = status;
41   sem_post(&pCallbackData->sem);
42}
43
44static void nfc_jni_send_callback(void *pContext, NFCSTATUS status)
45{
46   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
47   LOG_CALLBACK("nfc_jni_sendTo_callback", status);
48
49   /* Report the callback status and wake up the caller */
50   pCallbackData->status = status;
51   sem_post(&pCallbackData->sem);
52}
53
54/*
55* Methods
56*/
57static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data)
58{
59   NFCSTATUS ret;
60   struct timespec ts;
61   phLibNfc_Handle hRemoteDevice;
62   phLibNfc_Handle hLlcpSocket;
63   phNfc_sData_t sSendBuffer = {NULL, 0};
64   struct nfc_jni_callback_data cb_data;
65   jboolean result = JNI_FALSE;
66
67   /* Retrieve handles */
68   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
69   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
70
71   /* Create the local semaphore */
72   if (!nfc_cb_data_init(&cb_data, NULL))
73   {
74      goto clean_and_return;
75   }
76
77   sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
78   sSendBuffer.length = (uint32_t)e->GetArrayLength(data);
79
80   TRACE("phLibNfc_Llcp_SendTo()");
81   REENTRANCE_LOCK();
82   ret = phLibNfc_Llcp_SendTo(hRemoteDevice,
83                              hLlcpSocket,
84                              nsap,
85                              &sSendBuffer,
86                              nfc_jni_send_callback,
87                              (void*)&cb_data);
88   REENTRANCE_UNLOCK();
89   if(ret != NFCSTATUS_PENDING)
90   {
91      LOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
92      goto clean_and_return;
93   }
94   TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
95
96   /* Wait for callback response */
97   if(sem_wait(&cb_data.sem))
98   {
99      LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
100      goto clean_and_return;
101   }
102
103   if(cb_data.status != NFCSTATUS_SUCCESS)
104   {
105      goto clean_and_return;
106   }
107
108   result = JNI_TRUE;
109
110clean_and_return:
111   if (sSendBuffer.buffer != NULL)
112   {
113      e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT);
114   }
115   nfc_cb_data_deinit(&cb_data);
116   return result;
117}
118
119static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu)
120{
121   NFCSTATUS ret;
122   struct timespec ts;
123   uint8_t ssap;
124   jobject llcpPacket = NULL;
125   phLibNfc_Handle hRemoteDevice;
126   phLibNfc_Handle hLlcpSocket;
127   phNfc_sData_t sReceiveBuffer;
128   jclass clsLlcpPacket;
129   jfieldID f;
130   jbyteArray receivedData = NULL;
131   struct nfc_jni_callback_data cb_data;
132
133   /* Create the local semaphore */
134   if (!nfc_cb_data_init(&cb_data, NULL))
135   {
136      goto clean_and_return;
137   }
138
139   /* Create new LlcpPacket object */
140   if(nfc_jni_cache_object(e,"android/nfc/LlcpPacket",&(llcpPacket)) == -1)
141   {
142      LOGE("Find LlcpPacket class error");
143      goto clean_and_return;
144   }
145
146   /* Get NativeConnectionless class object */
147   clsLlcpPacket = e->GetObjectClass(llcpPacket);
148   if(e->ExceptionCheck())
149   {
150      LOGE("Get Object class error");
151      goto clean_and_return;
152   }
153
154   /* Retrieve handles */
155   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
156   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
157   TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu);
158
159   sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu);
160   sReceiveBuffer.length = linkMiu;
161
162   REENTRANCE_LOCK();
163   ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice,
164                                hLlcpSocket,
165                                &sReceiveBuffer,
166                                nfc_jni_receive_callback,
167                                &cb_data);
168   REENTRANCE_UNLOCK();
169   if(ret != NFCSTATUS_PENDING)
170   {
171      LOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
172      goto clean_and_return;
173   }
174   TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
175
176   /* Wait for callback response */
177   if(sem_wait(&cb_data.sem))
178   {
179      LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
180      goto clean_and_return;
181   }
182
183   if(cb_data.status != NFCSTATUS_SUCCESS)
184   {
185       goto clean_and_return;
186   }
187
188   ssap = (uint32_t)cb_data.pContext;
189   TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length);
190
191   /* Set Llcp Packet remote SAP */
192   f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I");
193   e->SetIntField(llcpPacket, f,(jbyte)ssap);
194
195   /* Set Llcp Packet Buffer */
196   LOGD("Set LlcpPacket Data Buffer\n");
197   f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B");
198   receivedData = e->NewByteArray(sReceiveBuffer.length);
199   e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer);
200   e->SetObjectField(llcpPacket, f, receivedData);
201
202clean_and_return:
203   if (receivedData != NULL)
204   {
205      e->ReleaseByteArrayElements(receivedData, (jbyte*)sReceiveBuffer.buffer, 0);
206   }
207   nfc_cb_data_deinit(&cb_data);
208   return llcpPacket;
209}
210
211static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o)
212{
213   NFCSTATUS ret;
214   phLibNfc_Handle hLlcpSocket;
215   TRACE("Close Connectionless socket");
216
217   /* Retrieve socket handle */
218   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
219
220   TRACE("phLibNfc_Llcp_Close()");
221   REENTRANCE_LOCK();
222   ret = phLibNfc_Llcp_Close(hLlcpSocket);
223   REENTRANCE_UNLOCK();
224   if(ret == NFCSTATUS_SUCCESS)
225   {
226      TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
227      return TRUE;
228   }
229   else
230   {
231      LOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
232      return FALSE;
233   }
234}
235
236
237/*
238 * JNI registration.
239 */
240static JNINativeMethod gMethods[] =
241{
242   {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo},
243
244   {"doReceiveFrom", "(I)Landroid/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom},
245
246   {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose},
247};
248
249
250int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e)
251{
252   return jniRegisterNativeMethods(e,
253      "com/android/nfc/nxp/NativeLlcpConnectionlessSocket",
254      gMethods, NELEM(gMethods));
255}
256
257} // android namespace
258