NXP NFC移植及學習筆記(原創)


NFC功能介紹

NFC 目前使用的三種功能:

1. P2P模式:基於LLCP協議的基礎上,以NDEF數據交換格式來通信。

2. 讀寫模式:當作為讀卡器,對NFC Tag的讀寫。

3. 卡模擬模式:模塊成卡,可以與讀卡器(或pos機)進行數據通信。

移植過程

驅動移植:

kernel-3.10/drivers/misc/mediatek/nfc/nxp

Framework移植:

1. 增加 packages/apps/Nfc-nxp

2. 增加 vendor/NXP/device

3. 更改 hardware/libhardware/include/hardware/nfc.h

4. 增加 frameworks/base/gsma-extras/java/com/android/nfcgsma_extras/NfcAdapterGsmaExtras.java

5. 增加 frameworks/base/core/java/com/vzw

6. 增加 frameworks/base/core/java/com/nxp

7. 更改替換 frameworks/base/core/java/android/nfc

8. 更改替換 frameworks/base/Android.mk

9. 增加 external/libp61-jcop-kit

10.增加 external/libnfc-nci-nxp

11.增加 external/dta

12. 更改 device/mediatek/common/device.mk (增加對 vendor/NXP/device/device-NXP.mk 的編譯選項

NFC 啟動過程

相關服務的啟動 

1. NfcService 在開機時 自動啟動的。 

Packages/app/Nfc-nxp/AndroidManifest.xml 

1     <application android:name=".NfcApplication"
2                  android:icon="@drawable/icon"
3                  android:label="@string/app_name"
4                  android:theme="@android:style/Theme.Material.Light"
5                  android:persistent="true"       

NfcApplication 會在Android SystemReady 時啟動,從而會把NfcService 這個服務啟動起來。

    public NfcService(Application nfcApplication) {
        mUserId = ActivityManager.getCurrentUser();
        mContext = nfcApplication;

        mNfcTagService = new TagService();
        mNfcAdapter = new NfcAdapterService();
        mNxpNfcAdapter = new NxpNfcAdapterService();
        mExtrasService = new NfcAdapterExtrasService();
        mNxpExtrasService = new NxpNfcAdapterExtrasService();

TagService 是對Tag的讀寫服務

NfcAdapterService NfcAdapter 的遠端服務。對NFC功能的操作的服務(包括打開,關閉,設置工作模式等)。

NxpNfcAdapterService NXP Ic 控制和設置的服務。有 獲取控制的接口,選擇路由,設置配置參數,還有對ese的訪問等。

NfcAdapterExtraService 是卡模擬功能的服務。打開關閉卡模擬,獲取,設置卡模擬路由。

NxpNfcAdapterExtrasService ese 安全功能的服務。獲取,指定安全訪問路由。

NfcService初始化的時序圖:

 1 NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
 2 theInstance.Initialize(); //start GKI, NCI task, NFC task 
 3 創建NCI task 線程和 NFC task 線程
 4 
 5 NFA_Init (halFuncEntries);
 6 stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback);
 7 
 8  SecureElement::getInstance().initialize (getNative(e, o));
 9  //setListenMode();
10 RoutingManager::getInstance().initialize(getNative(e, o));
11 HciRFParams::getInstance().initialize ();
12  sIsSecElemSelected = (SecureElement::getInstance().getActualNumEe() - 1 );
13  sIsSecElemDetected = sIsSecElemSelected;
14   nativeNfcTag_registerNdefTypeHandler ();
15 NfcTag::getInstance().initialize (getNative(e, o));
16 PeerToPeer::getInstance().initialize ();
17   PeerToPeer::getInstance().handleNfcOnOff (true);

這里面基本都是NXP 硬件 和 HAL層的初始化。重點看看 NfcAdaptation Initialize()

 

1 void NfcAdaptation::Initialize ()
2 {
3     ..........................................................
4     InitializeHalDeviceContext ();
5     .........................................................
6 }

 

繼續看 InitializeHalDeviceContext()

 

 1 void NfcAdaptation::InitializeHalDeviceContext (){
 2 ….........................................................
 3 ret = hw_get_module (nci_hal_module, &hw_module);
 4 if (ret == 0)
 5     {
 6         ret = nfc_nci_open (hw_module, &mHalDeviceContext);
 7         if (ret != 0)
 8             ALOGE ("%s: nfc_nci_open fail", func);
 9     }
10 }

 

這一塊就對NFC HAL 做了初始化了,我們再繼續往下跟會發現創建了兩個線程,一個讀線程,一個寫線程:

 

 1 /* Create Reader and Writer threads */
 2     pthread_create_status = pthread_create(&gpphTmlNfc_Context->readerThread,NULL,(void *)&phTmlNfc_TmlThread,
 3                                   (void *)h_threadsEvent);
 4     if(0 != pthread_create_status)
 5     {
 6         wStartStatus = NFCSTATUS_FAILED;
 7     }
 8     else
 9     {
10         /*Start Writer Thread*/
11         pthread_create_status = pthread_create(&gpphTmlNfc_Context->writerThread,NULL,(void *)&phTmlNfc_TmlWriterThread, (void *)h_threadsEvent);
12         if(0 != pthread_create_status)
13         {
14             wStartStatus = NFCSTATUS_FAILED;
15         }
16     }

讀線程調用select 對 設備節點/dev/pn544做了監聽掛起, 有nfc 檢測到有設備 中斷上來時,會將數據寫往此設備節點,此時監聽線程 檢測到有數據寫入時,會喚醒線程來讀出寫入的數據。

 1 ret_Select = select((int)((intptr_t)pDevHandle + (int)1), &rfds, NULL, NULL, &tv);
 2     if (ret_Select < 0)
 3     {
 4         NXPLOG_TML_E("i2c select() errno : %x",errno);
 5         return -1;
 6     }
 7     else if (ret_Select == 0)
 8     {
 9         NXPLOG_TML_E("i2c select() Timeout");
10         return -1;
11     }
12     else
13     {
14         ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead – numRead);

TAG的讀寫

當有TAG靠近手機NFC讀寫區域,驅動中會觸發中斷,把讀到數據寫入到設備節點中,i2c讀線程會喚醒,讀到數據后,將數據封裝好,回調指定的回調函數,將數據和消息類型封裝成一個消息,然后發送消息任務線程去處理,再回調指定的監聽。

jniNativeNfcManager.cpp 中 通過NotifyNdefMessageListeners回調到 NativeNfcManager.java中,再通過OnRemoteEndPointDiscovered回傳到NfcService. NfcSevice 再做Dispatch分發,將NDEF 消息格式解析中,再根據類型,找到最合適的Activity 來啟動。

看看 NDEF 的格式:

Bundle extras = tag.getTechExtras(TagTechnology.NDEF);

if (extras != null) {

mMaxNdefSize = extras.getInt(EXTRA_NDEF_MAXLENGTH);

mCardState = extras.getInt(EXTRA_NDEF_CARDSTATE);

mNdefMsg = extras.getParcelable(EXTRA_NDEF_MSG);

mNdefType = extras.getInt(EXTRA_NDEF_TYPE);

}

P2P功能的send 

看看時序圖:

當兩上機器靠近時,中斷來了,驅動就會往/dev/pn544設備中寫數據,從而喚醒i2c_reader 線程,從而根據報來的消息類型,會調用NativeNfcManager 去處理此類型消息,然后notifyLlcpLinkActivation, 告訴NativeNfcManagerP2P的消息來了,並且回調NfcServiceonLlcpLinkActivatedNfcService 會把此消息交給NfcServiceHandler來處理,此時會調用P2PLinkManageronLlcpActivated。然后 會調用P2pEventManageronP2pSendConfirmationRequested來確認是否p2pSend。 這個P2PEventManager 會調用SendUi 里的 showPreSend. 這個sendUi就在界面上做UI處理了(這個是一個傳界面的UI,還有一個fileSendUi 專用於傳文件的UI顯示,根據當前界面為判斷用哪種UI來顯示),就是我們看到縮小的界面圖了。這個showPreSend 其實做了一個截屏的操作,然后加上了一個動畫,讓其縮小,並提示“觸摸即可傳輸”。當我們點擊屏幕,就是調用onTouch事件了, sendUi 顯示一個動畫,然后就是sendNdefMessage

我們再來看看 sendNdefMessage的過程:

最后就是通過 SnepClient 通過SnepMessager 將消息發送出來。SnepClient 其實就是在sendNdefMessage之間就有個connect的操作, 這個connect就是創建了一個socket 去連接服務端的socketsendMessage 就是通過socket 把這個給消息給發過去。

當然根據傳的東西不同,如果傳的文件,歌曲,圖片,我們會啟動 wifiDirect去傳輸。Android原生會調用藍牙來傳輸。

P2P功能的接收

我們先看一下接收一個時序圖:

P2P的接收就簡單說明下,NfcService 啟動的時候,會實例化P2PLinkManager, 同時 P2PLinkManager會實例化一個SnepServer (這時候應該想到send過程中的SnepClient),會開啟兩個進程,一個是Socket進程,就是會監聽接收客戶端的sockek連接。 另一個就是ConnectionThread,用於將連接到messager 處理,會回調 P2PLinkManager doGet doPut.. 這時就成功能將Ndef的消息獲取到了。之后的流程就與TAG的讀過程差不多了,解析Message, 然后dispatcher, 啟動對應的Activity.

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM