开发目标:

(1) 对于Android手机,直接通过微信小程序调用手机的NFC功能,对15693协议的芯片进行读写操作;

(2)对于苹果手机(及没有NFC模块的手机),通过微信小程序的蓝牙功能连接到蓝牙/NFC读写器,然后通过蓝牙发送指令操作读写器对15693协议的芯片进行读写操作。

DAY #1

上午开了半天会,下午开始开发。

先开发简单的:直接通过Android手机的NFC模块读写芯片。开发思路如下:

1. 首先调用 wx.getHCEState(OBJECT), 判断设备是否支持NFC,如果不支持就走蓝牙通道;

2. 调用 wx.startHCE(OBJECT) 初始化手机的NFC模块;

3. 初始化完成后,调用  wx.onHCEMessage(CALLBACK) 监听芯片响应的消息;

4. 点击页面上的“询卡”按钮,调用 wx.sendHCEMessage(OBJECT)发送询卡指令;

5. 这时 wx.onHCEMessage(CALLBACK) 应该可以收到带有uid信息的芯片响应数据;

6. 根据uid发送select指令,以及后续多个指令;

7. 全部操作完成后之后,调用 wx.stopHCE(OBJECT) 停止手机的NFC模块;

8. 完成。

思路很清晰,并且开发思路中需要用到的每一个NFC的接口都有对应文档,应该是没有什么问题了,接着就开始开发NFC模块了。

第一步、微信小程序基本框架搭建,非常顺利的完成界面,调试模式等。

然后开始写nfc模块,首先是 wx.getHCEState(OBJECT),比较顺利,同时测试了一下没有NFC模块的手机/NFC为开启等多种情况的返回值(因为小程序开发文档没有写啊)。

然后是初始化NFC模块,也比较顺利。

然后完成wx.onHCEMessage(CALLBACK)消息监听,然后就是点击按钮发送消息  wx.sendHCEMessage(OBJECT),从这时开始就开始进入无助的状态。

尝试了多组数据进行发送,始终不能触发 wx.onHCEMessage, 折腾了半个小时,未果,等第二天解决吧。

DAY #2

首先仍然怀疑是数据格式不对,因为第一次开发跟芯片相关的程序,并且也是第一次接触15693协议,所以一开始非常坚定的相信是自己组装的发送数据不对,然后就去请教了芯片开发大牛,以及把15693协议的相关部分读了大约10遍,在网上找15693协议相关资料,百度微信小程序NFC开发资料。

还是不能触发 wx.onHCEMessage。

直到在微信小程序开发社区,输入关键字“wx.onHCEMessage”,然后从寥寥的几篇post中,终于明白:TMD微信小程序的NFC功能仅仅是把手机模拟成一张芯片卡,而不是把手机当做芯片读写器!WTF

这时已经下午3点。

因为我一开始跟公司领导说的是微信小程序可以直接调NFC读取芯片,这下就尴尬了,对项目的规划影响巨大。然后,抱着一丝恐惧,也抱着一丝希望,多方搜索,多方确认,TMD微信小程序目前确实只能把手机模拟成一张芯片卡。

然后跟公司领导电话里简单汇报了一下,领导说第二天开会讨论。

然后开始写蓝牙通道的解决方案。

微信小程序开放的蓝牙接口如下:

共18个接口,实在是太多了。这里不得不吐槽一下微信小程序的架构师们,你们设计的开发文档太粗糙了,需要开发人员写大量的代码才能完成一些基本功能,比如我自己想要完成的一些功能:

1. 初始化蓝牙模块;

2. 打开/关闭蓝牙发现;

3. 随时只允许单一设备连接,不允许多设备连接;

4. 已连接上的蓝牙断开后自动重连,自动重连失败后提示并继续自动重连;

5. 每次连上蓝牙设备后自动记住蓝牙设备ID,并写入一个长度为5的数组,并写到storage里面,这样下次进入小程序后就可以自动连接曾经连过的蓝牙设备。

下面是我希望自己的程序可以这样调用蓝牙模块的伪代码:

 Page({
     onLoad: function(){
         ble.onMessageReceived = function(res){

         };
         ble.onDeviceFound = function(device){
             //参数是device 而不要 devices
         };
         ble.autoReconnect = true;
         ble.maxConnections = 1;
         ble.maxRememberedConnections = 5;
         ble.init(function(){ //init 方法里面初始化蓝牙模块
             ble.autoConnectToRememberedDevice(function(res){
                 if(ble.connectedDevices.length == 0){
                     //连接记住的设备失败,跳转到蓝牙发现页面
                 }
             });
         });
     },
     connectToNewDevice: function(newDeviceId){
         //由于设置了最大连接数为1,这时调这个方法就会主动断掉之前的连接
         //这样就不需要先调 disconnect了, 也不需要检查设备ID/状态是否不一致
         ble.connectToDevice(newDeviceId, function(){

         });
     }
 });

