B4A Library [B4X] BLE 2 - Bluetooth Low Energy

Status
Not open for further replies.
This library replaces the previous BLE library.
It is simpler to use and it is more powerful. Its API is based on B4i iBLE library which makes it easy to reuse B4i code.

See the iBLE tutorial: https://www.b4x.com/android/forum/threads/ble-bluetooth-low-energy-library.46099/#content

Tips & Notes

- You can call Manager.Scan2 with AllowDuplicates set to True if you want to monitor the state of an unconnected device.
- The AdvertisingData map in DeviceFound event holds pairs of integers as keys (data types) and bytes arrays as values.
- Call ReadData2 if you are only interested in a single characteristic.
- BLE is only supported on Android 4.3+.

See the attached example. Note that the important code in in the Starter service module.

Edit:

A new version of BLE_Example was uploaded. targetSdkVersion is now set to 29
Setting the targetSdkVersion to 29 requires some changes:

1. Add the fine location permission in the manifest editor.
2. Request this permission with RuntimePermissions.

Otherwise scanning will fail with a message visible in the unfiltered logs.

BLE2 is an internal library now. It is included in the IDE.

Example is based on B4XPages and will work with B4A and B4i.

Updates:
- Example updated with targetSdkVersion = 31. Note the permissions in the manifest editor:
B4X:
AddPermission(android.permission.ACCESS_FINE_LOCATION)
AddPermission(android.permission.BLUETOOTH_SCAN)
AddPermission(android.permission.BLUETOOTH_CONNECT)
And requesting at runtime:
B4X:
Dim Permissions As List
Dim phone As Phone
If phone.SdkVersion >= 31 Then
    Permissions = Array("android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT", rp.PERMISSION_ACCESS_FINE_LOCATION)
Else
    Permissions = Array(rp.PERMISSION_ACCESS_FINE_LOCATION)
End If
For Each per As String In Permissions
    rp.CheckAndRequest(per)
    Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
    If Result = False Then
        ToastMessageShow("No permission: " & Permission, True)
        Return
    End If
Next
 

Attachments

  • BLEExample.zip
    181.6 KB · Views: 1,815
Last edited:

ncabilis

Member
Licensed User
Longtime User
Hello Erel
Today I was update android to Marshmallow (Motorola Moto g 2nd gen). From that time BLE2 is not working. The same happens with the library BleExt, so all my programs based on Ble not working. What can i do with this problem?
 

freedom2000

Well-Known Member
Licensed User
Longtime User
Hi

I have tested on an old Samsung Galaxy S3 with cyanogen ROM Marshmallow and BLE2 works (surprisingly for me)
 

ncabilis

