com_android_nfc_NativeP2pDevice.cpp revision 7f5487be0414b1f92b41cc5f7b0b7db846d9b1c9
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      goto clean_and_return;
149    }
150    TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
151
152    /* Wait for callback response */
153    if(sem_wait(&cb_data.sem))
154    {
155       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
156       goto clean_and_return;
157    }
158
159    if(cb_data.status != NFCSTATUS_SUCCESS)
160    {
161        goto clean_and_return;
162    }
163
164    /* Set General Bytes */
165    target_cls = e->GetObjectClass(o);
166
167    f = e->GetFieldID(target_cls, "mGeneralBytes", "[B");
168
169    TRACE("General Bytes Length = %d", sGeneralBytes.length);
170    TRACE("General Bytes =");
171    for(i=0;i<sGeneralBytes.length;i++)
172    {
173      TRACE("0x%02x ", sGeneralBytes.buffer[i]);
174    }
175
176    generalBytes = e->NewByteArray(sGeneralBytes.length);
177
178    e->SetByteArrayRegion(generalBytes, 0,
179                         sGeneralBytes.length,
180                         (jbyte *)sGeneralBytes.buffer);
181
182    e->SetObjectField(o, f, generalBytes);
183
184    result = JNI_TRUE;
185
186clean_and_return:
187    if (result != JNI_TRUE)
188    {
189       /* Restart the polling loop if the connection failed */
190       nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
191    }
192    nfc_cb_data_deinit(&cb_data);
193    CONCURRENCY_UNLOCK();
194    return result;
195}
196
197static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o)
198{
199    phLibNfc_Handle     handle = 0;
200    jboolean            result = JNI_FALSE;
201    NFCSTATUS           status;
202    struct nfc_jni_callback_data cb_data;
203
204    CONCURRENCY_LOCK();
205
206    handle = nfc_jni_get_p2p_device_handle(e, o);
207
208    /* Create the local semaphore */
209    if (!nfc_cb_data_init(&cb_data, NULL))
210    {
211       goto clean_and_return;
212    }
213
214    /* Disconnect */
215    TRACE("Disconnecting from target (handle = 0x%x)", handle);
216
217    /* NativeNfcTag waits for tag to leave the field here with presence check.
218     * We do not in P2P path because presence check is not safe while transceive may be
219     * in progress.
220     */
221
222    TRACE("phLibNfc_RemoteDev_Disconnect()");
223    REENTRANCE_LOCK();
224    status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data);
225    REENTRANCE_UNLOCK();
226    if(status != NFCSTATUS_PENDING)
227    {
228        LOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
229        if(status == NFCSTATUS_TARGET_NOT_CONNECTED)
230        {
231            LOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected");
232        }
233        else
234        {
235            LOGE("phLibNfc_RemoteDev_Disconnect() failed");
236            nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
237        }
238
239        goto clean_and_return;
240    }
241    TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
242
243    /* Wait for callback response */
244    if(sem_wait(&cb_data.sem))
245    {
246       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
247       goto clean_and_return;
248    }
249
250    /* Disconnect Status */
251    if(cb_data.status != NFCSTATUS_SUCCESS)
252    {
253        goto clean_and_return;
254    }
255    result = JNI_TRUE;
256
257clean_and_return:
258    nfc_cb_data_deinit(&cb_data);
259    CONCURRENCY_UNLOCK();
260    return result;
261}
262
263static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e,
264   jobject o, jbyteArray data)
265{
266   NFCSTATUS status;
267   uint8_t offset = 2;
268   uint8_t *buf;
269   uint32_t buflen;
270   phLibNfc_sTransceiveInfo_t transceive_info;
271   jbyteArray result = NULL;
272   phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
273   phNfc_sData_t * receive_buffer = NULL;
274   struct nfc_jni_callback_data cb_data;
275
276   CONCURRENCY_LOCK();
277
278   /* Create the local semaphore */
279   if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer))
280   {
281      goto clean_and_return;
282   }
283
284   /* Transceive*/
285   TRACE("Transceive data to target (handle = 0x%x)", handle);
286
287   buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
288   buflen = (uint32_t)e->GetArrayLength(data);
289
290   TRACE("Buffer Length = %d\n", buflen);
291
292   transceive_info.sSendData.buffer = buf; //+ offset;
293   transceive_info.sSendData.length = buflen; //- offset;
294   transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
295   transceive_info.sRecvData.length = 1024;
296
297   if(transceive_info.sRecvData.buffer == NULL)
298   {
299      goto clean_and_return;
300   }
301
302   TRACE("phLibNfc_RemoteDev_Transceive(P2P)");
303   REENTRANCE_LOCK();
304   status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data);
305   REENTRANCE_UNLOCK();
306   if(status != NFCSTATUS_PENDING)
307   {
308      LOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
309      goto clean_and_return;
310   }
311   TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
312
313   /* Wait for callback response */
314   if(sem_wait(&cb_data.sem))
315   {
316      LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
317      goto clean_and_return;
318   }
319
320   if(cb_data.status != NFCSTATUS_SUCCESS)
321   {
322      goto clean_and_return;
323   }
324
325   /* Copy results back to Java */
326   result = e->NewByteArray(receive_buffer->length);
327   if(result != NULL)
328      e->SetByteArrayRegion(result, 0,
329         receive_buffer->length,
330         (jbyte *)receive_buffer->buffer);
331
332clean_and_return:
333   if(transceive_info.sRecvData.buffer != NULL)
334   {
335      free(transceive_info.sRecvData.buffer);
336   }
337
338   e->ReleaseByteArrayElements(data,
339      (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);
340
341   nfc_cb_data_deinit(&cb_data);
342
343   CONCURRENCY_UNLOCK();
344
345   return result;
346}
347
348
349static jbyteArray com_android_nfc_NativeP2pDevice_doReceive(
350   JNIEnv *e, jobject o)
351{
352   NFCSTATUS status;
353   struct timespec ts;
354   phLibNfc_Handle handle;
355   jbyteArray buf = NULL;
356   static phNfc_sData_t *data;
357   struct nfc_jni_callback_data cb_data;
358
359   CONCURRENCY_LOCK();
360
361   handle = nfc_jni_get_p2p_device_handle(e, o);
362
363   /* Create the local semaphore */
364   if (!nfc_cb_data_init(&cb_data, (void*)data))
365   {
366      goto clean_and_return;
367   }
368
369   /* Receive */
370   TRACE("phLibNfc_RemoteDev_Receive()");
371   REENTRANCE_LOCK();
372   status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data);
373   REENTRANCE_UNLOCK();
374   if(status != NFCSTATUS_PENDING)
375   {
376      LOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
377      goto clean_and_return;
378   }
379   TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
380
381   /* Wait for callback response */
382   if(sem_wait(&cb_data.sem))
383   {
384      LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
385      goto clean_and_return;
386   }
387
388   if(data == NULL)
389   {
390      goto clean_and_return;
391   }
392
393   buf = e->NewByteArray(data->length);
394   e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer);
395
396clean_and_return:
397   nfc_cb_data_deinit(&cb_data);
398   CONCURRENCY_UNLOCK();
399   return buf;
400}
401
402static jboolean com_android_nfc_NativeP2pDevice_doSend(
403   JNIEnv *e, jobject o, jbyteArray buf)
404{
405   NFCSTATUS status;
406   phNfc_sData_t data;
407   jboolean result = JNI_FALSE;
408   struct nfc_jni_callback_data cb_data;
409
410   phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
411
412   CONCURRENCY_LOCK();
413
414   /* Create the local semaphore */
415   if (!nfc_cb_data_init(&cb_data, NULL))
416   {
417      goto clean_and_return;
418   }
419
420   /* Send */
421   TRACE("Send data to the Initiator (handle = 0x%x)", handle);
422
423   data.length = (uint32_t)e->GetArrayLength(buf);
424   data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL);
425
426   TRACE("phLibNfc_RemoteDev_Send()");
427   REENTRANCE_LOCK();
428   status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data);
429   REENTRANCE_UNLOCK();
430   if(status != NFCSTATUS_PENDING)
431   {
432      LOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
433      goto clean_and_return;
434   }
435   TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
436
437   /* Wait for callback response */
438   if(sem_wait(&cb_data.sem))
439   {
440      LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
441      goto clean_and_return;
442   }
443
444   if(cb_data.status != NFCSTATUS_SUCCESS)
445   {
446      goto clean_and_return;
447   }
448
449   result = JNI_TRUE;
450
451clean_and_return:
452   if (result != JNI_TRUE)
453   {
454      e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT);
455   }
456   nfc_cb_data_deinit(&cb_data);
457   CONCURRENCY_UNLOCK();
458   return result;
459}
460
461/*
462 * JNI registration.
463 */
464static JNINativeMethod gMethods[] =
465{
466   {"doConnect", "()Z",
467      (void *)com_android_nfc_NativeP2pDevice_doConnect},
468   {"doDisconnect", "()Z",
469      (void *)com_android_nfc_NativeP2pDevice_doDisconnect},
470   {"doTransceive", "([B)[B",
471      (void *)com_android_nfc_NativeP2pDevice_doTransceive},
472   {"doReceive", "()[B",
473      (void *)com_android_nfc_NativeP2pDevice_doReceive},
474   {"doSend", "([B)Z",
475      (void *)com_android_nfc_NativeP2pDevice_doSend},
476};
477
478int register_com_android_nfc_NativeP2pDevice(JNIEnv *e)
479{
480   return jniRegisterNativeMethods(e,
481      "com/android/nfc/NativeP2pDevice",
482      gMethods, NELEM(gMethods));
483}
484
485} // namepspace android
486