既然微信没有实现这个简便的ble,就只有我自己来实现了。

当天下午剩下的一两个小时,已经将这个ble写的差不多了,等到第二天来调试。

DAY #3

早上一来跟领导开会,确认对于Android手机必须开发APP以避免使用蓝牙读写器,小程序仍然要开发,因为iOS系统始终需要读写器才能对芯片进行操作。

开完会就开始进入蓝牙模块的调试。

首先遇到的问题就是获取不到蓝牙设备的名称,尝试从advertiseData解析,尝试在网上找了很多资料,未果。看了论坛的很多帖子,应该是小程序API还不能很好的兼容其他设备的,也就是说对于这块功能还很不成熟。

于是就只有暂时放弃解决蓝牙设备名称的问题。

继续完善ble模块,到下午下班的时候蓝牙连接模块已经比较成熟了,上文提到的那些功能全部都已实现,并且封装之后的BluetoothManager非常好用,表现也很稳定,体验很流畅,跟iOS系统的wifi连接模块的体验差不多。

DAY #4

早上一来就开始继续写蓝牙的读写功能。这里不得不吐槽一下微信小程序的架构师们,开发人员使用你们设计的接口,就完成一个读写功能需要调好几个接口,太复杂了。下方是我写的ble开放的几个接口,真希望微信小程序的架构师们也能开发一些这样的快捷接口:

 Page({
     onLoad: function(){
         ble.onMessageReceived = function(res){
             if(询卡指令返回){
                 ble.sendMessage("发送select指令");
             }
         };
         ble.init(......);
     },
     doInventory: function(){
         ble.sendMessage("发送询卡指令")
     }
 });

等到把这部分代码写完,正好公司购买的蓝牙读写器到货,马上拆开进行测试。

首先是启动微信小程序,自动进入发现页面,很快找到了新的蓝牙设备,值得庆幸的是竟然读到了新设备的名称(而不是像其他蓝牙设备一样返回空)。选择该设备进行连接,非常顺利,然后继续测试了一下断开自动重连,更换设备(保持单一连接),记住连接过的蓝牙设备,中途修复了两三个小bug,又改进了一下体验,应该说连接部分比较完美了。

然后就是要测试第一个指令:询卡。

由于读写器自带一个询卡按钮,通过按一下按钮就发送询卡指令的方式,所以询卡变得很简单。于是对于代码而言,按了询卡按钮之后应该直接进入wx.notifyBLECharacteristicValueChange(OBJECT)。写好相应初始化以及消息监听代码之后,就等着按一下询卡按钮了。

一按,果然收到消息回调了!调试了这么多天,终于可以触发NFC消息通知了!虽然很简单,但是确实是很激动。

消息回调虽然收到了,但是不知道响应消息的格式,也就无法解析,不晓得芯片是不是正确响应了。问了芯片厂家,又问了读写器生产厂家,终于问到了询卡指令的响应格式,按照格式解析出来了UID,这么多天终于读到了UID!再对比芯片厂家提供的demo app以及读写器厂家提提供的桌面程序,确认读到的UID是正确的。

接下来便是发送select指令。下图为15693 select指令格式:

首先第一个字节flags就不知道怎么拼,select字节传0x25,UID已得到,CRC不知道怎么计算。

在网上看了很多资料,包括芯片厂家也说CRC一般是不需要传值的,因为大多数读写器都会在内部进行CRC的计算。好吧,我暂且相信,那么就只剩下一个参数了,那就是flags参数。按照15693协议规定,试了多种组合,尝试发送select指令(在第一个询卡成功的消息回调中发送),然而收不到任何响应消息。

下班后折腾了一个多小时,做了各种数据格式的尝试,翻阅了多个资料,将手里的15693协议的相关部分阅读了多次,还是收不到任何响应消息。无赖,不得不下班了。等第二天再来研究吧。

DAY #5

继续研究select指令。在跟读写器厂家交流的过程中得知,CRC是必须自己计算的,不能不传,然后就从读写器厂家提供的DEMO代码中找到了CRC的算法,然后用JS实现了一遍,然后好不容易在读写器厂家的技术文档中看到一个CRC计算示例,根据示例的传入参数和计算结果再次确认了自己的JS算法是正确的。

然后,不管怎么传参数格式,select指令发送成功后收不到任何消息。

在绝望之时,干脆不用读写器自带的询卡按钮,自己按照15693协议发送询卡指令。到这时,在跟读写器厂家沟通的过程中得知,他们生产的蓝牙NFC读写器都有自己的数据传输格式,不能完全按照ISO15693协议来写,得按照他们提供的文档来写,当然,到这时候读写器厂家提供的文档也读过奖金十遍了,请求格式响应格式已比较熟悉。所以几分钟就完成了询卡代码。

