本文是对已实现的蓝牙防丢器项目的总结,阐述蓝牙防丢器的原理、实现与Android客户端的蓝牙BLE接口编程。在这里重点关注如何利用BLE接口来进行工程实现,对于BLE的协议、涉及到JNI的BLE接口内部源码实现,笔者以后再详细剖析。但要求读者对BLE协议有一定的认识,如GAP、GATTprofile在BLE中的角色和作用,如何使用Service、Characteristic等。

一、蓝牙防丢器原理和产品需求

蓝牙防丢器的核心原理是根据接收到的蓝牙设备端的无线信号强度(RSSI)来估算距离。其计算公式是:

d是计算距离,RSSI是信号强度,A为发射端和接收端相隔1米时的信号强度,n是环境衰减因子。对于不同的蓝牙设备该值是不一样的,同样的设备在不同的发射功率的情况下其信号强度也是不一样的,而且对于同是1米的情况下,环境对于信号强度也是有影响的。n是环境衰减因子,自然跟环境有关。所以在确切发射功率的情况下,A和n对于同一款设备来说,也是一个经验值。

在实际的防丢器产品中,一般有以下功能:

1. 当手机(接收端)检测到发射端设备的距离超过一定距离时,发出告警提示,设备根据告警级别进行相应的指示,如发出不同频率的音频或者闪灯。

2. 当发射设备端发现和手机端建立的链路断开(意味着距离已经超过连接范围)时,其会自动发出某种形式的警告。

二、蓝牙防丢profile

笔者以业界目前功耗最低的蓝牙单芯片(Dialog公司的DA14580)来说明。针对DA14580,Dialog公司有提供开发SDK(以后会对该SDK框架进行分析,以指导开发),其中就有实现防丢profile,命名是Proximity。     该profile针对以上防丢的功能提供的Characteristic如下:

1.TXP(txpower) Characteristic, 设备端需要通过主机控制接口HCI来获得发射功率参数,并以read属性提供给master。

2.IAS(immediate alter service), write属性,供master写告警级别。当master写入新的值时,设备端会收到write的回调,其根据告警级别进行相应告警。

3. LLS(link loss service),write/read属性,供master设置链路断开情况下默认的告警级别。

RSSI通过接收端的接口来获得,并不需要设备端提供service。

以上Characteristic都通过GATT profile提供服务,在蓝牙通信协议上,每个Characteristic都会对应一个UUID。

三、android蓝牙BLE接口编程

androidBLE接口在android4.3版本以上提供。

1.   判断当前系统是否支持BLE

getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)

返回真表示支持。

2.   获得蓝牙适配器类

用户通过统一的蓝牙适配器类BluetoothAdapter来使用BLE API。

先获得蓝牙管理器:

BluetoothManagerbluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE);

再获得蓝牙适配器实例(单体对象):

BluetoothAdaptermBluetoothAdapter = bluetoothManager.getAdapter();

3.   启动手机蓝牙硬件功能(相当于在设置界面开启蓝牙功能)

mBluetoothAdapter.enable();

4.   开始扫描

BluetoothAdapter.startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallbackcallback)

callback是当扫描到蓝牙设备时的回调接口。实现callback中的onLeScan接口:

@Override

public void onLeScan(finalBluetoothDevice device, int rssi, byte[] scanRecord)

其中,device代表扫描到的设备,可以获得其MAC地址、设备名等等;rssi即信号强度,这是未连接时获取RSSI的方法;scanRecord代表扫描设备得到的响应参数,ibeacon即通过该参数来获得广播内容。

假设String bluetoothAddress = device.getAddress(),获取蓝牙48位MAC地址

5.   连接GATT,获取设备端的UUID服务,并进行数据通信交互

通过MAC地址获得代表设备端的蓝牙设备类

BluetoothDevicedevice = mBluetoothAdapter.getRemoteDevice(bluetoothAddress);

连接GATT

BluetoothGatt mBluetoothGatt = device.connectGatt(android.content.Context context, booleanautoConnect, android.bluetooth.BluetoothGattCallback callback);

Callback是连接GATT之后,所有数据交互的回调入口。分别包括:

1)设备服务发现

@Override

publicvoid onServicesDiscovered(BluetoothGatt gatt, int status)

mBluetoothGatt.getServices()代表设备服务集合,

for (BluetoothGattService gattService : mBluetoothGatt.getServices())

对于每个服务service,用getUuid()可以获得服务的UUID,getCharacteristics()代表该服务的Characteristic集合。

for(BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics)

对于每个Characteristic,getUuid()获得UUID,getPermissions()获得属性权限,getValue()获得属性值。

在该回调中我们只提取感兴趣的三个Characteristic的UUID,对于其他的如电池、设备服务等UUID可以不管。

gattCharacteristic_char5_TXP=gattCharacteristic;

2)连接状态改变

@Override

public voidonConnectionStateChange(BluetoothGatt gatt, int status,intnewState)

有两种状态,BluetoothProfile.STATE_CONNECTED代表连接,BluetoothProfile.STATE_DISCONNECTED代表断开连接。

3)读回调

@Override

public voidonCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristiccharacteristic, int status)

其对应手机端发出读请求后,当收到设备端的数据时的回调。如

mBluetoothGatt.readCharacteristic(gattCharacteristic_char5_TXP)

4)设备端数据变化回调

这里对应设备的characteristic的属性是notify或者indication,即相当手机端订阅这个characteristic的值变更服务,当设备端的characteristic发生变化时,设备端会主动发出通知给手机端。

@Override

