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.
 

Attachments

  • BLEExample.zip
    181.5 KB · Views: 516
Last edited:

Turbo3

Active Member
Licensed 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
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
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.
 

Erel

Administrator
Staff member
Licensed User

Turbo3

Active Member
Licensed User
I really need to be able to disable retries and handle them in my code if and when they are needed.

The fact that the automatic retries are capable of hanging the foreground process is a no-go for me. It is just too dangerous to have enabled. Not being able to exit my app because auto retry has taken over is not something I ever expected.

Can you say a little more then "retries are important" or is it some how proprietary?

Are you doing auto retry in the iOS version of BLE which has given me no problems. The iOS version of my app has been released for many months now with no problems from any of my many users using the same device I am testing with the Android version.
 

Erel

Administrator
Staff member
Licensed User
Can you say a little more then "retries are important" or is it some how proprietary?
There are cases where writings will fail which are difficult to handle outside of the library. The writings do succeed after another attempt or two (and a short delay). This can happen for example if the BLE adapter is busy with a different task.

All of this is not relevant to B4i as it is taken care in a lower level.

As I wrote, I can make this feature optional in the future. However you should first try to manage the writings and make sure that you only call Write after the previous one completed.
 

Turbo3

Active Member
Licensed User
Thanks for the explanation. I appreciate you taking the time to answer my questions.

I have added a simple OkToSend flag that gets set to false after a WriteData and set to true when the WriteComplete event is received. A WriteData is skipped if the OkToSend flag is false. Seem to work with my limited testing tonight. Will test some more tomorrow. The only issue is if the WriteComplete does not happen. I do have a hang timer running so I could set the flag to true in there if needed.

But even with this I would rather have the option to disable the auto retry as my device is always available so no need for the auto retry function.

My app is always trying to connect. This means connections might start at the far limits of the BTLE range so the connection might not be a solid connection and come and go. So the stream of data is hard to predict.
 

Krammig

Member
Licensed User
I have two Bluetooth devices here and have tried to use the BLE Example app to detect them. However not having much luck. Each device has it's own Eclipse style demo program and they work fine.

What I am seeing here on the phone is

BLE State: POWERED ON

The Scan & Connect button is active, and when I press that the Log file reports as follows (see below)
The Disconnect button is never active (per log file I guess)
Status is always Not Connected
Read Data button is never active.

Would appreciate comments
thanks


** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Found: MP100, 8C:DE:52:F1:B6:33, RSSI = -85, (MyMap) {1=[B@2ff21bd4, 9=[B@888a17d, 3=[B@270f0872, 10=[B@302584c3}
Disconnected
Found: MP100, 8C:DE:52:F1:B6:33, RSSI = -88, (MyMap) {1=[B@124139be, 9=[B@c51aa1f, 3=[B@1395116c, 10=[B@274f8335}
Disconnected
** Activity (main) Pause, UserClosed = true **
** Activity (main) Create, isFirst = false **
** Activity (main) Resume **
Found: Suppay_161510, 74:F8:DB:7D:20:FC, RSSI = -50, (MyMap) {1=[B@338c6eb, 2=[B@308a7c48, 10=[B@4850ae1, 9=[B@fc6006}
Disconnected
 

Syd Wright

Well-Known Member
Licensed User
I have a Nexus-7 2012 that has been upgraded to Android version 4.3. Erel wrote that "BLE2 is supported from Android version 4.3 upwards", but the sample project shows: "BLE State: UNSUPPORTED".

If I want to use Blue Tooth with older Android versions, am I obliged to use the Blue Tooth Forum stuff from 2012, or is there a BLE version that runs on Android 4.2 and older? I cannot find any libraries that BLE2 has supposedly replaced.
 
Last edited:

Erel

Administrator
Staff member
Licensed User
BLE2 v1.35 is attached to the first post. It allows reading the RSSI value of a connected device.
You need to call Manager.ReadRemoteRssi and handle the RssiAvailable event.
B4X:
Sub Manager_RssiAvailable (Success As Boolean, RSSI As Double)
   Log(Success)
   Log(RSSI)
End Sub
 
Last edited:

Juan Carlos López

New Member
Licensed User
Hello

I'm working with the RN4020 module, as host-less.
I have defined one private service with 4 characteristics.
When I list the services with the LS command with Teraterm, it lists these:

11223344556677889900AABBCCDDEEFF
AA0203040506070809000A0B0C0D0E0F,0018,06,02
BB0203040506070809000A0B0C0D0E0F,001A,06,02
CC0203040506070809000A0B0C0D0E0F,001C,06,02
DD0203040506070809000A0B0C0D0E0F,001E,06,08

On my B4A app, I'm reading the services with this code using the BLE2 library: (from an example I have find somewhere)

Sub ble_Connected (Services As Map)
Dim i,j As Int
If ConnectState=cstatePreConnect Then
ConnectState = cstateConnect
For i = 0 To Services.Size - 1
s = Services.GetValueAt(i)
For j = 0 To s.GetCharacteristics.Size - 1
c = s.GetCharacteristics.GetValueAt(j)
Next
Next
PrivServ = Services.GetValueAt(3)
Fabierto = PrivServ.GetCharacteristics.GetValueAt(0)
Fcerrado = PrivServ.GetCharacteristics.GetValueAt(1)
Motor = PrivServ.GetCharacteristics.GetValueAt(2)
Dispositivo = PrivServ.GetCharacteristics.GetValueAt(3)
End If
End Sub

Am I using the characteristic enumeration correctly?
How can I read each characteristic value? It seems I'm using it on the wrong way.

Thank you for your comments.

Juan Carlos.
 

kompiler

Member
Licensed User
I have problem with BLE2 library and Arduino Bluno form DFRoot
https://www.dfrobot.com/wiki/index.php/Bluno_SKU:DFR0267

DF Robot Service: 0000dfb0-0000-1000-8000-00805f9b34fb
DF Robot Characteristics: 0000dfb1-0000-1000-8000-00805f9b34fb

when I try SetIndication

B4X:
ServiceId = "0000dfb0-0000-1000-8000-00805f9b34fb"
ReadChar = "0000dfb1-0000-1000-8000-00805f9b34fb"

Private Sub Manager_Connected (Services As List)
    manager.SetIndication(ServiceId,ReadChar,True)
End Sub

in log

starter_manager_connected (java line: 144)
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.bluetooth.BluetoothGattDescriptor.setValue(byte[])' on a null object reference
at anywheresoftware.b4a.objects.BleManager2.setNotify(BleManager2.java:305)
at anywheresoftware.b4a.objects.BleManager2.SetNotify(BleManager2.java:295)
at b4a.example.starter._manager_connected(starter.java:144)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
at anywheresoftware.b4a.BA$2.run(BA.java:328)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6126)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)


Bluno sends one character every second

Please help
 

deantangNYP

Active Member
Licensed User
How come there is no "write" example in the sample code , BLE_Example.zip ? Or did i miss it. Thanks

I'm not familiar with BleExtEx implementation. BLE (the protocol) doesn't support streaming. BLE2 library exposes all the relevant APIs. You can read and write to the BLE peripheral.
 
Status
Not open for further replies.
Top