• 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.

     

     

  • 相关阅读:
    Maven private reprository 更新
    Spark运行模式:cluster与client
    Spark脚本调用
    Java中hashCode与equal方法详解
    String值传递剖析
    Comparator 与 Comparable
    深入理解Java的接口和抽象类
    HitHub使用
    二叉树的递归与非递归遍历
    P1137 旅行计划
  • 原文地址:https://www.cnblogs.com/jack2010/p/5478700.html
Copyright © 2020-2023  润新知