BluetoothGattCallback - onConnectionStateChange returns status22 - android

I am developing an Android application to interface with Bluetooth module dual mode.
Due to the module is dual mode, I am confronting the same problems described here.
However I trying to do a workaround, because after first connection the callback onConnectionStateChange() returns status 133. Always in the onStop() method from Main Activity, I close BluetoothGatt object to free resources. Further was added bluetoothGatt.disconnect() before bluetooth.close().
When was called disconnect(), my cellphone get more connections with the module, however after reconnecting sometimes, the callback onConnectionStateChange returns status 22.
I didn't find about status 22 in the BluetoothGatt documentation.
UPDATE
In BLE callbacks are passed status codes that are not in the public API. topic is about status 22 and others.
Thanks

133 error code: Connect timeout or device not found.
22 error code: The bluetooth is closed then device is disconnected.
22 error code: The Connection Terminated By Local Host error code indicates that the local device terminated the connection.

Related

readCharacteristic returned true, but onCharacteristicRead is not called

After connecting to BLE device and discovering its services, I check that a certain characteristic is readable, then, I call readCharacteristic. This call returns true, but the callback onCharacteristicRead is not called.
After merely 30 seconds, the onCharacteristicRead is called with characteristic == null and the onDeviceDisconnected is called with status code equal to 22.
I have tested nRF Connecte to read the same characteristic and it worked fine.
What could possibly be wrong ?
The fact that it timeouts after 30 seconds and disconnects with error 22 (local device terminated the connection) indicates that the peripheral did not respond within 30 seconds, as required by the GATT standard. You should debug the peripheral to find the cause.
The reason it works in nRF Connect might be that the previous GATT sent / received put the peripheral in a different state.
You could check out the HCI log in Android to see all raw packets to maybe figure out what's going on.

Android: Catching BLE Connection Fails/Disconnects?

