I wish to read a characteristic value stored in a device, modify the value, and then write it to the device. For some reason, writeCharacteristic()
return true, but the internal device value does not change and onCharacteristicWrite()
is not called. In fact, for some reason it is only called if I attempt to write something, and then is called shortly after I close or reopen the app - and doesn't change the device value. I've been looking into this for a few days and it's driving me crazy. It may be worth noting that reading characteristics both manually and via a notification both work fine.
Why is the writeCharacteristic()
not going through, and why is onCharacteristicWrite()
being called at such an odd time?
I am not sure where the issue stems from. It could be something dumb and simple like calling writeCharacteristic()
incorrectly (my implementation is based off the question "Working with BLE Android 4.3 how to write characteristics?"). Would it be possible that the request is being ignored because onCharacteristicRead()
is somehow unfinished?
I believe these links appear most helpful for indicating the issue but I haven't been able to pull anything from them myself:
- Android BLE API: GATT Notification not received
- https://code.google.com/p/android-developer-preview/issues/detail?id=1714
As a walkthrough of my code, an onItemClick()
event is hit, which initiates the sequence.
int flag = 1;
((MainActivity)getActivity()).BtService.readFlag(flag);
It calls a function (in a Service
) which verifies the Bluetooth connection and reads the characteristic.
public boolean readFlag(int flag){
/*... removed code here verifies that the Bluetooth Gatt is available,
that the Service exists...*/
BluetoothGattCharacteristic characteristic = Service.getCharacteristic(SEND_FLAGS_CHAR);
if (characteristic == null) {
Log.e(TAG, "char not found!");
return false;
}
try {
// Store intended flag value in SharedPreferences, then read the current one.
Editor fEditor = sPrefs.edit();
fEditor.putInt(calibrationSetFlagToSendKey, flag);
fEditor.commit();
mConnectedGatt.readCharacteristic(characteristic);
// Catch response in onCharacteristicRead() callback.
return true;
}
catch (NullPointerException e) {
Log.w("readCharacteristic", "The characteristic could not be read.");
return false;
}
}
onCharacteristicRead()
is called, which only calls a Handler
to modify and broadcast the result back to MainActivity
. trueFlagValue
is a byte that is stored globally within the Service
(bad practise I know, but I intend to modify this later.)
case MSG_SEND_FLAG:
characteristic = (BluetoothGattCharacteristic) msg.obj;
if (characteristic.getValue() == null) {
Log.w(TAG, "Error obtaining current flags");
return;
}
int recentReadDeviceFlag = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
int initialFlag = sPrefs.getInt(calibrationSetFlagToSendKey, 0);
if (initialFlag == 0) Log.e("Write Debug", "Flag to send is apparently 0");
/*... Arithmetic modifying flag integer value...*/
//Desired value is the OR'd value of the value read and value desired
trueFlagValue = (byte) ((byte) initialFlag | (byte) recentReadDeviceFlag);
Log.d("Read Debug", "OR'd value is " + trueFlagValue +", sending broadcast");
Intent fIntent = new Intent("com.example.appwithble.SEND_FLAGS");
sendBroadcast(fIntent);
break;
The BroadcastReceiver
in MainActivity
then calls a method in my Service
, verifying an asking for a writeCharacteristic()
, as was done for readCharacteristic()
. Accesses the trueFlagValue
set earlier.
else if("com.example.appwithble.SEND_FLAGS".equals(intent.getAction())) {
BtService.performWriteFlag();
}
// ...
public boolean performWriteFlag () {
/*... check Gatt is available and that Service exists...*/
BluetoothGattCharacteristic characteristic = Service.getCharacteristic(SEND_FLAGS_CHAR);
if (characteristic == null) {
Log.e(TAG, "char not found!");
return false;
}
byte[] byteValue = new byte[1];
byteValue[0] = trueFlagValue;
characteristic.setValue(byteValue);
boolean status = mConnectedGatt.writeCharacteristic(characteristic);
return status;
}
My onCharacteristicWrite()
callback should then be called, and currently contains only a line of code to log a message. In reality, this is only ever called sometimes, as the app is closed or reopened. The value stored in my peripheral's characteristic never changes.