写完代码之后进入调试,直接就收到了询卡之后的响应,然而在接下来的发送select指令后还是没有收到任何响应。当然,这也本在预料之中。这个时候对读写器厂家的怀疑不断加深,越来越觉得他们卖的读写器无法读到我们的芯片,想要退货。

但我还是没有死心,尝试按照读写器厂家提供的文档,一步一步组装数据。在之后的大概第3次尝试中,竟然收到了select指令的响应!并且按照响应格式解析数据表明芯片响应成功!

太激动了!!!

后来才明白,为什么按读写器自带的询卡按钮之后发送的select指令收不到响应,而自己通过蓝牙发送的询卡指令就收到了响应,我猜测是因为按钮发起的通讯会话跟蓝牙发起的会话完全就是不同的会话导致的,所以点击读写器自带的询卡按钮之后再通过蓝牙发送select指令,应该就相当于直接对着一张芯片发送select指令,当然不会收到任何响应了。

这时,调通了第一个指令,想当然的我觉得后面的指令肯定不是问题了,肯定就会变得非常简单。

然而,更让人绝望的事情发生了。

要说select指令的困惑,差不多花了我4个小时,并且一开始还是非常相信读写器可以通过蓝牙完成select指令的,一直到最后才有点怀疑读写器的问题。

接下来的这个指令是芯片厂家的一个定制指令,不属于ISO15693协议规定的范围之内,读写器厂家提供的文档中自然不会包含整个定制指令。所以只能按照芯片厂家给的文档来发送指令。

很显然,这肯定是行不通的。读写器肯定只能认识读写器厂家给的文档中定义的指令格式,然而这个浅显的道理我大概花了1个小时才明白,在尝试了多种尝试之后冷静下来一思考就明白了。

然后就是找读写器厂家沟通。这个过程也是非常绝望的,因为在跟芯片厂家沟通的过程中得知,必须要读写器支持15693透传协议才可能发送定制指令。然而问了读写器厂商,他们自己也不确认 这款产品的蓝牙通道是否支持透传,他们有另一款产品支持透传,但是不支持蓝牙,这让我一度觉得肯定要把读写器退货了,然后再重新买一个支持15693协议并支持蓝牙透传的读写器。

然后抱着一丝丝希望,跟读写器厂家咨询了很久,他们建议我按照他们另一款支持透传协议的读写器的文档来开发。

真的自己都不抱什么希望了,只是再写几行代码总比立即去买一个新的读写器来的更简单一些,于是又做了一次尝试。

这次按照另一款读写器的透传协议,更改了定制指令的格式。

竟然!竟然直接就收到了芯片响应!

太激动了!

激动了3分钟之后,静下来一看,响应的数据太短,肯定不是正确的数据,然后比对文档中的响应格式,确认芯片没有能够正确响应。

这时还是继续怀疑读写器不支持透传指令,于是再跟读写器厂家沟通,把响应数据发给了他们看,他们确定芯片是收到了指令了,只是指令格式不对,芯片没有回发正确的数据。

这时已经下班十几分钟了,感觉就还剩这一个问题了,如果不能确定该读写器是否支持透传,那接下来的周末肯定是无法好好休息的。

但这时已经对读写器很有信心了,比较坚定的认为是定制指令格式不对。然后又找芯片厂家要了他们以前发送的demo代码,指令的示例,然后又把芯片厂家的对应文档阅读了几遍,几乎一个字一个字去理解协议中的每一个字。

终于,终于发现指令中的某个代表响应数据长度的字节计算错误,当把这个错误数据修复之后就立即收到了正确的响应了。

太不容易了!

终于可以安心的下班了!

后记

之后的开发都比较顺利了,因为要么就是给读写器发送读写器自定义的指令,要么就是用透传功能发送芯片自定义的指令,可以说是所有指令都可以发送了。

这次芯片项目开发收货到最有价值的经验就是,一般读写器厂家都会有自己定义的一套指令格式,或者SDK,当通过读写器操作芯片的时候,必须要首先按照读写器的API文档来写,否则芯片不可能有响应的。

信息

