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

     <application android:name=".NfcApplication"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.Material.Light"
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初始化的时序图:

 NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
theInstance.Initialize(); //start GKI, NCI task, NFC task
创建NCI task 线程和 NFC task 线程 NFA_Init (halFuncEntries);
stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); SecureElement::getInstance().initialize (getNative(e, o));
//setListenMode();
RoutingManager::getInstance().initialize(getNative(e, o));
HciRFParams::getInstance().initialize ();
sIsSecElemSelected = (SecureElement::getInstance().getActualNumEe() - 1 );
sIsSecElemDetected = sIsSecElemSelected;
nativeNfcTag_registerNdefTypeHandler ();
NfcTag::getInstance().initialize (getNative(e, o));
PeerToPeer::getInstance().initialize ();
PeerToPeer::getInstance().handleNfcOnOff (true);

这里面基本都是NXP 硬件 和 HAL层的初始化。重点看看 NfcAdaptation Initialize()

 void NfcAdaptation::Initialize ()
{
..........................................................
InitializeHalDeviceContext ();
.........................................................
}

继续看 InitializeHalDeviceContext()

 void NfcAdaptation::InitializeHalDeviceContext (){
….........................................................
ret = hw_get_module (nci_hal_module, &hw_module);
if (ret == )
{
ret = nfc_nci_open (hw_module, &mHalDeviceContext);
if (ret != )
ALOGE ("%s: nfc_nci_open fail", func);
}
}

这一块就对NFC HAL 做了初始化了,我们再继续往下跟会发现创建了两个线程,一个读线程,一个写线程:

 /* Create Reader and Writer threads */
pthread_create_status = pthread_create(&gpphTmlNfc_Context->readerThread,NULL,(void *)&phTmlNfc_TmlThread,
(void *)h_threadsEvent);
if( != pthread_create_status)
{
wStartStatus = NFCSTATUS_FAILED;
}
else
{
/*Start Writer Thread*/
pthread_create_status = pthread_create(&gpphTmlNfc_Context->writerThread,NULL,(void *)&phTmlNfc_TmlWriterThread, (void *)h_threadsEvent);
if( != pthread_create_status)
{
wStartStatus = NFCSTATUS_FAILED;
}
}

读线程调用select 对 设备节点/dev/pn544做了监听挂起, 有nfc 检测到有设备 中断上来时,会将数据写往此设备节点,此时监听线程 检测到有数据写入时,会唤醒线程来读出写入的数据。

 ret_Select = select((int)((intptr_t)pDevHandle + (int)), &rfds, NULL, NULL, &tv);
if (ret_Select < )
{
NXPLOG_TML_E("i2c select() errno : %x",errno);
return -;
}
else if (ret_Select == )
{
NXPLOG_TML_E("i2c select() Timeout");
return -;
}
else
{
ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead – numRead);

TAG的读写

当有TAG靠近手机NFC读写区域,驱动中会触发中断,把读到数据写入到设备节点中,i2c读线程会唤醒,读到数据后,将数据封装好,回调指定的回调函数,将数据和消息类型封装成一个消息,然后发送消息任务线程去处理,再回调指定的监听。

从jni中 NativeNfcManager.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, 告诉NativeNfcManager有P2P的消息来了,并且回调NfcService的onLlcpLinkActivated。NfcService 会把此消息交给NfcServiceHandler来处理,此时会调用P2PLinkManager的onLlcpActivated。然后 会调用P2pEventManager的onP2pSendConfirmationRequested来确认是否p2pSend。 这个P2PEventManager 会调用SendUi 里的 showPreSend. 这个sendUi就在界面上做UI处理了(这个是一个传界面的UI,还有一个fileSendUi 专用于传文件的UI显示,根据当前界面为判断用哪种UI来显示),就是我们看到缩小的界面图了。这个showPreSend 其实做了一个截屏的操作,然后加上了一个动画,让其缩小,并提示“触摸即可传输”。当我们点击屏幕,就是调用onTouch事件了, sendUi 显示一个动画,然后就是sendNdefMessage。

我们再来看看 sendNdefMessage的过程:

最后就是通过 SnepClient 通过SnepMessager 将消息发送出来。SnepClient 其实就是在sendNdefMessage之间就有个connect的操作, 这个connect就是创建了一个socket 去连接服务端的socket。sendMessage 就是通过socket 把这个给消息给发过去。

当然根据传的东西不同,如果传的文件,歌曲,图片,我们会启动 wifiDirect去传输。Android原生会调用蓝牙来传输。

P2P功能的接收

我们先看一下接收一个时序图:

