Android Question [SOLVED] BLE connection problems

wes58

Active Member
Licensed User
I have tried the code from the old example https://www.b4x.com/android/forum/threads/ble2-old-example.132966/post-839937 and I have problems with the connection to the BLE device.
I searched the forum and found many posts with similar issue but I couldn't find any solution.

I tried to connect to the device using "nRF Connect" and "BLE Scanner" android applications and they connect without problem.
I logcat output from nRF Connect app and my (B4A) app, and below are the results:
nRF Connect:
2021-08-04 15:26:34.509 5373-5373/? D/BluetoothGatt: connect() - device: A4:C1:38:EF:9E:A8, auto: false
2021-08-04 15:26:34.518 8183-10017/? D/BtGatt.GattService: clientConnect(no.nordicsemi.android.mcp) - address = EF:9, isDirect=true transport =2 set own addr = false own addr type:0, clientIf: 11, opportunistic=false, phy: 1
2021-08-04 15:26:34.546 1273-2026/? D/SLocation: BluetoothStatusMonitor - sgfm received : android.bluetooth.device.action.ACL_CONNECTED
2021-08-04 15:26:34.546 8183-8311/? W/bt_btif: BTA_DM_BUSY_LEVEL_EVT :: p_data->busy_level.level_flags : 0x0, spen_connected : 0 0
2021-08-04 15:26:34.546 1803-1957/? V/BluetoothEventManager: onReceive :: android.bluetooth.device.action.ACL_CONNECTED
my app:
2021-08-04 15:16:57.819 26326-26326/? I/B4A: ~l451441796: Device Selected: ATC_1958H9 (A4:C1:38:EF:9E:A8)
2021-08-04 15:16:57.819 26326-26326/? I/B4A: ~l551900545:name ATC_1958H9, Id A4:C1:38:EF:9E:A8
2021-08-04 15:16:58.835 8183-8201/? D/BtGatt.GattService: registerClient(b4a.ble3) - UUID=aee82138-b616-4aea-81eb-c1c719681db5
2021-08-04 15:16:58.839 8183-8201/? D/BtGatt.ContextMap: add() - appUid: 10372, appPid: 26326, appName: b4a.ble3
2021-08-04 15:16:58.849 8183-8201/? D/BtGatt.GattService: clientConnect(b4a.ble3) - address = EF:9, isDirect=false transport =0 set own addr = false own addr type:0, clientIf: 11, opportunistic=false, phy: 1
2021-08-04 15:16:58.858 8183-8201/? D/BtGatt.GattService: unregisterClient(b4a.ble3) - clientIf=11
2021-08-04 15:16:58.859 26326-26326/? I/B4A: ~l652162689: Disconnected
The only differences that I can see in BtGatt.GattService: clientConnect are transport= isDirect=true (for nRF) and isDirect=false (for B4A), transport=2 (for nRF) transport= 0 (for B4A)
I don't know what "transport" is but can this be an issue?
How to change it to "2"?
Any suggestions are welcome.

Edit:
One other thing:
When I connect to the unpaired device with nRF Connect app - I get pop up to pair the device with the phone. In my (B4A) app - no such pop up with unpaired device!

Searching the internet I have found definition of the "transport"
#define BT_TRANSPORT_AUTO 0
#define BT_TRANSPORT_BR_EDR 1
#define BT_TRANSPORT_LE 2
So value 2 is for BLE

Also this code:
Java:
/*******************************************************************************
 *
 * Function         GATT_Connect
 *
 * Description      This function initiate a connecttion to a remote device on
 *                  GATT channel.
 *
 * Parameters       gatt_if: applicaiton interface
 *                  bd_addr: peer device address.
 *                  is_direct: is a direct conenection or a background auto
 *                             connection
 *
 * Returns          true if connection started; false if connection start
 *                  failure.
 *
 ******************************************************************************/
bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct,
                  tBT_TRANSPORT transport, bool opportunistic) {
  uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
  return GATT_Connect(gatt_if, bd_addr, is_direct, transport, opportunistic,
                      phy);
}

bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct,
                  tBT_TRANSPORT transport, bool opportunistic,
                  uint8_t initiating_phys) {
  /* Make sure app is registered */
  tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
  if (!p_reg) {
    LOG(ERROR) << __func__
               << ": Unable to find registered app gatt_if=" << +gatt_if;
    return false;
  }

  if (!is_direct && transport != BT_TRANSPORT_LE) {
    LOG(ERROR) << __func__
               << ": Unsupported transport for background connection gatt_if="
               << +gatt_if;
    return false;
  }

  if (opportunistic) {
    LOG(INFO) << __func__
              << ": Registered for opportunistic connection gatt_if="
              << +gatt_if;
    return true;
  }

  bool ret;
  if (is_direct) {
    LOG_DEBUG("Starting direct connect gatt_if=%u address=%s", gatt_if,
              bd_addr.ToString().c_str());
    ret = gatt_act_connect(p_reg, bd_addr, transport, initiating_phys);
  } else {
    LOG_DEBUG("Starting background connect gatt_if=%u address=%s", gatt_if,
              bd_addr.ToString().c_str());
    if (!BTM_BackgroundConnectAddressKnown(bd_addr)) {
      //  RPA can rotate, causing address to "expire" in the background
      //  connection list. RPA is allowed for direct connect, as such request
      //  times out after 30 seconds
      LOG(INFO) << __func__
                << ": Unable to add RPA to background connection gatt_if="
                << +gatt_if;
      ret = true;
    } else {
      LOG_DEBUG("Adding to acceptlist device:%s", PRIVATE_ADDRESS(bd_addr));
      ret = connection_manager::background_connect_add(gatt_if, bd_addr);
    }
  }

  tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
  // background connections don't necessarily create tcb
  if (p_tcb && ret)
    gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, !is_direct);

  return ret;
}
From line 35 the code is like this:
Java:
  if (!is_direct && transport != BT_TRANSPORT_LE) {
    LOG(ERROR) << __func__
               << ": Unsupported transport for background connection gatt_if="
               << +gatt_if;
    return false;
  }
