Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable multiple BLE characteristic notifications on Xamarin/Android?

I am trying to enable notifications for more than one BLE characteristic using Xamarin/Android but seem unable to do so. The app seems to stop receiving any BLE events if I try and enable more than one at a time.

Can anyone confirm whether this is possible using Tamarin/Android. We have a native iOS app that works just fine with multiple notifications enabled. The basic steps we use are as follows:

  1. Scan for device
  2. Connect to device
  3. Discover services
  4. For each discovered service iterate through characteristics and enable the ones that are required
  5. Process each asynchronous callback event in the BLE callback

Any time we try and enable notifications on more than one characteristic we no longer receive any events.

I have also been unable to find any examples where more than one characteristic is being enabled.

I hope I have simply missed something fundamental about using the Xamarin/Android APIs here.

public override void OnServicesDiscovered (BluetoothGatt gatt, GattStatus status)
{
    base.OnServicesDiscovered (gatt, status);
    foreach (BluetoothGattService service in gatt.Services) {
        string uuid = service.Uuid.ToString ().ToUpper();
        if (uuid.Equals (BLEServices.HRService.ToUpper())) {
            _Adap.LogMessage ("HRService discovered");
            foreach(BluetoothGattCharacteristic characteristic in service.Characteristics) {
                string c_uuid = characteristic.Uuid.ToString ().ToUpper ();
                _Adap.LogMessage (" HRCharacteristic: " + c_uuid);

                if (c_uuid.Equals(_Adap.useCharacteristic.ToUpper())) {
                    _Adap.LogMessage ("  enabling HRCharacteristic");
                    gatt.SetCharacteristicNotification(characteristic, true);
                    BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor (Java.Util.UUID.FromString (BLEServices.CLIENT_CHARACTERISTIC_CONFIG), GattDescriptorPermission.Write | GattDescriptorPermission.Read);
                    characteristic.AddDescriptor (descriptor);
                    descriptor.SetValue (BluetoothGattDescriptor.EnableNotificationValue.ToArray ());
                    gatt.WriteDescriptor (descriptor);
                    _Adap.StartTimer ();
                }
            }

        } else if (uuid.Equals (BLEServices.BatteryService.ToUpper())) {
            _Adap.LogMessage ("BatteryService discovered");
            foreach (BluetoothGattCharacteristic characteristic in service.Characteristics) {
                string c_uuid = characteristic.Uuid.ToString ().ToUpper ();
                _Adap.LogMessage (" BatteryService: " + c_uuid);

                if (c_uuid.Equals (_Adap.useCharacteristic.ToUpper ())) {
                    _Adap.LogMessage ("  reading batteryCharacteristic");
                    // This may only be reported when the battery level changes so get the level first by doing a read
                    gatt.ReadCharacteristic (characteristic);

                    //gatt.SetCharacteristicNotification (characteristic, true);
                    //BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor (Java.Util.UUID.FromString (BLEServices.CLIENT_CHARACTERISTIC_CONFIG), GattDescriptorPermission.Write | GattDescriptorPermission.Read);
                    //characteristic.AddDescriptor (descriptor);
                    //descriptor.SetValue (BluetoothGattDescriptor.EnableNotificationValue.ToArray ());
                    //gatt.WriteDescriptor (descriptor);
                }
            }
        } else if (uuid.Equals (BLEServices.DeviceInfoService.ToUpper())) {
            _Adap.LogMessage ("DeviceInfoService discovered");
            foreach (BluetoothGattCharacteristic characteristic in service.Characteristics) {
                string c_uuid = characteristic.Uuid.ToString ().ToUpper ();
                _Adap.LogMessage (" DeviceInfoService: " + c_uuid);
                if (c_uuid.Equals (BLEServices.kModelNumberCharacteristicUuidString.ToUpper ())) {
                    //gatt.ReadCharacteristic (characteristic);
                }
            }
        } else if (uuid.Equals (BLEServices.kHxM2CustomServiceUuidString.ToUpper())) {
            _Adap.LogMessage ("HxM2CustomService discovered");
            foreach (BluetoothGattCharacteristic characteristic in service.Characteristics) {
                string c_uuid = characteristic.Uuid.ToString ().ToUpper ();
                _Adap.LogMessage (" HxM2CustomCharacteristic: " + c_uuid);

                if (c_uuid.Equals (_Adap.useCharacteristic.ToUpper ())) {
                    _Adap.LogMessage ("  enabling HxM2 characteristic: "+_Adap.useCharacteristic);
                    gatt.SetCharacteristicNotification (characteristic, true);
                    BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor (Java.Util.UUID.FromString (BLEServices.CLIENT_CHARACTERISTIC_CONFIG), GattDescriptorPermission.Write | GattDescriptorPermission.Read);
                    characteristic.AddDescriptor (descriptor);
                    descriptor.SetValue (BluetoothGattDescriptor.EnableNotificationValue.ToArray ());
                    gatt.WriteDescriptor (descriptor);
                    // Start a timer to make sure that we can recover if we never receive any data from the device
                    _Adap.StartTimer ();
                }

            }
        } else {
            _Adap.LogMessage ("Unknown Service "+uuid+" discovered");
        }
    }
}

Can anyone explain what the following lines are for

BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor (Java.Util.UUID.FromString (BLEServices.CLIENT_CHARACTERISTIC_CONFIG), GattDescriptorPermission.Write | GattDescriptorPermission.Read);
characteristic.AddDescriptor (descriptor);
descriptor.SetValue (BluetoothGattDescriptor.EnableNotificationValue.ToArray ());
gatt.WriteDescriptor (descriptor);
like image 592
Duncan Groenewald Avatar asked Apr 11 '16 03:04

Duncan Groenewald


1 Answers

Beside your found solution: Be aware, that you can't listen to an unlimited number of characteristics. The maximum is limited hardcoded in the android source to BTA_GATTC_NOTIF_REG_MAX.

  • Android >= 4.3: 4 http://androidxref.com/4.3_r2.1/xref/external/bluetooth/bluedroid/bta/gatt/bta_gattc_int.h#301
  • Android >= 4.4: 7 http://androidxref.com/4.4.4_r1/xref/external/bluetooth/bluedroid/bta/gatt/bta_gattc_int.h#333
  • Android >= 5.0: 15 http://androidxref.com/5.0.0_r2/xref/external/bluetooth/bluedroid/bta/gatt/bta_gattc_int.h#345

So your app should not rely on more than the maximum number of notifying characteristics of your minimum supported android version.

like image 95
Sven-Michael Stübe Avatar answered Nov 01 '22 14:11

Sven-Michael Stübe