Android Question Bluetooth 4.0 data exchange

red30

Well-Known Member
Licensed User
Longtime User
I have a microcontroller to which the Bluetooth HC-08 (Bluetooth 4.0) module is connected. I want to exchange data, but I have not found a single example on the forum. I need to work exactly with Bluetooth 4.0. How can i do this?
I found the program Serial Bluetooth Terminal. Can I do the same with b4a?

I tried this example. I get the error: java.io.IOException: read failed, socket might closed or timeout, read ret: -1

I found the program from the official manufacturer, it works fine with this bluetooth module.
 

Attachments

  • 2016330162415101 (1).zip
    329.7 KB · Views: 639
Last edited:

red30

Well-Known Member
Licensed User
Longtime User
Maybe I do not understand something ...
I figured out with android devices, now they all see my bluetooth module! I use the application example in the topic BLE2. I can connect to the device, but I don’t understand how to implement data exchange ...
I installed nRF Connect. I found my bluetooth module. Connect to it.
Screenshot_20190227-110149.png Screenshot_20190227-110245.png Screenshot_20190227-110250.png Screenshot_20190227-110300.png
I do not understand what to do next ...
 
Upvote 0

emexes

Expert
Licensed User
It's looking good. The list of the 0x18xx services is at https://www.bluetooth.com/specifications/gatt/services

0x1800 = org.bluetooth.service.generic_access
0x1801 = org.bluetooth.service.generic_attribute
0x180A = org.bluetooth.service.device_information

I've just gotten back home now, so I'll get cracking with that test code. If you could meanwhile try reading the device name (service 0x1800, characteristic 0x2A00) by pressing the downward-pointing arrow to the far right of "Device Name", and then have an explore around and read anything else that looks interesting, that can only improve our prospects of success :)

upload_2019-2-27_20-38-45.png
 
Upvote 0

emexes

Expert
Licensed User
Righto, we are on the home straight. Below is the output of the simple-as-I-can-make-it test program that I've just run, which finds, connects to, and reads from a pressure sensor that's on the table on the other side of this room. Translationed, they are:

"Let the games begin..." is just so I know things are running ok (plus always good to keep a cheerful attitude ;-)
"Device =" are the devices found during the scan, and their name (mostly blank, except for the pressure sensor) and the RSSI
"Discovering services." is a message from the BLE2 connect function
"Connected" means a BLE2 connected event happened
"Service =" are the services available on the pressure sensor
"DataAvailable" means a BLE2 dataavailable event happened
"Characteristic blahblahblah = hex" are the readings from the pressure sensor

The key reading I'm interested in is the one starting with 835a - this is pressure reading in 0.1 PSI, as a signed 16-bit value
There is a set of readings every ten seconds, and if you look at the 835a one, you'll see:

- it was slightly negative for a few readings ('coz el slacko here hasn't zeroed it for ages)
- it increased for a couple of readings, when I walked over to the table and pressed on the piston
- it returned to slightly negative when I stopped pressing on the piston

