0
votes

I'm new to Android. I'm trying to subscribe characteristic notifications from 2 BLE devices. Now, my App can only receive the BLE data from the 1st device. I understand that BLE is serial communication, so I must wait until the onDescriptorWrite() callback is called before I enable the notification for the 2nd device. We can ONLY have 1 GATT operation each time. My questions are:

  1. How to modify the onDescriptorWrite()? Thread.sleep() delay method doesn't help.

  2. Some people mentioned to use queue to add/remove something?

     public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled,int device) {
     if (mBluetoothAdapter == null || mBluetoothGatt == null || mBluetoothGatt1 == null) {
         Log.e(TAG, "BluetoothAdapter not initialized");
         return;
     }
     if(device == 0) {
         mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
         BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
         descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
         mBluetoothGatt.writeDescriptor(descriptor);
         try {
             Thread.sleep(100);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         Log.e(TAG,"Device #0 is done for notification!");
     }
     else if(device == 1){
         mBluetoothGatt1.setCharacteristicNotification(characteristic,enabled);
         BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
         descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
         mBluetoothGatt.writeDescriptor(descriptor);
         try {
             Thread.sleep(100);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         Log.e(TAG,"Device #1 is done for notification!");
     }
    

    }

     private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
     @Override
     public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
         String intentAction;
         if (newState == BluetoothProfile.STATE_CONNECTED) {
             intentAction = ACTION_GATT_CONNECTED;
             mConnectionState = STATE_CONNECTED;
             broadcastUpdate(intentAction);
             Log.e(TAG, "Connected to GATT server #0.");
             // Attempts to discover services after successful connection.
             Log.e(TAG, "Attempting to start service discovery #0:" + mBluetoothGatt.discoverServices());
    
         } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
             intentAction = ACTION_GATT_DISCONNECTED;
             mConnectionState = STATE_DISCONNECTED;
             Log.e(TAG, "Disconnected from GATT server #0.");
             broadcastUpdate(intentAction);
         }
     }
    
     @Override
     public void onServicesDiscovered(BluetoothGatt gatt, int status) {
         if (status == BluetoothGatt.GATT_SUCCESS) {
             broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
         } else {
             Log.e(TAG, "onServicesDiscovered received: " + status);
         }
     }
    
     @Override
     public void onCharacteristicRead(BluetoothGatt gatt,
                                      BluetoothGattCharacteristic characteristic,
                                      int status) {
         if (status == BluetoothGatt.GATT_SUCCESS) {
             broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic,0);
         }
         try {
             Thread.sleep(700);
         }catch(InterruptedException ex) {
             Thread.currentThread().interrupt();
         }
         Log.e(TAG,"onCHAR READ");
     }
    
     @Override
     public void onCharacteristicChanged(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic) {
         broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic,0);
         try {
             Thread.sleep(700);
         }catch(InterruptedException ex) {
             Thread.currentThread().interrupt();
         }
         Log.e(TAG,"onCharacteristicChanged #0 = ACTION_DATA_AVAILABLE, Done! ");
     }
    
     @Override
     public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
         super.onDescriptorWrite(gatt, descriptor, status);
    
         // Do something here ????????????
    
         // Thread.sleep() delay method doesn't help
         try {
             Thread.sleep(700);
         }catch(InterruptedException ex) {
             Thread.currentThread().interrupt();
         }
         Log.e(TAG,"onDescriptorWrite #0, Done! ");
     }
    

    };

1
Does onDescriptorWrite get called after you enabled the notifications for the first characteristic?Michael Kotzjan
Hi @M. Kotzjan , Thanks for your support. Yes, onDescriptorWrite() is called for the 1st characteristic. That's why I can receive 1 BLE device data.Steven Wang
Please never use delays/sleep like tihs in BLE code. It will never help you in a correct way. Anyway, the rule of only having one pending operation in progress is per BluetoothGatt object, so you can safely have two pending operations in parallel if they are to one device each.Emil

1 Answers

0
votes
 mBluetoothGatt1.setCharacteristicNotification(characteristic,enabled);
 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
 descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
 mBluetoothGatt.writeDescriptor(descriptor);

I think that should be:

 mBluetoothGatt1.setCharacteristicNotification(characteristic,enabled);
 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
 descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
 mBluetoothGatt1.writeDescriptor(descriptor);