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#include <ScopedLocalRef.h>
21
22#include "com_android_nfc.h"
23
24extern uint8_t device_connected_flag;
25
26namespace android {
27
28extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat);
29
30/*
31 * Callbacks
32 */
33static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status)
34{
35   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
36   LOG_CALLBACK("nfc_jni_presence_check_callback", status);
37
38   /* Report the callback status and wake up the caller */
39   pCallbackData->status = status;
40   sem_post(&pCallbackData->sem);
41}
42
43static void nfc_jni_connect_callback(void *pContext,
44                                     phLibNfc_Handle /*hRemoteDev*/,
45                                     phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
46{
47   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
48   phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext;
49   LOG_CALLBACK("nfc_jni_connect_callback", status);
50
51   if(status == NFCSTATUS_SUCCESS)
52   {
53      psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length;
54      psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length);
55      psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo;
56   }
57
58   /* Report the callback status and wake up the caller */
59   pCallbackData->status = status;
60   sem_post(&pCallbackData->sem);
61}
62
63static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle /*hRemoteDev*/, NFCSTATUS status)
64{
65   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
66   LOG_CALLBACK("nfc_jni_disconnect_callback", status);
67
68   /* Report the callback status and wake up the caller */
69   pCallbackData->status = status;
70   sem_post(&pCallbackData->sem);
71}
72
73static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status)
74{
75   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
76   phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext;
77   LOG_CALLBACK("nfc_jni_receive_callback", status);
78
79   if(status == NFCSTATUS_SUCCESS)
80   {
81      *ptr = data;
82   }
83   else
84   {
85      *ptr = NULL;
86   }
87
88   /* Report the callback status and wake up the caller */
89   pCallbackData->status = status;
90   sem_post(&pCallbackData->sem);
91}
92
93static void nfc_jni_send_callback(void *pContext, NFCSTATUS status)
94{
95   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
96   LOG_CALLBACK("nfc_jni_send_callback", status);
97
98   /* Report the callback status and wake up the caller */
99   pCallbackData->status = status;
100   sem_post(&pCallbackData->sem);
101}
102
103/*
104 * Functions
105 */
106
107static void nfc_jni_transceive_callback(void *pContext,
108  phLibNfc_Handle /*handle*/, phNfc_sData_t *pResBuffer, NFCSTATUS status)
109{
110   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
111   LOG_CALLBACK("nfc_jni_transceive_callback", status);
112
113   /* Report the callback data and wake up the caller */
114   pCallbackData->pContext = pResBuffer;
115   pCallbackData->status = status;
116   sem_post(&pCallbackData->sem);
117}
118
119static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o)
120{
121    phLibNfc_Handle handle = 0;
122    NFCSTATUS status;
123    jboolean result = JNI_FALSE;
124    struct nfc_jni_callback_data cb_data;
125
126    ScopedLocalRef<jclass> target_cls(e, NULL);
127    jobject tag;
128    jmethodID ctor;
129    jfieldID f;
130    jbyteArray generalBytes = NULL;
131    phNfc_sData_t sGeneralBytes;
132    unsigned int i;
133
134    CONCURRENCY_LOCK();
135
136    handle = nfc_jni_get_p2p_device_handle(e, o);
137
138    /* Create the local semaphore */
139    if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes))
140    {
141       goto clean_and_return;
142    }
143
144    TRACE("phLibNfc_RemoteDev_Connect(P2P)");
145    REENTRANCE_LOCK();
146    status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data);
147    REENTRANCE_UNLOCK();
148    if(status != NFCSTATUS_PENDING)
149    {
150      ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
151      goto clean_and_return;
152    }
153    TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
154
155    /* Wait for callback response */
156    if(sem_wait(&cb_data.sem))
157    {
158       ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
159       goto clean_and_return;
160    }
161
162    if(cb_data.status != NFCSTATUS_SUCCESS)
163    {
164        goto clean_and_return;
165    }
166
167    /* Set General Bytes */
168    target_cls.reset(e->GetObjectClass(o));
169
170    f = e->GetFieldID(target_cls.get(), "mGeneralBytes", "[B");
171
172    TRACE("General Bytes Length = %d", sGeneralBytes.length);
173    TRACE("General Bytes =");
174    for(i=0;i<sGeneralBytes.length;i++)
175    {
176      TRACE("0x%02x ", sGeneralBytes.buffer[i]);
177    }
178
179    generalBytes = e->NewByteArray(sGeneralBytes.length);
180
181    e->SetByteArrayRegion(generalBytes, 0,
182                         sGeneralBytes.length,
183                         (jbyte *)sGeneralBytes.buffer);
184
185    e->SetObjectField(o, f, generalBytes);
186
187    result = JNI_TRUE;
188
189clean_and_return:
190    if (result != JNI_TRUE)
191    {
192       /* Restart the polling loop if the connection failed */
193       nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
194    }
195    nfc_cb_data_deinit(&cb_data);
196    CONCURRENCY_UNLOCK();
197    return result;
198}
199
200static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o)
201{
202    phLibNfc_Handle     handle = 0;
203    jboolean            result = JNI_FALSE;
204    NFCSTATUS           status;
205    struct nfc_jni_callback_data cb_data;
206
207    CONCURRENCY_LOCK();
208
209    handle = nfc_jni_get_p2p_device_handle(e, o);
210
211    /* Create the local semaphore */
212    if (!nfc_cb_data_init(&cb_data, NULL))
213    {
214       goto clean_and_return;
215    }
216
217    /* Disconnect */
218    TRACE("Disconnecting from target (handle = 0x%x)", handle);
219
220    /* NativeNfcTag waits for tag to leave the field here with presence check.
221     * We do not in P2P path because presence check is not safe while transceive may be
222     * in progress.
223     */
224
225    TRACE("phLibNfc_RemoteDev_Disconnect()");
226    REENTRANCE_LOCK();
227    status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data);
228    REENTRANCE_UNLOCK();
229    if(status != NFCSTATUS_PENDING)
230    {
231        ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
232        if(status == NFCSTATUS_TARGET_NOT_CONNECTED)
233        {
234            ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected");
235        }
236        else
237        {
238            ALOGE("phLibNfc_RemoteDev_Disconnect() failed");
239            nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
240        }
241
242        goto clean_and_return;
243    }
244    TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
245
246    /* Wait for callback response */
247    if(sem_wait(&cb_data.sem))
248    {
249       ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
250       goto clean_and_return;
251    }
252
253    /* Disconnect Status */
254    if(cb_data.status != NFCSTATUS_SUCCESS)
255    {
256        goto clean_and_return;
257    }
258
259    result = JNI_TRUE;
260
261clean_and_return:
262    /* Reset device connected flag */
263    device_connected_flag = 0;
264    nfc_cb_data_deinit(&cb_data);
265    CONCURRENCY_UNLOCK();
266    return result;
267}
268
269static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e,
270   jobject o, jbyteArray data)
271{
272   NFCSTATUS status;
273   uint8_t offset = 2;
274   uint8_t *buf;
275   uint32_t buflen;
276   phLibNfc_sTransceiveInfo_t transceive_info;
277   jbyteArray result = NULL;
278   phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
279   phNfc_sData_t * receive_buffer = NULL;
280   struct nfc_jni_callback_data cb_data;
281
282   CONCURRENCY_LOCK();
283
284   /* Create the local semaphore */
285   if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer))
286   {
287      goto clean_and_return;
288   }
289
290   /* Transceive*/
291   TRACE("Transceive data to target (handle = 0x%x)", handle);
292
293   buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
294   buflen = (uint32_t)e->GetArrayLength(data);
295
296   TRACE("Buffer Length = %d\n", buflen);
297
298   transceive_info.sSendData.buffer = buf; //+ offset;
299   transceive_info.sSendData.length = buflen; //- offset;
300   transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
301   transceive_info.sRecvData.length = 1024;
302
303   if(transceive_info.sRecvData.buffer == NULL)
304   {
305      goto clean_and_return;
306   }
307
308   TRACE("phLibNfc_RemoteDev_Transceive(P2P)");
309   REENTRANCE_LOCK();
310   status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data);
311   REENTRANCE_UNLOCK();
312   if(status != NFCSTATUS_PENDING)
313   {
314      ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
315      goto clean_and_return;
316   }
317   TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
318
319   /* Wait for callback response */
320   if(sem_wait(&cb_data.sem))
321   {
322      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
323      goto clean_and_return;
324   }
325
326   if(cb_data.status != NFCSTATUS_SUCCESS)
327   {
328      goto clean_and_return;
329   }
330
331   /* Copy results back to Java */
332   result = e->NewByteArray(receive_buffer->length);
333   if(result != NULL)
334      e->SetByteArrayRegion(result, 0,
335         receive_buffer->length,
336         (jbyte *)receive_buffer->buffer);
337
338clean_and_return:
339   if(transceive_info.sRecvData.buffer != NULL)
340   {
341      free(transceive_info.sRecvData.buffer);
342   }
343
344   e->ReleaseByteArrayElements(data,
345      (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);
346
347   nfc_cb_data_deinit(&cb_data);
348
349   CONCURRENCY_UNLOCK();
350
351   return result;
352}
353
354
355static jbyteArray com_android_nfc_NativeP2pDevice_doReceive(
356   JNIEnv *e, jobject o)
357{
358   NFCSTATUS status;
359   struct timespec ts;
360   phLibNfc_Handle handle;
361   jbyteArray buf = NULL;
362   static phNfc_sData_t *data;
363   struct nfc_jni_callback_data cb_data;
364
365   CONCURRENCY_LOCK();
366
367   handle = nfc_jni_get_p2p_device_handle(e, o);
368
369   /* Create the local semaphore */
370   if (!nfc_cb_data_init(&cb_data, (void*)data))
371   {
372      goto clean_and_return;
373   }
374
375   /* Receive */
376   TRACE("phLibNfc_RemoteDev_Receive()");
377   REENTRANCE_LOCK();
378   status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data);
379   REENTRANCE_UNLOCK();
380   if(status != NFCSTATUS_PENDING)
381   {
382      ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
383      goto clean_and_return;
384   }
385   TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
386
387   /* Wait for callback response */
388   if(sem_wait(&cb_data.sem))
389   {
390      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
391      goto clean_and_return;
392   }
393
394   if(data == NULL)
395   {
396      goto clean_and_return;
397   }
398
399   buf = e->NewByteArray(data->length);
400   e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer);
401
402clean_and_return:
403   nfc_cb_data_deinit(&cb_data);
404   CONCURRENCY_UNLOCK();
405   return buf;
406}
407
408static jboolean com_android_nfc_NativeP2pDevice_doSend(
409   JNIEnv *e, jobject o, jbyteArray buf)
410{
411   NFCSTATUS status;
412   phNfc_sData_t data;
413   jboolean result = JNI_FALSE;
414   struct nfc_jni_callback_data cb_data;
415
416   phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
417
418   CONCURRENCY_LOCK();
419
420   /* Create the local semaphore */
421   if (!nfc_cb_data_init(&cb_data, NULL))
422   {
423      goto clean_and_return;
424   }
425
426   /* Send */
427   TRACE("Send data to the Initiator (handle = 0x%x)", handle);
428
429   data.length = (uint32_t)e->GetArrayLength(buf);
430   data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL);
431
432   TRACE("phLibNfc_RemoteDev_Send()");
433   REENTRANCE_LOCK();
434   status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data);
435   REENTRANCE_UNLOCK();
436   if(status != NFCSTATUS_PENDING)
437   {
438      ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
439      goto clean_and_return;
440   }
441   TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
442
443   /* Wait for callback response */
444   if(sem_wait(&cb_data.sem))
445   {
446      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
447      goto clean_and_return;
448   }
449
450   if(cb_data.status != NFCSTATUS_SUCCESS)
451   {
452      goto clean_and_return;
453   }
454
455   result = JNI_TRUE;
456
457clean_and_return:
458   if (result != JNI_TRUE)
459   {
460      e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT);
461   }
462   nfc_cb_data_deinit(&cb_data);
463   CONCURRENCY_UNLOCK();
464   return result;
465}
466
467/*
468 * JNI registration.
469 */
470static JNINativeMethod gMethods[] =
471{
472   {"doConnect", "()Z",
473      (void *)com_android_nfc_NativeP2pDevice_doConnect},
474   {"doDisconnect", "()Z",
475      (void *)com_android_nfc_NativeP2pDevice_doDisconnect},
476   {"doTransceive", "([B)[B",
477      (void *)com_android_nfc_NativeP2pDevice_doTransceive},
478   {"doReceive", "()[B",
479      (void *)com_android_nfc_NativeP2pDevice_doReceive},
480   {"doSend", "([B)Z",
481      (void *)com_android_nfc_NativeP2pDevice_doSend},
482};
483
484int register_com_android_nfc_NativeP2pDevice(JNIEnv *e)
485{
486   return jniRegisterNativeMethods(e,
487      "com/android/nfc/dhimpl/NativeP2pDevice",
488      gMethods, NELEM(gMethods));
489}
490
491} // namepspace android
492