com_android_nfc_NativeP2pDevice.cpp revision c2fdb614879c601b5162d5d93d705b05c7b1e072
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
20#include "com_android_nfc.h"
21
22static sem_t nfc_jni_peer_sem;
23static NFCSTATUS nfc_jni_cb_status = NFCSTATUS_FAILED;
24
25uint8_t nfc_jni_p2p_presence_check = 0;
26
27namespace android {
28
29static phNfc_sData_t sGeneralBytes;
30
31/*
32 * Callbacks
33 */
34static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status)
35{
36   LOG_CALLBACK("nfc_jni_presence_check_callback", status);
37
38   if(status != NFCSTATUS_SUCCESS)
39   {
40      nfc_jni_p2p_presence_check = 1;
41   }
42
43   sem_post(&nfc_jni_peer_sem);
44}
45
46static void nfc_jni_connect_callback(void *pContext,
47                                            phLibNfc_Handle hRemoteDev,
48                                            phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
49{
50
51
52
53   LOG_CALLBACK("nfc_jni_connect_callback", status);
54
55   if(status == NFCSTATUS_SUCCESS)
56   {
57      sGeneralBytes.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length;
58      sGeneralBytes.buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length);
59      sGeneralBytes.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo;
60   }
61
62   nfc_jni_cb_status = status;
63
64   sem_post(&nfc_jni_peer_sem);
65}
66
67static void nfc_jni_disconnect_callback(void *pContext,
68   phLibNfc_Handle hRemoteDev, NFCSTATUS status)
69{
70   LOG_CALLBACK("nfc_jni_disconnect_callback", status);
71
72   nfc_jni_cb_status = status;
73
74   sem_post(&nfc_jni_peer_sem);
75}
76
77static void nfc_jni_receive_callback(void *pContext,
78   phNfc_sData_t *data, NFCSTATUS status)
79{
80   phNfc_sData_t **ptr = (phNfc_sData_t **)pContext;
81
82   LOG_CALLBACK("nfc_jni_receive_callback", status);
83
84   nfc_jni_cb_status = status;
85
86   if(status == NFCSTATUS_SUCCESS)
87      *ptr = data;
88   else
89      *ptr = NULL;
90
91   sem_post(&nfc_jni_peer_sem);
92}
93
94static void nfc_jni_send_callback(void *pContext, NFCSTATUS status)
95{
96   LOG_CALLBACK("nfc_jni_send_callback", status);
97
98   nfc_jni_cb_status = status;
99
100   sem_post(&nfc_jni_peer_sem);
101}
102
103/*
104 * Functions
105 */
106
107static phNfc_sData_t *nfc_jni_transceive_buffer;
108
109static void nfc_jni_transceive_callback(void *pContext,
110  phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status)
111{
112   LOG_CALLBACK("nfc_jni_transceive_callback", status);
113
114   nfc_jni_cb_status = status;
115   nfc_jni_transceive_buffer = pResBuffer;
116
117   sem_post(&nfc_jni_peer_sem);
118}
119
120static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o)
121{
122   phLibNfc_Handle handle = 0;
123   NFCSTATUS status;
124   jboolean result = JNI_FALSE;
125
126   jclass target_cls = NULL;
127   jobject tag;
128   jmethodID ctor;
129   jfieldID f;
130   jbyteArray generalBytes = NULL;
131   int i;
132
133   CONCURRENCY_LOCK();
134
135   handle = nfc_jni_get_p2p_device_handle(e, o);
136
137   LOGD("phLibNfc_RemoteDev_Connect(P2P)");
138   REENTRANCE_LOCK();
139   status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)e);
140   REENTRANCE_UNLOCK();
141   if(status != NFCSTATUS_PENDING)
142   {
143      LOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
144      goto clean_and_return;
145   }
146   LOGD("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
147
148   /* Wait for callback response */
149   sem_wait(&nfc_jni_peer_sem);
150
151   if(nfc_jni_cb_status != NFCSTATUS_SUCCESS)
152   {
153      goto clean_and_return;
154   }
155
156   /* Set General Bytes */
157   target_cls = e->GetObjectClass(o);
158
159   f = e->GetFieldID(target_cls, "mGeneralBytes", "[B");
160
161   LOGD("General Bytes Length = %d", sGeneralBytes.length);
162   LOGD("General Bytes =");
163   for(i=0;i<sGeneralBytes.length;i++)
164   {
165      LOGD("0x%02x ", sGeneralBytes.buffer[i]);
166   }
167
168
169   generalBytes = e->NewByteArray(sGeneralBytes.length);
170
171   e->SetByteArrayRegion(generalBytes, 0,
172                         sGeneralBytes.length,
173                         (jbyte *)sGeneralBytes.buffer);
174
175   e->SetObjectField(o, f, generalBytes);
176
177   result = JNI_TRUE;
178
179clean_and_return:
180   CONCURRENCY_UNLOCK();
181   return result;
182}
183
184static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e,
185   jobject o)
186{
187   phLibNfc_Handle   handle = 0;
188   jboolean          result = JNI_FALSE;
189
190   CONCURRENCY_LOCK();
191
192   handle = nfc_jni_get_p2p_device_handle(e, o);
193
194   /* Disconnect */
195   LOGD("Disconnecting from target (handle = 0x%x)", handle);
196
197   /* Presence Check */
198   while(nfc_jni_p2p_presence_check == 0)
199   {
200      REENTRANCE_LOCK();
201      phLibNfc_RemoteDev_CheckPresence(handle,nfc_jni_presence_check_callback,(void *)e);
202      REENTRANCE_UNLOCK();
203
204      /* Wait for callback response */
205      sem_wait(&nfc_jni_peer_sem);
206   }
207
208   nfc_jni_p2p_presence_check = 0;
209   LOGD("Target removed from the RF Field\n");
210
211   REENTRANCE_LOCK();
212   phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,
213      nfc_jni_disconnect_callback, (void *)e);
214   REENTRANCE_UNLOCK();
215
216   /* Wait for callback response */
217   sem_wait(&nfc_jni_peer_sem);
218
219   if(nfc_jni_cb_status != NFCSTATUS_SUCCESS)
220   {
221      goto clean_and_return;
222   }
223
224   result = JNI_TRUE;
225
226clean_and_return:
227   CONCURRENCY_UNLOCK();
228   return result;
229}
230
231static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e,
232   jobject o, jbyteArray data)
233{
234   NFCSTATUS status;
235   uint8_t offset = 2;
236   uint8_t *buf;
237   uint32_t buflen;
238   phLibNfc_sTransceiveInfo_t transceive_info;
239   jbyteArray result = NULL;
240   phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
241
242   CONCURRENCY_LOCK();
243
244   /* Transceive*/
245   LOGD("Transceive data to target (handle = 0x%x)", handle);
246
247   buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
248   buflen = (uint32_t)e->GetArrayLength(data);
249
250   LOGD("Buffer Length = %d\n", buflen);
251
252   transceive_info.sSendData.buffer = buf; //+ offset;
253   transceive_info.sSendData.length = buflen; //- offset;
254   transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
255   transceive_info.sRecvData.length = 1024;
256
257   if(transceive_info.sRecvData.buffer == NULL)
258   {
259      goto clean_and_return;
260   }
261
262   LOGD("phLibNfc_RemoteDev_Transceive(P2P)");
263   REENTRANCE_LOCK();
264   status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)e);
265   REENTRANCE_UNLOCK();
266   if(status != NFCSTATUS_PENDING)
267   {
268      LOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
269      goto clean_and_return;
270   }
271   LOGD("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
272
273   /* Wait for callback response */
274   sem_wait(&nfc_jni_peer_sem);
275
276   if(nfc_jni_cb_status != NFCSTATUS_SUCCESS)
277   {
278      goto clean_and_return;
279   }
280
281   /* Copy results back to Java */
282   result = e->NewByteArray(nfc_jni_transceive_buffer->length);
283   if(result != NULL)
284      e->SetByteArrayRegion(result, 0,
285         nfc_jni_transceive_buffer->length,
286         (jbyte *)nfc_jni_transceive_buffer->buffer);
287
288clean_and_return:
289   LOGD("P2P Transceive status = 0x%08x",nfc_jni_cb_status);
290   if(transceive_info.sRecvData.buffer != NULL)
291      free(transceive_info.sRecvData.buffer);
292
293   e->ReleaseByteArrayElements(data,
294      (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);
295
296   CONCURRENCY_UNLOCK();
297
298   return result;
299}
300
301
302static jbyteArray com_android_nfc_NativeP2pDevice_doReceive(
303   JNIEnv *e, jobject o)
304{
305   NFCSTATUS status;
306   struct timespec ts;
307   phLibNfc_Handle handle;
308   jbyteArray buf = NULL;
309   static phNfc_sData_t *data;
310
311   CONCURRENCY_LOCK();
312
313   handle = nfc_jni_get_p2p_device_handle(e, o);
314
315   /* Receive */
316   LOGD("phLibNfc_RemoteDev_Receive()");
317   REENTRANCE_LOCK();
318   status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&data);
319   REENTRANCE_UNLOCK();
320   if(status != NFCSTATUS_PENDING)
321   {
322      LOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
323      goto clean_and_return;
324   }
325   LOGD("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
326
327   /* Wait for callback response */
328   if(sem_wait(&nfc_jni_peer_sem) == -1)
329   {
330      goto clean_and_return;
331   }
332
333   if(data == NULL)
334   {
335      goto clean_and_return;
336   }
337
338   buf = e->NewByteArray(data->length);
339   e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer);
340
341clean_and_return:
342   CONCURRENCY_UNLOCK();
343   return buf;
344}
345
346static jboolean com_android_nfc_NativeP2pDevice_doSend(
347   JNIEnv *e, jobject o, jbyteArray buf)
348{
349   NFCSTATUS status;
350   phNfc_sData_t data;
351   jboolean result = JNI_FALSE;
352
353   phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
354
355   CONCURRENCY_LOCK();
356
357   /* Send */
358   LOGD("Send data to the Initiator (handle = 0x%x)", handle);
359
360   data.length = (uint32_t)e->GetArrayLength(buf);
361   data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL);
362
363   LOGD("phLibNfc_RemoteDev_Send()");
364   REENTRANCE_LOCK();
365   status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)e);
366   REENTRANCE_UNLOCK();
367   if(status != NFCSTATUS_PENDING)
368   {
369      LOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
370      goto clean_and_return;
371   }
372   LOGD("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
373
374   /* Wait for callback response */
375   sem_wait(&nfc_jni_peer_sem);
376
377   if(nfc_jni_cb_status != NFCSTATUS_SUCCESS)
378   {
379      goto clean_and_return;
380   }
381
382   result = JNI_TRUE;
383
384clean_and_return:
385   if (result != JNI_TRUE)
386   {
387      e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT);
388   }
389   CONCURRENCY_UNLOCK();
390   return result;
391}
392
393/*
394 * JNI registration.
395 */
396static JNINativeMethod gMethods[] =
397{
398   {"doConnect", "()Z",
399      (void *)com_android_nfc_NativeP2pDevice_doConnect},
400   {"doDisconnect", "()Z",
401      (void *)com_android_nfc_NativeP2pDevice_doDisconnect},
402   {"doTransceive", "([B)[B",
403      (void *)com_android_nfc_NativeP2pDevice_doTransceive},
404   {"doReceive", "()[B",
405      (void *)com_android_nfc_NativeP2pDevice_doReceive},
406   {"doSend", "([B)Z",
407      (void *)com_android_nfc_NativeP2pDevice_doSend},
408};
409
410int register_com_android_nfc_NativeP2pDevice(JNIEnv *e)
411{
412   if(sem_init(&nfc_jni_peer_sem, 0, 0) == -1)
413      return -1;
414
415   return jniRegisterNativeMethods(e,
416      "com/android/nfc/NativeP2pDevice",
417      gMethods, NELEM(gMethods));
418}
419
420} // namepspace android
421