B4X:
Logger connected to:  samsung SM-T280
--------- beginning of system
--------- beginning of main
*** Service (starter) Create ***
Let the games begin...
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Device = 7C:CE:77:17:DE:72  -31
Device = C8:69:CD:10:1E:C9  -32
Device = 07:42:08:E3:ED:4A  -47
Device = 48:6C:B9:B9:B5:1B  -28
Device = 60:03:08:B9:B3:AA  -32
Device = D3:CC:CB:F7:AC:09 34507 -27
Discovering services.
Connected
Service = 00001800-0000-1000-8000-00805f9b34fb
Service = 00001801-0000-1000-8000-00805f9b34fb
Service = cc4a6a80-51e0-11e3-b451-0002a5d5c51b
Service = 0000180f-0000-1000-8000-00805f9b34fb
Service = 00001804-0000-1000-8000-00805f9b34fb
Service = 0000180a-0000-1000-8000-00805f9b34fb
Service = 000018ff-0000-1000-8000-00805f9b34fb
DataAvailable
Characteristic 835ab4c0-51e4-11e3-a5bd-0002a5d5c51b = FF DF
Characteristic 8cd67da0-da9b-11e3-9087-0002a5d5c51b = 01
Characteristic 00002a1c-0000-1000-8000-00805f9b34fb = 00 41 AC 80 00
Characteristic 00002a21-0000-1000-8000-00805f9b34fb = 1E 00
DataAvailable
Characteristic 835ab4c0-51e4-11e3-a5bd-0002a5d5c51b = FF DF
Characteristic 8cd67da0-da9b-11e3-9087-0002a5d5c51b = 01
Characteristic 00002a1c-0000-1000-8000-00805f9b34fb = 00 41 AC 80 00
Characteristic 00002a21-0000-1000-8000-00805f9b34fb = 1E 00
DataAvailable
Characteristic 835ab4c0-51e4-11e3-a5bd-0002a5d5c51b = FF E0
Characteristic 8cd67da0-da9b-11e3-9087-0002a5d5c51b = 01
Characteristic 00002a1c-0000-1000-8000-00805f9b34fb = 00 41 AC 80 00
Characteristic 00002a21-0000-1000-8000-00805f9b34fb = 1E 00
DataAvailable
Characteristic 835ab4c0-51e4-11e3-a5bd-0002a5d5c51b = 01 1F
Characteristic 8cd67da0-da9b-11e3-9087-0002a5d5c51b = 01
Characteristic 00002a1c-0000-1000-8000-00805f9b34fb = 00 41 AC 80 00
Characteristic 00002a21-0000-1000-8000-00805f9b34fb = 1E 00
DataAvailable
Characteristic 835ab4c0-51e4-11e3-a5bd-0002a5d5c51b = 01 1D
Characteristic 8cd67da0-da9b-11e3-9087-0002a5d5c51b = 01
Characteristic 00002a1c-0000-1000-8000-00805f9b34fb = 00 41 AC 80 00
Characteristic 00002a21-0000-1000-8000-00805f9b34fb = 1E 00
DataAvailable
Characteristic 835ab4c0-51e4-11e3-a5bd-0002a5d5c51b = FF E4
Characteristic 8cd67da0-da9b-11e3-9087-0002a5d5c51b = 01
Characteristic 00002a1c-0000-1000-8000-00805f9b34fb = 00 41 AC 80 00
Characteristic 00002a21-0000-1000-8000-00805f9b34fb = 1E 00
DataAvailable
Characteristic 835ab4c0-51e4-11e3-a5bd-0002a5d5c51b = FF E0
Characteristic 8cd67da0-da9b-11e3-9087-0002a5d5c51b = 01
Characteristic 00002a1c-0000-1000-8000-00805f9b34fb = 00 41 AC 80 00
Characteristic 00002a21-0000-1000-8000-00805f9b34fb = 1E 00
DataAvailable
Characteristic 835ab4c0-51e4-11e3-a5bd-0002a5d5c51b = FF E0
Characteristic 8cd67da0-da9b-11e3-9087-0002a5d5c51b = 01
Characteristic 00002a1c-0000-1000-8000-00805f9b34fb = 00 41 AC 80 00
Characteristic 00002a21-0000-1000-8000-00805f9b34fb = 1E 00
 
Upvote 0

emexes

Expert
Licensed User
Here is the test program for above. Start a new project in B4A and do the following:

