您的位置:

蓝牙Gatt的详细解析

一、Gatt的概述

Bluetooth GATT (Generic Attribute Profile) 是蓝牙4.0新加入的一项协议,它规定了设备之间基于属性的通信方式。其主要作用是用于BLE(蓝牙低功耗)设备之间的数据传输。通过Gatt来完成对设备的控制、设置设备的属性、进行数据传输、监听设备的属性变化等。其主要的核心是通过UUID(通用唯一识别码)来区分不同的服务和特征(含多个属性)。Gatt的优势在于其低功耗、易于使用和大量使用的标准协议。

二、Gatt的体系架构

在Gatt的体系架构中包含了Service、Characteristic和Descriptor三个部分,它们构成了一个完整的Gatt服务。

Service:包含一个或多个Characteristic,一个Service可以包含多个Descriptor,可以理解为一个Service对应于一个设备模块(如温度计)或一组相关属性(如心率服务),每个Service均被分配了一个唯一的16位或128位的UUID。

Characteristic:由于service可能包含多个Characteristic,因此每一个Characteristic都应该包含一个唯一的UUID标识。Characteristic被用来表示一个数据的特征,一个Characteristic可能包含一个指针,指向当前Characteristic的值,也可能包含多个属性的集合。包括read(读取)、write(写入)、notify(通知)和indicate(指向)等操作。

Descriptor:为了描述一个Characteristics的属性,曲线求助 Descriptors。Descriptors也是包含一个唯一UUID标识,用来描述某个Characteristic中的一个特征,可以用于对Characteristic的Permissions(权限)和Characteristic的Value(数值)进行描述。

三、Gatt的实现方式

Gatt可以通过Android中的BluetoothGatt类进行实现。以下是Gatt实现的示例代码,其中主要包括了Gatt的连接、服务扫描、数据读写等操作。

 /**
     * 确保该操作完成后,才进行下一步操作
     */

    private CountDownLatch countDownLatch = null;

    public void getMtvAllNotification() {
        List supportedGattServices = getSupportedGattServices();
        Logger.i("服务数量 " + supportedGattServices.size());
        for (BluetoothGattService bluetoothGattService : supportedGattServices) {
            if (bluetoothGattService != null) {
                Logger.i("服务uuid " + bluetoothGattService.getUuid().toString());
                List
    characteristics = bluetoothGattService.getCharacteristics();
                for (BluetoothGattCharacteristic characteristic : characteristics) {
                    if (characteristic != null) {
                        Logger.i("特征uuid " + characteristic.getUuid().toString());
                        if (countDownLatch != null) {
                            try {
                                countDownLatch.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        final int charaProp = characteristic.getProperties();
                        Logger.d("当期操作属性 " + charaProp);
                        if ((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
                            // 据说按照4.4 版本core specification 规定,android 4.3需要做这个特殊处理 不然会出现133错误
                            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    Logger.d("readCharacteristic(characteristic) " + characteristic.getUuid());
                                    readCharacteristic(characteristic);
                                }
                            }, 33);
                        }
                        if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
                            boolean isAdded = enableNotification(true, characteristic);
                            if (isAdded) {
                                // 设置同步工具类初始值为1
                                countDownLatch = new CountDownLatch(1);
                            }
                        }
                    }
                }
            }
        }
    } 
    
   private void readCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (bluetoothGatt == null) {
            return;
        }
        boolean isRead = bluetoothGatt.readCharacteristic(characteristic);
        Logger.d("readCharacteristic isRead:" + isRead);
    }
    
    /**
     * 注册/取消通知
     */
    private List
     characteristicNotificationList = new ArrayList<>();

    public boolean enableNotification(boolean enable, BluetoothGattCharacteristic characteristic) {
        if (bluetoothGatt == null || characteristic == null) {
            return false;
        }
        int properties = characteristic.getProperties();
        boolean success = bluetoothGatt.setCharacteristicNotification(characteristic, enable);
        Logger.d("setCharacteristicNotification status = " + success);

        /*
         * 取得描述符
         * 必须要有的代码,根据已有的uuid创建描述符,特征描述的UUID是固定的,根据业务逻辑定。
         * 下面描述符的UUID固定为0x2902
         */
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                UUID.fromString(SampleGattAttributes.DESCRIPTOR_CONFIG));
        if (descriptor != null) {
            if (enable) {
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
            } else {
                descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
            }
            success = bluetoothGatt.writeDescriptor(descriptor);
            Logger.d("writeDescriptor status = " + success);
            if (success) {
                if (enable) {
                    characteristicNotificationList.add(characteristic);
                } else {
                    characteristicNotificationList.remove(characteristic);
                }
            }
        }
        return success;
    }

    
   
  

四、Gatt的相关注意事项

在使用Gatt时,需要注意以下事项:

1、Gatt的操作为异步操作,需要处理好操作完成后的回调;

2、Gatt的连接错误码较多,需要根据实际情况进行处理;

3、Gatt在传输数据时需要确保数据格式正确,如endian的问题;

4、Gatt的模式分为GATT、ATT,其中GATT区分操作和数据,ATT不区分操作和数据;

5、Gatt中的权限问题需要注意,需要确保应用有足够的权限进行Gatt操作。

五、Gatt的应用场景

Gatt主要应用于一些低功耗、易于连接和易于控制的设备中,如智能家居、智能穿戴、健康检测设备等。它可以通过传输数据来进行设备之间的通讯和控制,具有广泛的应用前景。