1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Tag-reading, tag-writing operations.
19 */
20 #include "NfcTag.h"
21
22 #include <android-base/logging.h>
23 #include <android-base/stringprintf.h>
24 #include <log/log.h>
25 #include <nativehelper/ScopedLocalRef.h>
26 #include <nativehelper/ScopedPrimitiveArray.h>
27 #include <statslog_nfc.h>
28
29 #include "JavaClassConstants.h"
30 #include "nfc_brcm_defs.h"
31 #include "nfc_config.h"
32 #include "rw_int.h"
33
34 using android::base::StringPrintf;
35
36 static void deleteglobaldata(JNIEnv* e);
37 static jobjectArray sTechPollBytes;
38 static jobjectArray gtechActBytes;
39 static int sLastSelectedTagId = 0;
40
41 /*******************************************************************************
42 **
43 ** Function: NfcTag
44 **
45 ** Description: Initialize member variables.
46 **
47 ** Returns: None
48 **
49 *******************************************************************************/
NfcTag()50 NfcTag::NfcTag()
51 : mNumTechList(0),
52 mNumRfDiscId(0),
53 mTechnologyTimeoutsTable(MAX_NUM_TECHNOLOGY),
54 mNativeData(NULL),
55 mIsActivated(false),
56 mActivationState(Idle),
57 mProtocol(NFC_PROTOCOL_UNKNOWN),
58 mtT1tMaxMessageSize(0),
59 mReadCompletedStatus(NFA_STATUS_OK),
60 mLastKovioUidLen(0),
61 mNdefDetectionTimedOut(false),
62 mIsDynamicTagId(false),
63 mPresenceCheckAlgorithm(NFA_RW_PRES_CHK_DEFAULT),
64 mIsFelicaLite(false),
65 mNumDiscNtf(0),
66 mNumDiscTechList(0),
67 mTechListTail(0),
68 mIsMultiProtocolTag(false) {
69 memset(mTechList, 0, sizeof(mTechList));
70 memset(mTechHandles, 0, sizeof(mTechHandles));
71 memset(mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes));
72 memset(mTechParams, 0, sizeof(mTechParams));
73 memset(mLastKovioUid, 0, NFC_KOVIO_MAX_LEN);
74 memset(&mLastKovioTime, 0, sizeof(timespec));
75 mNfcStatsUtil = new NfcStatsUtil();
76 }
77
78 /*******************************************************************************
79 **
80 ** Function: getInstance
81 **
82 ** Description: Get a reference to the singleton NfcTag object.
83 **
84 ** Returns: Reference to NfcTag object.
85 **
86 *******************************************************************************/
getInstance()87 NfcTag& NfcTag::getInstance() {
88 static NfcTag tag;
89 return tag;
90 }
91
92 /*******************************************************************************
93 **
94 ** Function: initialize
95 **
96 ** Description: Reset member variables.
97 ** native: Native data.
98 **
99 ** Returns: None
100 **
101 *******************************************************************************/
initialize(nfc_jni_native_data * native)102 void NfcTag::initialize(nfc_jni_native_data* native) {
103 mNativeData = native;
104 mIsActivated = false;
105 mActivationState = Idle;
106 mProtocol = NFC_PROTOCOL_UNKNOWN;
107 mNumRfDiscId = 0;
108 mtT1tMaxMessageSize = 0;
109 mReadCompletedStatus = NFA_STATUS_OK;
110 resetTechnologies();
111 if (NfcConfig::hasKey(NAME_PRESENCE_CHECK_ALGORITHM))
112 mPresenceCheckAlgorithm =
113 NfcConfig::getUnsigned(NAME_PRESENCE_CHECK_ALGORITHM);
114 }
115
116 /*******************************************************************************
117 **
118 ** Function: abort
119 **
120 ** Description: Unblock all operations.
121 **
122 ** Returns: None
123 **
124 *******************************************************************************/
abort()125 void NfcTag::abort() {
126 SyncEventGuard g(mReadCompleteEvent);
127 mReadCompleteEvent.notifyOne();
128 }
129
130 /*******************************************************************************
131 **
132 ** Function: getActivationState
133 **
134 ** Description: What is the current state: Idle, Sleep, or Activated.
135 **
136 ** Returns: Idle, Sleep, or Activated.
137 **
138 *******************************************************************************/
getActivationState()139 NfcTag::ActivationState NfcTag::getActivationState() {
140 return mActivationState;
141 }
142
143 /*******************************************************************************
144 **
145 ** Function: setDeactivationState
146 **
147 ** Description: Set the current state: Idle or Sleep.
148 ** deactivated: state of deactivation.
149 **
150 ** Returns: None.
151 **
152 *******************************************************************************/
setDeactivationState(tNFA_DEACTIVATED & deactivated)153 void NfcTag::setDeactivationState(tNFA_DEACTIVATED& deactivated) {
154 static const char fn[] = "NfcTag::setDeactivationState";
155 mActivationState = Idle;
156 mNdefDetectionTimedOut = false;
157 if (deactivated.type == NFA_DEACTIVATE_TYPE_SLEEP) mActivationState = Sleep;
158 LOG(DEBUG) << StringPrintf("%s: state=%u", fn, mActivationState);
159 }
160
161 /*******************************************************************************
162 **
163 ** Function: setActivationState
164 **
165 ** Description: Set the current state to Active.
166 **
167 ** Returns: None.
168 **
169 *******************************************************************************/
setActivationState()170 void NfcTag::setActivationState() {
171 static const char fn[] = "NfcTag::setActivationState";
172 mNdefDetectionTimedOut = false;
173 mActivationState = Active;
174 LOG(DEBUG) << StringPrintf("%s: state=%u", fn, mActivationState);
175 }
176
177 /*******************************************************************************
178 **
179 ** Function: isActivated
180 **
181 ** Description: Is tag activated?
182 **
183 ** Returns: True if tag is activated.
184 **
185 *******************************************************************************/
isActivated()186 bool NfcTag::isActivated() { return mIsActivated; }
187
188 /*******************************************************************************
189 **
190 ** Function: getProtocol
191 **
192 ** Description: Get the protocol of the current tag.
193 **
194 ** Returns: Protocol number.
195 **
196 *******************************************************************************/
getProtocol()197 tNFC_PROTOCOL NfcTag::getProtocol() { return mProtocol; }
198
199 /*******************************************************************************
200 **
201 ** Function TimeDiff
202 **
203 ** Description Computes time difference in milliseconds.
204 **
205 ** Returns Time difference in milliseconds
206 **
207 *******************************************************************************/
TimeDiff(timespec start,timespec end)208 uint32_t TimeDiff(timespec start, timespec end) {
209 timespec temp;
210 if ((end.tv_nsec - start.tv_nsec) < 0) {
211 temp.tv_sec = end.tv_sec - start.tv_sec - 1;
212 temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
213 } else {
214 temp.tv_sec = end.tv_sec - start.tv_sec;
215 temp.tv_nsec = end.tv_nsec - start.tv_nsec;
216 }
217
218 return (temp.tv_sec * 1000) + (temp.tv_nsec / 1000000);
219 }
220
221 /*******************************************************************************
222 **
223 ** Function: IsSameKovio
224 **
225 ** Description: Checks if tag activate is the same (UID) Kovio tag
226 *previously
227 ** activated. This is needed due to a problem with some Kovio
228 ** tags re-activating multiple times.
229 ** activationData: data from activation.
230 **
231 ** Returns: true if the activation is from the same tag previously
232 ** activated, false otherwise
233 **
234 *******************************************************************************/
IsSameKovio(tNFA_ACTIVATED & activationData)235 bool NfcTag::IsSameKovio(tNFA_ACTIVATED& activationData) {
236 static const char fn[] = "NfcTag::IsSameKovio";
237 LOG(DEBUG) << StringPrintf("%s: enter", fn);
238 tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf;
239
240 if (rfDetail.protocol != NFC_PROTOCOL_KOVIO) return false;
241
242 memcpy(&(mTechParams[0]), &(rfDetail.rf_tech_param),
243 sizeof(rfDetail.rf_tech_param));
244 if (mTechParams[0].mode != NFC_DISCOVERY_TYPE_POLL_KOVIO) return false;
245
246 struct timespec now;
247 clock_gettime(CLOCK_REALTIME, &now);
248
249 bool rVal = false;
250 if (mTechParams[0].param.pk.uid_len == mLastKovioUidLen) {
251 if (memcmp(mLastKovioUid, &mTechParams[0].param.pk.uid,
252 mTechParams[0].param.pk.uid_len) == 0) {
253 // same tag
254 if (TimeDiff(mLastKovioTime, now) < 500) {
255 // same tag within 500 ms, ignore activation
256 rVal = true;
257 }
258 }
259 }
260
261 // save Kovio tag info
262 if (!rVal) {
263 if ((mLastKovioUidLen = mTechParams[0].param.pk.uid_len) >
264 NFC_KOVIO_MAX_LEN)
265 mLastKovioUidLen = NFC_KOVIO_MAX_LEN;
266 memcpy(mLastKovioUid, mTechParams[0].param.pk.uid, mLastKovioUidLen);
267 }
268 mLastKovioTime = now;
269 LOG(DEBUG) << StringPrintf("%s: exit, is same Kovio=%d", fn, rVal);
270 return rVal;
271 }
272
273 /*******************************************************************************
274 **
275 ** Function: discoverTechnologies
276 **
277 ** Description: Discover the technologies that NFC service needs by
278 *interpreting
279 ** the data structures from the stack.
280 ** activationData: data from activation.
281 **
282 ** Returns: None
283 **
284 *******************************************************************************/
discoverTechnologies(tNFA_ACTIVATED & activationData)285 void NfcTag::discoverTechnologies(tNFA_ACTIVATED& activationData) {
286 static const char fn[] = "NfcTag::discoverTechnologies (activation)";
287 LOG(DEBUG) << StringPrintf("%s: enter", fn);
288 tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf;
289
290 if (mTechListTail < (MAX_NUM_TECHNOLOGY - 1)) {
291 mNumTechList = mTechListTail;
292 } else {
293 LOG(ERROR) << StringPrintf("%s: exceed max=%d", fn, MAX_NUM_TECHNOLOGY);
294 android_errorWriteLog(0x534e4554, "189942532");
295 goto TheEnd;
296 }
297 mTechHandles[mNumTechList] = rfDetail.rf_disc_id;
298 mTechLibNfcTypes[mNumTechList] = rfDetail.protocol;
299
300 // save the stack's data structure for interpretation later
301 memcpy(&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param),
302 sizeof(rfDetail.rf_tech_param));
303
304 if (NFC_PROTOCOL_T1T == rfDetail.protocol) {
305 mTechList[mNumTechList] =
306 TARGET_TYPE_ISO14443_3A; // is TagTechnology.NFC_A by Java API
307 } else if (NFC_PROTOCOL_T2T == rfDetail.protocol) {
308 mTechList[mNumTechList] =
309 TARGET_TYPE_ISO14443_3A; // is TagTechnology.NFC_A by Java API
310 // could be MifFare UL or Classic or Kovio
311 {
312 // need to look at first byte of uid to find Manufacture Byte
313 tNFC_RF_TECH_PARAMS tech_params;
314 memcpy(&tech_params, &(rfDetail.rf_tech_param),
315 sizeof(rfDetail.rf_tech_param));
316
317 if ((tech_params.param.pa.nfcid1[0] == 0x04 &&
318 rfDetail.rf_tech_param.param.pa.sel_rsp == 0) ||
319 rfDetail.rf_tech_param.param.pa.sel_rsp == 0x18 ||
320 rfDetail.rf_tech_param.param.pa.sel_rsp == 0x08) {
321 if (rfDetail.rf_tech_param.param.pa.sel_rsp == 0) {
322 mNumTechList++;
323 mTechHandles[mNumTechList] = rfDetail.rf_disc_id;
324 mTechLibNfcTypes[mNumTechList] = rfDetail.protocol;
325 // save the stack's data structure for interpretation later
326 memcpy(&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param),
327 sizeof(rfDetail.rf_tech_param));
328 mTechList[mNumTechList] =
329 TARGET_TYPE_MIFARE_UL; // is TagTechnology.MIFARE_ULTRALIGHT by
330 // Java API
331 }
332 }
333 }
334 } else if (NFC_PROTOCOL_T3T == rfDetail.protocol) {
335 uint8_t xx = 0;
336
337 mTechList[mNumTechList] = TARGET_TYPE_FELICA;
338
339 // see if it is Felica Lite.
340 while (xx < activationData.params.t3t.num_system_codes) {
341 if (activationData.params.t3t.p_system_codes[xx++] ==
342 T3T_SYSTEM_CODE_FELICA_LITE) {
343 mIsFelicaLite = true;
344 break;
345 }
346 }
347 } else if (NFC_PROTOCOL_ISO_DEP == rfDetail.protocol) {
348 // type-4 tag uses technology ISO-DEP and technology A or B
349 mTechList[mNumTechList] =
350 TARGET_TYPE_ISO14443_4; // is TagTechnology.ISO_DEP by Java API
351 if (NFC_DISCOVERY_TYPE_POLL_A == rfDetail.rf_tech_param.mode) {
352 uint8_t fwi = rfDetail.intf_param.intf_param.pa_iso.fwi;
353 if (fwi >= MIN_FWI && fwi <= MAX_FWI) {
354 //2^MIN_FWI * 256 * 16 * 1000 / 13560000 is approximately 618
355 int fwt = (1 << (fwi - MIN_FWI)) * 618;
356 LOG(DEBUG) << StringPrintf(
357 "Setting the transceive timeout = %d, fwi = %0#x", fwt, fwi);
358 setTransceiveTimeout(mTechList[mNumTechList], fwt);
359 }
360 }
361 if ((rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) ||
362 (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A)) {
363 mNumTechList++;
364 mTechHandles[mNumTechList] = rfDetail.rf_disc_id;
365 mTechLibNfcTypes[mNumTechList] = rfDetail.protocol;
366 mTechList[mNumTechList] =
367 TARGET_TYPE_ISO14443_3A; // is TagTechnology.NFC_A by Java API
368 // save the stack's data structure for interpretation later
369 memcpy(&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param),
370 sizeof(rfDetail.rf_tech_param));
371 } else if ((rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) ||
372 (rfDetail.rf_tech_param.mode ==
373 NFC_DISCOVERY_TYPE_POLL_B_PRIME) ||
374 (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) ||
375 (rfDetail.rf_tech_param.mode ==
376 NFC_DISCOVERY_TYPE_LISTEN_B_PRIME)) {
377 mNumTechList++;
378 mTechHandles[mNumTechList] = rfDetail.rf_disc_id;
379 mTechLibNfcTypes[mNumTechList] = rfDetail.protocol;
380 mTechList[mNumTechList] =
381 TARGET_TYPE_ISO14443_3B; // is TagTechnology.NFC_B by Java API
382 // save the stack's data structure for interpretation later
383 memcpy(&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param),
384 sizeof(rfDetail.rf_tech_param));
385 }
386 } else if (NFC_PROTOCOL_T5T == rfDetail.protocol) {
387 // is TagTechnology.NFC_V by Java API
388 mTechList[mNumTechList] = TARGET_TYPE_V;
389 } else if (NFC_PROTOCOL_KOVIO == rfDetail.protocol) {
390 LOG(DEBUG) << StringPrintf("%s: Kovio", fn);
391 mTechList[mNumTechList] = TARGET_TYPE_KOVIO_BARCODE;
392 } else if (NFC_PROTOCOL_MIFARE == rfDetail.protocol) {
393 LOG(DEBUG) << StringPrintf("%s: Mifare Classic", fn);
394 mTechList[mNumTechList] =
395 TARGET_TYPE_ISO14443_3A; // is TagTechnology.NFC_A by Java API
396 mNumTechList++;
397 mTechHandles[mNumTechList] = rfDetail.rf_disc_id;
398 mTechLibNfcTypes[mNumTechList] = rfDetail.protocol;
399 // save the stack's data structure for interpretation later
400 memcpy(&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param),
401 sizeof(rfDetail.rf_tech_param));
402 mTechList[mNumTechList] =
403 TARGET_TYPE_MIFARE_CLASSIC; // is TagTechnology.MIFARE_CLASSIC by Java
404 // API
405 } else {
406 LOG(ERROR) << StringPrintf("%s: unknown protocol ????", fn);
407 mTechList[mNumTechList] = TARGET_TYPE_UNKNOWN;
408 }
409
410 mNumTechList++;
411 for (int i = 0; i < mNumTechList; i++) {
412 LOG(DEBUG) << StringPrintf("%s: index=%d; tech=%d; handle=%d; nfc type=%d",
413 fn, i, mTechList[i], mTechHandles[i],
414 mTechLibNfcTypes[i]);
415 }
416 mNfcStatsUtil->logNfcTagType(mTechLibNfcTypes[mTechListTail],
417 mTechParams[mTechListTail].mode);
418 TheEnd:
419 LOG(DEBUG) << StringPrintf("%s: exit", fn);
420 }
421
422 /*******************************************************************************
423 **
424 ** Function: discoverTechnologies
425 **
426 ** Description: Discover the technologies that NFC service needs by
427 *interpreting
428 ** the data structures from the stack.
429 ** discoveryData: data from discovery events(s).
430 **
431 ** Returns: None
432 **
433 *******************************************************************************/
discoverTechnologies(tNFA_DISC_RESULT & discoveryData)434 void NfcTag::discoverTechnologies(tNFA_DISC_RESULT& discoveryData) {
435 static const char fn[] = "NfcTag::discoverTechnologies (discovery)";
436 tNFC_RESULT_DEVT& discovery_ntf = discoveryData.discovery_ntf;
437 uint8_t index = mNumDiscNtf;
438
439 LOG(DEBUG) << StringPrintf(
440 "%s: enter: rf disc. id=%u; protocol=%u, mNumTechList=%u", fn,
441 discovery_ntf.rf_disc_id, discovery_ntf.protocol, mNumTechList);
442 if (index >= MAX_NUM_TECHNOLOGY) {
443 LOG(ERROR) << StringPrintf("%s: exceed max=%d", fn, MAX_NUM_TECHNOLOGY);
444 goto TheEnd;
445 }
446 mTechHandlesDiscData[index] = discovery_ntf.rf_disc_id;
447 mTechLibNfcTypesDiscData[index] = discovery_ntf.protocol;
448 if (mNumDiscTechList < MAX_NUM_TECHNOLOGY) {
449 mNumDiscTechList++;
450 }
451 if (discovery_ntf.more != NCI_DISCOVER_NTF_MORE) {
452 for (int i = 0; i < mNumDiscTechList; i++) {
453 LOG(DEBUG) << StringPrintf("%s: index=%d; handle=%d; nfc type=%d", fn, i,
454 mTechHandlesDiscData[i],
455 mTechLibNfcTypesDiscData[i]);
456 }
457 }
458 LOG(DEBUG) << StringPrintf("%s; mNumDiscTechList=%x", fn, mNumDiscTechList);
459 mNumRfDiscId = discovery_ntf.rf_disc_id;
460 TheEnd:
461 LOG(DEBUG) << StringPrintf("%s: exit", fn);
462 }
463
464 /*******************************************************************************
465 **
466 ** Function: createNativeNfcTag
467 **
468 ** Description: Create a brand new Java NativeNfcTag object;
469 ** fill the objects's member variables with data;
470 ** notify NFC service;
471 ** activationData: data from activation.
472 **
473 ** Returns: None
474 **
475 *******************************************************************************/
createNativeNfcTag(tNFA_ACTIVATED & activationData)476 void NfcTag::createNativeNfcTag(tNFA_ACTIVATED& activationData) {
477 static const char fn[] = "NfcTag::createNativeNfcTag";
478 LOG(DEBUG) << StringPrintf("%s: enter", fn);
479
480 if (mNativeData == NULL) {
481 LOG(ERROR) << StringPrintf("%s: mNativeData is null", fn);
482 return;
483 }
484
485 JNIEnv* e = NULL;
486 ScopedAttach attach(mNativeData->vm, &e);
487 if (e == NULL) {
488 LOG(ERROR) << StringPrintf("%s: jni env is null", fn);
489 return;
490 }
491
492 ScopedLocalRef<jclass> tag_cls(e,
493 e->GetObjectClass(mNativeData->cached_NfcTag));
494 if (e->ExceptionCheck()) {
495 e->ExceptionClear();
496 LOG(ERROR) << StringPrintf("%s: failed to get class", fn);
497 return;
498 }
499
500 // create a new Java NativeNfcTag object
501 jmethodID ctor = e->GetMethodID(tag_cls.get(), "<init>", "()V");
502 ScopedLocalRef<jobject> tag(e, e->NewObject(tag_cls.get(), ctor));
503
504 // fill NativeNfcTag's mProtocols, mTechList, mTechHandles, mTechLibNfcTypes
505 fillNativeNfcTagMembers1(e, tag_cls.get(), tag.get());
506
507 // fill NativeNfcTag's members: mHandle, mConnectedTechnology
508 fillNativeNfcTagMembers2(e, tag_cls.get(), tag.get(), activationData);
509
510 // fill NativeNfcTag's members: mTechPollBytes
511 fillNativeNfcTagMembers3(e, tag_cls.get(), tag.get(), activationData);
512
513 // fill NativeNfcTag's members: mTechActBytes
514 fillNativeNfcTagMembers4(e, tag_cls.get(), tag.get(), activationData);
515
516 // fill NativeNfcTag's members: mUid
517 fillNativeNfcTagMembers5(e, tag_cls.get(), tag.get(), activationData);
518
519 if (mNativeData->tag != NULL) {
520 e->DeleteGlobalRef(mNativeData->tag);
521 }
522 mNativeData->tag = e->NewGlobalRef(tag.get());
523
524 LOG(DEBUG) << StringPrintf("%s; mNumDiscNtf=%x", fn, mNumDiscNtf);
525
526 if (!mNumDiscNtf) {
527 // notify NFC service about this new tag
528 LOG(DEBUG) << StringPrintf("%s: try notify nfc service", fn);
529 e->CallVoidMethod(mNativeData->manager,
530 android::gCachedNfcManagerNotifyNdefMessageListeners,
531 tag.get());
532 if (e->ExceptionCheck()) {
533 e->ExceptionClear();
534 LOG(ERROR) << StringPrintf("%s: fail notify nfc service", fn);
535 }
536 deleteglobaldata(e);
537 } else {
538 LOG(DEBUG) << StringPrintf("%s: Selecting next tag", fn);
539 }
540
541 LOG(DEBUG) << StringPrintf("%s: exit", fn);
542 }
543
544 /*******************************************************************************
545 **
546 ** Function: deleteglobaldata
547 **
548 ** Description: Deletes the global data reference after notifying to service
549 ** e: JVM environment.
550 **
551 ** Returns: None
552 **
553 *******************************************************************************/
deleteglobaldata(JNIEnv * e)554 static void deleteglobaldata(JNIEnv* e) {
555 static const char fn[] = "deleteglobaldata";
556 LOG(DEBUG) << StringPrintf("%s: enter", fn);
557 if (sTechPollBytes != NULL) {
558 e->DeleteGlobalRef(sTechPollBytes);
559 }
560 if (gtechActBytes != NULL) {
561 e->DeleteGlobalRef(gtechActBytes);
562 }
563 LOG(DEBUG) << StringPrintf("%s: exit", fn);
564 }
565
566 /*******************************************************************************
567 **
568 ** Function: fillNativeNfcTagMembers1
569 **
570 ** Description: Fill NativeNfcTag's members: mProtocols, mTechList,
571 *mTechHandles, mTechLibNfcTypes.
572 ** e: JVM environment.
573 ** tag_cls: Java NativeNfcTag class.
574 ** tag: Java NativeNfcTag object.
575 **
576 ** Returns: None
577 **
578 *******************************************************************************/
fillNativeNfcTagMembers1(JNIEnv * e,jclass tag_cls,jobject tag)579 void NfcTag::fillNativeNfcTagMembers1(JNIEnv* e, jclass tag_cls, jobject tag) {
580 static const char fn[] = "NfcTag::fillNativeNfcTagMembers1";
581 LOG(DEBUG) << StringPrintf("%s", fn);
582
583 // create objects that represent NativeNfcTag's member variables
584 ScopedLocalRef<jintArray> techList(e, e->NewIntArray(mNumTechList));
585 ScopedLocalRef<jintArray> handleList(e, e->NewIntArray(mNumTechList));
586 ScopedLocalRef<jintArray> typeList(e, e->NewIntArray(mNumTechList));
587
588 {
589 ScopedIntArrayRW technologies(e, techList.get());
590 ScopedIntArrayRW handles(e, handleList.get());
591 ScopedIntArrayRW types(e, typeList.get());
592 for (int i = 0; i < mNumTechList; i++) {
593 mNativeData->tProtocols[i] = mTechLibNfcTypes[i];
594 mNativeData->handles[i] = mTechHandles[i];
595 technologies[i] = mTechList[i];
596 handles[i] = mTechHandles[i];
597 types[i] = mTechLibNfcTypes[i];
598 }
599 }
600
601 jfieldID f = NULL;
602
603 f = e->GetFieldID(tag_cls, "mTechList", "[I");
604 e->SetObjectField(tag, f, techList.get());
605
606 f = e->GetFieldID(tag_cls, "mTechHandles", "[I");
607 e->SetObjectField(tag, f, handleList.get());
608
609 f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I");
610 e->SetObjectField(tag, f, typeList.get());
611 }
612
613 /*******************************************************************************
614 **
615 ** Function: fillNativeNfcTagMembers2
616 **
617 ** Description: Fill NativeNfcTag's members: mConnectedTechIndex or
618 *mConnectedTechnology.
619 ** The original Google's implementation is in
620 *set_target_pollBytes(
621 ** in com_android_nfc_NativeNfcTag.cpp;
622 ** e: JVM environment.
623 ** tag_cls: Java NativeNfcTag class.
624 ** tag: Java NativeNfcTag object.
625 ** activationData: data from activation.
626 **
627 ** Returns: None
628 **
629 *******************************************************************************/
fillNativeNfcTagMembers2(JNIEnv * e,jclass tag_cls,jobject tag,tNFA_ACTIVATED &)630 void NfcTag::fillNativeNfcTagMembers2(JNIEnv* e, jclass tag_cls, jobject tag,
631 tNFA_ACTIVATED& /*activationData*/) {
632 static const char fn[] = "NfcTag::fillNativeNfcTagMembers2";
633 LOG(DEBUG) << StringPrintf("%s", fn);
634 jfieldID f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I");
635 e->SetIntField(tag, f, (jint)0);
636 }
637
638 /*******************************************************************************
639 **
640 ** Function: fillNativeNfcTagMembers3
641 **
642 ** Description: Fill NativeNfcTag's members: mTechPollBytes.
643 ** The original Google's implementation is in
644 *set_target_pollBytes(
645 ** in com_android_nfc_NativeNfcTag.cpp;
646 ** e: JVM environment.
647 ** tag_cls: Java NativeNfcTag class.
648 ** tag: Java NativeNfcTag object.
649 ** activationData: data from activation.
650 **
651 ** Returns: None
652 **
653 *******************************************************************************/
fillNativeNfcTagMembers3(JNIEnv * e,jclass tag_cls,jobject tag,tNFA_ACTIVATED & activationData)654 void NfcTag::fillNativeNfcTagMembers3(JNIEnv* e, jclass tag_cls, jobject tag,
655 tNFA_ACTIVATED& activationData) {
656 static const char fn[] = "NfcTag::fillNativeNfcTagMembers3";
657 ScopedLocalRef<jbyteArray> pollBytes(e, e->NewByteArray(0));
658 ScopedLocalRef<jclass> byteArrayClass(e, e->GetObjectClass(pollBytes.get()));
659 ScopedLocalRef<jobjectArray> techPollBytes(
660 e, e->NewObjectArray(mNumTechList, byteArrayClass.get(), 0));
661 int len = 0;
662 if (mTechListTail == 0) {
663 sTechPollBytes =
664 reinterpret_cast<jobjectArray>(e->NewGlobalRef(techPollBytes.get()));
665 } else {
666 if (sTechPollBytes == NULL) {
667 sTechPollBytes =
668 reinterpret_cast<jobjectArray>(e->NewGlobalRef(techPollBytes.get()));
669 }
670 /* Add previously activated tag's tech poll bytes also in the
671 list for multiprotocol tag*/
672 jobject techPollBytesObject;
673 for (int j = 0; j < mTechListTail; j++) {
674 techPollBytesObject = e->GetObjectArrayElement(sTechPollBytes, j);
675 e->SetObjectArrayElement(techPollBytes.get(), j, techPollBytesObject);
676 }
677 }
678
679 for (int i = mTechListTail; i < mNumTechList; i++) {
680 LOG(DEBUG) << StringPrintf("%s: index=%d; rf tech params mode=%u", fn, i,
681 mTechParams[i].mode);
682 if (NFC_DISCOVERY_TYPE_POLL_A == mTechParams[i].mode ||
683 NFC_DISCOVERY_TYPE_LISTEN_A == mTechParams[i].mode) {
684 LOG(DEBUG) << StringPrintf("%s: tech A", fn);
685 pollBytes.reset(e->NewByteArray(2));
686 e->SetByteArrayRegion(pollBytes.get(), 0, 2,
687 (jbyte*)mTechParams[i].param.pa.sens_res);
688 } else if (NFC_DISCOVERY_TYPE_POLL_B == mTechParams[i].mode ||
689 NFC_DISCOVERY_TYPE_POLL_B_PRIME == mTechParams[i].mode ||
690 NFC_DISCOVERY_TYPE_LISTEN_B == mTechParams[i].mode ||
691 NFC_DISCOVERY_TYPE_LISTEN_B_PRIME == mTechParams[i].mode) {
692 if (mTechList[i] ==
693 TARGET_TYPE_ISO14443_3B) // is TagTechnology.NFC_B by Java API
694 {
695 /*****************
696 see NFC Forum Digital Protocol specification; section 5.6.2;
697 in SENSB_RES response, byte 6 through 9 is Application Data, byte 10-12
698 or 13 is Protocol Info; used by public API: NfcB.getApplicationData(),
699 NfcB.getProtocolInfo();
700 *****************/
701 LOG(DEBUG) << StringPrintf("%s: tech B; TARGET_TYPE_ISO14443_3B", fn);
702 len = mTechParams[i].param.pb.sensb_res_len;
703 if (len >= NFC_NFCID0_MAX_LEN) {
704 // subtract 4 bytes for NFCID0 at byte 2 through 5
705 len = len - NFC_NFCID0_MAX_LEN;
706 } else {
707 android_errorWriteLog(0x534e4554, "124940143");
708 LOG(ERROR) << StringPrintf("%s: sensb_res_len error", fn);
709 len = 0;
710 }
711 pollBytes.reset(e->NewByteArray(len));
712 e->SetByteArrayRegion(pollBytes.get(), 0, len,
713 (jbyte*)(mTechParams[i].param.pb.sensb_res + 4));
714 } else {
715 pollBytes.reset(e->NewByteArray(0));
716 }
717 } else if (NFC_DISCOVERY_TYPE_POLL_F == mTechParams[i].mode ||
718 NFC_DISCOVERY_TYPE_LISTEN_F == mTechParams[i].mode) {
719 /****************
720 see NFC Forum Type 3 Tag Operation Specification; sections 2.3.2, 2.3.1.2;
721 see NFC Forum Digital Protocol Specification; sections 6.6.2;
722 PMm: manufacture parameter; 8 bytes;
723 System Code: 2 bytes;
724 ****************/
725 LOG(DEBUG) << StringPrintf("%s: tech F", fn);
726 uint8_t result[10]; // return result to NFC service
727 memset(result, 0, sizeof(result));
728 len = 10;
729
730 /****
731 for (int ii = 0; ii < mTechParams [i].param.pf.sensf_res_len; ii++)
732 {
733 LOG(DEBUG) << StringPrintf("%s: tech F,
734 sendf_res[%d]=%d (0x%x)", fn, ii, mTechParams
735 [i].param.pf.sensf_res[ii],mTechParams [i].param.pf.sensf_res[ii]);
736 }
737 ***/
738 memcpy(result, mTechParams[i].param.pf.sensf_res + 8, 8); // copy PMm
739 if (activationData.params.t3t.num_system_codes >
740 0) // copy the first System Code
741 {
742 uint16_t systemCode = *(activationData.params.t3t.p_system_codes);
743 result[8] = (uint8_t)(systemCode >> 8);
744 result[9] = (uint8_t)systemCode;
745 LOG(DEBUG) << StringPrintf("%s: tech F; sys code=0x%X 0x%X", fn,
746 result[8], result[9]);
747 }
748 pollBytes.reset(e->NewByteArray(len));
749 e->SetByteArrayRegion(pollBytes.get(), 0, len, (jbyte*)result);
750 } else if (NFC_DISCOVERY_TYPE_POLL_V == mTechParams[i].mode ||
751 NFC_DISCOVERY_TYPE_LISTEN_ISO15693 == mTechParams[i].mode) {
752 LOG(DEBUG) << StringPrintf("%s: tech iso 15693", fn);
753 // iso 15693 response flags: 1 octet
754 // iso 15693 Data Structure Format Identifier (DSF ID): 1 octet
755 // used by public API: NfcV.getDsfId(), NfcV.getResponseFlags();
756 uint8_t data[2] = {activationData.params.i93.afi,
757 activationData.params.i93.dsfid};
758 pollBytes.reset(e->NewByteArray(2));
759 e->SetByteArrayRegion(pollBytes.get(), 0, 2, (jbyte*)data);
760 } else {
761 LOG(ERROR) << StringPrintf("%s: tech unknown ????", fn);
762 pollBytes.reset(e->NewByteArray(0));
763 } // switch: every type of technology
764 e->SetObjectArrayElement(techPollBytes.get(), i, pollBytes.get());
765 } // for: every technology in the array
766 if (sTechPollBytes != NULL && mTechListTail != 0) {
767 /* Save tech poll bytes of all activated tags of a multiprotocol tag in
768 * sTechPollBytes*/
769 e->DeleteGlobalRef(sTechPollBytes);
770 sTechPollBytes =
771 reinterpret_cast<jobjectArray>(e->NewGlobalRef(techPollBytes.get()));
772 }
773 jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B");
774 e->SetObjectField(tag, f, techPollBytes.get());
775 }
776
777 /*******************************************************************************
778 **
779 ** Function: fillNativeNfcTagMembers4
780 **
781 ** Description: Fill NativeNfcTag's members: mTechActBytes.
782 ** The original Google's implementation is in
783 *set_target_activationBytes()
784 ** in com_android_nfc_NativeNfcTag.cpp;
785 ** e: JVM environment.
786 ** tag_cls: Java NativeNfcTag class.
787 ** tag: Java NativeNfcTag object.
788 ** activationData: data from activation.
789 **
790 ** Returns: None
791 **
792 *******************************************************************************/
fillNativeNfcTagMembers4(JNIEnv * e,jclass tag_cls,jobject tag,tNFA_ACTIVATED & activationData)793 void NfcTag::fillNativeNfcTagMembers4(JNIEnv* e, jclass tag_cls, jobject tag,
794 tNFA_ACTIVATED& activationData) {
795 static const char fn[] = "NfcTag::fillNativeNfcTagMembers4";
796 ScopedLocalRef<jbyteArray> actBytes(e, e->NewByteArray(0));
797 ScopedLocalRef<jclass> byteArrayClass(e, e->GetObjectClass(actBytes.get()));
798 ScopedLocalRef<jobjectArray> techActBytes(
799 e, e->NewObjectArray(mNumTechList, byteArrayClass.get(), 0));
800 jobject gtechActBytesObject;
801 // Restore previously selected tag information from the gtechActBytes to
802 // techActBytes.
803 for (int j = 0; j < mTechListTail; j++) {
804 gtechActBytesObject = e->GetObjectArrayElement(gtechActBytes, j);
805 e->SetObjectArrayElement(techActBytes.get(), j, gtechActBytesObject);
806 }
807
808 // merging sak for combi tag
809 if (activationData.activate_ntf.protocol &
810 (NFC_PROTOCOL_T1T | NFC_PROTOCOL_T2T | NFC_PROTOCOL_MIFARE |
811 NFC_PROTOCOL_ISO_DEP)) {
812 uint8_t merge_sak = 0;
813 for (int i = 0; i < mNumTechList; i++) {
814 merge_sak = (merge_sak | mTechParams[i].param.pa.sel_rsp);
815 }
816 for (int i = 0; i < mNumTechList; i++) {
817 if (TARGET_TYPE_ISO14443_3A == mTechList[i]) {
818 mTechParams[i].param.pa.sel_rsp = merge_sak;
819 actBytes.reset(e->NewByteArray(1));
820 e->SetByteArrayRegion(actBytes.get(), 0, 1,
821 (jbyte*)&mTechParams[i].param.pa.sel_rsp);
822 e->SetObjectArrayElement(techActBytes.get(), i, actBytes.get());
823 }
824 }
825 }
826
827 if (mTechListTail == 0) {
828 // Keep the backup of the selected tag information to restore back with
829 // multi selection.
830 gtechActBytes =
831 reinterpret_cast<jobjectArray>(e->NewGlobalRef(techActBytes.get()));
832 } else {
833 for (int j = 0; j < mTechListTail; j++) {
834 gtechActBytesObject = e->GetObjectArrayElement(gtechActBytes, j);
835 e->SetObjectArrayElement(techActBytes.get(), j, gtechActBytesObject);
836 }
837 }
838
839 for (int i = mTechListTail; i < mNumTechList; i++) {
840 LOG(DEBUG) << StringPrintf("%s: index=%d", fn, i);
841 if (NFC_PROTOCOL_T1T == mTechLibNfcTypes[i] ||
842 NFC_PROTOCOL_T2T == mTechLibNfcTypes[i]) {
843 if (mTechLibNfcTypes[i] == NFC_PROTOCOL_T1T)
844 LOG(DEBUG) << StringPrintf("%s: T1T; tech A", fn);
845 else if (mTechLibNfcTypes[i] == NFC_PROTOCOL_T2T)
846 LOG(DEBUG) << StringPrintf("%s: T2T; tech A", fn);
847 actBytes.reset(e->NewByteArray(1));
848 e->SetByteArrayRegion(actBytes.get(), 0, 1,
849 (jbyte*)&mTechParams[i].param.pa.sel_rsp);
850 } else if (NFC_PROTOCOL_T3T == mTechLibNfcTypes[i]) {
851 // felica
852 LOG(DEBUG) << StringPrintf("%s: T3T; felica; tech F", fn);
853 // really, there is no data
854 actBytes.reset(e->NewByteArray(0));
855 } else if (NFC_PROTOCOL_MIFARE == mTechLibNfcTypes[i]) {
856 LOG(DEBUG) << StringPrintf("%s: Mifare Classic; tech A", fn);
857 actBytes.reset(e->NewByteArray(1));
858 e->SetByteArrayRegion(actBytes.get(), 0, 1,
859 (jbyte*)&mTechParams[i].param.pa.sel_rsp);
860 } else if (NFC_PROTOCOL_ISO_DEP == mTechLibNfcTypes[i]) {
861 // t4t
862 if (mTechList[i] ==
863 TARGET_TYPE_ISO14443_4) // is TagTechnology.ISO_DEP by Java API
864 {
865 if ((mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) ||
866 (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A)) {
867 // see NFC Forum Digital Protocol specification, section 11.6.2, "RATS
868 // Response"; search for "historical bytes"; copy historical bytes
869 // into Java object; the public API, IsoDep.getHistoricalBytes(),
870 // returns this data;
871 if (activationData.activate_ntf.intf_param.type ==
872 NFC_INTERFACE_ISO_DEP) {
873 tNFC_INTF_PA_ISO_DEP& pa_iso =
874 activationData.activate_ntf.intf_param.intf_param.pa_iso;
875 LOG(DEBUG) << StringPrintf(
876 "%s: T4T; ISO_DEP for tech A; copy historical bytes; len=%u",
877 fn, pa_iso.his_byte_len);
878 actBytes.reset(e->NewByteArray(pa_iso.his_byte_len));
879 if (pa_iso.his_byte_len > 0)
880 e->SetByteArrayRegion(actBytes.get(), 0, pa_iso.his_byte_len,
881 (jbyte*)(pa_iso.his_byte));
882 } else {
883 LOG(ERROR) << StringPrintf(
884 "%s: T4T; ISO_DEP for tech A; wrong interface=%u", fn,
885 activationData.activate_ntf.intf_param.type);
886 actBytes.reset(e->NewByteArray(0));
887 }
888 } else if ((mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B) ||
889 (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) ||
890 (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B) ||
891 (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME)) {
892 // see NFC Forum Digital Protocol specification, section 12.6.2,
893 // "ATTRIB Response"; copy higher-layer response bytes into Java
894 // object; the public API, IsoDep.getHiLayerResponse(), returns this
895 // data;
896 if (activationData.activate_ntf.intf_param.type ==
897 NFC_INTERFACE_ISO_DEP) {
898 tNFC_INTF_PB_ISO_DEP& pb_iso =
899 activationData.activate_ntf.intf_param.intf_param.pb_iso;
900 LOG(DEBUG) << StringPrintf(
901 "%s: T4T; ISO_DEP for tech B; copy response bytes; len=%u", fn,
902 pb_iso.hi_info_len);
903 actBytes.reset(e->NewByteArray(pb_iso.hi_info_len));
904 if (pb_iso.hi_info_len > 0)
905 e->SetByteArrayRegion(actBytes.get(), 0, pb_iso.hi_info_len,
906 (jbyte*)(pb_iso.hi_info));
907 } else {
908 LOG(ERROR) << StringPrintf(
909 "%s: T4T; ISO_DEP for tech B; wrong interface=%u", fn,
910 activationData.activate_ntf.intf_param.type);
911 actBytes.reset(e->NewByteArray(0));
912 }
913 }
914 } else if (mTechList[i] ==
915 TARGET_TYPE_ISO14443_3A) // is TagTechnology.NFC_A by Java API
916 {
917 LOG(DEBUG) << StringPrintf("%s: T4T; tech A", fn);
918 actBytes.reset(e->NewByteArray(1));
919 e->SetByteArrayRegion(actBytes.get(), 0, 1,
920 (jbyte*)&mTechParams[i].param.pa.sel_rsp);
921 } else {
922 actBytes.reset(e->NewByteArray(0));
923 }
924 } // case NFC_PROTOCOL_ISO_DEP: //t4t
925 else if (NFC_PROTOCOL_T5T == mTechLibNfcTypes[i]) {
926 LOG(DEBUG) << StringPrintf("%s: tech iso 15693", fn);
927 // iso 15693 response flags: 1 octet
928 // iso 15693 Data Structure Format Identifier (DSF ID): 1 octet
929 // used by public API: NfcV.getDsfId(), NfcV.getResponseFlags();
930 uint8_t data[2] = {activationData.params.i93.afi,
931 activationData.params.i93.dsfid};
932 actBytes.reset(e->NewByteArray(2));
933 e->SetByteArrayRegion(actBytes.get(), 0, 2, (jbyte*)data);
934 } else {
935 LOG(DEBUG) << StringPrintf("%s: tech unknown ????", fn);
936 actBytes.reset(e->NewByteArray(0));
937 }
938 e->SetObjectArrayElement(techActBytes.get(), i, actBytes.get());
939 } // for: every technology in the array of current selected tag
940 if (gtechActBytes != NULL && mTechListTail != 0) {
941 e->DeleteGlobalRef(gtechActBytes);
942 gtechActBytes =
943 reinterpret_cast<jobjectArray>(e->NewGlobalRef(techActBytes.get()));
944 }
945 jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B");
946 e->SetObjectField(tag, f, techActBytes.get());
947 }
948
949 /*******************************************************************************
950 **
951 ** Function: fillNativeNfcTagMembers5
952 **
953 ** Description: Fill NativeNfcTag's members: mUid.
954 ** The original Google's implementation is in
955 *nfc_jni_Discovery_notification_callback()
956 ** in com_android_nfc_NativeNfcManager.cpp;
957 ** e: JVM environment.
958 ** tag_cls: Java NativeNfcTag class.
959 ** tag: Java NativeNfcTag object.
960 ** activationData: data from activation.
961 **
962 ** Returns: None
963 **
964 *******************************************************************************/
fillNativeNfcTagMembers5(JNIEnv * e,jclass tag_cls,jobject tag,tNFA_ACTIVATED & activationData)965 void NfcTag::fillNativeNfcTagMembers5(JNIEnv* e, jclass tag_cls, jobject tag,
966 tNFA_ACTIVATED& activationData) {
967 static const char fn[] = "NfcTag::fillNativeNfcTagMembers5";
968 int len = 0;
969 ScopedLocalRef<jbyteArray> uid(e, NULL);
970
971 if (NFC_DISCOVERY_TYPE_POLL_KOVIO == mTechParams[0].mode) {
972 LOG(DEBUG) << StringPrintf("%s: Kovio", fn);
973 len = mTechParams[0].param.pk.uid_len;
974 uid.reset(e->NewByteArray(len));
975 e->SetByteArrayRegion(uid.get(), 0, len,
976 (jbyte*)&mTechParams[0].param.pk.uid);
977 } else if (NFC_DISCOVERY_TYPE_POLL_A == mTechParams[0].mode ||
978 NFC_DISCOVERY_TYPE_LISTEN_A == mTechParams[0].mode) {
979 LOG(DEBUG) << StringPrintf("%s: tech A", fn);
980 len = mTechParams[0].param.pa.nfcid1_len;
981 uid.reset(e->NewByteArray(len));
982 e->SetByteArrayRegion(uid.get(), 0, len,
983 (jbyte*)&mTechParams[0].param.pa.nfcid1);
984 // a tag's NFCID1 can change dynamically at each activation;
985 // only the first byte (0x08) is constant; a dynamic NFCID1's length
986 // must be 4 bytes (see NFC Digitial Protocol,
987 // section 4.7.2 SDD_RES Response, Requirements 20).
988 mIsDynamicTagId = (mTechParams[0].param.pa.nfcid1_len == 4) &&
989 (mTechParams[0].param.pa.nfcid1[0] == 0x08);
990 } else if (NFC_DISCOVERY_TYPE_POLL_B == mTechParams[0].mode ||
991 NFC_DISCOVERY_TYPE_POLL_B_PRIME == mTechParams[0].mode ||
992 NFC_DISCOVERY_TYPE_LISTEN_B == mTechParams[0].mode ||
993 NFC_DISCOVERY_TYPE_LISTEN_B_PRIME == mTechParams[0].mode) {
994 LOG(DEBUG) << StringPrintf("%s: tech B", fn);
995 uid.reset(e->NewByteArray(NFC_NFCID0_MAX_LEN));
996 e->SetByteArrayRegion(uid.get(), 0, NFC_NFCID0_MAX_LEN,
997 (jbyte*)&mTechParams[0].param.pb.nfcid0);
998 } else if (NFC_DISCOVERY_TYPE_POLL_F == mTechParams[0].mode ||
999 NFC_DISCOVERY_TYPE_LISTEN_F == mTechParams[0].mode) {
1000 uid.reset(e->NewByteArray(NFC_NFCID2_LEN));
1001 e->SetByteArrayRegion(uid.get(), 0, NFC_NFCID2_LEN,
1002 (jbyte*)&mTechParams[0].param.pf.nfcid2);
1003 LOG(DEBUG) << StringPrintf("%s: tech F", fn);
1004 } else if (NFC_DISCOVERY_TYPE_POLL_V == mTechParams[0].mode ||
1005 NFC_DISCOVERY_TYPE_LISTEN_ISO15693 == mTechParams[0].mode) {
1006 LOG(DEBUG) << StringPrintf("%s: tech iso 15693", fn);
1007 jbyte data[I93_UID_BYTE_LEN]; // 8 bytes
1008 for (int i = 0; i < I93_UID_BYTE_LEN; ++i) // reverse the ID
1009 data[i] = activationData.params.i93.uid[I93_UID_BYTE_LEN - i - 1];
1010 uid.reset(e->NewByteArray(I93_UID_BYTE_LEN));
1011 e->SetByteArrayRegion(uid.get(), 0, I93_UID_BYTE_LEN, data);
1012 } else {
1013 LOG(ERROR) << StringPrintf("%s: tech unknown ????", fn);
1014 uid.reset(e->NewByteArray(0));
1015 }
1016 jfieldID f = e->GetFieldID(tag_cls, "mUid", "[B");
1017 e->SetObjectField(tag, f, uid.get());
1018 mTechListTail = mNumTechList;
1019 if (mNumDiscNtf == 0) mTechListTail = 0;
1020 LOG(DEBUG) << StringPrintf("%s;mTechListTail=%x", fn, mTechListTail);
1021 }
1022
1023 /*******************************************************************************
1024 **
1025 ** Function: resetTechnologies
1026 **
1027 ** Description: Clear all data related to the technology, protocol of the
1028 *tag.
1029 **
1030 ** Returns: None
1031 **
1032 *******************************************************************************/
resetTechnologies()1033 void NfcTag::resetTechnologies() {
1034 static const char fn[] = "NfcTag::resetTechnologies";
1035 LOG(DEBUG) << StringPrintf("%s", fn);
1036 mNumTechList = 0;
1037 mNumDiscNtf = 0;
1038 mNumDiscTechList = 0;
1039 mTechListTail = 0;
1040 mIsMultiProtocolTag = false;
1041 memset(mTechList, 0, sizeof(mTechList));
1042 memset(mTechHandles, 0, sizeof(mTechHandles));
1043 memset(mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes));
1044 memset(mTechParams, 0, sizeof(mTechParams));
1045 mIsDynamicTagId = false;
1046 mIsFelicaLite = false;
1047 resetAllTransceiveTimeouts();
1048 }
1049
1050 /*******************************************************************************
1051 **
1052 ** Function: selectFirstTag
1053 **
1054 ** Description: When multiple tags are discovered, just select the first one
1055 *to activate.
1056 **
1057 ** Returns: None
1058 **
1059 *******************************************************************************/
selectFirstTag()1060 void NfcTag::selectFirstTag() {
1061 static const char fn[] = "NfcTag::selectFirstTag";
1062 int foundIdx = -1;
1063 tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME;
1064
1065 for (int i = 0; i < mNumDiscTechList; i++) {
1066 LOG(DEBUG) << StringPrintf("%s: nfa target idx=%d h=0x%X; protocol=0x%X",
1067 fn, i, mTechHandlesDiscData[i],
1068 mTechLibNfcTypesDiscData[i]);
1069 if (mTechLibNfcTypesDiscData[i] != NFA_PROTOCOL_NFC_DEP) {
1070 sLastSelectedTagId = i;
1071 foundIdx = i;
1072 break;
1073 }
1074 }
1075
1076 if (foundIdx != -1) {
1077 if (mTechLibNfcTypesDiscData[foundIdx] == NFA_PROTOCOL_ISO_DEP) {
1078 rf_intf = NFA_INTERFACE_ISO_DEP;
1079 } else if (mTechLibNfcTypesDiscData[foundIdx] == NFC_PROTOCOL_MIFARE) {
1080 rf_intf = NFA_INTERFACE_MIFARE;
1081 } else
1082 rf_intf = NFA_INTERFACE_FRAME;
1083
1084 tNFA_STATUS stat = NFA_Select(mTechHandlesDiscData[foundIdx],
1085 mTechLibNfcTypesDiscData[foundIdx], rf_intf);
1086 if (stat != NFA_STATUS_OK)
1087 LOG(ERROR) << StringPrintf("%s: fail select; error=0x%X", fn, stat);
1088 } else
1089 LOG(ERROR) << StringPrintf("%s: only found NFC-DEP technology.", fn);
1090 }
1091
1092 /*******************************************************************************
1093 **
1094 ** Function: selectNextTagIfExists
1095 **
1096 ** Description: When multiple tags are discovered, selects the next tag to
1097 ** activate.
1098 **
1099 ** Returns: None
1100 **
1101 *******************************************************************************/
selectNextTagIfExists()1102 void NfcTag::selectNextTagIfExists() {
1103 static const char fn[] = "NfcTag::selectNextTagIfExists";
1104 int foundIdx = -1;
1105 tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME;
1106 tNFA_STATUS stat = NFA_STATUS_FAILED;
1107
1108 if (mNumDiscNtf == 0) {
1109 return;
1110 }
1111 mNumDiscNtf--;
1112 LOG(DEBUG) << StringPrintf("%s: enter, mNumDiscTechList=%x", fn,
1113 mNumDiscTechList);
1114 for (int i = 0; i < mNumDiscTechList; i++) {
1115 LOG(DEBUG) << StringPrintf("%s: nfa target idx=%dh=0x%X; protocol=0x%X", fn,
1116 i, mTechHandlesDiscData[i],
1117 mTechLibNfcTypesDiscData[i]);
1118 if (((mTechHandlesDiscData[sLastSelectedTagId] !=
1119 mTechHandlesDiscData[i]) ||
1120 (mTechLibNfcTypesDiscData[sLastSelectedTagId] !=
1121 mTechLibNfcTypesDiscData[i])) &&
1122 (mTechLibNfcTypesDiscData[i] != NFA_PROTOCOL_NFC_DEP)) {
1123 sLastSelectedTagId = i;
1124 foundIdx = i;
1125 break;
1126 }
1127 }
1128
1129 if (foundIdx != -1) {
1130 if (mTechLibNfcTypesDiscData[foundIdx] == NFA_PROTOCOL_ISO_DEP) {
1131 rf_intf = NFA_INTERFACE_ISO_DEP;
1132 } else if (mTechLibNfcTypesDiscData[foundIdx] == NFC_PROTOCOL_MIFARE) {
1133 rf_intf = NFA_INTERFACE_MIFARE;
1134 } else {
1135 rf_intf = NFA_INTERFACE_FRAME;
1136 }
1137
1138 stat = NFA_Select(mTechHandlesDiscData[foundIdx],
1139 mTechLibNfcTypesDiscData[foundIdx], rf_intf);
1140 if (stat == NFA_STATUS_OK) {
1141 LOG(ERROR) << StringPrintf("%s: Select Success, wait for activated ntf",
1142 fn);
1143 } else {
1144 LOG(ERROR) << StringPrintf("%s: fail select; error=0x%X", fn, stat);
1145 }
1146 } else {
1147 LOG(ERROR) << StringPrintf("%s: only found NFC-DEP technology.", fn);
1148 }
1149 }
1150
1151 /*******************************************************************************
1152 **
1153 ** Function: getT1tMaxMessageSize
1154 **
1155 ** Description: Get the maximum size (octet) that a T1T can store.
1156 **
1157 ** Returns: Maximum size in octets.
1158 **
1159 *******************************************************************************/
getT1tMaxMessageSize()1160 int NfcTag::getT1tMaxMessageSize() {
1161 static const char fn[] = "NfcTag::getT1tMaxMessageSize";
1162
1163 if (mProtocol != NFC_PROTOCOL_T1T) {
1164 LOG(ERROR) << StringPrintf("%s: wrong protocol %u", fn, mProtocol);
1165 return 0;
1166 }
1167 return mtT1tMaxMessageSize;
1168 }
1169
1170 /*******************************************************************************
1171 **
1172 ** Function: calculateT1tMaxMessageSize
1173 **
1174 ** Description: Calculate type-1 tag's max message size based on header ROM
1175 *bytes.
1176 ** activate: reference to activation data.
1177 **
1178 ** Returns: None
1179 **
1180 *******************************************************************************/
calculateT1tMaxMessageSize(tNFA_ACTIVATED & activate)1181 void NfcTag::calculateT1tMaxMessageSize(tNFA_ACTIVATED& activate) {
1182 static const char fn[] = "NfcTag::calculateT1tMaxMessageSize";
1183
1184 // make sure the tag is type-1
1185 if (activate.activate_ntf.protocol != NFC_PROTOCOL_T1T) {
1186 mtT1tMaxMessageSize = 0;
1187 return;
1188 }
1189
1190 // examine the first byte of header ROM bytes
1191 switch (activate.params.t1t.hr[0]) {
1192 case RW_T1T_IS_TOPAZ96:
1193 mtT1tMaxMessageSize = 90;
1194 break;
1195 case RW_T1T_IS_TOPAZ512:
1196 mtT1tMaxMessageSize = 462;
1197 break;
1198 default:
1199 LOG(ERROR) << StringPrintf("%s: unknown T1T HR0=%u", fn,
1200 activate.params.t1t.hr[0]);
1201 mtT1tMaxMessageSize = 0;
1202 break;
1203 }
1204 }
1205
1206 /*******************************************************************************
1207 **
1208 ** Function: isMifareUltralight
1209 **
1210 ** Description: Whether the currently activated tag is Mifare Ultralight.
1211 **
1212 ** Returns: True if tag is Mifare Ultralight.
1213 **
1214 *******************************************************************************/
isMifareUltralight()1215 bool NfcTag::isMifareUltralight() {
1216 static const char fn[] = "NfcTag::isMifareUltralight";
1217 bool retval = false;
1218
1219 for (int i = 0; i < mNumTechList; i++) {
1220 if (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) {
1221 // see NFC Digital Protocol, section 4.6.3 (SENS_RES); section 4.8.2
1222 // (SEL_RES). see "MF0ICU1 Functional specification MIFARE Ultralight",
1223 // Rev. 3.4 - 4 February 2008, section 6.7.
1224 if ((mTechParams[i].param.pa.sens_res[0] == 0x44) &&
1225 (mTechParams[i].param.pa.sens_res[1] == 0) &&
1226 ((mTechParams[i].param.pa.sel_rsp == 0) ||
1227 (mTechParams[i].param.pa.sel_rsp == 0x04)) &&
1228 (mTechParams[i].param.pa.nfcid1[0] == 0x04)) {
1229 retval = true;
1230 }
1231 break;
1232 }
1233 }
1234 LOG(DEBUG) << StringPrintf("%s: return=%u", fn, retval);
1235 return retval;
1236 }
1237
1238 /*******************************************************************************
1239 **
1240 ** Function: isMifareDESFire
1241 **
1242 ** Description: Whether the currently activated tag is Mifare DESFire.
1243 **
1244 ** Returns: True if tag is Mifare DESFire.
1245 **
1246 *******************************************************************************/
isMifareDESFire()1247 bool NfcTag::isMifareDESFire() {
1248 static const char fn[] = "NfcTag::isMifareDESFire";
1249 bool retval = false;
1250
1251 for (int i = 0; i < mNumTechList; i++) {
1252 if ((mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) ||
1253 (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A)) {
1254 /* DESfire has one sak byte and 2 ATQA bytes */
1255 if ((mTechParams[i].param.pa.sens_res[0] == 0x44) &&
1256 (mTechParams[i].param.pa.sens_res[1] == 0x03) &&
1257 (mTechParams[i].param.pa.sel_rsp == 0x20)) {
1258 retval = true;
1259 }
1260 break;
1261 }
1262 }
1263
1264 LOG(DEBUG) << StringPrintf("%s: return=%u", fn, retval);
1265 return retval;
1266 }
1267
1268 /*******************************************************************************
1269 **
1270 ** Function: isFelicaLite
1271 **
1272 ** Description: Whether the currently activated tag is Felica Lite.
1273 **
1274 ** Returns: True if tag is Felica Lite.
1275 **
1276 *******************************************************************************/
1277
isFelicaLite()1278 bool NfcTag::isFelicaLite() { return mIsFelicaLite; }
1279
1280 /*******************************************************************************
1281 **
1282 ** Function: isT2tNackResponse
1283 **
1284 ** Description: Whether the response is a T2T NACK response.
1285 ** See NFC Digital Protocol Technical Specification
1286 *(2010-11-17).
1287 ** Chapter 9 (Type 2 Tag Platform), section 9.6 (READ).
1288 ** response: buffer contains T2T response.
1289 ** responseLen: length of the response.
1290 **
1291 ** Returns: True if the response is NACK
1292 **
1293 *******************************************************************************/
isT2tNackResponse(const uint8_t * response,uint32_t responseLen)1294 bool NfcTag::isT2tNackResponse(const uint8_t* response, uint32_t responseLen) {
1295 static const char fn[] = "NfcTag::isT2tNackResponse";
1296 bool isNack = false;
1297
1298 if (responseLen == 1) {
1299 if (response[0] == 0xA)
1300 isNack = false; // an ACK response, so definitely not a NACK
1301 else
1302 isNack = true; // assume every value is a NACK
1303 }
1304 LOG(DEBUG) << StringPrintf("%s: return %u", fn, isNack);
1305 return isNack;
1306 }
1307
1308 /*******************************************************************************
1309 **
1310 ** Function: isNdefDetectionTimedOut
1311 **
1312 ** Description: Whether NDEF-detection algorithm timed out.
1313 **
1314 ** Returns: True if NDEF-detection algorithm timed out.
1315 **
1316 *******************************************************************************/
isNdefDetectionTimedOut()1317 bool NfcTag::isNdefDetectionTimedOut() { return mNdefDetectionTimedOut; }
1318
1319 /*******************************************************************************
1320 **
1321 ** Function: connectionEventHandler
1322 **
1323 ** Description: Handle connection-related events.
1324 ** event: event code.
1325 ** data: pointer to event data.
1326 **
1327 ** Returns: None
1328 **
1329 *******************************************************************************/
connectionEventHandler(uint8_t event,tNFA_CONN_EVT_DATA * data)1330 void NfcTag::connectionEventHandler(uint8_t event, tNFA_CONN_EVT_DATA* data) {
1331 static const char fn[] = "NfcTag::connectionEventHandler";
1332
1333 switch (event) {
1334 case NFA_DISC_RESULT_EVT: {
1335 tNFA_DISC_RESULT& disc_result = data->disc_result;
1336 if (disc_result.status == NFA_STATUS_OK) {
1337 discoverTechnologies(disc_result);
1338 }
1339 } break;
1340
1341 case NFA_ACTIVATED_EVT:
1342 // Only do tag detection if we are polling and it is not 'EE Direct RF'
1343 // activation (which may happen when we are activated as a tag).
1344 if (data->activated.activate_ntf.rf_tech_param.mode <
1345 NCI_DISCOVERY_TYPE_LISTEN_A &&
1346 data->activated.activate_ntf.intf_param.type !=
1347 NFC_INTERFACE_EE_DIRECT_RF) {
1348 tNFA_ACTIVATED& activated = data->activated;
1349 if (IsSameKovio(activated)) break;
1350 mIsActivated = true;
1351 mProtocol = activated.activate_ntf.protocol;
1352 calculateT1tMaxMessageSize(activated);
1353 discoverTechnologies(activated);
1354 createNativeNfcTag(activated);
1355 }
1356 break;
1357
1358 case NFA_DEACTIVATED_EVT:
1359 mIsActivated = false;
1360 mProtocol = NFC_PROTOCOL_UNKNOWN;
1361 resetTechnologies();
1362 break;
1363
1364 case NFA_READ_CPLT_EVT: {
1365 SyncEventGuard g(mReadCompleteEvent);
1366 mReadCompletedStatus = data->status;
1367 mNdefDetectionTimedOut = data->status != NFA_STATUS_OK;
1368 if (mNdefDetectionTimedOut)
1369 LOG(ERROR) << StringPrintf("%s: NDEF detection timed out", fn);
1370 mReadCompleteEvent.notifyOne();
1371 } break;
1372
1373 case NFA_NDEF_DETECT_EVT: {
1374 tNFA_NDEF_DETECT& ndef_detect = data->ndef_detect;
1375 mNdefDetectionTimedOut = ndef_detect.status == NFA_STATUS_TIMEOUT;
1376 if (mNdefDetectionTimedOut)
1377 LOG(ERROR) << StringPrintf("%s: NDEF detection timed out", fn);
1378 }
1379 }
1380 }
1381
1382 /*******************************************************************************
1383 **
1384 ** Function setActive
1385 **
1386 ** Description Sets the active state for the object
1387 **
1388 ** Returns None.
1389 **
1390 *******************************************************************************/
setActive(bool active)1391 void NfcTag::setActive(bool active) { mIsActivated = active; }
1392
1393 /*******************************************************************************
1394 **
1395 ** Function: isDynamicTagId
1396 **
1397 ** Description: Whether a tag has a dynamic tag ID.
1398 **
1399 ** Returns: True if ID is dynamic.
1400 **
1401 *******************************************************************************/
isDynamicTagId()1402 bool NfcTag::isDynamicTagId() {
1403 return mIsDynamicTagId &&
1404 (mTechList[0] == TARGET_TYPE_ISO14443_4) && // type-4 tag
1405 (mTechList[1] == TARGET_TYPE_ISO14443_3A); // tech A
1406 }
1407
1408 /*******************************************************************************
1409 **
1410 ** Function: resetAllTransceiveTimeouts
1411 **
1412 ** Description: Reset all timeouts for all technologies to default values.
1413 **
1414 ** Returns: none
1415 **
1416 *******************************************************************************/
resetAllTransceiveTimeouts()1417 void NfcTag::resetAllTransceiveTimeouts() {
1418 mTechnologyTimeoutsTable[TARGET_TYPE_ISO14443_3A] = 618; // NfcA
1419 mTechnologyTimeoutsTable[TARGET_TYPE_ISO14443_3B] = 1000; // NfcB
1420 mTechnologyTimeoutsTable[TARGET_TYPE_ISO14443_4] = 618; // ISO-DEP
1421 mTechnologyTimeoutsTable[TARGET_TYPE_FELICA] = 255; // Felica
1422 mTechnologyTimeoutsTable[TARGET_TYPE_V] = 1000; // NfcV
1423 mTechnologyTimeoutsTable[TARGET_TYPE_NDEF] = 1000;
1424 mTechnologyTimeoutsTable[TARGET_TYPE_NDEF_FORMATABLE] = 1000;
1425 mTechnologyTimeoutsTable[TARGET_TYPE_MIFARE_CLASSIC] = 618; // MifareClassic
1426 mTechnologyTimeoutsTable[TARGET_TYPE_MIFARE_UL] = 618; // MifareUltralight
1427 mTechnologyTimeoutsTable[TARGET_TYPE_KOVIO_BARCODE] = 1000; // NfcBarcode
1428 }
1429
1430 /*******************************************************************************
1431 **
1432 ** Function: getTransceiveTimeout
1433 **
1434 ** Description: Get the timeout value for one technology.
1435 ** techId: one of the values in TARGET_TYPE_* defined in
1436 *NfcJniUtil.h
1437 **
1438 ** Returns: Timeout value in millisecond.
1439 **
1440 *******************************************************************************/
getTransceiveTimeout(int techId)1441 int NfcTag::getTransceiveTimeout(int techId) {
1442 static const char fn[] = "NfcTag::getTransceiveTimeout";
1443 int retval = 1000;
1444 if ((techId > 0) && (techId < (int)mTechnologyTimeoutsTable.size()))
1445 retval = mTechnologyTimeoutsTable[techId];
1446 else
1447 LOG(ERROR) << StringPrintf("%s: invalid tech=%d", fn, techId);
1448 return retval;
1449 }
1450
1451 /*******************************************************************************
1452 **
1453 ** Function: setTransceiveTimeout
1454 **
1455 ** Description: Set the timeout value for one technology.
1456 ** techId: one of the values in TARGET_TYPE_* defined in
1457 *NfcJniUtil.h
1458 ** timeout: timeout value in millisecond.
1459 **
1460 ** Returns: Timeout value.
1461 **
1462 *******************************************************************************/
setTransceiveTimeout(int techId,int timeout)1463 void NfcTag::setTransceiveTimeout(int techId, int timeout) {
1464 static const char fn[] = "NfcTag::setTransceiveTimeout";
1465 if ((techId >= 0) && (techId < (int)mTechnologyTimeoutsTable.size()))
1466 mTechnologyTimeoutsTable[techId] = timeout;
1467 else
1468 LOG(ERROR) << StringPrintf("%s: invalid tech=%d", fn, techId);
1469 }
1470
1471 /*******************************************************************************
1472 **
1473 ** Function: getPresenceCheckAlgorithm
1474 **
1475 ** Description: Get presence-check algorithm from .conf file.
1476 **
1477 ** Returns: Presence-check algorithm.
1478 **
1479 *******************************************************************************/
getPresenceCheckAlgorithm()1480 tNFA_RW_PRES_CHK_OPTION NfcTag::getPresenceCheckAlgorithm() {
1481 return mPresenceCheckAlgorithm;
1482 }
1483
1484 /*******************************************************************************
1485 **
1486 ** Function: isInfineonMyDMove
1487 **
1488 ** Description: Whether the currently activated tag is Infineon My-D Move.
1489 **
1490 ** Returns: True if tag is Infineon My-D Move.
1491 **
1492 *******************************************************************************/
isInfineonMyDMove()1493 bool NfcTag::isInfineonMyDMove() {
1494 static const char fn[] = "NfcTag::isInfineonMyDMove";
1495 bool retval = false;
1496
1497 for (int i = 0; i < mNumTechList; i++) {
1498 if (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) {
1499 // see Infineon my-d move, my-d move NFC, SLE 66R01P, SLE 66R01PN,
1500 // Short Product Information, 2011-11-24, section 3.5
1501 if (mTechParams[i].param.pa.nfcid1[0] == 0x05) {
1502 uint8_t highNibble = mTechParams[i].param.pa.nfcid1[1] & 0xF0;
1503 if (highNibble == 0x30) retval = true;
1504 }
1505 break;
1506 }
1507 }
1508 LOG(DEBUG) << StringPrintf("%s: return=%u", fn, retval);
1509 return retval;
1510 }
1511
1512 /*******************************************************************************
1513 **
1514 ** Function: isKovioType2Tag
1515 **
1516 ** Description: Whether the currently activated tag is Kovio Type-2 tag.
1517 **
1518 ** Returns: True if tag is Kovio Type-2 tag.
1519 **
1520 *******************************************************************************/
isKovioType2Tag()1521 bool NfcTag::isKovioType2Tag() {
1522 static const char fn[] = "NfcTag::isKovioType2Tag";
1523 bool retval = false;
1524
1525 for (int i = 0; i < mNumTechList; i++) {
1526 if (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) {
1527 // Kovio 2Kb RFID Tag, Functional Specification,
1528 // March 2, 2012, v2.0, section 8.3.
1529 if (mTechParams[i].param.pa.nfcid1[0] == 0x37) retval = true;
1530 break;
1531 }
1532 }
1533 LOG(DEBUG) << StringPrintf("%s: return=%u", fn, retval);
1534 return retval;
1535 }
1536
1537 /*******************************************************************************
1538 **
1539 ** Function: setMultiProtocolTagSupport
1540 **
1541 ** Description: Update mIsMultiProtocolTag
1542 **
1543 ** Returns: None
1544 **
1545 *******************************************************************************/
1546
setMultiProtocolTagSupport(bool isMultiProtocolSupported)1547 void NfcTag::setMultiProtocolTagSupport(bool isMultiProtocolSupported) {
1548 mIsMultiProtocolTag = isMultiProtocolSupported;
1549 }
1550
1551 /*******************************************************************************
1552 **
1553 ** Function: setNumDiscNtf
1554 **
1555 ** Description: Update number of Discovery NTF received
1556 **
1557 ** Returns: None
1558 **
1559 *******************************************************************************/
setNumDiscNtf(int numDiscNtfValue)1560 void NfcTag::setNumDiscNtf(int numDiscNtfValue) {
1561 if (numDiscNtfValue < MAX_NUM_TECHNOLOGY) {
1562 mNumDiscNtf = numDiscNtfValue;
1563 }
1564 }
1565
1566 /*******************************************************************************
1567 **
1568 ** Function: getNumDiscNtf
1569 **
1570 ** Description: number of discovery notifications received from NFCC after
1571 ** last RF DISCOVERY state
1572 **
1573 ** Returns: number of discovery notifications received from NFCC
1574 **
1575 *******************************************************************************/
getNumDiscNtf()1576 int NfcTag::getNumDiscNtf() { return mNumDiscNtf; }
1577