- Main module, in Region Project Attributes, add "#BridgeLogger: True"
(or run it in debug mode, which also enables logging but, as we all know deep in our hearts: real programmers don't need no newfangled debug mode ;-)
(I am wondering whether I should wrap the latter half of the previous line with [joke] [/joke] but... nah, she'll be right :)

upload_2019-2-28_0-1-47.png



- Libraries Manager tab, include the following libraries: BLE2, ByteConverter, RuntimePermissions (Core should already be included by default)

upload_2019-2-27_23-58-32.png



- Menu, Project, Manifest Editor: add "AddPermission(android.permission.ACCESS_COARSE_LOCATION" at the end

upload_2019-2-28_0-5-29.png



- Replace all the default code in the Starter module with everything from below, then give it a burl (and read the next post, because this code is set up to read a specific pressure sensor at this end, and will only get as far as listing devices when you run it at your end):

B4X:
#Region  Service Attributes
    #StartAtBoot: False
    #ExcludeFromLibrary: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

    Public BleMan As BleManager2
    Public RunPer As RuntimePermissions
    Public BytCon As ByteConverter
  
    Public SaveDeviceName As String
    Public SaveDeviceId As String
    Public SaveServiceId As String
    Public SaveCharacteristicId As String
  
    Public BleReadTimer As Timer
  
    Public DeviceIdStartsWith As String = "D3:CC:"
    Public ServiceIdStartsWith As String  = "cc4a"
    Public CharacteristicIdStartsWith As String = "835a"
  
End Sub

Sub Service_Create
    'This is the program entry point.
    'This is a good place to load resources that are not specific to a single activity.

    BleMan.Initialize("BleMan")
    BleReadTimer.Initialize("BleReadTimer", 123)    'will set interval when enable timer (ie 123 = don't care)
  
    If BleMan.State <> BleMan.STATE_POWERED_ON Then
        Log("Not powered on.")
    Else If RunPer.Check(RunPer.PERMISSION_ACCESS_COARSE_LOCATION) = False Then
        Log("No location permission.")
    Else
        Log("Let the games begin...")
        BleMan.Scan2(Null, False)    'set second parameter to True to see multiple/all scans per device
    End If
  
End Sub

Sub Service_Start (StartingIntent As Intent)
End Sub

Sub Service_TaskRemoved
    'This event will be raised when the user removes the app from the recent apps list.
End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub Service_Destroy
End Sub

'*** THE THREE HANDLERS FOR BLE EVENTS ***

Sub BleMan_DeviceFound (Name As String, Id As String, AdvertisingData As Map, RSSI As Double)
  
    Log("Device = " & Id.Trim & " " & Name.Trim & " " & RSSI)
  
    If SaveDeviceId = "" Then    'if we haven't yet found the device we're looking for
        If Id.StartsWith(DeviceIdStartsWith) Then    'and this one is it
            SaveDeviceId = Id    'then save it
            BleMan.Connect2(SaveDeviceId, False)    'and connect to it
          
            BleMan.StopScan    'this can be done anytime after the device-of-interest has been found and its id saved
        End If
    End If
End Sub

Sub BleMan_Connected (Services As List)
  
    Log("Connected")
      
    For Each S As String In Services
        Log("Service = " & S)
        If SaveServiceId = "" Then    'if we haven't yet found the service we're looking for
            If S.StartsWIth(ServiceIdStartsWith) Then    'and this one is it
                SaveServiceId = S    'then save it
                BleMan.ReadData(SaveServiceId)    'and read it
            End If
        End If
    Next
  
End Sub

Sub BleMan_DataAvailable (ServiceId As String, Characteristics As Map)
  
    Log("DataAvailable")
  
    For Each C As String In Characteristics.Keys
        Dim V() As Byte = Characteristics.Get(C)
        Log("Characteristic " & C & " = " & ByteArrayToSpaceSeparatedHexString(V))
      
        If SaveCharacteristicId = "" Then    'if haven't yet found the characteristic we're looking for
            If ServiceId = SaveServiceId Then
                If C.StartsWith(CharacteristicIdStartsWith) Then    'and this one is it
                    SaveCharacteristicId = C    'then save it (ServiceId already saved)
                  
                    BleReadTimer.Interval = 10000    'and read it every 10 seconds
                    BleReadTimer.Enabled = True
                End If
            End If
        End If
    Next
  
End Sub

'*** TIMER DEMONSTRATING READDATA2 (RETURNS SPECIFIC CHARACTERISTIC, CF READDATA RETURNS ALL) ***

Sub BleReadTimer_Tick
  
    'SaveServiceId should have already been set in BleMan_Connected, before BleMan.ReadData was done
    'SaveCharacteristicId should have already been set in BleMan_DataAvailable, before this timer was enabled
  
    BleMan.ReadData2(SaveServiceId, SaveCharacteristicId)
      
End Sub

'*** AND LAST, BUT BY NO MEANS LEAST, A FUNCTION TO STOP ME GOING CROSS-EYED ***

Sub ByteArrayToSpaceSeparatedHexString(BA() As Byte) As String
  
    Dim HexString As String = ""
  
    For I = 0 To BA.Length -1
        HexString = HexString & " " & BytCon.HexFromBytes(Array As Byte(BA(I)))
    Next
  
    Return HexString.Trim    'trims leading space

End Sub
 
Upvote 0

emexes

Expert
Licensed User
Firstly, let me get two small confessions out of the way:

1/ The first read is a full ReadData that returns all available characteristics for the specified service, and that works fine. The second read is a ReadData2 that is meant to only return the specified characteristic, not all four of them. At least, I'm pretty sure that's how it's meant to work. I'll have to check that out. In the meantime, just ignore the characteristics you don't need...

2/ I wanted to log the advertising data of the DeviceAvailable event, because you'll probably be needing that info so that your app only connects to compatible devices, but... it's getting late here, and I couldn't get my head around presenting the advertising in a half-readable form. I'll have to check that out too. In the meantime, get your app going with the (one?) known hardware that we've confirmed working with nRF Connect, and I'll have my side fixed before you need it.

Back to main show:

In Starter.Process_Globals there is:

B4X:
Public DeviceIdStartsWith As String = "D3:CC:"
Public ServiceIdStartsWith As String  = "cc4a"
Public CharacteristicIdStartsWith As String = "835a"

which constrains the test code to only talking to my test hardware. Replace the quoted strings with values applicable to your test hardware, eg:

B4X:
Public DeviceIdStartsWith As String = "20:C3:8F:FD:68:52"
based on:

upload_2019-2-28_0-45-53.png


I'll let you select the service and characteristic to read, although it does look like "Unknown Service" 0000fff0-... is a good candidate, in that it appears the manufacturer has configured it to have five default/sample characteristics 0000fff1-... thru 0000fff5-... ready to go. And that you've managed to read the values 0x01 and 0x02 from the first two at least.

B4X:
Public ServiceIdStartsWith As String  = "0000fff0"
Public CharacteristicIdStartsWith As String = "0000fff1"

upload_2019-2-28_0-57-14.png
 
Upvote 0

red30

Well-Known Member
Licensed User
Longtime User
Many thanks for your sample application.
I have tracked what comes to me with the help of the application nRF Connect. I should have received the data "12345".
Screenshot_2019-02-27-20-17-30-402_no.nordicsemi.android.mcp.png
I changed:
B4X:
    Public ServiceIdStartsWith As String  = "0000ffe0"
    Public CharacteristicIdStartsWith As String = "0000ffe1"
But received: Characteristic 0000ffe1-0000-1000-8000-00805f9b34fb = 00
Why it happens?
 
Upvote 0

red30

Well-Known Member
Licensed User
Longtime User
I see in the app nRF Connect
UUID: 0000ffe1-0000-1000-8000-00805f9b34fb
Value: "Those data that come to me".
But in the application on B4A I see 00

In characteristics 0000fff1-... thru 0000fff5-
Characteristic 0000fff1-0000-1000-8000-00805f9b34fb = 01
Characteristic 0000fff2-0000-1000-8000-00805f9b34fb = 02
Characteristic 0000fff5-0000-1000-8000-00805f9b34fb = 01 02 03 04 05
Characteristic 0000fff3-0000-1000-8000-00805f9b34fb =
Characteristic 0000fff4-0000-1000-8000-00805f9b34fb =
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
Why it happens?

That is a good question :)
.
First thought is: can you read any of the other fields? Especially fixed fields that are specific to your device? Eg, when I read service 00001800 below, then I can see the serial number of the device in characteristic 00002a00. On your device, nRF Connect indicates that service 0000180a (note lowercase a) returns a characteristic called "System ID" with 8 bytes of data - can you read that?

