I'm writing some code to get TI Keyfob(cc2540) accelerator data. There are 3 CharacteristicNotifications should be enabled. I set them one by one and enabled the BluetoothGattDescriptor, but after the code run, only the first BluetoothGattDescriptor can send notification.
My device is Samsung S3 with Android 4.3.
Here are some code in my BluetoothService.java :
static final byte[] DISABLE = {0x00};
static final byte[] ENABLE = {0x01};
public void enableKeyfobAccelService(boolean enable) {
BluetoothGattService _service = mBluetoothGatt.getService(UUID_KEYFOB_ACCEL_SERVICE);
if (_service == null) {
Log.d(TAG, "Keyfob Accel service not found!");
return;
}
Log.d(TAG, "Keyfob Accel service found!");
// write value to Characteristic ACCEL_ENABLER "0000ffa1-0000-1000-8000-00805f9b34fb"
BluetoothGattCharacteristic _nc = _service.getCharacteristic(UUID_KEYFOB_ACCEL_ENABLER);
if (_nc != null) {
if (enable)
_nc.setValue(ENABLE);
else
_nc.setValue(DISABLE);
mBluetoothGatt.writeCharacteristic(_nc);
}
accel_enabled = enable;
}
// Implements callback methods for GATT events that the app cares about. For
// example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:"
+ mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.v(TAG, "onCharacteristicWrite value : " + byteArrayToHex(characteristic.getValue()));
if (UUID_KEYFOB_ACCEL_ENABLER.equals(characteristic.getUuid())) {
BluetoothGattCharacteristic _nc = characteristic.getService().getCharacteristic(UUID_KEYFOB_ACCEL_X);
if( _nc != null ) {
setCharacteristicNotification(_nc, accel_enabled);
Log.d(TAG, "Keyfob Accel X ready! " + accel_enabled);
}
else {
Log.d(TAG, "Keyfob Accel UUID_KEYFOB_ACCEL_X is null! ");
}
_nc = characteristic.getService().getCharacteristic(UUID_KEYFOB_ACCEL_Y);
if( _nc != null ) {
setCharacteristicNotification(_nc, accel_enabled);
Log.d(TAG, "Keyfob Accel Y ready! " + accel_enabled);
}
else {
Log.d(TAG, "Keyfob Accel UUID_KEYFOB_ACCEL_Y is null! ");
}
_nc = characteristic.getService().getCharacteristic(UUID_KEYFOB_ACCEL_Z);
if( _nc != null ) {
setCharacteristicNotification(_nc, accel_enabled);
Log.d(TAG, "Keyfob Accel Z ready! " + accel_enabled);
}
else {
Log.d(TAG, "Keyfob Accel UUID_KEYFOB_ACCEL_Z is null! ");
}
}
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
if (characteristic == null) {
Log.w(TAG, "Bluetooth characteristic not initialized");
return;
}
boolean success = mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
Log.v(TAG, "setCharacteristicNotification = " + success);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
if (descriptor != null) {
byte[] val = enabled ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
descriptor.setValue(val);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
After I enbaled the UUID_KEYFOB_ACCEL_ENABLER, I can read the log to know all three mBluetoothGatt.writeDescriptor(descriptor) are runned. But onCharacteristicChanged() only can fetch the changed value from UUID_KEYFOB_ACCEL_X.
It is strange, and ask for your help.
Thanks very much.
I found the cause of this issus: for BLE, should wait some times between two write:
_nc = characteristic.getService().getCharacteristic(UUID_KEYFOB_ACCEL_Y);
if( _nc != null ) {
setCharacteristicNotification(_nc, accel_enabled);
Log.d(TAG, "Keyfob Accel Y ready! " + accel_enabled);
}
else {
Log.d(TAG, "Keyfob Accel UUID_KEYFOB_ACCEL_Y is null! ");
}
// MUST add wait some times
try {
Thread.sleep(100);
} catch (Exception e) {
// ignore
}
_nc = characteristic.getService().getCharacteristic(UUID_KEYFOB_ACCEL_Z);
if( _nc != null ) {
setCharacteristicNotification(_nc, accel_enabled);
Log.d(TAG, "Keyfob Accel Z ready! " + accel_enabled);
}
else {
Log.d(TAG, "Keyfob Accel UUID_KEYFOB_ACCEL_Z is null! ");
}