bluethooth BLE Android
一篇基本概念介绍的文章
http://mbientlab.com/blog/bluetooth-low-energy-introduction/
https://atmosphere.anaren.com/wiki/Data_rates_using_BLE
1. 带宽的计算
影响参数
Connection interval T 。
定义了多长时间建立一次连接,手册规定间隔可以为7.5ms~4s ,一些手机默认的间隔为7.5ms ,有些则是规定不小于37.5ms ,ios 一般规定最小为20ms
一般情况,Android 是不能改变interval,但可以发送update请求,Android 一般是可以接受的,ios要看是否在合理范围才决定接受。
关于连接参数,参考下面的连接
http://blog.csdn.net/lckj686/article/details/43153993
但有论坛贴说master是否接受设置建议还和是否打开wifi 有关 ,这可能与手机芯片使用的是GPS/WIFI/Bluethooth是三合一的有关。
Slave Latency Slave可以忽略master connection interval 的个数
参见https://atmosphere.anaren.com/wiki/Data_rates_using_BLE
Number of packets per even N
一次连接传输的包数 nFR51822 支持6个包 ,一般Andorid手机支持的是4个 ios支持6个包。
这个和Device的能力有关,包括了协议栈及处理芯片的能力 ,nRF51822支持6个包,cypress 的可以发送512B数据包
MTU ,包的大小 Byte
Android可以设置MUT 大小,这个也和Device的能力有关
http://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestMtu(int)
Throughput = N * MTU * 1/T
- iPhone 5/6 + IOS 8.0/8.1 with nRF51822: 6 * 20 B * 1/0.020 s = 6 kB/s = 48 kbps
- iPhone 5/6 + IOS 8.2/8.3 with nRF51822: 3 * 20 B * 1/0.020 s = 3 kB/s = 24 kbps
- Nexus 4 with nRF51822: 4 * 20 B * 1/0.0075 s = 10.6 kB/s = 84 kbps
有人测试过Andorid 的N才1个
https://devzone.nordicsemi.com/question/2540/understanding-ble_evt_tx_complete/
But within my own tests, I'd also seen Android Centrals (e.g. with Qualcomm RF chips) that drivers had only 1 packet at a connection interval. The best throughput I'd currently measured is at about 8-10 kByte/s using Android Centrals with Broadcom RC chip (and connection interval of 7,5 ms).
对N和MTU的理解
nFR51822 称可以支持在一个6个包 ,那么在一个传输时间内可以传 6*20B=120B个字节的净荷
IT 的CC2540可以通过以下方法获得较快的速率
http://processors.wiki.ti.com/index.php/OverlappedProcessing
http://processors.wiki.ti.com/index.php/CC2540_Data_Throughput
包的类型对throughput 的影响
Write Requests and Indications
write request from GATT client 或者indications from GATT server ,都会有ACK ,
这样效率下降一半
- Connection event x: Send notification/writeRequest packet
- Connection event x+1: Receive ATT acknowledgement packet
- Connection event x+2: Send notification/writeRequest packet
- Connection event x+3: Receive ATT acknowledgement packet
Write Commands and Notifications
write commands from GATT client或者 with notifications from GATT server ,一次可以传输N个包 ,没有ACK
Write from GATT client on an Android device
call writeCharacteristic 方法 ,设置 setWriteType 方法 ,需要等待一个callback
协议层的开销
根据Bluetooth 4.0 BLE部分协议:
BLE中物理层physical layer的传输速率是1Mbps,除了这个外,数据传输速率与包大小、CPU处理时间相关。
包结构:
1.总体结构:
preamble(1 Byte)+ Access Address(4 Bytes)+ PDU + CRC(3 Bytes)
preamble = 10101010 or 01010101
Access Address = 0x8e89bedd6
2. 广播包
PDU = Header(2 Bytes)+ Payload (37 Bytes max.)
Header: 1)0000 - connected undirected advertising event 可连接非定向广播事件
2)0001 - connected directed advertising event 可连接定向广播事件
3)0010 - non-connected undirected advertising event 不可连接非定向广播事件
4)0011 - response to scan request form scanner扫描请求响应
5)0101 - connect request by initiator连接请求
6)0110 -connected directed advertising event 可发现非定向广播事件
- 非定向广播包(Undirected advertising packets)
Payload = AdvA (6 Bytes) + AdvData (31 Bytes max.) ;
- 定向广播包(Directed advertising packets)
3. 扫描请求及扫描响应
PDU = Header(2 Bytes)+ Payload (37 Bytes max.)
Header: 1)0011 - scan request for further information from advertiser 扫描请求
2)0100 - response to scan request from scanner 扫描响应
- 扫描请求
- 扫描响应
3. 连接请求
PDU = Header(2 Bytes)+ Payload (34 Bytes)
Header:0101 - connect request by initiator
Payload =InitA(6 Bytes)+ AdvA(6bytes)+ LLData(22 Bytes)
LLData 包含连接信息,详细结构参考bluetooth 4.0 协议。
4. LL 数据通道及控制包
PDU = Header(2 Bytes)+ Payload (27 Bytes max.)
Header:详细说明参考bluetooth 4.0 协议;
- LL 数据通道
Payload = 0~27 bytes
- LL 控制包
若只考虑蓝牙设备连接之后,评估数据传输速率
- 最大包长度:preamble(1 Byte)+ Access Address(4 Bytes)+ PDU(29 Bytes) + CRC(3 Bytes)= 41 Bytes
- 射频PHY传输速率 1Mbps
一个27字节的传输周期 :328 + 150 + 80 + 150 = 708 us,若能持续传输,即传输速度:38KB/s,这样显然功耗不会低,也不符合BLE协议规范,真正的传输速度受连接事件间隔和间隔内能传输数据包数目相关。(此段计算表示怀疑,150为帧间隔,理论算出来的值大概是270kbit=33.75kbyte)
GATT 数据包封装需要7个字节 ,所以净荷为20Byte。
BLE 和 BR/EDR区别
参见 https://en.wikipedia.org/wiki/Bluetooth_low_energy
Technical Specification | Classic Bluetooth technology | Bluetooth Smart technology |
---|---|---|
Distance/Range (theoretical max.) | 100 m (330 ft) | >100 m (>330 ft) |
Over the air data rate | 1–3 Mbit/s | 1 Mbit/s |
Application throughput | 0.7–2.1 Mbit/s | 0.27 Mbit/s |
Active slaves | 7 | Not defined; implementation dependent |
Security | 56/128-bit and application layer user defined | 128-bit AES with Counter Mode CBC-MAC and application layer user defined |
Robustness | Adaptive fast frequency hopping, FEC, fast ACK | Adaptive frequency hopping, Lazy Acknowledgement, 24-bit CRC, 32-bit Message Integrity Check |
Latency (from a non-connected state) | Typically 100 ms | 6 ms |
Minimum total time to send data (det.battery life) | 100 ms | 3 ms [32] |
Voice capable | Yes | No |
Network topology | Scatternet | Scatternet |
Power consumption | 1 W as the reference | 0.01 to 0.5 W (depending on use case) |
Peak current consumption | <30 mA | <15 mA |
Service discovery | Yes | Yes |
Profile concept | Yes | Yes |
Primary use cases | Mobile phones, gaming, headsets, stereo audio streaming, smart homes, wearables, automotive, PCs, security, proximity, healthcare, sports & fitness, etc. | Mobile phones, gaming, PCs, watches, sports and fitness, healthcare, security & proximity, automotive, home electronics, automation, Industrial, etc. |
Android 开发BLE时遇到的常见问题
Android BLE开发参考
http://developer.android.com/guide/topics/connectivity/bluetooth-le.html
http://m.blog.csdn.net/blog/lckj686/43153993
http://blog.csdn.net/chaoyue0071/article/details/43450183
一、关键概念:
Generic Attribute Profile (GATT)
通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。
Attribute Protocol (ATT)
GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。
Characteristic
Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。
Descriptor
对Characteristic的描述,例如范围、计量单位等。
Service
Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。
二、角色和职责:
Android设备与BLE设备交互有两组角色:
中心设备和外围设备(Central vs. peripheral);
GATT server vs. GATT client.
Central vs. peripheral:
中心设备和外围设备的概念针对的是BLE连接本身。Central角色负责scan advertisement。而peripheral角色负责make advertisement。
GATT server vs. GATT client:
这两种角色取决于BLE连接成功后,两个设备间通信的方式。
举例说明:
现有一个活动追踪的BLE设备和一个支持BLE的Android设备。Android设备支持Central角色,而BLE设备支持peripheral角色。创建一个BLE连接需要这两个角色都存在,都仅支持Central角色或者都仅支持peripheral角色则无法建立连接。
当连接建立后,它们之间就需要传输GATT数据。谁做server,谁做client,则取决于具体数据传输的情况。例如,如果活动追踪的BLE设备需要向Android设备传输sensor数据,则活动追踪器自然成为了server端;而如果活动追踪器需要从Android设备获取更新信息,则Android设备作为server端可能更合适。
三、权限及feature:
和经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限:
<uses-permission android:name="android.permission.BLUETOOTH"/>
< uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
除了蓝牙权限外,如果需要BLE feature则还需要声明uses-feature:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
按时required为true时,则应用只能在支持BLE的Android设备上安装运行;required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE feature:
// Use this check to determine whether BLE is supported on the device. Then
// you can selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
四、启动蓝牙:
在使用蓝牙BLE之前,需要确认Android设备是否支持BLE feature(required为false时),另外要需要确认蓝牙是否打开。
如果发现不支持BLE,则不能使用BLE相关的功能。如果支持BLE,但是蓝牙没打开,则需要打开蓝牙。
打开蓝牙的步骤:
1、获取BluetoothAdapter
BluetoothAdapter是Android系统中所有蓝牙操作都需要的,它对应本地Android设备的蓝牙模块,在整个系统中BluetoothAdapter是单例的。当你获取到它的示例之后,就能进行相关的蓝牙操作了。
获取BluetoothAdapter代码示例如下:
// Initializes Bluetooth adapter.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
注:这里通过getSystemService获取BluetoothManager,再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。
2、判断是否支持蓝牙,并打开蓝牙
获取到BluetoothAdapter之后,还需要判断是否支持蓝牙,以及蓝牙是否打开。
如果没打开,需要让用户打开蓝牙:
private BluetoothAdapter mBluetoothAdapter;
...
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
五、搜索BLE设备:
通过调用BluetoothAdapter的startLeScan()搜索BLE设备。调用此方法时需要传入 BluetoothAdapter.LeScanCallback参数。
因此你需要实现 BluetoothAdapter.LeScanCallback接口,BLE设备的搜索结果将通过这个callback返回。
由于搜索需要尽量减少功耗,因此在实际使用时需要注意:
1、当找到对应的设备后,立即停止扫描;
2、不要循环搜索设备,为每次搜索设置适合的时间限制。避免设备不在可用范围的时候持续不停扫描,消耗电量。
搜索的示例代码如下:
/**
* Activity for scanning and displaying available BLE devices.
*/
public class DeviceScanActivity extends ListActivity {
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
...
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
...
}
...
}
如果你只需要搜索指定UUID的外设,你可以调用 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法。
其中UUID数组指定你的应用程序所支持的GATT Services的UUID。
BluetoothAdapter.LeScanCallback的实现示例如下:
private LeDeviceListAdapter mLeDeviceListAdapter;
...
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
注意:搜索时,你只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索。
六、连接GATT Server:
两个设备通过BLE通信,首先需要建立GATT连接。这里我们讲的是Android设备作为client端,连接GATT Server。
连接GATT Server,你需要调用BluetoothDevice的connectGatt()方法。此函数带三个参数:Context、autoConnect(boolean)和BluetoothGattCallback对象。调用示例:
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
函数成功,返回BluetoothGatt对象,它是GATT profile的封装。通过这个对象,我们就能进行GATT Client端的相关操作。BluetoothGattCallback用于传递一些连接状态及结果。
BluetoothGatt常规用到的几个操作示例:
connect() :连接远程设备。
discoverServices() : 搜索连接设备所支持的service。
disconnect():断开与远程设备的GATT连接。
close():关闭GATT Client端。
readCharacteristic(characteristic) :读取指定的characteristic。
setCharacteristicNotification(characteristic, enabled) :设置当指定characteristic值变化时,发出通知。
getServices() :获取远程设备所支持的services。
等等。
注:
1、某些函数调用之间存在先后关系。例如首先需要connect上才能discoverServices。
2、一些函数调用是异步的,需要得到的值不会立即返回,而会在BluetoothGattCallback的回调函数中返回。例如discoverServices与onServicesDiscovered回调,readCharacteristic与onCharacteristicRead回调,setCharacteristicNotification与onCharacteristicChanged回调等。