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