Next thought is: Can you make your device send data that changes, as in treat those 5 bytes like a counter and increment it every two seconds? Then check with nRF Connect to make sure the different readings come through, changing about every two seconds. Then do same with app.

Another thought is that we should add the DeviceId to the "Connected" log message, and the ServiceId to the "DataAvailable" log message.

B4X:
Public DeviceIdStartsWith As String = "D3:CC:"
Public ServiceIdStartsWith As String  = "00001800"    '"cc4a"
Public CharacteristicIdStartsWith As String = "don't match any"    '"835a"

B4X:
*** Service (starter) Create ***
Let the games begin...
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Device = 7C:CE:77:17:DE:72  -32
Device = 07:42:08:E3:ED:4A  -31
Device = 5C:2C:04:02:5C:E2  -25
Device = 60:03:08:B9:B3:AA  -32
Device = A0:E6:F8:4D:1D:71 63472 -32
Device = D3:CC:CB:F7:AC:09 34507 -28
Discovering services.
Connected
Service = 00001800-0000-1000-8000-00805f9b34fb
Service = 00001801-0000-1000-8000-00805f9b34fb
Service = cc4a6a80-51e0-11e3-b451-0002a5d5c51b
Service = 0000180f-0000-1000-8000-00805f9b34fb
Service = 00001804-0000-1000-8000-00805f9b34fb
Service = 0000180a-0000-1000-8000-00805f9b34fb
Service = 000018ff-0000-1000-8000-00805f9b34fb
DataAvailable
Characteristic 00002a00-0000-1000-8000-00805f9b34fb = 33 34 35 30 37 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
Characteristic 00002a01-0000-1000-8000-00805f9b34fb = 00 00
Characteristic 00002a04-0000-1000-8000-00805f9b34fb = 20 03 20 03 00 00 58 02
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
In characteristics 0000fff1-... thru 0000fff5-
Characteristic 0000fff1-0000-1000-8000-00805f9b34fb = 01
Characteristic 0000fff2-0000-1000-8000-00805f9b34fb = 02
Characteristic 0000fff5-0000-1000-8000-00805f9b34fb = 01 02 03 04 05
Characteristic 0000fff3-0000-1000-8000-00805f9b34fb =
Characteristic 0000fff4-0000-1000-8000-00805f9b34fb =

