I have the following problem - I must change the descriptor (BluetoothGattDescriptor) in my characteristic (BluetoothGattCharacteristic) dynamically as my application works.
Unfortunately function notifyCharacteristicChanged() from BluetoothGattServer updates only value of the characteristic (looked up this function in the Andoird sources - https://github.com/android/platform_frameworks_base/blob/master/core/java/android/bluetooth/BluetoothGattServer.java), it ignores the descriptors.
My descriptor is read only once - when the connection is established. But I want to change it dynamically and reconnection every time is not an option here.
Adding two services or characteristics with the same UUID but different descriptors did not solve the problem - distinguishing them was not possible.
Anyone faced similar problem?
This is the code:
BluetoothGattCharacteristic bc = mBluetoothGattServer.getService(service).getCharacteristic(characteristic);
bc.setValue(data);
bc.getDescriptor(descriptor).setValue(new byte[]{0, 0}); <- no effect here
mBluetoothGattServer.notifyCharacteristicChanged(connectedDevice, bc, false);
Thank you for any advice!
What you want to do indicates your system suffers from bad design.
Characteristic descriptors are generally not meant to be changed over time by the Server's Host. Either way, in the spirit of BLE, it's only the Characteristic's value that can be notified to Clients.
The fact that you want to change it "dynamically" is just not right. Why do you?
If it has some important, meaningful data for your entire application, then create a new Characteristic.
A Characteristic Descriptor should only have the purpose of "explaining" how the Characteristic's value is supposed to be used, its format, its units etc.
Related
I am trying to make a client-server connection with the server containing one service with one characteristic which contains one descriptor. I've made the service, characteristic and descriptor have the same UUID , but when I try to write on the descriptor/characteristic (in the android app) a pop-up appears that tells me , bluetooth has to shut down becouse of some problem (not known). Is there any condition that the UUID's have to be distinct ?
The "UU" of UUID means "Universally Unique". The UUID is describing the type of data, though, so you can have 2 characteristics with the same UUID if both are providing the same sort of data. (ex 2 thermometers) I think descriptors are supposed to have UUID's dictated by the standard (so you know they're descriptors).
So, the service, characteristic, and descriptor should all have different UUID's.
My issue is with lack of ability to determine the type of the value, that read BLE characteristic has been storing. According to bluetooth spec. https://www.bluetooth.com/specifications/assigned-numbers/format-types those types are predefined by the standard and therefore GATT client should be able to read them.
My app is an attempt to create generic GATT client with ability to read any service and any characteristics it stores. For this I must have some universal way to read the type of characteristic, so that I am able to read it properly. For this I lack BLE API, that would allow this
I think simillar question is asked here: How to get BluetoothGattCharacteristic value format type? but question did get no answer.
Unfortunatelly current workaround would be to map UUID of specified in bluetooth characteristic, with the stored value's type. This solves lots of daily cases, but still is not enough to create completely generic GATT client.
Ok, I found the answer. For the people having simillar issue the answer lays not in BLE android API, but in bluetooth GATT specification.
It turns out, that some descriptors are mandatory and one of this is characteristic presentation format, specified here:
https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
there we can find the "hard coded value type", which is 8bit value and enum, which represents this value as the type. Based on this value we can deduce the characteristic's value type and read it properly.
I am having some difficulties with Bluetooth Low Energy on Android. I have closely done the guide I linked, as well as checked the full example code. I have a BLE device I need to connect to and retrieve data frames from. The documentation at one point dictates to
Discover/Enable service: Service UUID UUID1, Characteristic UUID UUID2
Once this has been executed correctly, the device should start streaming frames of 20 bytes formatted in a particular way.
Searching for the device, connecting to it and discovering services on it I have no problem with. But then I'm stuck. To get the services, BluetoothGatt's method getServices() is called. This returns a list of BluetoothGattService's, which on their part also contain a list of BluetoothGattCharacteristic's. Obviously the BluetoothGattService's UUID must be equal to provided UUID1, and BluetoothGattCharacteristic's UUID to UUID2. But I do not know how to 'enable' this service with certain characteristic.
My documentation also does not mention descriptors. I have checked and there is only one descriptor in the UUID2 characteristic. So now I have everything one could possibly need - Service UUID, Characteristic UUID and Descriptor... But how do I read the data?
You can iterate over all found characteristics and get the BluetoothGattCharacteristic object with UUID1 and UUID2. Use "UUID.fromString()" to convert a string representing the UUID to a UUID object, which than can be used with ".equals" to compare with "characteristic.getUuid()".
If I've understood you correctly, you want to read some data of a characteristic. When you call "connectGatt" on your BluetoothDevice, you get an object of type "BluetoothGatt". Use this gatt object after discovering the service and characteristics to call "readCharacteristic()" on it, passing the desired BluetoothCharacteristic as argument.
I hope I could help and let me know if I should clarify my answer
Linard
My BLE application requires computation on the server side (BLE chip) which takes time and results with disconnection.
Th flow is like this:
1- Android phone writes the characteristic value to the BLE chip.
2- The chip evaluates this value and starts computation.
3- The connection is lost soon after the computation has started.
What solution can I apply to prevent the disconnecton? I have two solutions in my mind:
1- Changing the connection interval: Currently Android uses 7.5 msec as connection interval. Since the computation on BLE chip takes time, packets are not sent or received during the computation. Increasing the connection interval will decrease the number of lost packets. However there is no guarantee that Android phone will accept the new connection parameters.
2- Running the computation in a separate thread: I dont think that BLE chips' SDK support multi-threading such that while there is a computation process going on, it will keep receiving and sending packets and prevent the disconnection. I use CSR chip and I think it doesnt support.
Please correct me if I am wrong at my points.
Do you have any other suggestions to solve the issue?
Thanks in advance.
Thank you for the answers. I found out what the problem is after spending hours.
First of all, when Android gives error 133 or 129, it is most probably because of the remote device.
At the beginning I thought that the problem occurred because of the supervision timeout. Then I re-configured the connection parameters of the CSR chip but it didn't help.
There is a problem about CSR app development with xIDE (IDE of CSR). When there is run-time-error due to index overshoot or accessing some invalid pointers, then you would not receive any errors in xIDE. I finally found out the array problem and fixed it. Now it works perfect.
Thanks a lot!
I don't know exactly if what i going to explain it's feasible under Android because I used BLE only with a low level applications, anyway if your problems are the connection parameters you can try to change the Slave_Latency.
It should be usefull since playing with this parameter, you can change the number of connection intervals in which the Central device can wait until it considers the connection lost.
The following equation is usefull to derive the connection parameters:
Effective_Connection_Interval = (Connection_Interval)*(1+(Slave_Latency))
Remember that can exists some kind of Supervision_Timeout that can collide with your Effective_Connection_Interval
The BluetoothLeGatt Android BLE example contains the following code:
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
My question is basically, why is the marked code specific to Heart Rate Measurement? It seems like having a Client Characteristic Config Descriptor (CCCD) characteristic is the standard way to control characteristic notification, so why doesn't setCharacteristicNotification() take care of writing to it? And since it doesn't do that, what does setCharacteristicNotification() actually do?
I'm pretty new to BLE and there aren't any explanations of it on the internet that don't assume that you already understand it all! So don't assume I know what a CCCD or whatever is! It was difficult enough finding out what CCCD even stands for!
Edit: See also this answer which supports my understanding of CCCDs (and makes me continue to wonder why you have to write to them manually in Android when there is a function that looks like it should do that for you): https://devzone.nordicsemi.com/index.php/what-does-cccd-mean
I think is a litte bit late for give an answer but today I had the same doubt and I found a clear answer.
Using setCharacteristicNotification() you enable notification localy (on android device) and setting CCC descriptor to ENABLE_NOTIFICATION_VALUE you enable notification on ble peripheral. In fact for enabling CCC notification you have to use setValue() and writeDescriptor() that are methods used for writing characteristics (in this case characteristics descriptors) to remote device.
I found this on: http://processors.wiki.ti.com/index.php/SensorTag_User_Guide
Here is an excerpt from the O'Reilly book "Getting Started With Bluetooth Low Energy":
To enable notifications on Android, you normally have to locally
enable the notification for the particular characteristic you are
interested in.
Once that’s done, you also have to enable notifications on the peer
device by writing to the device’s client characteristic configuration
descriptor (CCCD)
I believe this answers your question.
So
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
refers to the first part
and
mBluetoothGatt.writeDescriptor(descriptor);
refers to the 2nd.
For future peoples coming across this, here's the best answer I could find:
By writing to the Client Characteristic Config descriptor, you, the client, are telling the BLE server to switch configurations. (This made no sense to me either initially, but in english:)
This tells the BLE device to switch modes (configurations) to actively gather and report changes to this characteristic instead of changing and only reporting when requested.
It's poorly named, but digging through the docs it appears this is also going to be used for other possible characteristic changes that the client might request: hence the confusing name.
https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
This begs the question, why call BluetoothGatt.setCharacteristicNotification() if we're only going to duplicate our efforts by modifying the descriptor?! Digging through the BluetoothGatt source shows us that setCharacteristicNotification only prepares the local service to receive notifications, not to enable persistent updates.
I know it looks silly, but setting CCCD value is the only way you can tell the API whether you are going to turn on notification or indication.
Currently there is no setCharacteristicIndication. To enable indication, you have to call setCharacteristicNotification (confusing) and then write BluetoothGattDescriptor.ENABLE_INDICATION_VALUE to CCCD, similar to what you did to enable Notification.
All the other answers do not really answer the question.
My guess would be that the Android BLE team took the assumption an application could have more than one BluetoothGattCallback().
By splitting the notification enabling (and disabling) in two steps it would allow the BluetoothGattCallback observers to listen for GATT notification (only invoke setCharacteristicNotification()) - and leave only one BluetoothGattCallback implemention doing the write operations to the GATT server aka the BLE peripheral.
"The Client Characteristic Configuration descriptor defines how the characteristic may be configured by a specific client."