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