I see you're already heading down that path :)

I am curious about the almighty coincidence that:

in nRF app, characteristic 0000ffe1 returns 31 32 33 34 35 = ASCII "12345"
in B4A app, characteristic 0000fff5 returns 01 02 03 04 05

and that's why I thought it might help to try sending different and changing data, rather than always having same/similar patterns of test data that are easy for us Einsteins to get mixed up.
 
Upvote 0

red30

Well-Known Member
Licensed User
Longtime User
Next thought is: Can you make your device send data that changes, as in treat those 5 bytes like a counter and increment it every two seconds? Then check with nRF Connect to make sure the different readings come through, changing about every 5 seconds. Then do same with app.
Yes, in nRF Connect (0000ffe1-0000-1000-8000-00805f9b34fb) data changes.
in nRF app, characteristic 0000ffe1 returns 31 32 33 34 35 = ASCII "12345"
in B4A app, characteristic 0000fff5 returns 01 02 03 04 05
That's a coincidence.
Now I am sending a "test"
Screenshot_2019-02-27-21-50-26-126_no.nordicsemi.android.mcp.png
And in the application, I see:
DataAvailable
Characteristic 0000fff1-0000-1000-8000-00805f9b34fb = 01
Characteristic 0000fff2-0000-1000-8000-00805f9b34fb = 02
Characteristic 0000fff5-0000-1000-8000-00805f9b34fb = 01 02 03 04 05
Characteristic 0000fff3-0000-1000-8000-00805f9b34fb =
Characteristic 0000fff4-0000-1000-8000-00805f9b34fb =
I tried to read:
B4X:
    Public DeviceIdStartsWith As String = "20:C3:8F:FD:68:52"
    Public ServiceIdStartsWith As String  = "00001800"
    Public CharacteristicIdStartsWith As String = "00002a00"'"0000ffe1"
The values do not change there ...
DataAvailable
Characteristic 00002a00-0000-1000-8000-00805f9b34fb =
Characteristic 00002a01-0000-1000-8000-00805f9b34fb = 00 00
Characteristic 00002a02-0000-1000-8000-00805f9b34fb = 00
Characteristic 00002a03-0000-1000-8000-00805f9b34fb = 00 00 00 00 00 00
Characteristic 00002a04-0000-1000-8000-00805f9b34fb = 50 00 A0 00 00 00 E8 03
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
Reasoning behind changing your test string is to make sure that we're not seeing cached or sample readings. I noticed that nRF Connect helpfully included easy-to-think-it-was-data placefillers like "Software Revision" and "Manufacturer Name", and that therefore perhaps the "12345" that it appears to have read from your device, might also be a placefiller/sample, and we're chasing things that don't exist :-/