So I'm able to connect to a BLE device just fine under normal circumstances. What I want to do is handle abnormal circumstances, like when the connection to a device fails or an established connection is lost (maybe it got thrown off a cliff or hit by a bus)
I'm using a CyPress BLE module to test this, and one of the tests I'm doing is to remove power from the module. However, onConnectionStateChange never gets called! All I ever see it respond to is successful connections. It'll spend hours trying to connect and never give up evidently. I would do a delayed cancellation of the connection attempt, but there is no way to cancel the connection attempt on a Bluetooth device (that I know of)! As far as I can tell it'll keep trying until the battery runs down.
Here's what my onConnectionStateChange looks like right now, inside the Gatt Callback. Note that I'm trying to catch and log ANY kind of callback involving ANY kind of connection state change... which never gets called unless connection success. Note that this is code is not on the activity itself. It's in an object held by a singleton. (I want to maintain connection across multiple activities)
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
mGatt = gatt;
Logy.CallPrint(LOGY_ENABLE, CLASSNAME, "Status: "+status+ " Newstate: "+newState);
switch(status)
{
case BluetoothGatt.GATT_SUCCESS:
mReconnectAttempts = MAX_ATTEMPTS;
if(newState == BluetoothGatt.STATE_CONNECTED)
{
DispatchEvent(Event.Type.BT_ON_CONNECT);
bIsConnected = true;
gatt.discoverServices();
} else if (newState == BluetoothGatt.STATE_DISCONNECTED)
{
DispatchEvent(Event.Type.BT_ON_DISCONNECT);
bIsConnected = false;
}
break;
default:
if(newState == BluetoothGatt.STATE_DISCONNECTED)
{
bIsConnected = false;
if(mReconnectAttempts > 0)
{ // if we have attempts left, auto attempt to reconnect
DispatchEvent(Event.Type.BT_RECONNECTING);
mReconnectAttempts--;
gatt.connect();
bIsConnected = false;
}
else
{
mReconnectAttempts = MAX_ATTEMPTS;
DispatchEvent(Event.Type.BT_ON_CONNECT_FAIL);
bIsConnected = false;
}
} else {
Logy.CallPrint(LOGY_ENABLE, CLASSNAME, "onConnectionStateChange: Failed?");
}
}
super.onConnectionStateChange(gatt, status, newState);
}
Not being able to detect disconnects is an issue elsewhere in my code, like where I show a Progress Dialog indicating the app is connecting to a BLE device. Well, that dialog never goes away because the event "On Connect Fail" never gets thrown.
I think what you are looking for is Bluetooth Supervision timeout which is according to Bluetooth LE specifications :
a parameter that defines the maximum time between two received Data Packet PDUs before the connection is considered lost
Default Supervision timeoout is set to 20 seconds on Android (depending on Android version & device). For instance, here is the value of Supervision Timeout on Android 5.1.
There is no API to set this parameter, so you will have to wait 20 seconds (depending on your Android version & device) to get onConnectionStateChange callback with status BluetoothGatt.STATE_DISCONNECTED after you power off your BLE module
This answer aligns with the answer from Emil.
I coded up a test App with a single Activity running on Moto G4 Play Android 6.0.1 (Marshmellow: API23) and a Peripheral based on a Laird BL600
I was going to post some logs - but they don't format so well - so I'll just describe the results.
As usual, the Peripheral advertised and the Central scanned, and obtained a device instance.
The question does not state exactly how the first connection is made, but let's assume it is with 'autoconnect' false, of the form
mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
(this is the only style of connection used in the test App)
This gives an instance of BluetoothGatt and, as noted in the question, events are then reported asynchronously through the call back,
but there is also an instance of BluetoothGatt on which to call disconnect() even before any connection events have occurred.
The API documentation for disconnect() states - especially the part after the ','
BluetoothGatt.disconnect()
Disconnects an established connection, or cancels a connection attempt currently in progress.
To free up GATT resources, after disconnecting, the test App also then always calls
mBluetoothGatt.close();
Here are some different scenarios
device.connectGatt() -- Peripheral advertising - connection made -- followed by mBluetoothGatt.disconnect() and close().
Result: this is a normal successful connection, followed by Central device closing the connection in code. Call back events are received as expected. When the Central disconnects in the code, the underlying Bluetooth Service disconnects and the Peripheral gets a Disconnection event.
.
device.connectGatt() -- Peripheral advertising - connection made - followed by Peripheral switched off.
Result: this is a normal successful connection, call back events as expected, followed by connection broken by Peripheral. The Peripheral indicates preferred connection supervision timeout in BleGapSvcInit and this is confirmed by Central in a Connection Parameters Update. After Peripheral drops the connection a Disconnection event occurs in Central just after the connection supervision timeout. (Repeated with 8 seconds and 4 seconds supervision timeouts).
.
device.connectGatt() -- but Peripheral has stopped advertising, connection attempt allowed to time out.
Result: (This is a specific scenario of the question) After 30 seconds, probably the connection timeout of the Bluetooth Service on the phone,
there is a an onConnectionStateChange event indicating the new connection state is Disconnected - with (error) status 133.
Must still remember to call mBluetoothGatt.close() else an interface leak occurs and subsequent connection is made on the next client interface.
.
device.connectGatt() -- Peripheral still advertising but connection cancelled after 200ms using mBluetoothGatt.disconnect() and close().
Result: (I found this case the most interesting, if also the most unlikely to happen in a real application) Sometimes, (about 1 in 10)
the underlying Bluetooth Service actually did connect to the Peripheral; which saw a connect, followed by a disconnect; even though the App doesn't see
these events in the call back. Sometimes, even though, as far as the App is concerned, the App is disconnected, the underlying Bluetooth phone service
connected to the Peripheral - and remained connected in my test for a few minutes until I timed out! - and turned the BT service, or the Peripheral, off.
First, if an established connection is dropped you should get a disconnected state change event when the supervision timeout has passed. Otherwise there is some bug in Android.
Now about connection attempts.
Once you create a BluetoothGatt object with connectGatt and specify the auto connect parameter to true OR execute the connect method on an existing BluetoothGatt object, the phone will be in a state where it always and indefinitely tries to connect to the device and reconnect to the device if it disconnects for any reason until you either call disconnect or close on the gatt object.
So if you want to abort the connection after a while, just set up any kind of timer which calls disconnect on the gatt object (or close if you don't need it anymore) when it is triggered.
Also note that the status parameter of the onConnectionStateChange when newState is disconnected is not well-defined. In older Android versions it contains usually 0 or 133 and in newer versions often the Bluetooth standard's error code of the disconnect reason.
Also, if you get a disconnect state change event without previously have got a connected state change event, it usually indicates something has gone wrong in the internal Bluetooth stack (unless you use non-auto connect for which you always get a disconnect state change event after some timeout). Then I'd recommend that you close the gatt object and try again later.

android BLE - automatic re-connect after spontaneous disconnect

using the android 4.4 BLE APIs on my Nexus7, i'm able to successfully interact with a peripheral BLE device -- connect, disconnect, read, write....
if however an active connection breaks for whatever reason (in this case, the peripheral is reset), i observe the following behavior....
my peripheral (by design) begins advertising after any active connection is terminated (for whatever reason); i can see this via my bluetooth packet sniffer....
i receive the onConnectionStateChanged callback as expected in my android app, at which point i invoke close() on my active BluetoothGatt instance; this is the same procedure i follow during a "normal" disconnect initiated from the client...
shortly after this, the android BLE stack tries to re-connect to the same peripheral; through the packet sniffer i can see the BLE connection request going out over the air...
my app, however, did not initiate this re-connection; indeed, i see no information from any bluetooth log suggesting this even happened!!!!
is there some "mode" in the BLE stack where it attempts to re-establish busted connections automatically???
thanks....
This happens on various Android phones whether the autoConnect flag is set to false or true.
Couldn't yet find a complete solution, it seems as the android BLE stack is spontaneously re-initiating the connection once it is getting the advertising signal again, just ignoring that it was the app that disconnected on purpose...
A partial solution may involve not using the BluetoothGatt.connect() method as explained here:
https://stackoverflow.com/a/23749770/4144487
So, a sample connect method can look like:
void connect(Context context) {
if (mGatt != null) {
mGatt.close();
}
mGatt = mDevice.connectGatt(context, false, callback);
}
To explain the importance of this issue, when it happens the peripheral thinks it is connected and my "real" app can't find it any more. At some phones like Galaxy S3 and Redmi note 3 I found that closing the bluetooth switch from the notification bar is "releasing" the peripheral and allowing me to discover the device. At others like Nexus 5x only a phone reboot will do the trick.
I've observed this happening if you use autoConnect=true when calling BluetoothGatt#connectGatt(). Generally I've found that it is best to use autoConnect=false, but with some devices you simply cannot connect unless you use true, so I usually do both. I try false first and if that fails then use true and then the behavior you're describing is something you simply have to work around.

Android 4.3 LE Bluetooth client server conflict

I am using Samsung Galaxy S4 running Android 4.3
I am trying to convert an app that ran on Samsung's LEB API with Android 4.2.2.
I can discover and connect (connectGatt) to the peripheral and run all "client" code successfully, provided I do not try to connect as a server.
Whenever I connected
mBluetoothGattServer = mBluetoothManager.openGattServer(this, mGattServerCallbacks);
the LogCat's indicated that the communication with BluetoothGatt cease.
I've tried to openGattServer after all the Gatt services are discovered. I attempt to addServices in the GattServerCallback onConnectionStateChange. The code runs but I do not get an onServiceAdded callback
Both the "gatt client" and "gatt server" code in my app fails to run.
I do get onConnectionStateChange callbacks for both.
How, when and where (MainActivity or BLEService) do I instantiate mBluetoothGattServer?
Is this documented somewhere? With some sample code?
The first part of my question is resolved temporarily. I started a new thread, added a one second delay, then called openGattServer. My "client" code now works fine. (I am not happy with this - it was a try generated out of frustration - I may try using a queue if I can get server code to work).
I do get a GattServerCallback for onConnectionStateChange.
However, I do not seem to have yet got any "server" code running.
I have found a temporary solution.
When I instantiated the mBluetoothGattServer object, the callback "onConnectionStateChange" was called while mBluetoothGattServer = null (still). This was a surprise as instantiating the object caused the callback to be registered. I put a delay into the code of onConnectionStateChange until mBluetoothGattServer != null (with suitable limit on number of tries) and was able to add a service successfully. At the time of writing it appears that I will have to add services one at a time and wait for the onServiceAdded callback before adding each service (this is not yet tested)
I must say the Samsung BLE SDK was easier to understand and manage.
You should initialize the BluetoothGattServer before calling connectGatt on any BluetoothDevice :
mBluetoothGattServer = mBluetoothManager.openGattServer(self, mGattServerCallbacks);
mBluetoothGatt = device.connectGatt(this, false, mGattCallbacks);
The fact is you only need one BluetoothGattServer instance, and the callbacks in mGattServerCallbacks will be called simultaneously with those in mGattCallbacks.
When you connect a device, the methods called onConnectionStateChange will be called in both callbacks wrappers.

BLE onConnectionStateChange called twice when closing a connection

Finally got my device (based on TI's CC2541) to work with my phone (a prototype/non-commercial-yet phone running Android 4.3). I can scan, discover, connect and get notifications successfully. However, when I disconnect (calling BluetoothGatt.disconnect()), the onConnectionStateChange callback is called with newState=STATE_DISCONNECTED (as expected) but then immediately called again with newState=STATE_CONNECTED.
The connection is definitely terminated so I'm not sure why I'm getting the 2nd onConnectionStateChange call. Has anyone experienced anything similar?
Check the status given to you in onConnectionStateChange; if the status isn't 0 (OK) then you didn't actually get a connection. I've found a number of occasions where I get the CONNECTED message but the status was indicating something else was happening.

Categories

Resources