public voidonCharacteristicChanged(BluetoothGatt gatt,

BluetoothGattCharacteristiccharacteristic)

在回调中获得新的值characteristic.getValue()。

5)获取到RSSI值的回调

RSSI在扫描时可以通过扫描回调接口获得,但是在连接之后要不断地使用

mBluetoothGatt.readRemoteRssi()向底层驱动发出读取RSSI请求,当底层获取到新的RSSI后会进行以下回调:

@Override

public voidonReadRemoteRssi(BluetoothGatt gatt, int rssi, int status)

rssi即是新的信号强度值。

连接后,由于手机和设备端的距离在发生变化,因此要不断地读取RSSI,实时计算两者之间的距离才能保证防丢功能的实现。

[yueqian_scut]蓝牙防丢器原理、实现与Android BLE接口编程的更多相关文章

  1. 蓝牙防丢器原理、实现与Android BLE接口编程

    本文是对已实现的蓝牙防丢器项目的总结,阐述蓝牙防丢器的原理.实现与android客户端的蓝牙BLE接口编程.在这里重点关注如何利用BLE接口来进行工程实现,对于BLE的协议.涉及到JNI的BLE接口内 ...

  2. struts2 javaweb 过滤器、监听器 拦截器 原理

    转: 过滤器.监听器 拦截器 过滤器 创建一个 Filter 只需两个步骤: (1)创建 Filter 处理类: (2)在 web.xml 文件中配置 Filter . 创建 Filter 必须实现 ...

  3. Struts2拦截器原理以及实例

    一.Struts2拦截器定义 1. Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现. 2. ...

  4. cocos2d-x触摸分发器原理

    屏幕捕捉到触摸消息的派发流程: 如果有一个组件如果想要接收触摸事件,会通过继承一个CCTouchDelegate接口注册给CCTouchDispatcher,CCTouchDispatcher 中维护 ...

  5. Typescript中的装饰器原理

    Typescript中的装饰器原理 1.小原理 因为react中的高阶组件本质上是个高阶函数的调用, 所以高阶组件的使用,我们既可以使用函数式方法调用,也可以使用装饰器. 也就是说,装饰器的本质就是一 ...

  6. Golang/Go goroutine调度器原理/实现【原】

    Go语言在2016年再次拿下TIBOE年度编程语言称号,这充分证明了Go语言这几年在全世界范围内的受欢迎程度.如果要对世界范围内的gopher发起一次“你究竟喜欢Go的哪一点”的调查,我相信很多Gop ...

  7. Python函数装饰器原理与用法详解《摘》

    本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...

  8. kafka拦截器原理|案例实操

    拦截器原理 Producer拦截器(interceptor)是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制逻辑. 对于producer而言,interceptor使得用 ...

  9. 南京大学计算机基础 X64函数调用和链接器原理和可重定位的文件.o

    一. 1.函数调用差别 X64的函数调用,和X86函数调用区别,在于参数的传递不一样了,X64的参数传递不在依靠栈来传,而是寄存器,不过还是具有局限性的 比如只能允许六个寄存器来传,分别是RDI,RS ...

随机推荐

  1. DBCONN

    package Ulike_servlet; //将该类保存到com.tools包中import java.sql.Connection;import java.sql.DriverManager;i ...

  2. nginx——location 优先级

    一. location 的匹配符1.等于匹配符:=等于匹配符就是等号,特点可以概括为两点:精确匹配不支持正则表达式2.空匹配符空匹配符的特点是:匹配以指定模式开始的 URI不支持正则表达式3.正则匹配 ...

  3. 总结几种C#窗体间通讯的处理方法

    摘要:本文介绍了C#窗体间通讯的几种处理方法,即传值.继承.事件回调,希望对大家有用. http://www.cnblogs.com/jara/p/3439603.html 应用程序开发中,经常需要多 ...

  4. C#【数据库】 Access类

    using System; using System.Data; using System.Data.OleDb; namespace AccessDb { /**//// <summary&g ...

  5. Python学习 - 使用BeautifulSoup来解析网页一:基础入门

    写技术博客主要就是总结和交流的,如果文章用错,请指正啊! 以前一直在使用SGMLParser,这个太费时间和精力了,现在为了毕业设计,改用BeautifulSoup来实现HTML页面的解析工作的. 一 ...

  6. Oracle数据库还原方法

    Win +X → 运行→cmd C:\Documents and Settings\Administrator>sqlplus /nolog SQL> connect sys/passwo ...

  7. fix iis Running slow

    为什么写这个文章.因为我现在再找一个站点的访问原因..方法还是老方法.. 1. 站点是否真的挂了 a. 基本上全挂.所有请求非常缓慢或超时. b.大多数请求慢,但最终还是执行了.有可能 队列再排队 怎 ...

  8. [BZOJ 1875] [SDOI 2009] HH去散步【矩阵乘法】

    题目链接:BZOJ - 1875 题目分析: 这道题如果去掉“不会立刻沿着刚刚走来的路走回”的限制,直接用邻接矩阵跑矩阵乘法就可以了.然而现在加了这个限制,建图的方式就要做一些改变.如果我们把每一条边 ...

  9. Tautology

    WFF 'N PROOF is a logic game played with dice. Each die has six faces representing some subset of th ...

  10. SCVMM更换数据库,如何搞?

    因为SCVMM和SQL不是集成在同一台机器上的. 所以,当SQL换机器或是换名字后,SCVMM就不能启动了. 并且MS没提供直观的更改数据库连接的工具,只是在安装的时候有选项. 网上找了方法,修改注册 ...