Following is my reliable gatt characteristic reliable write function and byte array byte1 is having value more than 20 bytes.
private void beginReliableWriteToGattServer(BluetoothDevice device, UUID serviceUUID,UUID charUUID, byte[] byte1){
if(mGatt != null){
BluetoothGattService service = mGatt.getService(serviceUUID);
if(service != null){
BluetoothGattCharacteristic gattCharacteristic = service.getCharacteristic(charUUID);
if(gattCharacteristic != null){
Logger.d(TAG, "BeginReliable Write="+mGatt.beginReliableWrite());
gattCharacteristic.setValue(byte1);
mGatt.writeCharacteristic(gattCharacteristic);
Logger.d(TAG, "ExecuteReliable Write="+mGatt.executeReliableWrite());
}
}
}
}
Below are write Gatt characteristic logs
BeginReliable Write=true
ExecuteReliable Write=false
D/Bluetooth_GATTCallBack: onCharacteristicWrite 17
First, you can't have multiple GATT requests outstanding at the same time. Since both writeCharacteristic and executeReliableWrite are requests to the peer device (beginReliableWrite is not a request but only sets a flag in Android's BLE stack that the following writes are "reliable writes"), you need to first wait for the onCharacteristicWrite until you are allowed to send executeReliableWrite.
Now, regarding error code 17, I assume this corresponds to the ATT error code Insufficient Resources 0x11. To handle that you need to check why the peripheral sends that error code.
You should also know that Android has a design bug that reliable writes aren't really reliable. The protocol is that the data is first sent to the server, then the server sends the same data back to the client. According to the GATT specification, the client must then verify that the received data is equal to the sent data, otherwise it must abort. Unfortunately that info gets lost between the C and Java layer in Android's Bluetooth stack so there is no way to verify this.
Related
After writing, onCharacteristicWrite() gets called with the status BluetoothGatt.GATT_SUCCESS, but I don't actually see it on my peripheral.
I know the issue isn't on the peripheral because it works when I use a generic BLE Scanner app.
This is what my writeCharacteristic function looks like:
fun writeCharacteristic(characteristic: BluetoothGattCharacteristic, value: String) {
characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
characteristic.setValue(value)
bluetoothGatt?.writeCharacteristic(characteristic)
?: run {
Log.w(TAG, "BluetoothGatt not initialized")
}
}
I've tried using a String or a ByteArray as the payload.
I've also tried adding the operation to a queue.
The issue remains the same.
Well the success status is only reported after the peripheral has actually sent back a Write Response.
So either you write to the wrong characteristic, the wrong device, or you are not correctly detecting at the peripheral when an incoming write has been received.
One way to debug this is to use the hci snoop log in Android, or using a BLE sniffer.
I am using an android device with Android 5.1 (Bluetooth 4.0) and a MCU Board which has Bluetooth 4.2.
On my MCU side i am updating my Gatt Characteristic in a Loop just to make sure, that i know if the data i am writing inside is consistent. before i am writing it inside the gatt database i am using a crc check.
on my android side i just have a thread which reads the characteristic out of that gatt database and directly after that i have the same crc but it seems like 50% of the values are corrupt (which doesn't make sense from my side).
i know that the data i am writing in my gatt database is correct so i guess the issue is with reading the characteristic several times in a thread.
i've already tried to read the characteristic via notifications on my android side but the bluetoothleservice is never jumping into the OnCharacteristicChanged callback.
my characteristic update Looks like this
tmpGatt.readCharacteristic(characteristic);
and the characteristic is filtered by the uuid before
for(int i = 0; i<Services.size(); i++){
Characteristics = Services.get(i).getCharacteristics();
for(int c=0;c < Characteristics.size();c++){
UUID myUUID = Characteristics.get(c).getUuid();
if(myUUID.toString().equals("354a1b8e-7597-11e6-8b77-86f30ca893d3")){
characteristic = Characteristics.get(c);
//refExternalData.getRefBluetoothGatt().readCharacteristic(characteristic);
descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
Log.i("BLE", "Characteristic " + myUUID.toString() + " found");
}
}
}
so do i Need to do anything Special to re-read the gattcharacteristic?
Did you follow the procedures at https://developer.android.com/guide/topics/connectivity/bluetooth-le.html#notification in order to enable notifications?
When you issue readCharacteristic, you are not allowed to issue a new readCharacteristic until you have got the onCharacteristicRead. Or actually you are not allowed to send ANY new request (readCharacteristic, writeCharacteristic, readDescriptor, writeDescriptor) until a previous request has completed. This is because there may only be one outstanding GATT request at a time and there is no internal queue.
I am trying to write data by using the blow code, successfully received on the target.
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
byte[] value = new byte[1];
value[0] = (byte)inputvalue;
characteristic.setValue(value);
if (value.length <20){
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
Log.d("send Status ******- : ", String.valueOf(status));
}
But, When I am trying the write the multiple times can't send the data.
Also tried to send with a 2 second delay then, it is working fine.
How can I do it with out a delay
BLE on Android is asynchronous and notoriously difficult to work with. Typically you have to wait for the first GATT operation to complete before you can perform follow up GATT operation (which is why it works when you add a delay).
I would recommend you checkout this project from Nordic semiconductor which includes a nice queue processor that makes BLE manageable. https://github.com/NordicSemiconductor/puck-central-android
I am implement the connection between Android and BLE? like Anti-lost or finder , After android phone has connected to the BLE device , phone read the RSSI of BLE device every second.
If the RSSI of BLE device is lower than RSSI threshold , it deem Out of Range. For example: Threshold is -70 , and the current RSSI of device is -80.
When app is deem Out of Range. it send the message to the BLE every 5 second. But it always disconnect after few times. I uses the following code to send the message to the BLE device.
BluetoothGattService HelloService = Gatt.getService(HELLO_SERVICE_UUID);
if(HelloService == null) {
Log.d(TAG, "HelloService not found!");
return;
}
//If the Service is not null , try to get the characteristic.
BluetoothGattCharacteristic Characteristic = HelloService.getCharacteristic(UUID_HELLO_CHARACTERISTIC);
if(Characteristic == null) {
Log.d(TAG, "Characteristic not found!");
return;
}
Gatt.setCharacteristicNotification(Characteristic, true);
Characteristic.setValue(text, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
Gatt.writeCharacteristic(Characteristic);
Log.d(TAG, "StepCount Characteristic End!");
The above code is correct , the BLE can receive the message. But the BLE device will disconnect after few second. It seems do more than one thing in a short time is burden to BLE device.
The question is: How to make the connection more stable between Android and BLE ?.
Some suggestions:
Don't use notifications if you can avoid it. Based on personal experience with some phones in some environments notifications can stop working and appear to cause general instability. Try to do periodic reads instead.
Only do a read or write once you have received a callback to BluetoothGattCallback.onCharacteristicWrite() or BluetoothGattCallback.onCharacteristicRead() for the previous read or write.
More generally, never do two things at once, whether that be scanning, connecting, reading, writing, whatever. You should serialize all operations using a job queue, only popping from that queue when the previous job completes (or fails).
In almost-out-of-range scenarios like you're talking about, operations can take a long time to complete, longer than 5 seconds sometimes. So doing another operation in 5 seconds or less you're effectively "stomping" the previous operation. However, operations can also never return with a callback in these cases, so you do have to implement a timeout. I use 10 seconds. Beyond that, the operation failed.
I'm trying to implement the application which will communicate with BLE findme device. I have the one of these devices, but have some problem with it. Using iPhone I have tested this device with bleTools application and this app works correctly, i.e. I have managed to read all device's characterictics and send the characteristics to make the device beep. But using Android (Nexus 5) I could only read the device's characteristics, but cannot make the device beep.
My code is:
private static final UUID IMMEDIATE_ALERT_SERVICE =
UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
private static final UUID IMMEDIATE_ALERT_LEVEL =
UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
...
public void beep(DeviceData device) {
BluetoothGatt gatt = mConnectedDevices.get(device.getDeviceAddress());
BluetoothGattService bluetoothGattService = gatt.getService(IMMEDIATE_ALERT_SERVICE);
if (bluetoothGattService == null) {
return;
}
BluetoothGattCharacteristic characteristic =
bluetoothGattService.getCharacteristic(IMMEDIATE_ALERT_LEVEL);
if (characteristic == null) {
return;
}
byte[] arrayOfByte = new byte[1];
arrayOfByte[0] = (byte) 0x01;
characteristic.setValue(arrayOfByte);
gatt.writeCharacteristic(characteristic);
}
The callback method returns Ok:
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (characteristic.getUuid().toString().equals(IMMEDIATE_ALERT_LEVEL.toString())) {
//TODO: use device address to identify the device-receiver
Message msg = new Message();
msg.what = MSG_PARAM_WRITTEN;
msg.obj = (status == BluetoothGatt.GATT_SUCCESS);
mHandler.sendMessage(msg);
}
}
but nothing happens on the device side.
Can anyone explain me what I'm doing wrong or maybe give some advice what should I do?
And again, I can read the device characteristics, but cannot write them to the device.
Unlike iOS, Android has quite a few undocumented tricks with Bluetooth. I'm assuming you are using the standard Bluetooth library included in Android 4.3 and later. If you using other libraries like Samsung or Broadcom, the results could be different.
Because I do not have a findeme device I cannot confirm anything. But I have worked with both classic and low energy Bluetooth energy on Android for a while now. My advice is to go through the complete process of scan, discover services and read/write characteristics.
startLeScan
onLeScanCallBack connect to the device
onConnect discoverServices
onServicesDiscovered get all characteristics
check the properties on each characteristic
if you can read it, go ahead and do that
after that is done, you can then write the characteristic and listen for the onCharacteristicWrite event. You may get the beep then. If not, you'll need to go back to the iOS project and trace every bit that is sent to and received from the findme device. That sounds difficult but it's really just a matter of reading bytes inside of the right delegates. Document that. Then go back and recreate the bit sequence on the Android side. Again, capture all the traffic to and from the findme device. If you can get the bit sequence to match, you'll have success.
There's one more very important thing to know about Android BLE. The writes must be sequential. By that I mean, if you write a characteristic, you must wait for the onCharacteristic event to fire before you can write another one. This is not documented on the Android developer site. The best way to implement this functionality is to use a LinkedList as a work queue.
Good luck and ping me if you have questions.