P2P的接收就简单说明下,NfcService 启动的时候,会实例化P2PLinkManager, 同时 P2PLinkManager会实例化一个SnepServer (这时候应该想到send过程中的SnepClient),会开启两个进程,一个是Socket进程,就是会监听接收客户端的sockek连接。 另一个就是ConnectionThread,用于将连接到messager 处理,会回调 P2PLinkManager 的doGet 和 doPut.. 这时就成功能将Ndef的消息获取到了。之后的流程就与TAG的读过程差不多了,解析Message, 然后dispatcher, 启动对应的Activity.

NXP NFC移植及学习笔记(原创)的更多相关文章

  1. jz2440-linux3.4.2-kernel移植【学习笔记】【原创】

    平台:jz2440 作者:庄泽彬(欢迎转载,请注明作者) 说明:韦东山二期视频学习笔记 交叉编译工具:arm-linux-gcc (GCC)4.3.2 linux:linu3.4.2 PC环境:ubu ...

  2. jz2440-uboot-201204版本移植【学习笔记】【原创】

    平台:jz2440 作者:庄泽彬(欢迎转载,请注明作者) 说明:韦东山二期视频学习笔记 交叉编译工具:arm-linux-gcc (GCC)4.3.2 PC环境:ubuntu18.04 一.uboot ...

  3. MongoDB 学习笔记(原创)

    MongoDB 学习笔记 mongodb 数据库 nosql 一.数据库的基本概念及操作 SQL术语/概念 MongoDB术语/概念 解释/说明 database database 数据库 table ...

  4. Angular源代码学习笔记-原创

    时间:2014年12月15日 14:15:10 /** * @license AngularJS v1.3.0-beta.15 * (c) 2010-2014 Google, Inc. http:// ...

  5. Python爬虫框架Scrapy学习笔记原创

     字号 scrapy [TOC] 开始 scrapy安装 首先手动安装windows版本的Twisted https://www.lfd.uci.edu/~gohlke/pythonlibs/#twi ...

  6. LwIP学习笔记——STM32 ENC28J60移植与入门

    0.前言     去年(2013年)的整理了LwIP相关代码,并在STM32上"裸奔"成功.一直没有时间深入整理,在这里借博文整理总结.LwIP的移植过程细节很多,博文也不可能一一 ...

  7. ucos实时操作系统学习笔记——操作系统在STM32的移植

    使用ucos实时操作系统是在上学的时候,导师科研项目中.那时候就是网上找到操作系统移植教程以及应用教程依葫芦画瓢,功能实现也就罢了,没有很深入的去研究过这个东西.后来工作了,闲来无聊就研究了一下这个只 ...

  8. [原创]java WEB学习笔记95:Hibernate 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  9. [原创]java WEB学习笔记75:Struts2 学习之路-- 总结 和 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

随机推荐

  1. How to Disable Strict SQL Mode in MySQL 5.7

    If your app was written for older versions of MySQL and is not compatible with strict SQL mode in My ...

  2. c语言之I/O函数

    c语言中常用的I/O函数 最常用的字符串的标准I/O函数有getchar().putchar().gets().puts().scanf().printf().fputs().fgets().getc ...

  3. css使absolute相对于父容器进行定位而不是以body(为什么绝对定位(absolute)的父级元素必须是相对定位(relative))

    借知乎的回答如下解释: 首先,我想告诉你的是,如果父级元素是绝对定位(absolute)或者没有设置,里面的绝对定位(absolute)自动以body定位.这句话是错的.正确的是:只要父级元素设了po ...

  4. Django models Form model_form 关系及区别

    Django models Form model_form

  5. Android源码——Broadcast Receiver

    Android源码分析——广播 广播是一种在组件之间进行消息传递的方式.广播机制的实现是基于Binder进程间通信. Binder进程间通信和广播的差别:Binder中,Client组件和Servic ...

  6. Beta阶段项目终审报告

    先上图 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件主要是用来解决玩狼人杀这款桌游时无牌.无法官.游戏流程不熟悉等情况的.我觉得我们对典型 ...

  7. 基于Dubbo框架构建分布式服务(二)

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> ...

  8. http请求与响应(content-type)

    http请求信息由浏览器把地址栏URL信息和页面(html.jsp.asp)组装成http请求消息体(如下). <request-line>(请求消息行)<headers>(请 ...

  9. Html中的文本框和单选按钮

    Html中的文本框和单选按钮用来制作页面的登录注册使用.. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN& ...

  10. coreseek操作

    开启服务$  /usr/local/coreseek/bin/searchd -c /usr/local/coreseek/etc/csft.conf 重新索引: /usr/local/coresee ...