Member
Licensed User
Longtime User
Okay, I made it working. I used the class MPermission.bas (https://www.b4x.com/android/forum/threads/marshmallow-permissions.58379/) and in manifest editor i add these commands: AddPermission(android.permission.ACCESS_COARSE_LOCATION)
AddPermission(android.permission.ACCESS_FINE_LOCATION).
Then on Activity_Create:
Permission.Initialize
If Permission.CheckPermission ("android.permission.ACCESS_COARSE_LOCATION") = False Then
Permission.RequestPermission ("android.permission.ACCESS_COARSE_LOCATION")
End If

If Permission.CheckPermission ("android.permission.ACCESS_FINE_LOCATION") = False Then
Permission.RequestPermission ("android.permission.ACCESS_FINE_LOCATION")
End If
All apps (BLE based) now work fine.

I forgot to mention that i have to enable Location in Phone System Settings
 
Last edited:

freedom2000

Well-Known Member
Licensed User
Longtime User

ncabilis

Member
Licensed User
Longtime User
I used
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23"/>
so in Marshmallow with sdk 23 i need to activate Location, otherwise app stop responding.
 

freedom2000

Well-Known Member
Licensed User
Longtime User
I used
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23"/>
so in Marshmallow with sdk 23 i need to activate Location, otherwise app stop responding.
Thank you for the advice.

I still have my Galaxy S5 stuck on Lollipop (thank you Samsung :mad:)
 

ncabilis

Member
Licensed User
Longtime User
Unfortunately, as developers, we need to respond to changes in the operating system...
 

Turbo3

Active Member
Licensed User
Longtime User
I need to send 22 bytes of data which is more data then will fit in one Writedata transfer which is limited to 20 bytes. To do this I send one transfer of 20 bytes followed by a second writedata of 2 bytes but the second writedata can not take place until the first write has completed. If the second writedata is executed before the first completes the app crashes with a write error. To avoid overrunning the first writedata I currently use a timer to wait 350 msecs before sending the second writedata. This does not seem like a good way to handle this.

Is there a way to detect when the Bluetooth controller has received the write response message signaling that the first writedata has completed? Keep in mind a notification is only sent back after the full 22 bytes have been received by the target device. So I can not use the DataAvailable event which I normally use to trigger when next the writedata can be sent.

I have been using WireShark to examine the btsnoop_hci.log files of the Bluetooth traffic to verify this behavior. On the trace I can see the Write Request going out followed by the the inbound "Number of Completed Packets" and "Write Response" sent from the controller to the host. I just need some way to see this in my app.
 

Turbo3

Active Member
Licensed User
Longtime User
V1.30 with retries causes my app to become unresponsive. I can still see all my debug messages from the Service code and the "retries: 4" down to "retries: 1" messages on the log screen. Eventually I get the "TM-Spy isn't responding. Do you want to close it?" message.

Looks like while you retry you are taking all the cycles not leaving any for the foreground process that handles user input and screen updates.

What was the version number of the latest code without retry? I need to put that one back.

Or provide a way to disable auto retry. I had my code working with my app handling the retry. Strange I don't have this problem on the iOS version that uses BLE 1.31. I only see these false write errors with B4A. I say false because I see the WriteComplete event shortly after the write error message with a status of 0.

Ok, I put back v1.21 and things are working again.
 
Last edited:

Turbo3

Active Member
Licensed User
Longtime User
The way my code works (same for iOS and Android) is a command is sent (WriteData) and then it waits for DataAvailable with a ">" response before sending the next command. But in the following log trace you can see that the WriteComplete event is delayed in some cases not showing up until after DataAvailable. This, I think, is causing the write failures.

B4X:
|Rcvd=> OK
|Rcvd=> >
|====> WriteData ATxxxx
|++++> Write Complete 0  0000ffe1-0000-1000-8000-00805f9b34fb
|Rcvd=> OK
|Rcvd=> >
|====> WriteData ATxxxx
|++++> Write Complete 0  0000ffe1-0000-1000-8000-00805f9b34fb
|Rcvd=> OK
|Rcvd=> >
|====> WriteData ATxxxx
|++++> Write Complete 0  0000ffe1-0000-1000-8000-00805f9b34fb
|Rcvd=> OK
|Rcvd=> >
|====> WriteData ATxxxx
|Rcvd=> OK
|Rcvd=> >
|====> WriteData ATxxxx
|++++> Write Complete 0  0000ffe1-0000-1000-8000-00805f9b34fb
|++++> Write Complete 0  0000ffe1-0000-1000-8000-00805f9b34fb
|Rcvd=> SEARCHING...
|====> WriteData ATxxxx
|++++> Write Complete 0  0000ffe1-0000-1000-8000-00805f9b34fb
|Rcvd=> STOPPED
|Rcvd=> >
|====> WriteData ATxxxx
|Rcvd=> ?
|Rcvd=> >
|====> WriteData ATxxxx
Write Fail: java.lang.RuntimeException: Error writing data to: 0000ffe1-0000-1000-8000-00805f9b34fb
|++++> Write Complete 0  0000ffe1-0000-1000-8000-00805f9b34fb
|Rcvd=> OK
|Rcvd=> >

In this example you can see two back to back Write Completes and above it two responses from the device ending with the ">" response that enables the next Write Data.

So how can the device receive, decode and respond to the Write Data and send back two responses to my app before the Write Complete event for the write data is given to my app.

Later you can see the Write Fail followed by the Write Complete. There is a race condition which should not be happening. The Write Complete event should always occur before the device has time to send back two data packets for that write.

I am taking a btsnoop_hci.log to see what is actually happening at that level.
 
Last edited:

Turbo3

Active Member
Licensed User
Longtime User
The btsnoop_hci.log reveals the real problem and it is not Erel's. There are cases when the device sends back two ">" characters for one Write Data command. This causes the app to send two back to back Write Data commands which most times results in the Write Failure.

I will need to come up with a way to handle this in the app.
 

Turbo3

Active Member
Licensed User
Longtime User
I have things working with version 1.21. But a few write failures are just unavoidable and are handled with Try Catch code.

When I switch back to 1.30 the auto retry you added still gets stuck in a loop with almost endless retries that hang the foreground process.

Can you explain why you think you need to do auto retry on write failures?

I think it is much safer to let the app handle this with a Try Catch statement. That way the correct method can be used to fix or handle the problem.

If there is some reported problem you are fixing with the auto retry code then please add the option for coders to disable it. Hanging the foreground process is a real killer for an app. Otherwise I am going to be stuck at version 1.21.
 
Status
Not open for further replies.
Top