Search code examples
androidbluetooth-lowenergygatt

Android Central with GattServer


I'm trying to program Bluetooth low energy - AlertNotificationService (ANS). It is a bit weird service because typically services run on GAP peripheral. But ANS run on GAP central. So typical way of working shall be for example this:

Watch - GAP peripheral (broadcasting), GATT client
Phone - GAP central                  , GATT server

Basically it works for me but not always. And this instability is very strange to me. When I look with bluetooth LE analyzer I see that Android GATT server sometimes tells there are no characteristic in my profile...

It looks like this: "watch" ask for my GATT service (I know it is proprietary not ANS UUID)

Slave->Master ATT Rcvd Find By Type Value Request, GATT Primary Service Declaration 11:22:33:44:11:22:33:44:11:76:62:65:01:00:00:00

Phone says the service is there starting from handle 0x35

Master->Slave ATT Rcvd Find By Type Value Response Handle: 0x0035

Watch ask for charactersitisc from handle 0x35

Slave->Master ATT Rcvd Read By Type Request, GATT Characteristic Declaration, Handles: 0x0035..0xffff

But phone sometimes incorrectly says that there is no characteristic from that handle:

Master->Slave ATT Rcvd Error Response - Attribute Not Found, Handle: 0x0035

When I do add service and characteristic into GATT server I always get "true" from functions. I do it like this:

BluetoothGattService service =new BluetoothGattService(Vbe_AnsExt.UUID_SERVICE,
        BluetoothGattService.SERVICE_TYPE_PRIMARY);

BluetoothGattCharacteristic characApp =
        new BluetoothGattCharacteristic(Vbe_AnsExt.UUID_CharacApp,
                BluetoothGattCharacteristic.PROPERTY_READ ,
                BluetoothGattCharacteristic.PERMISSION_READ);

BluetoothGattCharacteristic characMsg =
        new BluetoothGattCharacteristic(Vbe_AnsExt.UUID_CharacMsg,
                BluetoothGattCharacteristic.PROPERTY_READ ,
                BluetoothGattCharacteristic.PERMISSION_READ );

boolean ret;
ret = service.addCharacteristic(characApp);
Log.i("vbeInit_ASN_Ext_Server","addCharApp  retruned: "+ret);
ret = service.addCharacteristic(characMsg);
Log.i("vbeInit_ASN_Ext_Server","addCharMsg  retruned: "+ret);

ret = mGattServer.addService(service);
Log.i("vbeInit_ASN_Ext_Server","addService  retruned: "+ret);

Any idea what might be the problem? I noticed that there is function BluetoothGattServer::connect(). I'm not sure how to use it. I'm using standard BluetoothDevice::connectGatt(). But I guess if I would do something wrong it shall work never - not sometimes... I'm using Android M (6.0.1) on Samsung SM-G920F.

[UPDATE]

I noticed that after phone restart it always works. After application close and reopen it usually does not works. It does not works in different ways ->

  • sometimes no characteristic is found;
  • sometimes only first characteristic is found
  • sometimes only last(second) characteristic is found.

When I start Gatt Server I do it like this:

mGattServer = bluetoothManager.openGattServer(appContext, mGattServerCallback);
mGattServer.clearServices();

When I close app (onDestroy()) I do close gattserver:

mGattServer.close();

I also tried not to close the GATT server, but it did not help. Any ideas what might get wrong between closing and reopening?


Solution

  • So I may have found the reason. I'm adding 2 services: ANS and my service ANS_extension. It seems it helps when I wait after adding the service on call back onServiceAdded()

    So now it looks like this:

    public static UUID UUID_SupportedNewAlertCategory     = UUID.fromString("00002a47-0000-1000-8000-00805f9b34fb");
    public static UUID UUID_NewAlert                      = UUID.fromString("00002a46-0000-1000-8000-00805f9b34fb");
    // descriptor used for enabling notify feature
    public static UUID UUID_Descr_new                     = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    mGattServer = bluetoothManager.openGattServer(appContext, mGattServerCallback);
    mGattServer.clearServices();
    waitServiceAdded = true;
    BluetoothGattService service = new BluetoothGattService(Vbe_Ans.UUID_SERVICE,
                    BluetoothGattService.SERVICE_TYPE_PRIMARY);
    
    BluetoothGattCharacteristic characSupportedNewAlerCategory =
                    new BluetoothGattCharacteristic(Vbe_Ans.UUID_SupportedNewAlertCategory,
                            BluetoothGattCharacteristic.PROPERTY_READ ,
                            BluetoothGattCharacteristic.PERMISSION_READ);
    BluetoothGattCharacteristic characNewAlert =
                    new BluetoothGattCharacteristic(Vbe_Ans.UUID_NewAlert,
                            BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
                            BluetoothGattCharacteristic.PERMISSION_READ );
    BluetoothGattDescriptor bgd = new BluetoothGattDescriptor(UUID_Descr_new,
                    BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE);
    
    characNewAlert.addDescriptor(bgd);
    ...
    ret = service.addCharacteristic(characSupportedNewAlerCategory);
    ret = service.addCharacteristic(characNewAlert);
    ...
    ret = mGattServer.addService(service);
    while(waitServiceAdded);
    
    waitServiceAdded = true;
    //init second service similar way as previous
    while(waitServiceAdded);
    

    Then I clear waiting flag waitServiceAdded in GATT server call back. (I'm java newbie so you might want to use some thread mutex synchro to access boolean?)

    private BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {
    @Override
      public void onServiceAdded (int status,
                                        BluetoothGattService service){
        waitServiceAdded = false;
      }