My BLE server permanently measures a sensor value and sends a notification with 20 byte user data after each measurement. The goal is to generate as much throughput as possible.
On the client side, the value sent by the server is received and processed.
rxBleConnection.setupNotification(setDescriptorEnableNotification(characteristic))
.flatMap(notificationObservable -> notificationObservable)
.observeOn(Schedulers.newThread())
.buffer(1)
.subscribe(bytes -> {
onNotificationReceived(bytes, buffer);
} , throwable -> {
// Handle an error here.
onNotificationSetupFailure(throwable);
}
);
If I set the Connection intervall to 11.25ms, I receive all values. However, if I set the connection interval to 30ms, I receive a few values and then the connection is closed.
In the Android Log i see the followed message:
BleGattException status=8 (0x8),
bleGattOperationType=BleGattOperation{description='CONNECTION_STATE'
Why is the connection interrupted and what is the trigger?
With the help of a BLE Sniffer this is not recognizable. The set connection parameters are accepted and the transfer begins. Suddenly the transmission ends and the error message appears.
Update:
BLE Sniffer screenshot has been added:
30ms, this is connection interval you set in server or android?
Btw, on android you can set speed mode
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
}
Error 8 means the connection timed out. There is nothing wrong on the Android side. The problem is with the communication between the two Bluetooth controllers. If you have a sniffer then you should be able to see who is the one that fails to send packets.
Here is an Image from BLE Sniffer.
BLE Sniffer
I have the similar problem. On Android 7.0 there were two ways to keep connection:
1) If devices are bonded and there is a charachteristic reading callback with constant thread of packets. If there are no packets by some time, then connection fails.
2) If devides are not bonded, but I do TXCharacheristic.read every few seconds. If don't do that some time, then connection fails.
But now in Android 7.1.2 this way doesn't work.
May be the first way will work for you.
On your Android device you should make bonding, on your kit you should handle this bonding.
On Nexus 6P and Samsung S7 it doesn't work anymore, but I didn't try it on the other devices.
I suppose, you have min connection interval 7.5 on your BLE kit, but now it is deprecated on Android.
Try to set min connection interval to 11.25 on your BLE kit and set connection priority
gatt.requestConnectionPriority(CONNECTION_PRIORITY_HIGH);
where CONNECTION_PRIORITY_HIGH = 1
in onConnectionStateChange.
It had worked for me when I had changed min connection interval in my nordic from 7.5 to 11.25.
Related
I need to know exactly how many packets per interval my BLE can handle. The peripheral, as per its datasheet, handles 6 packets per interval, but I have been unable to find out how many packets the Central can handle. The Central device is a Motorola Moto G (generation 2), running Android 5.0.2.
By examining he btsnoop_hci.log file I have been able to identify multiple connection parameters, such as the connection interval (7.5ms in my case). My questions is wheter it is possible to determine how many packages can be exchanged in a single coonection interval, by examining the negotiation packets in Wireshark.
In the spec, there is no negociation about the max number of packets in a Connection Event. A connection event can simply last for at most (ConnectionInterval - 150µs) (See 6.B.4.5.1).
Limitations, if any, are in the PHYs, at either side. Most HCI firmwares limit to 4-5 packets per connection event, per direction.
It is up to the controller on the master side to decide how long the connection event should be open (as long there are more packets from any side). The slave has nothing to say about this.
For a central host, when creating a connection as well as when updating connection parameters there are two HCI parameters Minimum_CE_Length and Maximum_CE_Length. These are informational parameters that indicate how long it should keep its connection event open. If these are set to high numbers, the controller will have the connection event open as long as possible.
Sadly, Android set these parameters both to 0 which means most controllers will restrict the connection event to only 3 or 4 packets.
We are facing one issue when reading characteristics from remote BLE device.
This issue happen in Android OS 5.0 and above.
Points are below to generate issue :
Make one peripheral device with one service and one characteristics.
Characteristics will have only read permission. Now set the value of this characteristics with more than 20 characters i.e. 20 bytes.
Now let peripheral device broadcast itself with one service and one characteristics.
Now launch any BLE scanner app from market and connect with this peripheral device.
Once successfully connected with peripheral device just try to read characteristics.
In this case it will not show any data and when debugging the app it show that it returns null data.
The above same case not working in the Android OS 5.0 and above.
Same case working in android 4.4.
So there is something change in Android OS 5.0 and above that internally disable readblob() request that can read data having more that 20 characters.
This can be simply achievable by splitting your data into 20 byte packets and implementing a short delay (i.e. using sleep()) between sending each packet.
You can use BluetoothGatt.requestMtu(). See the Official document of BluetoothGatt.requestMtu
Request an MTU size used for a given connection.
When performing a write request operation (write without response), the data
sent is truncated to the MTU size. This function may be used to request a larger MTU size to be able to send more data at once.
A onMtuChanged(BluetoothGatt, int, int) callback will indicate whether this operation was successful.
Requires BLUETOOTH permission.
If you want send more 20 bytes, you should define array byte[] include how many packet you want.
There is an example Android: Sending data >20 bytes by BLE
Also there is another example How to send more than 20 bytes data over ble in android?
The Bluetooth Low Energy connection parameters management seems to have changed in Android 6.
I have a BLE Peripheral device who needs to use some specific connection parameters (notably, the connection interval), and I want to use the minimum connection interval allowed by the BLE specification (i.e. 7,5ms).
The Android SDK doesn't allow to choose it from the BLE GAP Central (the smartphone) side, so the proper way to do it is to make my GAP Peripheral device send a L2CAP Connection Parameter Update Request after the GAP connection is made.
The parameters I request are:
conn interval min : 7,5ms
conn interval max : 7,5ms
slave latency : 0
supervision timeout : 2000ms
This worked as expected with all Android devices I've been testing, from 4.3 to 5.x : after sending the L2CAP Connection Parameter Update Request, my device receives a L2CAP Connection Parameter Update Response with 0x0000 (accepted), followed by a LE Connection Update Complete event where I can see that the requested connection parameters have well been taken into account.
Now, with a Nexus 9 tablet or with 2 different Nexus 5 devices, all having Android 6.0.1, I can see that the the L2CAP Connection Parameter Update Request is always rejected (I receive a L2CAP Connection Parameter Update Response with 0x0001 (rejected)). Then I receive a LE Connection Update Complete event where I can see that the requested connection parameters have NOT been taken into account.
I've been trying this with 2 different implementations on the Peripheral side (one with ST Microelectronics' BlueNRG, one with Nordic Semiconductor's nRF52), both with the exact same result.
Then, after more testing : I have tried different parameter sets, changing the conn interval max (I kept other parameters the same). Here is what I found :
with conn interval max = 18.75ms, update request was accepted with interval set to 18.75ms
with conn interval max = 17.50ms, update request was accepted with interval set to 15.00ms
with conn interval max = 15.00ms, update request was accepted with interval set to 15.00ms
with conn interval max = 13.75ms, update request was accepted with interval set to 11.25ms
with conn interval max = 11.25ms, update request was accepted with interval set to 11.25ms
with any other conn interval max value below 11.25ms, I get rejected.
So the observation is that something has clearly changed with the way Android 6's BLE stack handles the connection parameters. But there doesn't seem to be any kind of information or documentation to confirm that.
My observations lead to a conclusion that the minimum connection interval allowed is now 11.25ms (which actually fits my needs) instead of 7.5ms in earlier Android versions. But having found it empirically, I'd want to be sure that I'm not missing some other constraints/rules or if that minimum would not be dynamic, depending for example on the current battery level...
What would be great would be to have the equivalent of Apple's Bluetooth Design Guidelines (cf. §3.6) to set things clear on how an LE Peripheral should deal with this topic.
Is anyone having the same issue or is aware of some more helpful information from Google ?
Compare method connectionParameterUpdate() from GattService.java in AOSP 6.0.1_r17 vs AOSP 5.1.1_r14. In both instances, call goes all the way to Buedroid in BTA_DmBleUpdateConnectionParams() in bta_dm_api.c with same params.
6.0:
switch (connectionPriority)
{
case BluetoothGatt.CONNECTION_PRIORITY_HIGH:
minInterval = 9; // 11.25ms
maxInterval = 12; // 15ms
break;
case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER:
minInterval = 80; // 100ms
maxInterval = 100; // 125ms
latency = 2;
break;
}
5.1:
switch (connectionPriority)
{
case BluetoothGatt.CONNECTION_PRIORITY_HIGH:
minInterval = 6; // 7.5ms
maxInterval = 8; // 10ms
break;
case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER:
minInterval = 80; // 100ms
maxInterval = 100; // 125ms
latency = 2;
break;
}
This might be a part of the answer to your question. Although BLE allows down to 7.5ms CI, I cannot speculate why link layer would not switch to lower CI on request by peripheral. I don't know if any part of android code controls outcome of negotiations with peripheral device.
Google has not provided any documentation about the Bluetooth LE stack changes concerning connection parameter changes even though there have clearly been some in Android 6.
My experience with it has been the same as your own, that being that 11.25ms is now the fastest connection interval allowed in Android 6+.
My educated guess as to why they don't release documentation is that many manufacturers put their own BLE stacks into their phones (the BLE on Samsung and HTC behave differently from vanilla Android).
One other observation I have made that caused a great deal of problems is that Android 6+ will change the connection parameters 2 to 6 times before settling on the requested parameters.
I observed that after requesting a connection parameter update interval of 800ms to 1100ms, I saw the initial interval come back at 7.5ms, that then jumped to 48.75ms and then jumped to the 1098.75ms I requested. Then I subscribed to notifications on one of my services and the connection interval again jumped back to 7.5ms and then back to 1098.75ms. After this, it stabilized at 1098.75ms for the duration of the connection.
These tests were run on a Nexus 6 with Android 6.0.1
Obviously, some very strange things are happening on the Android 6 BLE stack.
11.25 ms is the new minimum connection interval. The reason they don't allow 7.5 ms anymore is because if you stream audio over bluetooth at the same time the audio might became choppy.
Google guys made a mistake in one of recent commits in Bluedroid by defining BTM_BLE_CONN_INT_MIN_LIMIT as 0x0009 which gives you 1.25ms x 9 = 11.25ms. In order to comply with standard it has to be defined as 0x0006.
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.
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