记录使用微信小程序的NFC和蓝牙功能读取15693芯片的开发历程的更多相关文章

  1. 基于微信小程序的用户列表点赞功能

    代码地址如下:http://www.demodashi.com/demo/13997.html 一.前言 (1).适合人群 1.微信小程序开发者 2.前端工程师 3.想入门学习小程序开发的人员 4.想 ...

  2. 微信小程序之换肤的功能

    pc或者移动端实现换肤功能还是比较简单的,大致就是需要换肤的css,还有正常的css:把当前皮肤类型存入本地:然后通过js读取并判断当前应该加载哪套css. 由于微信小程序没有操作wxss的api,所 ...

  3. [转]微信小程序实现图片上传功能

    本文转自:http://blog.csdn.net/feter1992/article/details/77877659 前端: 微信开发者工具 后端:.Net 服务器:阿里云 这里介绍微信小程序如何 ...

  4. 微信小程序上传Excel文本文件功能

    问题: 在开发过程中会发现微信小程序有很多功能都还不能满足我们的需求,谁叫客户就是上帝呢,前几天小编遇到了这么个问题,就是用微信小程序上传文件,但是还以为微信带有这个模块,可是查了许久还是没有找到,只 ...

  5. 微信小程序背景音频播放分享功能

    如果正常背景音频播放的话,只能跳转到自己对应的微信小程序,无法分享朋友圈,我们需要设置分享朋友圈,需要调用一个API 音频背景播放 注意:背景播放在锁屏后播放只支持IOS端,安卓端虽然可以播放,但是锁 ...

  6. 微信小程序实现图片上传功能

    前端: 微信开发者工具 后端:.Net 服务器:阿里云 这里介绍微信小程序如何实现上传图片到自己的服务器上 前端代码 data: { productInfo: {} }, //添加Banner bin ...

  7. 微信小程序实现连续扫码功能(uniapp)

    注:本文使用的是 uniapp 语法. 微信小程序提供了扫码API:wx.scanCode,但它只能扫一次码,想要实现连续扫码,需要借用 camera 组件.camera 组件不仅能拍照,还具有扫码功 ...

  8. 微信小程序 发送模板消息的功能实现

    背景 - 小程序开发的过程中,绝大多数会满足微信支付 - 那么,作为友好交互的体现,自然就会考虑到支付后的消息通知咯 - 所以,我的小程序项目也要求完成这个效果,so.分享一下自己的实现步骤,以方便道 ...

  9. 微信小程序开发抖音去水印功能

    之前找了很多抖音去水印的工具全是广告,所以索性自己写了一个,提供给大家免费试用以下是微信小程序的二维码 使用教程: 1.打开微信搜索小程序:沸点软件技术服务 2.打开沸点软件技术服务小程序 3.去抖音 ...

随机推荐

  1. bzoj 2217 [Poi2011]Lollipop 乱搞 贪心

    2217: [Poi2011]Lollipop Time Limit: 15 Sec  Memory Limit: 64 MBSec  Special JudgeSubmit: 383  Solved ...

  2. git一键部署代码到远程服务器(linux)(采坑总结)

    原来一直使用FileZilla来代码部署,去年使用git,代码版本管理,真TM好用,一起回顾下历程! 一. 代码部署方式及思路: 1. 使用FTP/SFTP工具,上传代码 2. git人工部署.1. ...

  3. Java中子类能继承父类的私有属性吗?

    前段时间去听老师讲课的时候,老师告诉我子类是可以继承父类所有的属性和方法的.当时我是极其疑惑的,因为之前学校考试时这个考点我记得很清楚:子类只能继承父类的非私有属性和方法.老师给我的解释是这样的--先 ...

  4. Linux CentOS 安装MySql以及搭建MySql主从复制

    前言 在之前的博客中,有过几篇都写了关于mysql在linux下的搭建教程,可能以后还会再写,但是又不想重复在写, 于是便想单独将此抽出来,单独写成一篇博客,并详细记录一些安装过程以及遇到的问题解决办 ...

  5. jqeury显示前几个,隐藏后几个,点击后隐藏前几个显示后几个

    <script type="text/javascript"> $(".ul li").each(function(){ if($(this).in ...

  6. Oracle SQL Developer 连接数据库如何对应数据库配置文件

    Oracle SQL Developer 连接数据库如何对应数据库配置文件 1.数据库配置文件 hibernate.connection.url jdbc:oracle:thin:@146.56.35 ...

  7. Openstack_O版(otaka)部署_Nova部署

    控制节点配置 1. 建库建用户 CREATE DATABASE nova_api; CREATE DATABASE nova; GRANT ALL PRIVILEGES ON nova_api.* T ...

  8. OpenStack_I版 4.Dashboard部署

    由python的DjangoWeb框架开发的   使用keystone默认的角色来访问各种服务   Dashboard安装       Dashboard是openstack的Web管理界面,需要将它 ...

  9. 如何登录mysql? cmd怎么连接mysql数据库||从MYSQL客户端登录MYSQL

    1 2 3 4 5 6 7 分步阅读 Mysql开源数据库,任何人都可以下载安装使用.那么安装好的mysql如何登陆连接mysql数据库呢?本经验咗嚛介绍几种常见的方法 工具/原料   mysql 连 ...

  10. maven项目转eclipse

    很多国外的开源项目是用maven编译的,对于我们比较熟悉eclipse开发的童鞋来说,能转成.project是最好不过了. 很简单,装好maven后,在项目目录打开命令行,输入 mvn eclipse ...