So, in case of B4A app - is_direct = false and transport = 0 (not 2, which might cause it fail. Probably? )
 
Last edited:

wes58

Active Member
Licensed User
Erel, here is the code that is used to call connectGatt function in nRF Connect app:
Java:
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
            // connectRequest will never be null here.
            final int preferredPhy = connectRequest.getPreferredPhy();
            log(Log.DEBUG, "gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, "
                    + ParserUtils.phyMaskToString(preferredPhy) + ")");

            bluetoothGatt = device.connectGatt(context, false, gattCallback,
                    BluetoothDevice.TRANSPORT_LE, preferredPhy, handler);
        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
            // connectRequest will never be null here.
            final int preferredPhy = connectRequest.getPreferredPhy();
            log(Log.DEBUG, "gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, "
                    + ParserUtils.phyMaskToString(preferredPhy) + ")");
            // A variant of connectGatt with Handled can't be used here.
            // Check https://github.com/NordicSemiconductor/Android-BLE-Library/issues/54
            // This bug specifically occurs in SDK 26 and is fixed in SDK 27
            bluetoothGatt = device.connectGatt(context, false, gattCallback,
                    BluetoothDevice.TRANSPORT_LE, preferredPhy/*, handler*/);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            log(Log.DEBUG, "gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE)");
            bluetoothGatt = device.connectGatt(context, false, gattCallback,
                    BluetoothDevice.TRANSPORT_LE);
        } else {
            log(Log.DEBUG, "gatt = device.connectGatt(autoConnect = false)");
            bluetoothGatt = device.connectGatt(context, false, gattCallback);
        }
        return true;
So they are using function call public BluetoothGatt connectGatt (Context context, boolean autoConnect, BluetoothGattCallback callback, int transport) ,or another one depending on the SDK
You in your ble2 library use the function call without BluetoothTransports - public BluetoothGatt connectGatt (Context context, boolean autoConnect, BluetoothGattCallback callback)

And the difference is, that the function you are using was added in API level 18. The one used by nRF Connect was added in API level 23, There is also a newer one, added in API level 26 - public BluetoothGatt connectGatt (Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)
So you can see the difference. If they added them, they did it for a reason!
 
Upvote 0

wes58

Active Member
Licensed User
Debugging old examples is a waste of time.

First step is to run this example and post the results: https://www.b4x.com/android/forum/threads/b4x-ble-2-bluetooth-low-energy.59937/#content
I am not sure what you expect that this example (with B4XPages) will change. It is using the same BLE2 library and the same function calls. But, since I wasted 2 days I thought I can waste another couple of hours.
So to run this example I had to install the latest version of B4A, because v9.9 I am using doesn't work with this example.
So after installing and trying to compile this example I get an error:
Signing package file (private key). Error
Unsupported option: --v3-signing-enabled. See --help for supported options.
So I give up. Looking on the forum - solution update SDK to 30.

Instead I wrote a simple Android app in Android Studio and did the test with 2 options:
1 Using function without using BluetoothTransport:
bluetoothGatt = devicesDiscovered.get(deviceSelected).connectGatt(this, false, btleGattCallback);
Result - doesn't connect to my BLE device

2 Using function which use BluetoothTransport = 2:
bluetoothGatt = devicesDiscovered.get(deviceSelected).connectGatt(this, false, btleGattCallback, 2);
Result - connect to my BLE device.
So, I have no doubt, that this is a reason why I couldn't connect using BLE2 library.
So it is up to you, if you want to modify the library to add another connect function with bluetooth transport paramter.

And by the way, Android Studio, doesn't have a problem with the same signing key I use in B4A app. I can select any SDK and not limited to SDK30.
 
Upvote 0

wes58

Active Member
Licensed User
I have compiled BLE2 library with the connectGatt function that uses BluetoothTransport and set it to 2. And now I don't have any problems with connection to my device.
I did it just to test it, but the correct way to compile this library would be to add a new connect method with the BluetoothTransport parameter that can be set in B4A.
 
Upvote 0

emexes

Expert
Licensed User
But, since I wasted 2 days I thought I can waste another couple of hours.
If it's any consolation, you're not alone in having reached this point of a chase. 🍻

Bonus points for verifying that issue has indeed been resolved. More than once I have thought I've fixed something, only to find... nope, nice try but no cigar. :confused:
 
Upvote 0

Erel

Administrator
Staff member
Licensed User
So to run this example I had to install the latest version of B4A, because v9.9 I am using doesn't work with this example.
So after installing and trying to compile this example I get an error:
So I give up. Looking on the forum - solution update SDK to 30.
Just follow the installation instructions: https://www.b4x.com/b4a.html
 
Upvote 0
Top