一、GATT协议概述
GATT(Generic Attribute Profile)是蓝牙协议中的一个子协议,作为BLE(Bluetooth Low Energy)协议栈的一部分,提供了一种通用的机制来管理连接设备之间的数据传输。它定义了使用BLE协议栈上的外设之间的数据交换方式,并且使之成为可能的商业化的应用,比如智能物联网、健康监护设备等等。
GATT协议中的服务(Services)和特征(Characteristics)是BLE的核心概念之一,它们是应用程序建立蓝牙连接并在连接设备之间交换数据的基础。服务定义了一组相关的特征,而特征则包含了一些属性,包括类型、值和权限,以及一些关于如何访问这些属性的描述。通过GATT协议,应用程序可以向远程设备发送请求以读取或更改服务和特征的属性。
在BLE连接中,一个设备可以同时充当客户端和服务器端。作为服务器端的设备需要发布其提供的服务和特征,以便可用于客户端的应用程序进行订阅和请求。作为客户端的设备则可以扫描周围的设备,查找它们可以提供的服务和特征。当客户端订阅了一个服务或特征时,服务器就会发送通知或者指示以向客户端传递数据。
二、GATT协议的具体实现
1.服务和特征的定义
GATT协议中的服务和特征通过UUID(Universally Unique Identifier)来进行识别和命名。UUID是一个128位的数字,用于将服务和特征唯一地标识出来。
// 以下是一个服务的UUID定义 #define SERVICE_UUID 0x180D // 以下是一个特征的UUID定义 #define CHARACTERISTIC_UUID 0x2A37
服务和特征的定义需要在服务器端进行,包括一个服务的UUID、包含的特征的UUID以及每个特征的属性和权限。这些信息需要通过GATT API加到服务之中,例如在Android系统中,可以通过BluetoothGattService和BluetoothGattCharacteristic类来实现:
// 定义一个GATT服务 BluetoothGattService service = new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY); // 为服务添加特征 BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_READ); service.addCharacteristic(characteristic);
2.建立连接和发现服务
当一个设备(客户端)与另一个设备(服务器)建立连接时,需要先检查它是否支持GATT协议。这是通过发现设备是否支持LE(Low Energy)设备来完成的。
// 检查设备是否支持BLE PackageManager pm = getPackageManager(); if (!pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Log.e(TAG, "Device does not support BLE"); finish(); return; } // 初始化BLE适配器 final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); return; } // 搜索周围的BLE设备 mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); mBluetoothLeScanner.startScan(mScanCallback);
在发现服务并且连接成功后,需要请求进行服务和特征的发现。在Android中,可以使用BluetoothGatt#discoverServices()方法调用该请求。一旦服务被发现并且可用,应用程序就可以查看、订阅和请求服务和特征。
// 发现服务和特征 @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { gatt.discoverServices(); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Listservices = gatt.getServices(); // 处理服务和特征 } }
3.读写特征值
在GATT协议中,特征的值存储在设备内存中,可以通过读取和写入特定的特征进行数据传输。
在Android中,可以使用BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)方法来请求读取特征值,而使用BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic)方法来请求写入特征值:
// 读取特征值 BluetoothGattCharacteristic characteristic = mGattService.getCharacteristic(CHARACTERISTIC_UUID); mBluetoothGatt.readCharacteristic(characteristic); @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { byte[] value = characteristic.getValue(); // 处理读取到的特征值 } } // 写入特征值 BluetoothGattCharacteristic characteristic = mGattService.getCharacteristic(CHARACTERISTIC_UUID); byte[] value = new byte[] {0x00, 0x01}; characteristic.setValue(value); mBluetoothGatt.writeCharacteristic(characteristic); @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { // 处理写入结果 }
三、GATT协议的常见问题
1.连接问题
由于BLE是低功耗协议,因此它具有一些连接上的限制。如果在连接过程中没有成功发送或接收数据,连接就会自动关闭。由于BLE的连接速度较慢,因此在连接设备之间传输大量数据也很困难。这些问题可以通过保持连接、定期发送数据包和使用缓存的数据传输来解决。
2.功耗问题
由于BLE协议是一种低功耗协议,因此它使用的通信速率和数据量都相对较小。一些高效的GATT协议实现可以减少功耗,并在数据传输结束后自动关闭连接,以节省能量。
3.并发连接问题
GATT协议可以支持多个连接,但由于BLE是低功耗协议,它的连接速度非常慢。在同一时间内与多个设备进行数据交换可能会导致传输速度过慢,甚至导致连接失败。
可以通过使用广播通知和优化数据传输来最大程度地减少并发连接问题。特别是在同时与多个设备进行通信时,可以采用时间分割多址(Time Division Multiple Access,TDMA)的方式来避免冲突和丢包。
结论
通过对GATT协议的详细讲解,我们可以了解到BLE协议的几个关键点,包括服务和特征、连接和发现、读写特征值以及GATT协议的常见问题等等。这些问题不仅对于普通开发者来说很重要,而且对于物联网和健康监护等行业应用也非常有影响。