| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * Tag-reading, tag-writing operations. |
| */ |
| #include "OverrideLog.h" |
| #include "NfcTag.h" |
| #include "JavaClassConstants.h" |
| #include "config.h" |
| #include <log/log.h> |
| #include <ScopedLocalRef.h> |
| #include <ScopedPrimitiveArray.h> |
| |
| extern "C" |
| { |
| #include "rw_int.h" |
| #include "nfc_brcm_defs.h" |
| #include "phNxpExtns.h" |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: NfcTag |
| ** |
| ** Description: Initialize member variables. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| NfcTag::NfcTag () |
| : mNumTechList (0), |
| mTechnologyTimeoutsTable (MAX_NUM_TECHNOLOGY), |
| mNativeData (NULL), |
| mIsActivated (false), |
| mActivationState (Idle), |
| mProtocol(NFC_PROTOCOL_UNKNOWN), |
| mtT1tMaxMessageSize (0), |
| mReadCompletedStatus (NFA_STATUS_OK), |
| mLastKovioUidLen (0), |
| mNdefDetectionTimedOut (false), |
| mIsDynamicTagId (false), |
| mPresenceCheckAlgorithm (NFA_RW_PRES_CHK_DEFAULT), |
| mIsFelicaLite(false) |
| { |
| memset (mTechList, 0, sizeof(mTechList)); |
| memset (mTechHandles, 0, sizeof(mTechHandles)); |
| memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes)); |
| memset (mTechParams, 0, sizeof(mTechParams)); |
| memset(mLastKovioUid, 0, NFC_KOVIO_MAX_LEN); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: getInstance |
| ** |
| ** Description: Get a reference to the singleton NfcTag object. |
| ** |
| ** Returns: Reference to NfcTag object. |
| ** |
| *******************************************************************************/ |
| NfcTag& NfcTag::getInstance () |
| { |
| static NfcTag tag; |
| return tag; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: initialize |
| ** |
| ** Description: Reset member variables. |
| ** native: Native data. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::initialize (nfc_jni_native_data* native) |
| { |
| long num = 0; |
| |
| mNativeData = native; |
| mIsActivated = false; |
| mActivationState = Idle; |
| mProtocol = NFC_PROTOCOL_UNKNOWN; |
| mNumTechList = 0; |
| mtT1tMaxMessageSize = 0; |
| mReadCompletedStatus = NFA_STATUS_OK; |
| resetTechnologies (); |
| if (GetNumValue(NAME_PRESENCE_CHECK_ALGORITHM, &num, sizeof(num))) |
| mPresenceCheckAlgorithm = num; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: abort |
| ** |
| ** Description: Unblock all operations. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::abort () |
| { |
| SyncEventGuard g (mReadCompleteEvent); |
| mReadCompleteEvent.notifyOne (); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: getActivationState |
| ** |
| ** Description: What is the current state: Idle, Sleep, or Activated. |
| ** |
| ** Returns: Idle, Sleep, or Activated. |
| ** |
| *******************************************************************************/ |
| NfcTag::ActivationState NfcTag::getActivationState () |
| { |
| return mActivationState; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: setDeactivationState |
| ** |
| ** Description: Set the current state: Idle or Sleep. |
| ** deactivated: state of deactivation. |
| ** |
| ** Returns: None. |
| ** |
| *******************************************************************************/ |
| void NfcTag::setDeactivationState (tNFA_DEACTIVATED& deactivated) |
| { |
| static const char fn [] = "NfcTag::setDeactivationState"; |
| mActivationState = Idle; |
| mNdefDetectionTimedOut = false; |
| if (deactivated.type == NFA_DEACTIVATE_TYPE_SLEEP) |
| mActivationState = Sleep; |
| ALOGD ("%s: state=%u", fn, mActivationState); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: setActivationState |
| ** |
| ** Description: Set the current state to Active. |
| ** |
| ** Returns: None. |
| ** |
| *******************************************************************************/ |
| void NfcTag::setActivationState () |
| { |
| static const char fn [] = "NfcTag::setActivationState"; |
| mNdefDetectionTimedOut = false; |
| mActivationState = Active; |
| ALOGD ("%s: state=%u", fn, mActivationState); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: isActivated |
| ** |
| ** Description: Is tag activated? |
| ** |
| ** Returns: True if tag is activated. |
| ** |
| *******************************************************************************/ |
| bool NfcTag::isActivated () |
| { |
| return mIsActivated; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: getProtocol |
| ** |
| ** Description: Get the protocol of the current tag. |
| ** |
| ** Returns: Protocol number. |
| ** |
| *******************************************************************************/ |
| tNFC_PROTOCOL NfcTag::getProtocol() |
| { |
| return mProtocol; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function TimeDiff |
| ** |
| ** Description Computes time difference in milliseconds. |
| ** |
| ** Returns Time difference in milliseconds |
| ** |
| *******************************************************************************/ |
| UINT32 TimeDiff(timespec start, timespec end) |
| { |
| timespec temp; |
| if ((end.tv_nsec-start.tv_nsec)<0) |
| { |
| temp.tv_sec = end.tv_sec-start.tv_sec-1; |
| temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; |
| } |
| else |
| { |
| temp.tv_sec = end.tv_sec-start.tv_sec; |
| temp.tv_nsec = end.tv_nsec-start.tv_nsec; |
| } |
| |
| return (temp.tv_sec * 1000) + (temp.tv_nsec / 1000000); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: IsSameKovio |
| ** |
| ** Description: Checks if tag activate is the same (UID) Kovio tag previously |
| ** activated. This is needed due to a problem with some Kovio |
| ** tags re-activating multiple times. |
| ** activationData: data from activation. |
| ** |
| ** Returns: true if the activation is from the same tag previously |
| ** activated, false otherwise |
| ** |
| *******************************************************************************/ |
| bool NfcTag::IsSameKovio(tNFA_ACTIVATED& activationData) |
| { |
| static const char fn [] = "NfcTag::IsSameKovio"; |
| ALOGD ("%s: enter", fn); |
| tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf; |
| |
| if (rfDetail.protocol != NFC_PROTOCOL_KOVIO) |
| return false; |
| |
| memcpy (&(mTechParams[0]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); |
| if (mTechParams [0].mode != NFC_DISCOVERY_TYPE_POLL_KOVIO) |
| return false; |
| |
| struct timespec now; |
| clock_gettime(CLOCK_REALTIME, &now); |
| |
| bool rVal = false; |
| if (mTechParams[0].param.pk.uid_len == mLastKovioUidLen) |
| { |
| if (memcmp(mLastKovioUid, &mTechParams [0].param.pk.uid, mTechParams[0].param.pk.uid_len) == 0) |
| { |
| //same tag |
| if (TimeDiff(mLastKovioTime, now) < 500) |
| { |
| // same tag within 500 ms, ignore activation |
| rVal = true; |
| } |
| } |
| } |
| |
| // save Kovio tag info |
| if (!rVal) |
| { |
| if ((mLastKovioUidLen = mTechParams[0].param.pk.uid_len) > NFC_KOVIO_MAX_LEN) |
| mLastKovioUidLen = NFC_KOVIO_MAX_LEN; |
| memcpy(mLastKovioUid, mTechParams[0].param.pk.uid, mLastKovioUidLen); |
| } |
| mLastKovioTime = now; |
| ALOGD ("%s: exit, is same Kovio=%d", fn, rVal); |
| return rVal; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: discoverTechnologies |
| ** |
| ** Description: Discover the technologies that NFC service needs by interpreting |
| ** the data structures from the stack. |
| ** activationData: data from activation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::discoverTechnologies (tNFA_ACTIVATED& activationData) |
| { |
| static const char fn [] = "NfcTag::discoverTechnologies (activation)"; |
| ALOGD ("%s: enter", fn); |
| tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf; |
| |
| mNumTechList = 0; |
| mTechHandles [mNumTechList] = rfDetail.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; |
| |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); |
| |
| if (NFC_PROTOCOL_T1T == rfDetail.protocol) |
| { |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API |
| } |
| else if (NFC_PROTOCOL_T2T == rfDetail.protocol) |
| { |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API |
| // could be MifFare UL or Classic or Kovio |
| { |
| // need to look at first byte of uid to find Manufacture Byte |
| tNFC_RF_TECH_PARAMS tech_params; |
| memcpy (&tech_params, &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); |
| |
| if ((tech_params.param.pa.nfcid1[0] == 0x04 && rfDetail.rf_tech_param.param.pa.sel_rsp == 0) || |
| rfDetail.rf_tech_param.param.pa.sel_rsp == 0x18 || |
| rfDetail.rf_tech_param.param.pa.sel_rsp == 0x08) |
| { |
| if (rfDetail.rf_tech_param.param.pa.sel_rsp == 0) |
| { |
| mNumTechList++; |
| mTechHandles [mNumTechList] = rfDetail.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); |
| mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API |
| } |
| } |
| } |
| } |
| else if (NFC_PROTOCOL_T3T == rfDetail.protocol) |
| { |
| UINT8 xx = 0; |
| |
| mTechList [mNumTechList] = TARGET_TYPE_FELICA; |
| |
| //see if it is Felica Lite. |
| while (xx < activationData.params.t3t.num_system_codes) |
| { |
| if (activationData.params.t3t.p_system_codes[xx++] == T3T_SYSTEM_CODE_FELICA_LITE) |
| { |
| mIsFelicaLite = true; |
| break; |
| } |
| } |
| } |
| else if (NFC_PROTOCOL_ISO_DEP == rfDetail.protocol) |
| { |
| //type-4 tag uses technology ISO-DEP and technology A or B |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API |
| if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) || |
| (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) || |
| (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) || |
| (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) |
| { |
| mNumTechList++; |
| mTechHandles [mNumTechList] = rfDetail.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); |
| } |
| else if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) || |
| (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) || |
| (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) || |
| (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) ) |
| { |
| mNumTechList++; |
| mTechHandles [mNumTechList] = rfDetail.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); |
| } |
| } |
| else if (NFC_PROTOCOL_15693 == rfDetail.protocol) |
| { |
| //is TagTechnology.NFC_V by Java API |
| mTechList [mNumTechList] = TARGET_TYPE_ISO15693; |
| } |
| else if (NFC_PROTOCOL_KOVIO == rfDetail.protocol) |
| { |
| ALOGD ("%s: Kovio", fn); |
| mTechList [mNumTechList] = TARGET_TYPE_KOVIO_BARCODE; |
| } |
| else if (NFC_PROTOCOL_MIFARE == rfDetail.protocol) |
| { |
| ALOGD ("%s: Mifare Classic", fn); |
| EXTNS_MfcInit (activationData); |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API |
| mNumTechList++; |
| mTechHandles [mNumTechList] = rfDetail.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); |
| mTechList [mNumTechList] = TARGET_TYPE_MIFARE_CLASSIC; //is TagTechnology.MIFARE_CLASSIC by Java API |
| } |
| else |
| { |
| ALOGE ("%s: unknown protocol ????", fn); |
| mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN; |
| } |
| |
| mNumTechList++; |
| for (int i=0; i < mNumTechList; i++) |
| { |
| ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn, |
| i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]); |
| } |
| ALOGD ("%s: exit", fn); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: discoverTechnologies |
| ** |
| ** Description: Discover the technologies that NFC service needs by interpreting |
| ** the data structures from the stack. |
| ** discoveryData: data from discovery events(s). |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::discoverTechnologies (tNFA_DISC_RESULT& discoveryData) |
| { |
| static const char fn [] = "NfcTag::discoverTechnologies (discovery)"; |
| tNFC_RESULT_DEVT& discovery_ntf = discoveryData.discovery_ntf; |
| |
| ALOGD ("%s: enter: rf disc. id=%u; protocol=%u, mNumTechList=%u", fn, discovery_ntf.rf_disc_id, discovery_ntf.protocol, mNumTechList); |
| if (mNumTechList >= MAX_NUM_TECHNOLOGY) |
| { |
| ALOGE ("%s: exceed max=%d", fn, MAX_NUM_TECHNOLOGY); |
| goto TheEnd; |
| } |
| mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; |
| |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); |
| |
| if (NFC_PROTOCOL_T1T == discovery_ntf.protocol) |
| { |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API |
| } |
| else if (NFC_PROTOCOL_T2T == discovery_ntf.protocol) |
| { |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API |
| //type-2 tags are identical to Mifare Ultralight, so Ultralight is also discovered |
| if ((discovery_ntf.rf_tech_param.param.pa.sel_rsp == 0) && |
| (mNumTechList < (MAX_NUM_TECHNOLOGY-1))) |
| { |
| // Mifare Ultralight |
| mNumTechList++; |
| mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; |
| mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API |
| } |
| |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); |
| } |
| else if (NFC_PROTOCOL_T3T == discovery_ntf.protocol) |
| { |
| mTechList [mNumTechList] = TARGET_TYPE_FELICA; |
| } |
| else if (NFC_PROTOCOL_ISO_DEP == discovery_ntf.protocol) |
| { |
| //type-4 tag uses technology ISO-DEP and technology A or B |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API |
| if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) || |
| (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) || |
| (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) || |
| (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) |
| { |
| if (mNumTechList < (MAX_NUM_TECHNOLOGY-1)) |
| { |
| mNumTechList++; |
| mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); |
| } |
| } |
| else if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) || |
| (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) || |
| (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) || |
| (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) ) |
| { |
| if (mNumTechList < (MAX_NUM_TECHNOLOGY-1)) |
| { |
| mNumTechList++; |
| mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); |
| } |
| } |
| } |
| else if (NFC_PROTOCOL_15693 == discovery_ntf.protocol) |
| { |
| //is TagTechnology.NFC_V by Java API |
| mTechList [mNumTechList] = TARGET_TYPE_ISO15693; |
| } |
| else if (NFC_PROTOCOL_MIFARE == discovery_ntf.protocol) |
| { |
| mTechList [mNumTechList] = TARGET_TYPE_MIFARE_CLASSIC; |
| if (mNumTechList < (MAX_NUM_TECHNOLOGY-1)) |
| { |
| mNumTechList++; |
| mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; |
| mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; |
| mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; |
| //save the stack's data structure for interpretation later |
| memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); |
| } |
| } |
| else |
| { |
| ALOGE ("%s: unknown protocol ????", fn); |
| mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN; |
| } |
| |
| mNumTechList++; |
| if (discovery_ntf.more != NCI_DISCOVER_NTF_MORE) |
| { |
| for (int i=0; i < mNumTechList; i++) |
| { |
| ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn, |
| i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]); |
| } |
| } |
| |
| TheEnd: |
| ALOGD ("%s: exit", fn); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: createNativeNfcTag |
| ** |
| ** Description: Create a brand new Java NativeNfcTag object; |
| ** fill the objects's member variables with data; |
| ** notify NFC service; |
| ** activationData: data from activation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::createNativeNfcTag (tNFA_ACTIVATED& activationData) |
| { |
| static const char fn [] = "NfcTag::createNativeNfcTag"; |
| ALOGD ("%s: enter", fn); |
| |
| JNIEnv* e = NULL; |
| ScopedAttach attach(mNativeData->vm, &e); |
| if (e == NULL) |
| { |
| ALOGE("%s: jni env is null", fn); |
| return; |
| } |
| |
| ScopedLocalRef<jclass> tag_cls(e, e->GetObjectClass(mNativeData->cached_NfcTag)); |
| if (e->ExceptionCheck()) |
| { |
| e->ExceptionClear(); |
| ALOGE("%s: failed to get class", fn); |
| return; |
| } |
| |
| //create a new Java NativeNfcTag object |
| jmethodID ctor = e->GetMethodID(tag_cls.get(), "<init>", "()V"); |
| ScopedLocalRef<jobject> tag(e, e->NewObject(tag_cls.get(), ctor)); |
| |
| //fill NativeNfcTag's mProtocols, mTechList, mTechHandles, mTechLibNfcTypes |
| fillNativeNfcTagMembers1(e, tag_cls.get(), tag.get()); |
| |
| //fill NativeNfcTag's members: mHandle, mConnectedTechnology |
| fillNativeNfcTagMembers2(e, tag_cls.get(), tag.get(), activationData); |
| |
| //fill NativeNfcTag's members: mTechPollBytes |
| fillNativeNfcTagMembers3(e, tag_cls.get(), tag.get(), activationData); |
| |
| //fill NativeNfcTag's members: mTechActBytes |
| fillNativeNfcTagMembers4(e, tag_cls.get(), tag.get(), activationData); |
| |
| //fill NativeNfcTag's members: mUid |
| fillNativeNfcTagMembers5(e, tag_cls.get(), tag.get(), activationData); |
| |
| if (mNativeData->tag != NULL) |
| { |
| e->DeleteGlobalRef(mNativeData->tag); |
| } |
| mNativeData->tag = e->NewGlobalRef(tag.get()); |
| |
| //notify NFC service about this new tag |
| ALOGD ("%s: try notify nfc service", fn); |
| e->CallVoidMethod(mNativeData->manager, android::gCachedNfcManagerNotifyNdefMessageListeners, tag.get()); |
| if (e->ExceptionCheck()) |
| { |
| e->ExceptionClear(); |
| ALOGE ("%s: fail notify nfc service", fn); |
| } |
| |
| ALOGD ("%s: exit", fn); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: fillNativeNfcTagMembers1 |
| ** |
| ** Description: Fill NativeNfcTag's members: mProtocols, mTechList, mTechHandles, mTechLibNfcTypes. |
| ** e: JVM environment. |
| ** tag_cls: Java NativeNfcTag class. |
| ** tag: Java NativeNfcTag object. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::fillNativeNfcTagMembers1 (JNIEnv* e, jclass tag_cls, jobject tag) |
| { |
| static const char fn [] = "NfcTag::fillNativeNfcTagMembers1"; |
| ALOGD ("%s", fn); |
| |
| //create objects that represent NativeNfcTag's member variables |
| ScopedLocalRef<jintArray> techList(e, e->NewIntArray(mNumTechList)); |
| ScopedLocalRef<jintArray> handleList(e, e->NewIntArray(mNumTechList)); |
| ScopedLocalRef<jintArray> typeList(e, e->NewIntArray(mNumTechList)); |
| |
| { |
| ScopedIntArrayRW technologies(e, techList.get()); |
| ScopedIntArrayRW handles(e, handleList.get()); |
| ScopedIntArrayRW types(e, typeList.get()); |
| for (int i = 0; i < mNumTechList; i++) { |
| mNativeData->tProtocols [i] = mTechLibNfcTypes [i]; |
| mNativeData->handles [i] = mTechHandles [i]; |
| technologies [i] = mTechList [i]; |
| handles [i] = mTechHandles [i]; |
| types [i] = mTechLibNfcTypes [i]; |
| } |
| } |
| |
| jfieldID f = NULL; |
| |
| f = e->GetFieldID(tag_cls, "mTechList", "[I"); |
| e->SetObjectField(tag, f, techList.get()); |
| |
| f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); |
| e->SetObjectField(tag, f, handleList.get()); |
| |
| f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); |
| e->SetObjectField(tag, f, typeList.get()); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: fillNativeNfcTagMembers2 |
| ** |
| ** Description: Fill NativeNfcTag's members: mConnectedTechIndex or mConnectedTechnology. |
| ** The original Google's implementation is in set_target_pollBytes( |
| ** in com_android_nfc_NativeNfcTag.cpp; |
| ** e: JVM environment. |
| ** tag_cls: Java NativeNfcTag class. |
| ** tag: Java NativeNfcTag object. |
| ** activationData: data from activation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& /*activationData*/) |
| { |
| static const char fn [] = "NfcTag::fillNativeNfcTagMembers2"; |
| ALOGD ("%s", fn); |
| jfieldID f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); |
| e->SetIntField(tag, f, (jint) 0); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: fillNativeNfcTagMembers3 |
| ** |
| ** Description: Fill NativeNfcTag's members: mTechPollBytes. |
| ** The original Google's implementation is in set_target_pollBytes( |
| ** in com_android_nfc_NativeNfcTag.cpp; |
| ** e: JVM environment. |
| ** tag_cls: Java NativeNfcTag class. |
| ** tag: Java NativeNfcTag object. |
| ** activationData: data from activation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::fillNativeNfcTagMembers3 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) |
| { |
| static const char fn [] = "NfcTag::fillNativeNfcTagMembers3"; |
| ScopedLocalRef<jbyteArray> pollBytes(e, e->NewByteArray(0)); |
| ScopedLocalRef<jclass> byteArrayClass(e, e->GetObjectClass(pollBytes.get())); |
| ScopedLocalRef<jobjectArray> techPollBytes(e, e->NewObjectArray(mNumTechList, byteArrayClass.get(), 0)); |
| int len = 0; |
| |
| for (int i = 0; i < mNumTechList; i++) |
| { |
| ALOGD ("%s: index=%d; rf tech params mode=%u", fn, i, mTechParams [i].mode); |
| if (NFC_DISCOVERY_TYPE_POLL_A == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_POLL_A_ACTIVE == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_A == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE == mTechParams [i].mode) |
| { |
| ALOGD ("%s: tech A", fn); |
| pollBytes.reset(e->NewByteArray(2)); |
| e->SetByteArrayRegion(pollBytes.get(), 0, 2, (jbyte*) mTechParams [i].param.pa.sens_res); |
| } |
| else if (NFC_DISCOVERY_TYPE_POLL_B == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_POLL_B_PRIME == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_B == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_B_PRIME == mTechParams [i].mode) |
| { |
| if (mTechList [i] == TARGET_TYPE_ISO14443_3B) //is TagTechnology.NFC_B by Java API |
| { |
| /***************** |
| see NFC Forum Digital Protocol specification; section 5.6.2; |
| in SENSB_RES response, byte 6 through 9 is Application Data, byte 10-12 or 13 is Protocol Info; |
| used by public API: NfcB.getApplicationData(), NfcB.getProtocolInfo(); |
| *****************/ |
| ALOGD ("%s: tech B; TARGET_TYPE_ISO14443_3B", fn); |
| len = mTechParams [i].param.pb.sensb_res_len; |
| if (len >= NFC_NFCID0_MAX_LEN) { |
| // subtract 4 bytes for NFCID0 at byte 2 through 5 |
| len = len - NFC_NFCID0_MAX_LEN; |
| } else { |
| android_errorWriteLog(0x534e4554, "124940143"); |
| ALOGE ("%s: sensb_res_len error", fn); |
| len = 0; |
| } |
| pollBytes.reset(e->NewByteArray(len)); |
| e->SetByteArrayRegion(pollBytes.get(), 0, len, (jbyte*) (mTechParams [i].param.pb.sensb_res+4)); |
| } |
| else |
| { |
| pollBytes.reset(e->NewByteArray(0)); |
| } |
| } |
| else if (NFC_DISCOVERY_TYPE_POLL_F == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_POLL_F_ACTIVE == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_F == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE == mTechParams [i].mode) |
| { |
| /**************** |
| see NFC Forum Type 3 Tag Operation Specification; sections 2.3.2, 2.3.1.2; |
| see NFC Forum Digital Protocol Specification; sections 6.6.2; |
| PMm: manufacture parameter; 8 bytes; |
| System Code: 2 bytes; |
| ****************/ |
| ALOGD ("%s: tech F", fn); |
| UINT8 result [10]; //return result to NFC service |
| memset (result, 0, sizeof(result)); |
| len = 10; |
| |
| /**** |
| for (int ii = 0; ii < mTechParams [i].param.pf.sensf_res_len; ii++) |
| { |
| ALOGD ("%s: tech F, sendf_res[%d]=%d (0x%x)", |
| fn, ii, mTechParams [i].param.pf.sensf_res[ii],mTechParams [i].param.pf.sensf_res[ii]); |
| } |
| ***/ |
| memcpy (result, mTechParams [i].param.pf.sensf_res + 8, 8); //copy PMm |
| if (activationData.params.t3t.num_system_codes > 0) //copy the first System Code |
| { |
| UINT16 systemCode = *(activationData.params.t3t.p_system_codes); |
| result [8] = (UINT8) (systemCode >> 8); |
| result [9] = (UINT8) systemCode; |
| ALOGD ("%s: tech F; sys code=0x%X 0x%X", fn, result [8], result [9]); |
| } |
| pollBytes.reset(e->NewByteArray(len)); |
| e->SetByteArrayRegion(pollBytes.get(), 0, len, (jbyte*) result); |
| } |
| else if (NFC_DISCOVERY_TYPE_POLL_ISO15693 == mTechParams [i].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_ISO15693 == mTechParams [i].mode) |
| { |
| ALOGD ("%s: tech iso 15693", fn); |
| //iso 15693 response flags: 1 octet |
| //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet |
| //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags(); |
| uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid}; |
| pollBytes.reset(e->NewByteArray(2)); |
| e->SetByteArrayRegion(pollBytes.get(), 0, 2, (jbyte *) data); |
| } |
| else |
| { |
| ALOGE ("%s: tech unknown ????", fn); |
| pollBytes.reset(e->NewByteArray(0)); |
| } //switch: every type of technology |
| e->SetObjectArrayElement(techPollBytes.get(), i, pollBytes.get()); |
| } //for: every technology in the array |
| jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); |
| e->SetObjectField(tag, f, techPollBytes.get()); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: fillNativeNfcTagMembers4 |
| ** |
| ** Description: Fill NativeNfcTag's members: mTechActBytes. |
| ** The original Google's implementation is in set_target_activationBytes() |
| ** in com_android_nfc_NativeNfcTag.cpp; |
| ** e: JVM environment. |
| ** tag_cls: Java NativeNfcTag class. |
| ** tag: Java NativeNfcTag object. |
| ** activationData: data from activation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::fillNativeNfcTagMembers4 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) |
| { |
| static const char fn [] = "NfcTag::fillNativeNfcTagMembers4"; |
| ScopedLocalRef<jbyteArray> actBytes(e, e->NewByteArray(0)); |
| ScopedLocalRef<jclass> byteArrayClass(e, e->GetObjectClass(actBytes.get())); |
| ScopedLocalRef<jobjectArray> techActBytes(e, e->NewObjectArray(mNumTechList, byteArrayClass.get(), 0)); |
| |
| for (int i = 0; i < mNumTechList; i++) |
| { |
| ALOGD ("%s: index=%d", fn, i); |
| if (NFC_PROTOCOL_T1T == mTechLibNfcTypes[i] || NFC_PROTOCOL_T2T == mTechLibNfcTypes[i]) |
| { |
| if (mTechLibNfcTypes[i] == NFC_PROTOCOL_T1T) |
| ALOGD ("%s: T1T; tech A", fn); |
| else if (mTechLibNfcTypes[i] == NFC_PROTOCOL_T2T) |
| ALOGD ("%s: T2T; tech A", fn); |
| actBytes.reset(e->NewByteArray(1)); |
| e->SetByteArrayRegion(actBytes.get(), 0, 1, (jbyte*) &mTechParams [i].param.pa.sel_rsp); |
| } |
| else if (NFC_PROTOCOL_T3T == mTechLibNfcTypes[i]) |
| { |
| //felica |
| ALOGD ("%s: T3T; felica; tech F", fn); |
| //really, there is no data |
| actBytes.reset(e->NewByteArray(0)); |
| } |
| else if (NFC_PROTOCOL_MIFARE == mTechLibNfcTypes[i]) |
| { |
| ALOGD ("%s: Mifare Classic; tech A", fn); |
| actBytes.reset (e->NewByteArray(1)); |
| e->SetByteArrayRegion (actBytes.get(), 0, 1, |
| (jbyte*) &mTechParams [i].param.pa.sel_rsp); |
| } |
| else if (NFC_PROTOCOL_ISO_DEP == mTechLibNfcTypes[i]) |
| { |
| //t4t |
| if (mTechList [i] == TARGET_TYPE_ISO14443_4) //is TagTechnology.ISO_DEP by Java API |
| { |
| if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) |
| { |
| //see NFC Forum Digital Protocol specification, section 11.6.2, "RATS Response"; search for "historical bytes"; |
| //copy historical bytes into Java object; |
| //the public API, IsoDep.getHistoricalBytes(), returns this data; |
| if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP) |
| { |
| tNFC_INTF_PA_ISO_DEP& pa_iso = activationData.activate_ntf.intf_param.intf_param.pa_iso; |
| ALOGD ("%s: T4T; ISO_DEP for tech A; copy historical bytes; len=%u", fn, pa_iso.his_byte_len); |
| actBytes.reset(e->NewByteArray(pa_iso.his_byte_len)); |
| if (pa_iso.his_byte_len > 0) |
| e->SetByteArrayRegion(actBytes.get(), 0, pa_iso.his_byte_len, (jbyte*) (pa_iso.his_byte)); |
| } |
| else |
| { |
| ALOGE ("%s: T4T; ISO_DEP for tech A; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type); |
| actBytes.reset(e->NewByteArray(0)); |
| } |
| } |
| else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) ) |
| { |
| //see NFC Forum Digital Protocol specification, section 12.6.2, "ATTRIB Response"; |
| //copy higher-layer response bytes into Java object; |
| //the public API, IsoDep.getHiLayerResponse(), returns this data; |
| if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP) |
| { |
| tNFC_INTF_PB_ISO_DEP& pb_iso = activationData.activate_ntf.intf_param.intf_param.pb_iso; |
| ALOGD ("%s: T4T; ISO_DEP for tech B; copy response bytes; len=%u", fn, pb_iso.hi_info_len); |
| actBytes.reset(e->NewByteArray(pb_iso.hi_info_len)); |
| if (pb_iso.hi_info_len > 0) |
| e->SetByteArrayRegion(actBytes.get(), 0, pb_iso.hi_info_len, (jbyte*) (pb_iso.hi_info)); |
| } |
| else |
| { |
| ALOGE ("%s: T4T; ISO_DEP for tech B; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type); |
| actBytes.reset(e->NewByteArray(0)); |
| } |
| } |
| } |
| else if (mTechList [i] == TARGET_TYPE_ISO14443_3A) //is TagTechnology.NFC_A by Java API |
| { |
| ALOGD ("%s: T4T; tech A", fn); |
| actBytes.reset(e->NewByteArray(1)); |
| e->SetByteArrayRegion(actBytes.get(), 0, 1, (jbyte*) &mTechParams [i].param.pa.sel_rsp); |
| } |
| else |
| { |
| actBytes.reset(e->NewByteArray(0)); |
| } |
| } //case NFC_PROTOCOL_ISO_DEP: //t4t |
| else if (NFC_PROTOCOL_15693 == mTechLibNfcTypes[i]) |
| { |
| ALOGD ("%s: tech iso 15693", fn); |
| //iso 15693 response flags: 1 octet |
| //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet |
| //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags(); |
| uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid}; |
| actBytes.reset(e->NewByteArray(2)); |
| e->SetByteArrayRegion(actBytes.get(), 0, 2, (jbyte *) data); |
| } |
| else |
| { |
| ALOGD ("%s: tech unknown ????", fn); |
| actBytes.reset(e->NewByteArray(0)); |
| } |
| e->SetObjectArrayElement(techActBytes.get(), i, actBytes.get()); |
| } //for: every technology in the array |
| jfieldID f = e->GetFieldID (tag_cls, "mTechActBytes", "[[B"); |
| e->SetObjectField(tag, f, techActBytes.get()); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: fillNativeNfcTagMembers5 |
| ** |
| ** Description: Fill NativeNfcTag's members: mUid. |
| ** The original Google's implementation is in nfc_jni_Discovery_notification_callback() |
| ** in com_android_nfc_NativeNfcManager.cpp; |
| ** e: JVM environment. |
| ** tag_cls: Java NativeNfcTag class. |
| ** tag: Java NativeNfcTag object. |
| ** activationData: data from activation. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) |
| { |
| static const char fn [] = "NfcTag::fillNativeNfcTagMembers5"; |
| int len = 0; |
| ScopedLocalRef<jbyteArray> uid(e, NULL); |
| |
| if (NFC_DISCOVERY_TYPE_POLL_KOVIO == mTechParams [0].mode) |
| { |
| ALOGD ("%s: Kovio", fn); |
| len = mTechParams [0].param.pk.uid_len; |
| uid.reset(e->NewByteArray(len)); |
| e->SetByteArrayRegion(uid.get(), 0, len, |
| (jbyte*) &mTechParams [0].param.pk.uid); |
| } |
| else if (NFC_DISCOVERY_TYPE_POLL_A == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_POLL_A_ACTIVE == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_A == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE == mTechParams [0].mode) |
| { |
| ALOGD ("%s: tech A", fn); |
| len = mTechParams [0].param.pa.nfcid1_len; |
| uid.reset(e->NewByteArray(len)); |
| e->SetByteArrayRegion(uid.get(), 0, len, |
| (jbyte*) &mTechParams [0].param.pa.nfcid1); |
| //a tag's NFCID1 can change dynamically at each activation; |
| //only the first byte (0x08) is constant; a dynamic NFCID1's length |
| //must be 4 bytes (see NFC Digitial Protocol, |
| //section 4.7.2 SDD_RES Response, Requirements 20). |
| mIsDynamicTagId = (mTechParams [0].param.pa.nfcid1_len == 4) && |
| (mTechParams [0].param.pa.nfcid1 [0] == 0x08); |
| } |
| else if (NFC_DISCOVERY_TYPE_POLL_B == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_POLL_B_PRIME == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_B == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_B_PRIME == mTechParams [0].mode) |
| { |
| ALOGD ("%s: tech B", fn); |
| uid.reset(e->NewByteArray(NFC_NFCID0_MAX_LEN)); |
| e->SetByteArrayRegion(uid.get(), 0, NFC_NFCID0_MAX_LEN, |
| (jbyte*) &mTechParams [0].param.pb.nfcid0); |
| } |
| else if (NFC_DISCOVERY_TYPE_POLL_F == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_POLL_F_ACTIVE == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_F == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE == mTechParams [0].mode) |
| { |
| uid.reset(e->NewByteArray(NFC_NFCID2_LEN)); |
| e->SetByteArrayRegion(uid.get(), 0, NFC_NFCID2_LEN, |
| (jbyte*) &mTechParams [0].param.pf.nfcid2); |
| ALOGD ("%s: tech F", fn); |
| } |
| else if (NFC_DISCOVERY_TYPE_POLL_ISO15693 == mTechParams [0].mode |
| || NFC_DISCOVERY_TYPE_LISTEN_ISO15693 == mTechParams [0].mode) |
| { |
| ALOGD ("%s: tech iso 15693", fn); |
| jbyte data [I93_UID_BYTE_LEN]; //8 bytes |
| for (int i=0; i<I93_UID_BYTE_LEN; ++i) //reverse the ID |
| data[i] = activationData.params.i93.uid [I93_UID_BYTE_LEN - i - 1]; |
| uid.reset(e->NewByteArray(I93_UID_BYTE_LEN)); |
| e->SetByteArrayRegion(uid.get(), 0, I93_UID_BYTE_LEN, data); |
| } |
| else |
| { |
| ALOGE ("%s: tech unknown ????", fn); |
| uid.reset(e->NewByteArray(0)); |
| } |
| jfieldID f = e->GetFieldID(tag_cls, "mUid", "[B"); |
| e->SetObjectField(tag, f, uid.get()); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: isP2pDiscovered |
| ** |
| ** Description: Does the peer support P2P? |
| ** |
| ** Returns: True if the peer supports P2P. |
| ** |
| *******************************************************************************/ |
| bool NfcTag::isP2pDiscovered () |
| { |
| static const char fn [] = "NfcTag::isP2pDiscovered"; |
| bool retval = false; |
| |
| for (int i = 0; i < mNumTechList; i++) |
| { |
| if (mTechLibNfcTypes[i] == NFA_PROTOCOL_NFC_DEP) |
| { |
| //if remote device supports P2P |
| ALOGD ("%s: discovered P2P", fn); |
| retval = true; |
| break; |
| } |
| } |
| ALOGD ("%s: return=%u", fn, retval); |
| return retval; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: selectP2p |
| ** |
| ** Description: Select the preferred P2P technology if there is a choice. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::selectP2p() |
| { |
| static const char fn [] = "NfcTag::selectP2p"; |
| UINT8 rfDiscoveryId = 0; |
| |
| for (int i = 0; i < mNumTechList; i++) |
| { |
| //if remote device does not support P2P, just skip it |
| if (mTechLibNfcTypes[i] != NFA_PROTOCOL_NFC_DEP) |
| continue; |
| |
| //if remote device supports tech F; |
| //tech F is preferred because it is faster than tech A |
| if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F_ACTIVE) ) |
| { |
| rfDiscoveryId = mTechHandles[i]; |
| break; //no need to search further |
| } |
| else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) ) |
| { |
| //only choose tech A if tech F is unavailable |
| if (rfDiscoveryId == 0) |
| rfDiscoveryId = mTechHandles[i]; |
| } |
| } |
| |
| if (rfDiscoveryId > 0) |
| { |
| ALOGD ("%s: select P2P; target rf discov id=0x%X", fn, rfDiscoveryId); |
| tNFA_STATUS stat = NFA_Select (rfDiscoveryId, NFA_PROTOCOL_NFC_DEP, NFA_INTERFACE_NFC_DEP); |
| if (stat != NFA_STATUS_OK) |
| ALOGE ("%s: fail select P2P; error=0x%X", fn, stat); |
| } |
| else |
| ALOGE ("%s: cannot find P2P", fn); |
| resetTechnologies (); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: resetTechnologies |
| ** |
| ** Description: Clear all data related to the technology, protocol of the tag. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::resetTechnologies () |
| { |
| static const char fn [] = "NfcTag::resetTechnologies"; |
| ALOGD ("%s", fn); |
| mNumTechList = 0; |
| memset (mTechList, 0, sizeof(mTechList)); |
| memset (mTechHandles, 0, sizeof(mTechHandles)); |
| memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes)); |
| memset (mTechParams, 0, sizeof(mTechParams)); |
| mIsDynamicTagId = false; |
| mIsFelicaLite = false; |
| resetAllTransceiveTimeouts (); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: selectFirstTag |
| ** |
| ** Description: When multiple tags are discovered, just select the first one to activate. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::selectFirstTag () |
| { |
| static const char fn [] = "NfcTag::selectFirstTag"; |
| int foundIdx = -1; |
| tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME; |
| |
| for (int i = 0; i < mNumTechList; i++) |
| { |
| ALOGD ("%s: nfa target idx=%d h=0x%X; protocol=0x%X", |
| fn, i, mTechHandles [i], mTechLibNfcTypes [i]); |
| if (mTechLibNfcTypes[i] != NFA_PROTOCOL_NFC_DEP) |
| { |
| foundIdx = i; |
| break; |
| } |
| } |
| |
| if (foundIdx != -1) |
| { |
| if (mTechLibNfcTypes [foundIdx] == NFA_PROTOCOL_ISO_DEP) |
| { |
| rf_intf = NFA_INTERFACE_ISO_DEP; |
| } |
| else if (mTechLibNfcTypes [foundIdx] == NFA_PROTOCOL_MIFARE) |
| { |
| rf_intf = NFA_INTERFACE_MIFARE; |
| } |
| else |
| rf_intf = NFA_INTERFACE_FRAME; |
| |
| tNFA_STATUS stat = NFA_Select (mTechHandles [foundIdx], mTechLibNfcTypes [foundIdx], rf_intf); |
| if (stat != NFA_STATUS_OK) |
| ALOGE ("%s: fail select; error=0x%X", fn, stat); |
| } |
| else |
| ALOGE ("%s: only found NFC-DEP technology.", fn); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: getT1tMaxMessageSize |
| ** |
| ** Description: Get the maximum size (octet) that a T1T can store. |
| ** |
| ** Returns: Maximum size in octets. |
| ** |
| *******************************************************************************/ |
| int NfcTag::getT1tMaxMessageSize () |
| { |
| static const char fn [] = "NfcTag::getT1tMaxMessageSize"; |
| |
| if (mProtocol != NFC_PROTOCOL_T1T) |
| { |
| ALOGE ("%s: wrong protocol %u", fn, mProtocol); |
| return 0; |
| } |
| return mtT1tMaxMessageSize; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: calculateT1tMaxMessageSize |
| ** |
| ** Description: Calculate type-1 tag's max message size based on header ROM bytes. |
| ** activate: reference to activation data. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate) |
| { |
| static const char fn [] = "NfcTag::calculateT1tMaxMessageSize"; |
| |
| //make sure the tag is type-1 |
| if (activate.activate_ntf.protocol != NFC_PROTOCOL_T1T) |
| { |
| mtT1tMaxMessageSize = 0; |
| return; |
| } |
| |
| //examine the first byte of header ROM bytes |
| switch (activate.params.t1t.hr[0]) |
| { |
| case RW_T1T_IS_TOPAZ96: |
| mtT1tMaxMessageSize = 90; |
| break; |
| case RW_T1T_IS_TOPAZ512: |
| mtT1tMaxMessageSize = 462; |
| break; |
| default: |
| ALOGE ("%s: unknown T1T HR0=%u", fn, activate.params.t1t.hr[0]); |
| mtT1tMaxMessageSize = 0; |
| break; |
| } |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: isMifareUltralight |
| ** |
| ** Description: Whether the currently activated tag is Mifare Ultralight. |
| ** |
| ** Returns: True if tag is Mifare Ultralight. |
| ** |
| *******************************************************************************/ |
| bool NfcTag::isMifareUltralight () |
| { |
| static const char fn [] = "NfcTag::isMifareUltralight"; |
| bool retval = false; |
| |
| for (int i =0; i < mNumTechList; i++) |
| { |
| if (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) |
| { |
| //see NFC Digital Protocol, section 4.6.3 (SENS_RES); section 4.8.2 (SEL_RES). |
| //see "MF0ICU1 Functional specification MIFARE Ultralight", Rev. 3.4 - 4 February 2008, |
| //section 6.7. |
| if ( (mTechParams[i].param.pa.sens_res[0] == 0x44) && |
| (mTechParams[i].param.pa.sens_res[1] == 0) && |
| ( (mTechParams[i].param.pa.sel_rsp == 0) || (mTechParams[i].param.pa.sel_rsp == 0x04) ) && |
| (mTechParams[i].param.pa.nfcid1[0] == 0x04) ) |
| { |
| retval = true; |
| } |
| break; |
| } |
| } |
| ALOGD ("%s: return=%u", fn, retval); |
| return retval; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: isMifareDESFire |
| ** |
| ** Description: Whether the currently activated tag is Mifare DESFire. |
| ** |
| ** Returns: True if tag is Mifare DESFire. |
| ** |
| *******************************************************************************/ |
| bool NfcTag::isMifareDESFire () |
| { |
| static const char fn [] = "NfcTag::isMifareDESFire"; |
| bool retval = false; |
| |
| for (int i =0; i < mNumTechList; i++) |
| { |
| if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) || |
| (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) |
| { |
| /* DESfire has one sak byte and 2 ATQA bytes */ |
| if ( (mTechParams[i].param.pa.sens_res[0] == 0x44) && |
| (mTechParams[i].param.pa.sens_res[1] == 0x03) && |
| (mTechParams[i].param.pa.sel_rsp == 0x20) ) |
| { |
| retval = true; |
| } |
| break; |
| } |
| } |
| |
| ALOGD ("%s: return=%u", fn, retval); |
| return retval; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: isFelicaLite |
| ** |
| ** Description: Whether the currently activated tag is Felica Lite. |
| ** |
| ** Returns: True if tag is Felica Lite. |
| ** |
| *******************************************************************************/ |
| |
| bool NfcTag::isFelicaLite () |
| { |
| return mIsFelicaLite; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: isT2tNackResponse |
| ** |
| ** Description: Whether the response is a T2T NACK response. |
| ** See NFC Digital Protocol Technical Specification (2010-11-17). |
| ** Chapter 9 (Type 2 Tag Platform), section 9.6 (READ). |
| ** response: buffer contains T2T response. |
| ** responseLen: length of the response. |
| ** |
| ** Returns: True if the response is NACK |
| ** |
| *******************************************************************************/ |
| bool NfcTag::isT2tNackResponse (const UINT8* response, UINT32 responseLen) |
| { |
| static const char fn [] = "NfcTag::isT2tNackResponse"; |
| bool isNack = false; |
| |
| if (responseLen == 1) |
| { |
| if (response[0] == 0xA) |
| isNack = false; //an ACK response, so definitely not a NACK |
| else |
| isNack = true; //assume every value is a NACK |
| } |
| ALOGD ("%s: return %u", fn, isNack); |
| return isNack; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: isNdefDetectionTimedOut |
| ** |
| ** Description: Whether NDEF-detection algorithm timed out. |
| ** |
| ** Returns: True if NDEF-detection algorithm timed out. |
| ** |
| *******************************************************************************/ |
| bool NfcTag::isNdefDetectionTimedOut () |
| { |
| return mNdefDetectionTimedOut; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: connectionEventHandler |
| ** |
| ** Description: Handle connection-related events. |
| ** event: event code. |
| ** data: pointer to event data. |
| ** |
| ** Returns: None |
| ** |
| *******************************************************************************/ |
| void NfcTag::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data) |
| { |
| static const char fn [] = "NfcTag::connectionEventHandler"; |
| |
| switch (event) |
| { |
| case NFA_DISC_RESULT_EVT: |
| { |
| tNFA_DISC_RESULT& disc_result = data->disc_result; |
| if (disc_result.status == NFA_STATUS_OK) |
| { |
| discoverTechnologies (disc_result); |
| } |
| } |
| break; |
| |
| case NFA_ACTIVATED_EVT: |
| // Only do tag detection if we are polling and it is not 'EE Direct RF' activation |
| // (which may happen when we are activated as a tag). |
| if (data->activated.activate_ntf.rf_tech_param.mode < NCI_DISCOVERY_TYPE_LISTEN_A |
| && data->activated.activate_ntf.intf_param.type != NFC_INTERFACE_EE_DIRECT_RF) |
| { |
| tNFA_ACTIVATED& activated = data->activated; |
| if (IsSameKovio(activated)) |
| break; |
| mIsActivated = true; |
| mProtocol = activated.activate_ntf.protocol; |
| calculateT1tMaxMessageSize (activated); |
| discoverTechnologies (activated); |
| createNativeNfcTag (activated); |
| } |
| break; |
| |
| case NFA_DEACTIVATED_EVT: |
| mIsActivated = false; |
| mProtocol = NFC_PROTOCOL_UNKNOWN; |
| resetTechnologies (); |
| break; |
| |
| case NFA_READ_CPLT_EVT: |
| { |
| SyncEventGuard g (mReadCompleteEvent); |
| mReadCompletedStatus = data->status; |
| mNdefDetectionTimedOut = data->status != NFA_STATUS_OK; |
| if (mNdefDetectionTimedOut) |
| ALOGE ("%s: NDEF detection timed out", fn); |
| mReadCompleteEvent.notifyOne (); |
| } |
| break; |
| |
| case NFA_NDEF_DETECT_EVT: |
| { |
| tNFA_NDEF_DETECT& ndef_detect = data->ndef_detect; |
| mNdefDetectionTimedOut = ndef_detect.status == NFA_STATUS_TIMEOUT; |
| if (mNdefDetectionTimedOut) |
| ALOGE ("%s: NDEF detection timed out", fn); |
| } |
| } |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function setActive |
| ** |
| ** Description Sets the active state for the object |
| ** |
| ** Returns None. |
| ** |
| *******************************************************************************/ |
| void NfcTag::setActive(bool active) |
| { |
| mIsActivated = active; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: isDynamicTagId |
| ** |
| ** Description: Whether a tag has a dynamic tag ID. |
| ** |
| ** Returns: True if ID is dynamic. |
| ** |
| *******************************************************************************/ |
| bool NfcTag::isDynamicTagId () |
| { |
| return mIsDynamicTagId && |
| (mTechList [0] == TARGET_TYPE_ISO14443_4) && //type-4 tag |
| (mTechList [1] == TARGET_TYPE_ISO14443_3A); //tech A |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: resetAllTransceiveTimeouts |
| ** |
| ** Description: Reset all timeouts for all technologies to default values. |
| ** |
| ** Returns: none |
| ** |
| *******************************************************************************/ |
| void NfcTag::resetAllTransceiveTimeouts () |
| { |
| mTechnologyTimeoutsTable [TARGET_TYPE_ISO14443_3A] = 618; //NfcA |
| mTechnologyTimeoutsTable [TARGET_TYPE_ISO14443_3B] = 1000; //NfcB |
| mTechnologyTimeoutsTable [TARGET_TYPE_ISO14443_4] = 618; //ISO-DEP |
| mTechnologyTimeoutsTable [TARGET_TYPE_FELICA] = 255; //Felica |
| mTechnologyTimeoutsTable [TARGET_TYPE_ISO15693] = 1000;//NfcV |
| mTechnologyTimeoutsTable [TARGET_TYPE_NDEF] = 1000; |
| mTechnologyTimeoutsTable [TARGET_TYPE_NDEF_FORMATABLE] = 1000; |
| mTechnologyTimeoutsTable [TARGET_TYPE_MIFARE_CLASSIC] = 618; //MifareClassic |
| mTechnologyTimeoutsTable [TARGET_TYPE_MIFARE_UL] = 618; //MifareUltralight |
| mTechnologyTimeoutsTable [TARGET_TYPE_KOVIO_BARCODE] = 1000; //NfcBarcode |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function: getTransceiveTimeout |
| ** |
| ** Description: Get the timeout value for one technology. |
| ** techId: one of the values in TARGET_TYPE_* defined in NfcJniUtil.h |
| ** |
| ** Returns: Timeout value in millisecond. |
| ** |
| *******************************************************************************/ |
| int NfcTag::getTransceiveTimeout (int techId) |
| { |
| static const char fn [] = "NfcTag::getTransceiveTimeout"; |
| int retval = 1000; |
| if ((techId > 0) && (techId < (int) mTechnologyTimeoutsTable.size())) |
| retval = mTechnologyTimeoutsTable [techId]; |
| else |
| ALOGE ("%s: invalid tech=%d", fn, techId); |
| return retval; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: setTransceiveTimeout |
| ** |
| ** Description: Set the timeout value for one technology. |
| ** techId: one of the values in TARGET_TYPE_* defined in NfcJniUtil.h |
| ** timeout: timeout value in millisecond. |
| ** |
| ** Returns: Timeout value. |
| ** |
| *******************************************************************************/ |
| void NfcTag::setTransceiveTimeout (int techId, int timeout) |
| { |
| static const char fn [] = "NfcTag::setTransceiveTimeout"; |
| if ((techId >= 0) && (techId < (int) mTechnologyTimeoutsTable.size())) |
| mTechnologyTimeoutsTable [techId] = timeout; |
| else |
| ALOGE ("%s: invalid tech=%d", fn, techId); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: getPresenceCheckAlgorithm |
| ** |
| ** Description: Get presence-check algorithm from .conf file. |
| ** |
| ** Returns: Presence-check algorithm. |
| ** |
| *******************************************************************************/ |
| tNFA_RW_PRES_CHK_OPTION NfcTag::getPresenceCheckAlgorithm () |
| { |
| return mPresenceCheckAlgorithm; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: isInfineonMyDMove |
| ** |
| ** Description: Whether the currently activated tag is Infineon My-D Move. |
| ** |
| ** Returns: True if tag is Infineon My-D Move. |
| ** |
| *******************************************************************************/ |
| bool NfcTag::isInfineonMyDMove () |
| { |
| static const char fn [] = "NfcTag::isInfineonMyDMove"; |
| bool retval = false; |
| |
| for (int i =0; i < mNumTechList; i++) |
| { |
| if (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) |
| { |
| //see Infineon my-d move, my-d move NFC, SLE 66R01P, SLE 66R01PN, |
| //Short Product Information, 2011-11-24, section 3.5 |
| if (mTechParams[i].param.pa.nfcid1[0] == 0x05) |
| { |
| UINT8 highNibble = mTechParams[i].param.pa.nfcid1[1] & 0xF0; |
| if (highNibble == 0x30) |
| retval = true; |
| } |
| break; |
| } |
| } |
| ALOGD ("%s: return=%u", fn, retval); |
| return retval; |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function: isKovioType2Tag |
| ** |
| ** Description: Whether the currently activated tag is Kovio Type-2 tag. |
| ** |
| ** Returns: True if tag is Kovio Type-2 tag. |
| ** |
| *******************************************************************************/ |
| bool NfcTag::isKovioType2Tag () |
| { |
| static const char fn [] = "NfcTag::isKovioType2Tag"; |
| bool retval = false; |
| |
| for (int i =0; i < mNumTechList; i++) |
| { |
| if (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) |
| { |
| //Kovio 2Kb RFID Tag, Functional Specification, |
| //March 2, 2012, v2.0, section 8.3. |
| if (mTechParams[i].param.pa.nfcid1[0] == 0x37) |
| retval = true; |
| break; |
| } |
| } |
| ALOGD ("%s: return=%u", fn, retval); |
| return retval; |
| } |