upload_2019-2-28_5-59-50.png
 
Upvote 0

red30

Well-Known Member
Licensed User
Longtime User
I tried all characteristic in nRF Connect. When sending different data, nothing changes except 0000ffe1-0000-1000-8000-00805f9b34fb
If i press the "up arrow" to 111 and send a message, it comes to the device.
Screenshot_2019-02-27-22-15-54-548_no.nordicsemi.android.mcp.png ttt.jpg
 
Upvote 0

emexes

Expert
Licensed User
You wouldn't think nRF Connect would be caching data, but... airplane mode is supposed to disable all radio transmitters in the device, and there is a (small) possibility that Bluetooth isn't actually active at the moment. Yeah, I know there's that Bluetooth symbol in the status bar, but... I wouldn't trust my life on it.

Another problem I have is that some devices are keen power-savers, and they power-down wifi and Bluetooth at every opportunity they get. I had one device that worked great when the app was compiled in debug mode, but fell over constantly when compiled in release mode. Turned out that if Wifi was inactive for a 60 seconds then it got powered down, and that happened to take out the Bluetooth transceiver too. In debug mode, there is constant wifi activity by the debug link, thus no power-down. In release mode, there is no debug link activity.

Finding that out took a day of my life that I'll never get back :-(
 
Upvote 0

red30

Well-Known Member
Licensed User
Longtime User
I do not understand why nRF Connect correctly reads the value of 0000ffe1-0000-1000-8000-00805f9b34fb characteristics, and b4a does not ...
 
Upvote 0

emexes

Expert
Licensed User
That terminal window sends me back to thinking that you're using a serial link over Bluetooth BR/EDR, and not Bluetooth BLE.

https://en.wikipedia.org/wiki/Bluetooth_Low_Energy#Compatibility

"The Bluetooth 4.0 specification permits devices to implement either or both of the LE and BR/EDR systems."

The two are not compatible. BLE2 library only does BLE, not BR/EDR.

I have seen other forum entries about doing BR/EDR (aka "normal") Bluetooth, and I assume they must be interacting directly with Android using B4A JavaObject or "reflection". I have not done it myself, I've only done BLE.

On the other hand, I thought (ie, not definitely) I saw mention of the HC-08 doing BLE, so maybe there is another software interface on your device for doing that, or a setting to change, or AT commands that you can use to configure the BLE GATT side of things.
 
Upvote 0

emexes

Expert
Licensed User
I do not understand why nRF Connect correctly reads the value of 0000ffe1-0000-1000-8000-00805f9b34fb characteristics, and b4a does not ...

Is B4A reading *anything* for 0000ffe1 ? I've only seen logs for 0000fff1 thru 0000fff5. What do you get if you ask for service 0000ffe0 ?

Also, if the HC-08 is implementing a serial link over BLE, perhaps you need to set characteristic 0000ffe1 to use notifications or indications (using SetNotify or SetIndication) so that chunks of serial data are pushed across BLE to your Android device.
 
Upvote 0

emexes

Expert
Licensed User
Hang on...

What is that terminal window connected to?

Is there a physical cable somewhere in the serial link?

If so, what is each end of the physical serial cable connected to?

Can you send AT commands and queries to the device at the other end?
 
Upvote 0

red30

Well-Known Member
Licensed User
Longtime User
Tomorrow in the morning I will give detailed documentation on this module. Now it works like: Bluetooth module is connected to interface converter by UART and then to PC by USB. It's done for testing. In fact, the usb- module will be connected to a microcontroller and it will transfer some data.
Yes, this module supports AT commands. But when Ble-device is connected, it fails reacting. Tomorrow I will explain more accurately and andwer other questions.
 
Upvote 0

emexes

Expert
Licensed User
No need, I've gone a-hunting on the internet, and I think I've got a grip on the issues now.

The Classic Bluetooth BR/EDR SPP (Serial Port Profile) interface looks like a straightforward data pipe - stick a byte in one end, and it (eventually) pops out the other end. Ditto for a bunch of bytes. There are delays and timing misalignments introduced when the bytes are grouped into packets for transmission over radio (or USB) but generally those issues are small enough to not cause a problem, and thus most people aren't even aware they exist.

