Get secondary bluetooth gatt service android - android

Fetch android secondary bluetooth gatt service from bluetooth android API's.
Currently below is the code where we fetch ble services :
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
List<BluetoothGattService> gattServices = mBluetoothGatt.getServices();
Log.e("onServicesDiscovered", "Services count: "+gattServices.size());
BluetoothGattService bleServ = mBluetoothGatt.getService(UUID.fromString("22222222-0000-0000-0000-000000000000"));
for (BluetoothGattService gattService : gattServices) {
String serviceUUID = gattService.getUuid().toString();
Log.e("onServicesDiscovered", "Service uuid "+serviceUUID);
}
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
Even tried fetching exclusively the secondary service but it returns null object :
BluetoothGattService bleServ = mBluetoothGatt.getService(UUID.fromString("22222222-0000-0000-0000-000000000000"));
Can someone point any pointers how to search secondary ble service in Android.

You should use this method: https://developer.android.com/reference/android/bluetooth/BluetoothGattService.html#getIncludedServices() on a primary service.

Related

Android BLE - Device keep disconnecting after a succesfull characteristic write

I'm working on a mobile app that implements Bluetooth LE and communicates with a HC-08 device.
While everything is ok on iOS with CoreBluetooth, i encounter some problems on my Android version.
I start by getting a Bluetooth Device
BluetoothDevice bluetoothDevice;
After that, i connect to it:
bluetoothDevice.connectGatt(context, false, callback);
Which is calling a callback function inside which i wait for STATE_CONNECTED and discover services, then write to characteristic:
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if(status == BluetoothGatt.GATT_SUCCESS){
Log.e("BLE_LOG", "onConnectionStateChange with success");
if(newState == BluetoothProfile.STATE_CONNECTED){
Log.e("BLE_LOG", "sucessfully connected to device: " + bluetoothDevice.getName() + "/" + bluetoothDevice.getAddress());
bluetoothGatt = gatt;
gatt.discoverServices();
}
else if(newState == BluetoothProfile.STATE_DISCONNECTED){
Log.e("BLE_LOG", "succesfully Disconnected from device: " + bluetoothDevice.getName() + "/" + bluetoothDevice.getAddress());
gatt.close();
}
}
else{
Log.e("BLE_LOG", "onConnectionStateChange with status: " + status + " and newState: " + newState);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if(status == BluetoothGatt.GATT_SUCCESS){
Log.e("BLE_LOG", "sucessfully discovered services for device: " + bluetoothDevice.getName() + "/" + bluetoothDevice.getAddress());
service = bluetoothGatt.getService(UUID.fromString(BLEFunctions.PROPRIETARY_SERVICE));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(BLEFunctions.PROPRIETARY_CHARACTERISTIC));
//Souscription notifications
if(bluetoothGatt.setCharacteristicNotification(characteristic, true)){
Log.e("BLE_LOG", "subscribed to notifications from characteristic");
}
characteristic.setValue(SET_ON);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
bluetoothGatt.writeCharacteristic(characteristic);
}
else{
Log.e("BLE_LOG", "Error discovering services for device: " + bluetoothDevice.getName() + "/" + bluetoothDevice.getAddress() + " with status: " + status);
}
}
When services are discovered, i'm writting to characteristic, which actually work because my bluetooth device is acting as expected (it switches on a relay), and onCharacteristicWrite is called:
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if(status == BluetoothGatt.GATT_SUCCESS){
Log.e("BLE_LOG", "sucessfully written characteristic for device: " + bluetoothDevice.getName() + "/" + bluetoothDevice.getAddress());
}
else{
Log.e("BLE_LOG", "Error writing characteristic for device: " + bluetoothDevice.getName() + "/" + bluetoothDevice.getAddress() + " with status: " + status);
}
}
The problem is that, as soon as the characteristic is written, the device disconnect and i can't continue my process.
At a point in the program, i've got connectionStateChange with status 8 (which seems to be : GATT_INSUFFICIENT_AUTHORIZATION)
I investigated several potential causes, as :
-Maybe the characteristic needs bonding before writing? I know it is handled automatically on iOS for example.
-Maybe the device i use has some incompatibilities with Android (but it works well with software like 'LightBlue', 'BLE Scanner', etc...
Can't figure out what is wrong.
Please help me solve this problem
Adding the log to help:
2022-05-05 09:58:25.600 22204-22204/com.******.******E/BLE_LOG: clicked on device: Hall/B0:B1:13:76:0B:1E
2022-05-05 09:58:26.065 22204-22467/com.******.******E/BLE_LOG: onConnectionStateChange with success
2022-05-05 09:58:26.068 22204-22467/com.******.******E/BLE_LOG: sucessfully connected to device: AAA-000000000001001/B0:B1:13:76:0B:1E
2022-05-05 09:58:26.727 22204-22467/com.******.******E/BLE_LOG: sucessfully discovered services for device: AAA-000000000001001/B0:B1:13:76:0B:1E
2022-05-05 09:58:26.732 22204-22467/com.******.******E/BLE_LOG: subscribed to notifications from characteristic
2022-05-05 09:58:26.754 22204-22467/com.******.******E/BLE_LOG: sucessfully written characteristic for device: AAA-000000000001001/B0:B1:13:76:0B:1E
2022-05-05 09:58:31.854 22204-22467/com.******.******E/BLE_LOG: onConnectionStateChange with status: 8 and newState: 0
Using my device with software like nRF Connect or LightBlue works well. (no disconnection)
I made progress and managed to point out a reason why the problem occures.
Actually, i'm discovering services via
gatt.discoverServices();
and as soon as i get the callback method, i get the service and characteristic i need and write to it.
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if(status == BluetoothGatt.GATT_SUCCESS){
Log.e("BLE_LOG", "successfully discovered services");
}
BluetoothGattService service = gatt.getService(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"));
Log.e("BLE_LOG", "got serivce with uuid: " + service.getUuid().toString());
bluetoothGatt = gatt;
characteristic = service.getCharacteristic(UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
Log.e("BLE_LOG", "got characteristic with uuid: " + characteristic.getUuid().toString());
byte[] data = {
0x24, 0x6F, 0x6E, 0x25
};
characteristic.setValue(data);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
bluetoothGatt.writeCharacteristic(characteristic);
}
When i deport the write part in another function, like a button function, it works well and doesn't disconnect.
public void clicked_open(View v){
byte[] data = {
0x24, 0x6F, 0x6E, 0x25
};
characteristic.setValue(data);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
bluetoothGatt.writeCharacteristic(characteristic);
}
It's as if something wasn't totally finished when i call my write as soon as i get the service discovered callback.
Maybe there is a way to ensure everything is ok before writing...
As you realized in your last edit, you are writing to the characteristic too soon. onServicesDiscovered is called multiple times, once for each found characteristic. You are already checking for the finished discovery and just need to move your writing operation there.
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
BluetoothGattService service = gatt.getService(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"));
Log.e("BLE_LOG", "got serivce with uuid: " + service.getUuid().toString());
if(status == BluetoothGatt.GATT_SUCCESS){
Log.e("BLE_LOG", "successfully discovered services");
bluetoothGatt = gatt;
characteristic = service.getCharacteristic(UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
Log.e("BLE_LOG", "got characteristic with uuid: " + characteristic.getUuid().toString());
byte[] data = {
0x24, 0x6F, 0x6E, 0x25
};
characteristic.setValue(data);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
bluetoothGatt.writeCharacteristic(characteristic);
}
}
The parameter status will only be GATT_SUCCESS after the discovery finished, see the documentation for more information.

BluetoothGattCharacteristic.value returns empty value

I am trying to parse a value of a BluetoothGattCharacteristic to another activity. I can read the characteristic successfully, but then the value it gives me is empty...
I am trying to read the device name. In another BLE app (nRF connect) can I see the characteristic and its value. Can someone help me, what am I doing wrong?
This method loops and logs the services found with its characteristics:
private void displayGattServices(List<BluetoothGattService> gattServices) {
//Check if there is any gatt services. If not, return.
if (gattServices == null) return;
// Loop through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
Log.i(TAG, "SERVICE FOUND: " + gattService.getUuid().toString());
//Loop through available characteristics for each service
for (BluetoothGattCharacteristic gattCharacteristic : gattService.getCharacteristics()) {
Log.i(TAG, " CHAR. FOUND: " + gattCharacteristic.getUuid().toString());
}
}
//****************************************
// CONNECTION PROCESS FINISHED!
//****************************************
Log.i(TAG, "*************************************");
Log.i(TAG, "CONNECTION COMPLETED SUCCESFULLY");
Log.i(TAG, "*************************************");
goToDisplayBleServicesActivityOnListItemClick();
}
goToDisplayBleServiceActivityOnListItemClick():
private void goToDisplayBleServicesActivityOnListItemClick() {
Intent intent = new Intent(this, displayBleServicesActivity.class);
BluetoothGattService selectedService = mBluetoothGatt.getService(UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"));
BluetoothGattCharacteristic selectedCharacteristic = selectedService.getCharacteristic(UUID.fromString("00002a00-0000-1000-8000-00805f9b34fb"));
if (mBluetoothGatt.readCharacteristic(selectedCharacteristic)) {
intent.putExtra("READ_CHAR", selectedCharacteristic.getValue().toString());
} else {
intent.putExtra("READ_CHAR", "It did not work out");
}
startActivity(intent);
}
What am I doing wrong here?
If you read the documentation at https://developer.android.com/reference/android/bluetooth/BluetoothGatt#readCharacteristic(android.bluetooth.BluetoothGattCharacteristic) it says:
This is an asynchronous operation. The result of the read operation is reported by the BluetoothGattCallback#onCharacteristicRead callback.
So you must override the onCharacteristicRead callback. Inside that one you can get the value.

How to set/get/request MTU from android to iOS or viceversa BLE?

We are sending mtu request from android to iOS
Android - Requesting mtu from this function onServicesDiscovered callback
But I do not know the way how to find out if peer device support requested MTU and what is actually negotiated MTU. The required function: BluetoothGattCallback.onMtuChanged(BluetoothGatt gatt, int mtu, int status) was added only in API level 22 (Android L 5.1).
My problem is that I do not know how many bytes in packet I can send.
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//requestPriorityHigh();
gatt.requestMtu(182);
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
List<BluetoothGattService> Services = gatt.getServices();
for (BluetoothGattService gattService : Services) {
if (SERVICE_UUID.equals(gattService.getUuid())) {
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
if (CHARACTERISTIC_UUID.equals(gattCharacteristic.getUuid())) {
gatt.writeCharacteristic(gattCharacteristic);
List<BluetoothGattDescriptor> gattDescriptors = gattCharacteristic.getDescriptors();
for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {
gatt.readDescriptor(gattDescriptor);
}
}
}
}
}
} else {
Log.w(MainActivity.TAG, "onServicesDiscovered received: " + status);
}
}
Ex: gatt.requestMtu(182)
IOS - not triggered didSubscribeTo characteristic callback
- (void)peripheralManager:(CBPeripheralManager )peripheral central:(CBCentral )central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
NOTIFY_MTU = central.maximumUpdateValueLength;
NSLog(#"Central subscribed to characteristic");
NSLog(#"Supported to BLE Device Info:--> %lu",(unsigned long)[central maximumUpdateValueLength]);
[peripheral setDesiredConnectionLatency:CBPeripheralManagerConnectionLatencyLow forCentral:central];
}
We need to set packet size based on the connected BLE Devices.if MTU not requested we have a callback on didSubscribeTo characteristic, were the minimum MTU size is 20. How to get & set this mtu size form android.
How to we set the MTU?
The method requestMtu starts an MTU exchange between the two Bluetooth devices. They will agree on a value that both devices support.
So you can request a high MTU:
gatt.requestMtu(2000);
Then wait for the onMtuChanged callback. It will tell you the MTU that has been agreed:
#Override
public void onMtuChanged(BluetoothDevice device, int mtu) {
Log.i(TAG, "MTU: " + mtu);
}

Receiving multiple BLE Packets per one connection interval in Android

My device information
Nordic board :
MTU size : 247.
This board send notification multiple packets in one connection interval (Just counter value like 1,2,3,4...) at "Heart Rate Measurement".
Android device :
Version 5.0 and 6.0. (Using two device).
communicate Bluetooth Low Energy(BLE) with board.
board connect with my Android app MTU is setting 244.
Application source is google sample project BluetoothLeGatt
App send notification value at "Heart Rate Service" characteristic.
Receive notification value at Gattcallback "onCharacteristicChanged()"
Problem
My Android app lost some packet.
I read this post. Maximizing BLE Throughput on iOS and Android. So I send E-mail this post author and I search another information for Android.
I found some similarly question. but that question answer was not work. Then I found one question what I want exactly. but this question have no answers. Android receiving multiple BLE packets per connection interval. Unfortunately I don't have any reply E-mail answer.
My question is how do I set Android BLE notification. (Not Nordic board setting)
(My question is same Android receiving multiple BLE packets per connection interval)
Under line is my sample code. at notification.
#Connect
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
#GattCallback
/*broadcastUpdate method is display value*/
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:");
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected from GATT server.");
mConnectionState = STATE_DISCONNECTED;
broadcastUpdate(ACTION_GATT_DISCONNECTED);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onServicesDiscovered success: (status)" + status);
//findServiceOther(gatt);
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
Log.d(TAG, "Request MTU");
gatt.requestMtu(SET_MTU);
} else {
Log.w(TAG, "onServicesDiscovered failed: (status)" + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onCharRead Success");
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
} else {
Log.d(TAG, "OnCharRead Error: " + status);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (characteristic.getUuid().equals(SampleGattAttributes.UUID_HEART_RATE_MEASUREMENT))
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic, FLAG_HEART_RATE);
else
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
#Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
boolean priority = gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
Log.d(TAG, "MTU changed (mtu/status) / Priority : (" + mtu + "/" + status + ") / " + priority);
changed_MTU_Size = mtu;
broadcastUpdate(ACTION_DATA_AVAILABLE, changed_MTU_Size, FLAG_MTU);
broadcastUpdate(ACTION_GATT_CONNECTED);
}
#set notification
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
if (SampleGattAttributes.UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
// This is specific to Heart Rate Measurement.
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(SampleGattAttributes.UUID_CLIENT_CHARACTERISTIC_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
Edit_1
I test Nordic offical app in Google play store.
nRF Connect for Mobile
but this app miss packet too.
Edit_2
I found some problem too.
< Nordic board constant setting>
HEART_RATE_MEAS_INTERVAL : 10
MIN_CONN_INTERVAL : MSEC_TO_UNITS(40, UNIT_1_25_MS)
MAX_CONN_INTERVAL : MSEC_TO_UNITS(40, UNIT_1_25_MS)
SLAVE_LATENCY 0
CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
< Run in my Android app >
skip requestMTU : receive 20byte packet successful. (Data rate average is 2200byte/second in my app)
requestMTU : I try so many MTU size (ex: 23(can small size), 40, 100, 255(target) ...) but lost some packet (Data rate 8500 ~ 9500 byte/second in my app)
I wonder requestMTU and notification receive interrelation.
i have implemented a file transfer over LE on a nrf51422 and SD310 by using the Nordic UART Service. The android App is written in CPP by using Qt and the QtBluetooth library. Therefore, this answer my not really help you. But, i have taken some afford to achive a usable data rate. 1st, set the connection parameters to 7.5ms (min) and 15ms (max). 2nd, on the peripheral side, i send up to 7 packets (til the buffer is full). So the peripheral send up to 7 packets per connection event.
On the Android side, the charachteritic changed event arrive me frequently with a data size of 20 bytes (due to the maximum MTU size of 23, 3 bytes used by nordic uart service) and i read the data instantly.
Perhaps your mistake is the MTU size of 244. The default BLE MTU size is 23 (Core spec 4.1).
Regards

mBluetoothGatt.getService(uuid) returns null

In my app , i am passng the UUID number of the hearing aid service as in the BLE sample from google i.e. 0000a00-0000-1000-8000-00805f9b34fb
But the getservice returns null means that the service is not supported by the BluetoothGatt .
Why is this happening , can anybody please help me .
You have to first discover all services for the given device per documentation.
This function requires that service discovery has been completed for the given device.
http://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getService(java.util.UUID)
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService mBluetoothGattService = mBluetoothGatt.getService(UUID.fromString(serviceUUID));
if (mBluetoothGattService != null) {
Log.i(TAG, "Service characteristic UUID found: " + mBluetoothGattService.getUuid().toString());
} else {
Log.i(TAG, "Service characteristic not found for UUID: " + serviceUUID);
}
}
Or you can just run a search
for (BluetoothGattService gattService : gattServices) {
Log.i(TAG, "Service UUID Found: " + gattService.getUuid().toString());
}
Try doing a full discover[1] of the remote database and then iterate through the services. Maybe you've got the UUID wrong.
[1] http://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#discoverServices()
Your UUID is also wrong. It should be 0000a00X-0000-1000-8000-00805f9b34fb, not 0000a00-0000-1000-8000-00805f9b34fb

Categories

Resources