Reputation: 35
I need to communicate with a BLE thermometer. Workflow is:
This process works perfectly from Nordic nRF Connect app.
However, when doing it myself using the following BluetoothGattCallback object, it fails - I never get updates - the onCharacteristicRead or onCharacteristicChanged callbacks never fire. Everything works, though - all methods that should return true on success do return true... Anyway, here is the BluetoothGattCallback:
private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
/**
* Callback indicating when GATT client has connected/disconnected to/from a remote
* GATT server.
*
* @param gatt GATT client
* @param status Status of the connect or disconnect operation.
* {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
* @param newState Returns the new connection state. Can be one of
* {@link BluetoothProfile#STATE_DISCONNECTED} or
* {@link BluetoothProfile#STATE_CONNECTED}
*/
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothGatt.STATE_CONNECTED) {
gatt.discoverServices();
} else {
responseCharacteristic = null;
isConnected = false;
disconnected();
}
}
/**
* Callback invoked when the list of remote services, characteristics and descriptors
* for the remote device have been updated, ie new services have been discovered.
*
* @param gatt GATT client invoked {@link BluetoothGatt#discoverServices}
* @param status {@link BluetoothGatt#GATT_SUCCESS} if the remote device
*/
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.wtf("THERMO", "Services discovered");
BluetoothGattService thermoService = gatt.getService(THERMO_SERVICE);
if (thermoService != null) {
Log.wtf("THERMO", "Have service");
//Find the characteristic
configChar = thermoService.getCharacteristic(THERMO_CONFIGURATION);
responseCharacteristic = thermoService.getCharacteristic(THERMO_RESPONSE);
if (responseCharacteristic != null)
setCharacteristicNotification(responseCharacteristic, true);
else
incompatibleTarget();
} else
incompatibleTarget();
}
/**
* Callback triggered as a result of a remote characteristic notification.
*
* @param gatt GATT client the characteristic is associated with
* @param characteristic Characteristic that has been updated as a result
*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.wtf("THERMO", "onCharChanged");
dataReceived(characteristic);
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.wtf("THERMO", "onCharRead");
dataReceived(characteristic);
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.wtf("THERMO", "Write done");
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.wtf("THERMO", "Write ok");
if (responseCharacteristic != null) {
Log.wtf("THERMO", "Have response");
isConnected = true;
connected();
}
} else {
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
Log.wtf("THERMO", "onDescWrite");
if (status == BluetoothGatt.GATT_SUCCESS) {
if (configChar != null) {
Log.wtf("THERMO", "Have config");
configChar.setValue(thermoConfigData);
Log.wtf("THERMO", "Writing: " + gatt.writeCharacteristic(configChar));
}
}
}
};
And here is the method for registering the notifications:
private void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
gatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG);
if (descriptor != null) {
if (enabled) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else {
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}
Log.wtf("THERMO", "notifyDesc: " + gatt.writeDescriptor(descriptor));
}
}
The notification enabling method works with all other devices. Any ideas what I'm doing wrong?
Upvotes: 0
Views: 2028
Reputation: 35
For some reason, changing the callback code to this helped. Looks like you need to call getService and getCharacteristic in the callback you're using them, you can't keep them around in a variable...
private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
/**
* Callback indicating when GATT client has connected/disconnected to/from a remote
* GATT server.
*
* @param gatt GATT client
* @param status Status of the connect or disconnect operation.
* {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
* @param newState Returns the new connection state. Can be one of
* {@link BluetoothProfile#STATE_DISCONNECTED} or
* {@link BluetoothProfile#STATE_CONNECTED}
*/
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothGatt.STATE_CONNECTED) {
gatt.discoverServices();
} else {
responseCharacteristic = null;
isConnected = false;
disconnected();
}
}
/**
* Callback invoked when the list of remote services, characteristics and descriptors
* for the remote device have been updated, ie new services have been discovered.
*
* @param gatt GATT client invoked {@link BluetoothGatt#discoverServices}
* @param status {@link BluetoothGatt#GATT_SUCCESS} if the remote device
*/
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.wtf("THERMO", "Services discovered");
BluetoothGattService thermoService = gatt.getService(THERMO_SERVICE);
if (thermoService != null) {
Log.wtf("THERMO", "Have service");
//Find the characteristic
responseCharacteristic = thermoService.getCharacteristic(THERMO_RESPONSE);
if (responseCharacteristic != null)
setCharacteristicNotification(responseCharacteristic, true);
else
incompatibleTarget();
} else
incompatibleTarget();
}
/**
* Callback triggered as a result of a remote characteristic notification.
*
* @param gatt GATT client the characteristic is associated with
* @param characteristic Characteristic that has been updated as a result
*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.wtf("THERMO", "onCharChanged");
dataReceived(characteristic);
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.wtf("THERMO", "onCharRead");
dataReceived(characteristic);
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.wtf("THERMO", "Write done");
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.wtf("THERMO", "Write ok");
if (responseCharacteristic != null) {
Log.wtf("THERMO", "Have response");
isConnected = true;
connected();
}
} else {
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
Log.wtf("THERMO", "onDescWrite");
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService thermoService = gatt.getService(THERMO_SERVICE);
if (thermoService != null) {
configChar = thermoService.getCharacteristic(THERMO_CONFIGURATION);
if (configChar != null) {
Log.wtf("THERMO", "Have config");
configChar.setValue(thermoConfigData);
Log.wtf("THERMO", "Writing: " + gatt.writeCharacteristic(configChar));
}
}
}
}
};
Upvotes: 0