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
Related
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.
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 working on an Android BLE project. We are using BLE to configure some settings on an embedded device. The embedded device was going to take a long time to come up so I started using BlueSim to emulate the embedded connection.
There are essentially two messages that the Android (I'm requiring KitKat) device sends off to the embedded device. One is to write settings....One is to read the settings.
A Write message is going out to endpoint 0xFFF1 like the following
byte[] data2Send = new byte[11];
data2Send[0] = 0xAA; // signifying this is a write message to device
data2Send[1] = 0x01; // data value
data2Send[2] = 0x38; // data value
data2Send[3] = 0x47; // data value
data2Send[4] = 0x24; // data value
data2Send[5] = 0x01; // data value
data2Send[6] = 0x36; // data value
data2Send[7] = 0x49; // data value
data2Send[8] = 0x0b; // data value
data2Send[9] = 0x63; // data value
data2Send[10] = 0x0D; // CR to indicate the last byte of the packet
characteristic.setValue(data2Send);
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
Log.v(TAG,"Status is:" + String.valueOf(status));
I had verified this using BlueSim and we have confirmed that this works when transmitting data to the embedded device. We can successfully change all of the settings.
The other message is a Read request of the device so I can know what settings are already in there or to confirm that the settings actually changed.......
byte[] data3Send = new byte[3];
data3Send[0] = 0x55; // Signify this is a start of a READ message
data3Send[1] = 0x42; // Second part of the read designator
data3Send[2] = 0x0d; // Carriage return saying this is the last bit
characteristic.setValue(data3Send);
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
Log.v(TAG,"Status is:" + String.valueOf(status))
When I send this message over to BlueSim, I see the message on my iPhone and immediately send the settings back out. On Android I see the 11 bytes that are coming back informing me of all the settings! This almost happens instantaneously. Great!
But when we do this on the embedded device I see one byte come back. That's it. Using a debugger on the embedded side we can see all 11 bytes going into the BLE module on the embedded device. If we use a PC rather than my Android device we can see all 11 bytes show up on the PC (the manufacturer of the BLE module has a terminal like app that you can 'sniff' the data with).
The embedded device is an 8 bit micro that is hooked up to a BLE module (TI CC2540 chipset) via a UART so it's obviously SLOWER than the iPhone where BlueSim is running. The embedded device is going to need some time to receive the BLE message, process the request, and shove data back out the BLE module. Is there some setting I have to set in my Android program to allow for a slower response to come back?
I tried downloading LightBlue on iOS and sending that read request out, and we get the same results. We see the first byte of the data packet show up in LightBlue. But only that one.
Any help would be greatly appreciated as always.
It sounds like you are experiencing an issue with the TI Module, not Android. Not sure if its the same issue, but it seems others have been getting headaches from trying to establish connections from Android to the CC254X. See here: https://e2e.ti.com/support/wireless_connectivity/f/538/t/401240
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.