BLE 通知订阅获得 133
BLE notification subscription gets 133
1 Android phone (N5X 6.0.1) 是 运行 一个 BLE 服务器,另一个 (N5X O) 正在订阅。
可以启用特征通知,但是,在写入描述符部分,我一直收到 133.
Server.java
private void createServer() {
bluetoothGattServer = bluetoothManager.openGattServer(this, serverCallback);
BluetoothGattService service = new BluetoothGattService(Constants.SERVICE,
BluetoothGattService.SERVICE_TYPE_PRIMARY);
characteristic =
new BluetoothGattCharacteristic(Constants.CHARACTERISTIC,
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
// public static UUID DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
characteristic.addDescriptor(new BluetoothGattDescriptor(Constants.DESCRIPTOR,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE));
characteristic.setWriteType(
BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
service.addCharacteristic(characteristic);
bluetoothGattServer.addService(service);
}
private BluetoothGattServerCallback serverCallback = new BluetoothGattServerCallback() {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
Log.d(TAG, "onConnectionStateChange " + device.getName() + " " + status + " " + newState);
if (newState == BluetoothGatt.STATE_CONNECTED) {
bluetoothDevice = device;
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
bluetoothGattServer.cancelConnection(bluetoothDevice);
bluetoothGattServer.close();
}
}
};
private void sendData(String message) {
characteristic.setValue(message);
bluetoothGattServer.notifyCharacteristicChanged(bluetoothDevice, characteristic, true);
}
所有其他 UUID 都是从 here 创建的。
Client.java
device.establishConnection(false)
.flatMap(bleConnection -> bleConnection.setupNotification(Constants.CHARACTERISTIC))
.flatMap(onNotificationReceived -> onNotificationReceived)
.subscribe(data -> {
Log.d(TAG, "data: " + data);
}, throwable -> {
Log.d(TAG, "data error " + throwable);
});
logcat
05-15 15:26:50.097 D/BluetoothGatt: setCharacteristicNotification() - uuid: 8d7dda32-3759-11e7-a919-92ebcb67fe33 enable: true
05-15 15:26:50.105 D/RxBle#Radio: QUEUED RxBleRadioOperationDescriptorWrite(60042487)
05-15 15:26:50.110 D/RxBle#Radio: FINISHED RxBleRadioOperationServicesDiscover(231218312)
05-15 15:26:50.112 D/RxBle#Radio: STARTED RxBleRadioOperationDescriptorWrite(60042487)
05-15 15:27:20.119 D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(60042487)
05-15 15:27:20.121 D/BluetoothGatt: setCharacteristicNotification() - uuid: 8d7dda32-3759-11e7-a919-92ebcb67fe33 enable: false
05-15 15:27:20.126 D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=133
05-15 15:27:20.129 D/BLE: data error BleGattDescriptorException{macAddress=42:EE:5A:C6:C1:F0, status=133 (0x85 -> https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h), bleGattOperationType=BleGattOperation{description='DESCRIPTOR_WRITE'}}
注意:如果我使用本机 Android API,我可以订阅和接收通知,而无需写入描述符。
更新:不过有趣的是,当写入描述符过程正在进行时(大约需要 30 秒才能返回错误),我能够收到 onCharacteristicChanged
。
update2: 添加回调并写入特征码
蓝牙核心规范指出,如果一个特性支持通知,它应该包含一个客户端特性配置描述符,并且仅当 CCC 描述符将被写入一个正确的值时才开始通知。
您的配置中似乎存在问题,表现为 status = 133
。看来您在 characteristic
上设置属性时可能犯了一个错误。我假设你想要一个可以读取、写入和设置通知的特性——在这种情况下它看起来像:
characteristic =
new BluetoothGattCharacteristic(Constants.CHARACTERISTIC,
BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
编辑 - 请记住,如果中央请求打开通知,它会尝试写入客户端特征配置描述符。除非它是带有 NO_RESPONSE
设置的请求,否则中央正在等待响应。
正确的解决方案是向 onDescriptorWriteRequest
添加回调并向中央发送响应:
BluetoothGattServerCallback serverCallback = new BluetoothGattServerCallback() {
// (...)
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor,
boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
// validate if the request is exactly what you expect if needed
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
}
// (...)
};
可能的解决方法
一些中国制造商不符合蓝牙核心规范,他们在发送通知的特性下没有 CCC 描述符。如果您能够在不设置 CCC 的情况下获得通知,那么您可以使用兼容模式 RxBleConnection.setupNotifications(characteristic, NotificationSetupMode.COMPAT)
尽管不鼓励这样做并且应该对配置进行适当的修复。
1 Android phone (N5X 6.0.1) 是 运行 一个 BLE 服务器,另一个 (N5X O) 正在订阅。 可以启用特征通知,但是,在写入描述符部分,我一直收到 133.
Server.java
private void createServer() {
bluetoothGattServer = bluetoothManager.openGattServer(this, serverCallback);
BluetoothGattService service = new BluetoothGattService(Constants.SERVICE,
BluetoothGattService.SERVICE_TYPE_PRIMARY);
characteristic =
new BluetoothGattCharacteristic(Constants.CHARACTERISTIC,
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
// public static UUID DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
characteristic.addDescriptor(new BluetoothGattDescriptor(Constants.DESCRIPTOR,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE));
characteristic.setWriteType(
BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
service.addCharacteristic(characteristic);
bluetoothGattServer.addService(service);
}
private BluetoothGattServerCallback serverCallback = new BluetoothGattServerCallback() {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
Log.d(TAG, "onConnectionStateChange " + device.getName() + " " + status + " " + newState);
if (newState == BluetoothGatt.STATE_CONNECTED) {
bluetoothDevice = device;
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
bluetoothGattServer.cancelConnection(bluetoothDevice);
bluetoothGattServer.close();
}
}
};
private void sendData(String message) {
characteristic.setValue(message);
bluetoothGattServer.notifyCharacteristicChanged(bluetoothDevice, characteristic, true);
}
所有其他 UUID 都是从 here 创建的。
Client.java
device.establishConnection(false)
.flatMap(bleConnection -> bleConnection.setupNotification(Constants.CHARACTERISTIC))
.flatMap(onNotificationReceived -> onNotificationReceived)
.subscribe(data -> {
Log.d(TAG, "data: " + data);
}, throwable -> {
Log.d(TAG, "data error " + throwable);
});
logcat
05-15 15:26:50.097 D/BluetoothGatt: setCharacteristicNotification() - uuid: 8d7dda32-3759-11e7-a919-92ebcb67fe33 enable: true
05-15 15:26:50.105 D/RxBle#Radio: QUEUED RxBleRadioOperationDescriptorWrite(60042487)
05-15 15:26:50.110 D/RxBle#Radio: FINISHED RxBleRadioOperationServicesDiscover(231218312)
05-15 15:26:50.112 D/RxBle#Radio: STARTED RxBleRadioOperationDescriptorWrite(60042487)
05-15 15:27:20.119 D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(60042487)
05-15 15:27:20.121 D/BluetoothGatt: setCharacteristicNotification() - uuid: 8d7dda32-3759-11e7-a919-92ebcb67fe33 enable: false
05-15 15:27:20.126 D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=133
05-15 15:27:20.129 D/BLE: data error BleGattDescriptorException{macAddress=42:EE:5A:C6:C1:F0, status=133 (0x85 -> https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h), bleGattOperationType=BleGattOperation{description='DESCRIPTOR_WRITE'}}
注意:如果我使用本机 Android API,我可以订阅和接收通知,而无需写入描述符。
更新:不过有趣的是,当写入描述符过程正在进行时(大约需要 30 秒才能返回错误),我能够收到 onCharacteristicChanged
。
update2: 添加回调并写入特征码
蓝牙核心规范指出,如果一个特性支持通知,它应该包含一个客户端特性配置描述符,并且仅当 CCC 描述符将被写入一个正确的值时才开始通知。
您的配置中似乎存在问题,表现为 status = 133
。看来您在 characteristic
上设置属性时可能犯了一个错误。我假设你想要一个可以读取、写入和设置通知的特性——在这种情况下它看起来像:
characteristic =
new BluetoothGattCharacteristic(Constants.CHARACTERISTIC,
BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
编辑 - 请记住,如果中央请求打开通知,它会尝试写入客户端特征配置描述符。除非它是带有 NO_RESPONSE
设置的请求,否则中央正在等待响应。
正确的解决方案是向 onDescriptorWriteRequest
添加回调并向中央发送响应:
BluetoothGattServerCallback serverCallback = new BluetoothGattServerCallback() {
// (...)
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor,
boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
// validate if the request is exactly what you expect if needed
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
}
// (...)
};
可能的解决方法
一些中国制造商不符合蓝牙核心规范,他们在发送通知的特性下没有 CCC 描述符。如果您能够在不设置 CCC 的情况下获得通知,那么您可以使用兼容模式 RxBleConnection.setupNotifications(characteristic, NotificationSetupMode.COMPAT)
尽管不鼓励这样做并且应该对配置进行适当的修复。