The Bluetooth BLE GATT (Generic ATTribute) Profile interface looks like a industrial control panel, with gauges and controls and on/off indicators and switches and buttons.

A data pipe is great if all you need to do is exchange one reading (or a few on/off states) - as long as it fits within the 7-or-8 bit character size that the pipe uses, you just put that character in the pipe and it comes out the other end and everybody's happy... as long as they know how to interpret that character is, eg, which bits are what switches, is the numeric reading signed or unsigned, what units is it in.

Now imagine that you're implementing a tv remote (or airconditioner, or microwave oven, or...) Even the most basic tv has controls for volume, brightness, contrast, input selection and channel selection, and an on/off switch. You'll be needing more than 8 bits for all that, and so you have to implement a protocol which usually involves grouping characters into larger units (packets) and then you need to reassemble the individual incoming characters at the other end of the pipe into packets, and if there's possibly noise in the pipe that might cause data errors, then we'd better checksum the data, and make sure we can sync up again if we lose track of whereabouts the packets are in that incoming character stream. And every programmer has their own ideas about how this is best done, and the end result is... well, a significant component of my last long-term job was writing serial interfaces that linked our equipment up to a variety of different automotive test and measurement devices.

The GATT Profile does away with all that protocol mishmash, and makes it possible for software to intelligently communicate with appropriate equipment, with no configuration (well, other than if there are multiple plausibly-appropriate equipment visible, in which case the operator might need to designate *which* one to communicate with). The GATT Profile presents the equipment as a bunch of characteristics: a characteristic is like a single knob or button or selector or switch or gauge or number display or indicator light. So for the basic tv example, there would be 6 characteristics: volume, brightness, contrast, input and channel selection, and on/off switch. Characteristics can be inputs (readable), outputs (writeable) or both. And the readable inputs can be set to automatically send updates when they change (notifications) with optional confirmation that the update didn't get lost on the way (indications).

Now the best bit: the Bluetooth device can tell you what characteristics are available. Better yet, it can even describe them for you, tell you what format the raw reading is in (signed, unsigned, 8 bit, 16 bit, 32 bit, integer, floating point), what the scaling is (eg volume might be 0..10 on a guitar amplifier and 0..100 on a radio) and even what it is (pressure, weight, time, voltage) and the units (%, dB, arbitrary number), and what it's generally for (main, left, right, rear, front). No more custom protocols, just link up what-you-need with what-is-available.

I don't know about you, but I kinda like the possibilities this opens up.

GATT services are just a way of grouping related characteristics. Other than using them as a stepping stone to get to the individual characteristics, you can usually ignore them.

Each GATT characteristic should have some descriptors that tell you about the characteristic. Most people ignore them, and work on the basis that a characteristic with a given UUID is unlikely to change format (having said that, I have pressure sensors that, for the same characteristic UUID, use different scalings - and what a pain that is)

Right, now you're probably thinking: this is all great, but it doesn't help me with my current problem.

But it does. Before we can attack a problem, first we have to understand it. What the HC-08 people have done is shoehorned a data pipe aka serial link (because that's what people are used to and understand) onto BLE / GATT (because it allows much lower power requirements = longer battery life). There is an obvious way to do that, which immediately runs into some obvious problems, which have a variety of obvious solutions, and we just have to work out which solution they've gone for.

Like you, I am surprised this serial-comms-over-GATT doesn't seem to rate a mention on the B4A forums (until now). On the bright side, once our combined Russian-Australian efforts crack this little nut, then future users of that device will shower us with gratitude. Well, maybe not... but let's do it for the excitement of being pioneers anyway.

I have to go do other things now, but... it looks like you were on the right track looking at the 0000ffe1 characteristic, confirmed by this clue here, and so if you could start reading that characteristic repeatedly whilst sending chunks of data from your computer, and perhaps try using notifications and indications, see if that helps, and experiment more in nRF Connect to see if you can suss out why that app is able to read it using the generic interface, and see if you can glean any information about the shoehorning from the terminal app used in the Youtube video, then I am super-keen to know what you discover.
 
Last edited:
Upvote 0
Top