Leica Disto and Bosch laser rangefinder.
I have two new laser rangefinders and would like to read out the measurement data with an app. I am using BLE2 code for testing. I can connect both devices and display data via Read Data. but I don't know what I have to do to get the measurement data. I'm doing something wrong, but I can't figure out what the problem is. Maybe someone can look over the code and find the problem.
Translated with DeepL.com (free version)
I have two new laser rangefinders and would like to read out the measurement data with an app. I am using BLE2 code for testing. I can connect both devices and display data via Read Data. but I don't know what I have to do to get the measurement data. I'm doing something wrong, but I can't figure out what the problem is. Maybe someone can look over the code and find the problem.
Translated with DeepL.com (free version)
B4X:
Sub Class_Globals
Private Root As B4XView
Private xui As XUI
Private btnReadData As B4XView
Private btnDisconnect As B4XView
Private btnScan As B4XView
Private lblDeviceStatus As B4XView
Private lblState As B4XView
Private pbReadData As B4XLoadingIndicator
Private clv As CustomListView
#if B4A
Private manager As BleManager2
Private rp As RuntimePermissions
#else if B4i
Private manager As BleManager
#end if
Private currentStateText As String = "UNKNOWN"
Private currentState As Int
Private connected As Boolean = False
Private ConnectedName As String
Private ConnectedServices As List
Private pbScan As B4XLoadingIndicator
Private MODEL_NUMBER As String = "00002a00-0000-1000-8000-00805f9b34fb" ' Model Number String
Private MANUFACTURER As String = "00002a29-0000-1000-8000-00805f9b34fb" ' Manufacturer Name String
'Bosch Geräte-----------------------------------------------------------------------------------------
Private Bosch_GLM_50_C_G_ServiceUUID As String = "02a6c0d0-0451-4000-b000-fb3210111989"
Private Bosch_GLM_50_C_G_CharacteristicUUID As String = "02a6c0d1-0451-4000-b000-fb3210111989"
'Bosch Geräte-----------------------------------------------------------------------------------------
'Leica Geräte-----------------------------------------------------------------------------------------
Private Leica_Disto_X3_ServiceUUID As String = "3ab10100-f831-4395-b29d-570977d5bf94"
Private Leica_Disto_X3_CharacteristicUUID As String = "3ab1010d-f831-4395-b29d-570977d5bf94"
'Leica Geräte-----------------------------------------------------------------------------------------
Private firstRead As Boolean
End Sub
Public Sub Initialize
' B4XPages.GetManager.LogEvents = True
End Sub
'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
Root = Root1
Root.LoadLayout("1")
B4XPages.SetTitle(Me, "BLE Example")
manager.Initialize("manager")
StateChanged
End Sub
Public Sub StateChanged
lblState.Text = currentStateText
If connected Then
lblDeviceStatus.Text = "Connected: " & ConnectedName
Else
lblDeviceStatus.Text = "Not connected"
End If
btnDisconnect.Enabled = connected
btnScan.Enabled = Not(connected)
pbReadData.Hide
pbScan.Hide
btnReadData.Enabled = connected
btnScan.Enabled = (currentState = manager.STATE_POWERED_ON) And connected = False
End Sub
Sub btnScan_Click
#if B4A
'Don't forget to add permission to manifest
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
#end if
pbScan.Show
StartScan
End Sub
Sub btnDisconnect_Click
manager.Disconnect
Manager_Disconnected
End Sub
Sub btnReadData_Click
pbReadData.Show
clv.Clear
For Each s As String In ConnectedServices
manager.ReadData(s)
Next
End Sub
Sub CreateServiceItem (service As String) As Panel
Dim pnl As B4XView = xui.CreatePanel("")
pnl.Color = 0xFF808080
pnl.SetLayoutAnimated(0, 0, 0, clv.AsView.Width, 30dip)
Dim lbl As B4XView = XUIViewsUtils.CreateLabel
lbl.Text = service
lbl.SetTextAlignment("CENTER", "CENTER")
lbl.Font = xui.CreateDefaultBoldFont(14)
pnl.AddView(lbl, 0, 0, clv.AsView.Width, 30dip)
Return pnl
End Sub
Sub CreateCharacteristicItem(Id As String, Data() As Byte) As Panel
Dim pnl As B4XView = xui.CreatePanel("")
pnl.SetLayoutAnimated(0, 0, 0, clv.AsView.Width, 40dip)
pnl.Color = Colors.White
Dim lbl As B4XView = XUIViewsUtils.CreateLabel
lbl.Text = Id
pnl.AddView(lbl, 0, 0, clv.AsView.Width, 20dip)
Dim lbl2 As B4XView = XUIViewsUtils.CreateLabel
Try
lbl2.Text = BytesToString(Data, 0, Data.Length, "UTF8")
Catch
Log(LastException)
lbl2.Text = "Error reading data as string"
End Try
lbl2.TextColor = 0xFF909090
lbl2.TextSize = 14
pnl.AddView(lbl2, 0, 20dip, clv.AsView.Width, 20dip)
Return pnl
End Sub
Sub Manager_StateChanged (State As Int)
Select State
Case manager.STATE_POWERED_OFF
currentStateText = "POWERED OFF"
Case manager.STATE_POWERED_ON
currentStateText = "POWERED ON"
Case manager.STATE_UNSUPPORTED
currentStateText = "UNSUPPORTED"
End Select
currentState = State
StateChanged
End Sub
Sub Manager_DeviceFound (Name As String, Id As String, AdvertisingData As Map, RSSI As Double)
Log("Found: " & Name & ", " & Id & ", RSSI = " & RSSI & ", " & AdvertisingData) 'ignore
' If Id = "6D:D4:F2:0C:A4:74" Then
ConnectedName = Name
manager.StopScan
Log("connecting")
#if B4A
manager.Connect2(Id, False) 'disabling auto connect can make the connection quicker
#else if B4I
manager.Connect(Id)
#end if
' End If
End Sub
Sub Manager_Disconnected
Log("Disconnected")
connected = False
StateChanged
End Sub
Sub Manager_Connected (services As List)
Log("Connected")
connected = True
ConnectedServices = services
StateChanged
'manager.ReadData("3ab1010d-f831-4395-b29d-570977d5bf94")
End Sub
'utility to convert short UUIDs to long format on Android
Private Sub UUID(id As String) As String 'ignore
#if B4A
Return "0000" & id.ToLowerCase & "-0000-1000-8000-00805f9b34fb"
#else if B4I
Return id.ToUpperCase
#End If
End Sub
Public Sub StartScan
If manager.State <> manager.STATE_POWERED_ON Then
Log("Not powered on.")
Else
manager.Scan2(Null, False)
''Für die Boschlaser GLM 50-27 CG x9577------------------------------------
' Dim List1 As List
' List1.Initialize
' List1.AddAll(Array As String("02a6c0d0-0451-4000-b000-fb3210111989","3ab10100-f831-4395-b29d-570977d5bf94"))
' manager.Scan(List1)
''Für die Boschlaser GLM 50-27 CG x9577------------------------------------
End If
End Sub
Sub Manager_DataAvailable (ServiceId As String, Characteristics As Map)
pbReadData.Hide
' If firstRead Then
' firstRead = False
' manager.SetNotify(Leica_Disto_X3_ServiceUUID,Leica_Disto_X3_CharacteristicUUID,True)
' Return
' End If
' Private Leica_Disto_X3_ServiceUUID As String = "3ab10100-f831-4395-b29d-570977d5bf94"
' Private Leica_Disto_X3_CharacteristicUUID As String = "3ab1010d-f831-4395-b29d-570977d5bf94"
clv.Add(CreateServiceItem(ServiceId), "")
For Each id As String In Characteristics.Keys
clv.Add(CreateCharacteristicItem(id, Characteristics.Get(id)), "")
Next
For Each id As String In Characteristics.Keys
Dim dataContent() As Byte = Characteristics.Get(id)
Select id
Case MODEL_NUMBER
Dim conModelNumber As String = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
Log("Model: " & conModelNumber)
Case MANUFACTURER
Dim conManufacturerName As String = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
Log("Manufacturer: " & conManufacturerName)
Dim ArrayBytes() As Byte = Characteristics.Get(Leica_Disto_X3_CharacteristicUUID)
If ArrayBytes <> Null And ArrayBytes.Length > 0 Then
Log("Der Inhalt von ArrayBytes ist ungleich null")
Else
Log("Der Inhalt von ArrayBytes ist null")
End If
End Select
Next
End Sub
'Sub BluetoothCodeLeicaundBosch
'Die Leica-Generation, zu der der X3 gehört, verwendet im Prinzip einfach nur andere Characteristics.
'Der Service ist derselbe, nämlich immer noch der mit der
'UUID '{3AB10100-F831-4395-B29D-570977D5BF94}'.
'Der Trick besteht darin, dass man sich anscheinend mit sämtlichen Characteristics,
'die dieser Service zur Verfügung stellt, verbindet (SubscribeToCharacteristic),
'was mit allen außer ~ 2 möglich ist.
'Hat man das getan, so empfängt man, sobald man mit dem Laser misst,
'über die "BASIC_MEASUREMENT"-Characteristic mit der
'UUID '{3AB1010D-F831-4395-B29D-570977D5BF94}' ein Byte-Array,
'welches den Messwert enthält,den man sich auslesen kann,
'indem man die ersten 4 Werte des Arrays in umgekehrter Reihenfolge (Little Endian) in eine Float umwandelt.
' If debug_mode:
' # this is here for debugging ... there many more things to implement
' # if characteristic.uuid == '3ab10102-f831-4395-b29d-570977d5bf94':
' print(characteristic.uuid,':',type(value),len(value)) # ,int.from_bytes(value,byteorder='big', signed=False))
' # else:
' # print( characteristic.uuid, ":", value.decode("utf-8"))
' print('\traw :',value)
' If len(value) == 2:
' print("\tuint16 :",struct.unpack('>H',value)[0])
' If len(value) == 4:
' print("\tfloat :",struct.unpack('f',value)[0])
' elif len(value) == 8:
' print('\tdouble:',struct.unpack('d',value)[0])
'
' elif characteristic.uuid == '3ab10101-f831-4395-b29d-570977d5bf94':
' self.report_measurement(value)
' # Vendor ID
' elif characteristic.uuid == '00002a29-0000-1000-8000-00805f9b34fb':
' # for whatever reasons the D2 reports itself as the BLE SoC
' # thats driving it - a Nordic Semi nRF51822 - a 16MhZ Cortex-M0
' is_leica = value.decode('utf-8') == 'nRF51822'
' elif characteristic.uuid == '00002a1a-0000-1000-8000-00805f9b34fb':
' print('Battery level',value)
' def report_measurement(self,value):
' float_val = struct.unpack('f',value)[0]
' print(Round(float_val,3),'m')
'End Sub