iOS Question Can someone help me convert my B4A code to B4I?

Wolli013

Active Member
Licensed User
Can someone help me convert my B4A code to B4I?
A 1 to 1 conversion doesn't work because B4I probably asks for it differently.
Here is my code that runs in B4A. Bluetooth sensors are read out.

B4X:
Sub Manager_DeviceFound (Name As String, Id As String, AdvertisingData As Map, RSSI As Double)
Dim bc As ByteConverter
Dim key As Int = -1 'type is important. Must be Int.
If AdvertisingData.ContainsKey(key) Then

Dim b() As Byte = AdvertisingData.Get(key)
Dim hex As String = bc.HexFromBytes(b)

'Temperatur
Private temperature As Int
Private tem1,tem2,hum As Int
Private temp1,hum1 As Float
Dim temperatureSign As Boolean = Bit.And(b(4), 0x80) <> 0
temperature = Bit.And(b(4), 0x7f)' + (b(5) / 100.0)
    If temperatureSign Then
    temperature = -temperature
    End If
tem1 = temperature
tem2 = b(5)

'Luftfeuchtigkeit
    Dim Str3 As String
     Str3 = hex.SubString2(6, 8)
      hum = Bit.ParseInt(Str3, 16)
'Ergebniss
    temp1 = tem1&"."&tem2 ' = Grad
    hum1 = hum/2 ' = Relative Luftfeuchtigkeit
End If

End Sub
Hier noch ein Auszug aus dem SwiftCode

B4X:
class DecodeFormat3: RuuviTagDecoder {
    func decode(data: Data) -> RuuviTag {
        let ruuviTag = RuuviTag()
       
        ruuviTag.humidity = Double(data[3]) * 0.5
       
        let temperatureSign = (data[4] >> 7) & 1
        let temperatureBase = data[4] & 0x7F
        let temperatureFraction = Double(data[5]) / 100.0
        var temperature = Double(temperatureBase) + temperatureFraction
        if (temperatureSign == 1) {
            temperature *= -1;
        }
        ruuviTag.temperature = temperature
       
        let pressureHi = data[6] & 0xFF
        let pressureLo = data[7] & 0xFF
        ruuviTag.pressure = Double(pressureHi) * 256.0 + 50000.0 + Double(pressureLo)
        ruuviTag.pressure /= 100.0;
       
        ruuviTag.accelerationX = Double(UInt16(data[8]) << 8 | UInt16(data[9] & 0xFF)) / 1000.0;
        ruuviTag.accelerationY = Double(UInt16(data[10]) << 8 | UInt16(data[11] & 0xFF)) / 1000.0;
        ruuviTag.accelerationZ = Double(UInt16(data[12]) << 8 | UInt16(data[13] & 0xFF)) / 1000.0;
       
        let battHi = data[14] & 0xFF;
        let battLo = data[15] & 0xFF;
        ruuviTag.voltage = (Double(battHi) * 256.0 + Double(battLo)) / 1000.0;
       
        ruuviTag.updatedAt = NSDate()
        return ruuviTag
    }
}
 

Erel

Administrator
Staff member
Licensed User
Where is the failing B4i code? What have you tried? It should be very similar to the B4A code.
 

Wolli013

Active Member
Licensed User
B4X:
Dim bc As ByteConverter
Dim key As Int = -1 'type is important. Must be Int.
'If AdvertisingData.ContainsKey(key) Then

Dim b() As Byte = AdvertisingData.Get(key)
Dim hex As String = bc.HexFromBytes(b)

'Temperatur
Private temperature As Int
Private tem1,tem2,hum As Int
Private temp1,hum1 As Float

1081: Dim temperatureSign As Boolean = Bit.And(b(4), 0x80) <> 0

temperature = Bit.And(b(4), 0x7f)' + (b(5) / 100.0)
    If temperatureSign Then
    temperature = -temperature
    End If
tem1 = temperature
tem2 = b(5)

'Luftfeuchtigkeit
    Dim Str3 As String
     Str3 = hex.SubString2(6, 8)
      hum = Bit.ParseInt(Str3, 16)
'Ergebniss
    temp1 = tem1&"."&tem2 ' = Grad
    hum1 = hum/2 ' = Relative Luftfeuchtigkeit
'End If

Error occurred on line: 1081 (Main)
Target is null. Method called: getByteFast:
Stack Trace: (
CoreFoundation <redacted> + 252
libobjc.A.dylib objc_exception_throw + 56
CoreFoundation <redacted> + 0
Te+[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 192
Te-[B4IShell runMethod:] + 448
Te-[B4IShell raiseEventImpl:method:args::] + 1648
Te-[B4IShellBI raiseEvent:event:params:] + 1580
Te+[B4IObjectWrapper raiseEvent:::] + 300
Te-[BleDelegate centralManager:didDiscoverPeripheral:advertisementData:RSSI:] + 552
CoreBluetooth <redacted> + 1060
CoreBluetooth <redacted> + 620
CoreBluetooth <redacted> + 60
libdispatch.dylib <redacted> + 24
libdispatch.dylib <redacted> + 16
libdispatch.dylib <redacted> + 592
libdispatch.dylib <redacted> + 480
libdispatch.dylib <redacted> + 784
CoreFoundation <redacted> + 12
CoreFoundation <redacted> + 1924
CoreFoundation CFRunLoopRunSpecific + 436
GraphicsServices GSEventRunModal + 104
UIKitCore UIApplicationMain + 212
Temain + 124
libdyld.dylib <redacted> + 4
)
 

Wolli013

Active Member
Licensed User
And s I have also tried it only there fit then the temperature values do not ansimsten it goes.

B4X:
    Log("LogString: " & AdvertisingData.Get("kCBAdvDataManufacturerData"))
  
   Dim LogString As String = AdvertisingData.Get("kCBAdvDataManufacturerData")
   Log("LogString1: " & LogString.SubString2(1, LogString.Length-1))
  
   LogString = LogString.SubString2(1, LogString.Length-1).Replace(" ", "")
   Log("LogString2: " & LogString)

 
        Log("Scanne Sensor 1")
        Dim bc As ByteConverter   
        
 
 Dim temperature As Int
 Private tem1,tem2,hum As Int
 Private temp1,temp2,hum1 As Float
    
Dim temperatureSign As Boolean = Bit.And(LogString.SubString2(8, 10), 0x80) <> 0
temperature = Bit.And(LogString.SubString2(8, 10), 0x7f)' + (b(5) / 100.0)
If temperatureSign Then
temperature = -temperature
End If
tem1 = temperature
tem2 = LogString.SubString2(10, 11)
 
       Dim Str3 As String 
           Str3 = LogString.SubString2(6, 8)  '1 0 ... 200     Humidity (one lsb Is 0.5%, e.g. 128 Is 64%)
 
 'Luftfeuchtigkeit
 hum = Bit.ParseInt(Str3, 16)
 
         temp1 = tem1&"."&tem2 ' = Grad
 
          hum1 = hum/2 ' = Relative Luftfeuchtigkeit
 

Wolli013

Active Member
Licensed User
(read only map) {
kCBAdvDataIsConnectable = 0;
kCBAdvDataManufacturerData = <990403c5 1320c6f8 00fe03d8 000c0b89>;
 

Erel

Administrator
Staff member
Licensed User
Are you able to get the manufacturer data?
B4X:
Log(GetType(AdvertisingData.Get("kCBAdvDataManufacturerData"))
Log("LogString: " & AdvertisingData.Get("kCBAdvDataManufacturerData"))
 

Erel

Administrator
Staff member
Licensed User
A bit hacky but try this:
B4X:
Dim s As String = AdvertisingData.Get("kCBAdvDataManufacturerData")
s = s.SubString2(1, s.Length - 1)
Dim bc As ByteConverter
Dim b() As Byte = bc.HexToBytes(s)
 

Wolli013

Active Member
Licensed User
B4X:
Dim s As String = AdvertisingData.Get("kCBAdvDataManufacturerData")
s = s.SubString2(1, s.Length - 1)
Dim bc As ByteConverter
1076: Dim b() As Byte = bc.HexToBytes(s)

Dim hex As String = bc.HexFromBytes(b)

'Temperatur
Private temperature As Int
Private tem1,tem2,hum As Int
Private temp1,hum1 As Float
Dim temperatureSign As Boolean = Bit.And(b(4), 0x80) <> 0
temperature = Bit.And(b(4), 0x7f)' + (b(5) / 100.0)
    If temperatureSign Then
    temperature = -temperature
    End If
tem1 = temperature
tem2 = b(5)

'Luftfeuchtigkeit
    Dim Str3 As String
     Str3 = hex.SubString2(6, 8)
      hum = Bit.ParseInt(Str3, 16)
'Ergebniss
    temp1 = tem1&"."&tem2 ' = Grad
    hum1 = hum/2 ' = Relative Luftfeuchtigkeit
Error occurred on line: 1076 (Main)
-[__NSCFString characterAtIndex:]: Range or index out of bounds
Stack Trace: (
CoreFoundation <redacted> + 252
libobjc.A.dylib objc_exception_throw + 56
CoreFoundation <redacted> + 0
CoreFoundation <redacted> + 112
Te-[B4IByteConverter HexToBytes:] + 192
CoreFoundation <redacted> + 144
CoreFoundation <redacted> + 292
Te+[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1624
Te-[B4IShell runMethod:] + 448
Te-[B4IShell raiseEventImpl:method:args::] + 1648
Te-[B4IShellBI raiseEvent:event:params:] + 1580
Te+[B4IObjectWrapper raiseEvent:::] + 300
Te-[BleDelegate centralManager:didDiscoverPeripheral:advertisementData:RSSI:] + 552
CoreBluetooth <redacted> + 1060
CoreBluetooth <redacted> + 620
CoreBluetooth <redacted> + 60
libdispatch.dylib <redacted> + 24
libdispatch.dylib <redacted> + 16
libdispatch.dylib <redacted> + 592
libdispatch.dylib <redacted> + 480
libdispatch.dylib <redacted> + 784
CoreFoundation <redacted> + 12
CoreFoundation <redacted> + 1924
CoreFoundation CFRunLoopRunSpecific + 436
GraphicsServices GSEventRunModal + 104
UIKitCore UIApplicationMain + 212
Temain + 124
libdyld.dylib <redacted> + 4
)
 

Erel

Administrator
Staff member
Licensed User
B4X:
s = s.SubString2(1, s.Length - 1).Replace(" ", "")
log(s)
Dim b() As Byte = bc.HexToBytes(s)
 

Wolli013

Active Member
Licensed User
runs partially

B4X:
Dim bc As ByteConverter
Dim s As String = AdvertisingData.Get("kCBAdvDataManufacturerData")
s = s.SubString2(1, s.Length - 1).Replace(" ", "")
Log(s)
Dim b() As Byte = bc.HexToBytes(s)

Dim hex As String = bc.HexFromBytes(b)

'Temperatur
Private temperature As Int
Private tem1,tem2,hum As Int
Private temp1,hum1 As Float

1087:Dim temperatureSign As Boolean = Bit.And(b(4), 0x80) <> 0

temperature = Bit.And(b(4), 0x7f)' + (b(5) / 100.0)
    If temperatureSign Then
    temperature = -temperature
    End If
tem1 = temperature
tem2 = b(5)

'Luftfeuchtigkeit
    Dim Str3 As String
     Str3 = hex.SubString2(6, 8)
      hum = Bit.ParseInt(Str3, 16)
'Ergebniss
    temp1 = tem1&"."&tem2 ' = Grad
    hum1 = hum/2 ' = Relative Luftfeuchtigkeit
Error occurred on line: 1087 (Main)
Out of bounds. Index=4 Length=1
 

Erel

Administrator
Staff member
Licensed User
Help us help you. What is the output of Log(s)?

Put a breakpoint on that line. What is the length of b?
 

Wolli013

Active Member
Licensed User
Log(s)
ul

with Error

Error occurred on line: 1087 (Main)
Out of bounds. Index=4 Length=1
Stack Trace: (
CoreFoundation <redacted> + 252
libobjc.A.dylib objc_exception_throw + 56
CoreFoundation <redacted> + 0
Te-[B4IArray getByteFast:] + 224
CoreFoundation <redacted> + 144
CoreFoundation <redacted> + 292
Te+[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1624
Te-[B4IShell runMethod:] + 448
Te-[B4IShell raiseEventImpl:method:args::] + 1648
Te-[B4IShellBI raiseEvent:event:params:] + 1580
Te+[B4IObjectWrapper raiseEvent:::] + 300
Te-[BleDelegate centralManager:didDiscoverPeripheral:advertisementData:RSSI:] + 552
CoreBluetooth <redacted> + 1060
CoreBluetooth <redacted> + 620
CoreBluetooth <redacted> + 60
libdispatch.dylib <redacted> + 24
libdispatch.dylib <redacted> + 16
libdispatch.dylib <redacted> + 592
libdispatch.dylib <redacted> + 480
libdispatch.dylib <redacted> + 784
CoreFoundation <redacted> + 12
CoreFoundation <redacted> + 1924
CoreFoundation CFRunLoopRunSpecific + 436
GraphicsServices GSEventRunModal + 104
UIKitCore UIApplicationMain + 212
Temain + 124
libdyld.dylib <redacted> + 4
)
 

Erel

Administrator
Staff member
Licensed User
I'm sorry but I don't understand anything from these posts.


Works fine here:
B4X:
Dim s As String = "9904037a184ac72a0036fff104160bbf"
Dim bc As ByteConverter
Dim b() As Byte = bc.HexToBytes(s)
Log(b.Length)
Dim temperatureSign As Boolean = Bit.And(b(4), 0x80) <> 0
Log(temperatureSign)
Use the debugger to better understand the values.
 

Wolli013

Active Member
Licensed User
I'm probably getting something that doesn't belong there.
But I will find out.
Many, many thanks for your help.
I've made a lot of progress and now I can do the rest on my own.
Have a nice Sunday.
I love B4A and B4I
 

emexes

Well-Known Member
Licensed User
I started off converting your Swift code to B4A for fun, using a SInt8ToUInt16 sub, but then I decided to just do it line by line with no library. Probably too late, but perhaps there might be some stuff that is useful.

Btw I am a bit sus about the temperature fraction being in 0.01 (decimal) rather than 0.00000001 (binary), but given that other scalings are decimal, perhaps it is ok.

B4X:
Sub Process_Globals

    Type RuuviTagType( _
        Humidity As Double, _
        Temperature As Double, _
        Pressure As Double, _
        AccelerationX As Double, _
        AccelerationY As Double, _
        AccelerationZ As Double, _
        Voltage As Double, _
        UpdatedAt As Long _
    )
   
End Sub

Sub DecodeData(Data() As Byte) As RuuviTagType

    '''let ruuviTag = RuuviTag()
    Dim RuuviTag As RuuviTagType

    If Data.Length < 16 Then
        Log("Data(" & Data.Length & ") too short, should be at least 16 bytes")
    End If
   
    '''RuuviTag.humidity = Double(data[3]) * 0.5
    RuuviTag.Humidity = Data(3) * 0.5
   
    '''let temperatureSign = (data[4] >> 7) & 1
    '''let temperatureBase = data[4] & 0x7F
    Dim TemperatureSign As Int = Bit.And(Data(4), 0x80)    'slight deviation here - non-zero means negative
    Dim TemperatureBase As Int = Bit.And(Data(4), 0x7F)
   
    '''let temperatureFraction = Double(data[5]) / 100.0
    Dim TemperatureFraction As Double = Data(5) / 100    'decimal fraction? not binary? or 16-bit int scaled by 0.01?
   
    '''var Temperature = Double(temperatureBase) + TemperatureFraction
    Dim Temperature As Double = TemperatureBase + TemperatureFraction
   
    '''If (temperatureSign == 1) {
    '''    Temperature *= -1;
    '''}
    If TemperatureSign <> 0 Then
        Temperature = -Temperature
    End If
   
    '''RuuviTag.temperature = Temperature
    RuuviTag.Temperature = Temperature    'déjà vu ;-)
   
    '''let pressureHi = data[6] & 0xFF
    '''let pressureLo = data[7] & 0xFF
    Dim PressureHi As Int = Bit.And(Data(6), 0xFF)    'high byte first?
    Dim PressureLo As Int = Bit.And(Data(7), 0xFF)
   
    '''ruuviTag.pressure = Double(PressureHi) * 256.0 + 50000.0 + Double(pressureLo)
    '''ruuviTag.pressure /= 100.0;
    RuuviTag.Pressure = Bit.Or(Bit.ShiftLeft(PressureHi, 8), PressureLo) + 50000    'offset by 50000?
    RuuviTag.Pressure = RuuviTag.Pressure / 100
   
    '''RuuviTag.accelerationX = Double(UInt16(data[8]) << 8 | UInt16(data[9] & 0xFF)) / 1000.0;
    '''RuuviTag.accelerationY = Double(UInt16(data[10]) << 8 | UInt16(data[11] & 0xFF)) / 1000.0;
    '''RuuviTag.accelerationZ = Double(UInt16(data[12]) << 8 | UInt16(data[13] & 0xFF)) / 1000.0;
    RuuviTag.AccelerationX = Bit.Or(Bit.ShiftLeft(Bit.And(Data( 8), 0xFF), 8), Bit.And(Data( 9), 0xFF)) / 1000
    RuuviTag.AccelerationY = Bit.Or(Bit.ShiftLeft(Bit.And(Data(10), 0xFF), 8), Bit.And(Data(11), 0xFF)) / 1000
    RuuviTag.AccelerationZ = Bit.Or(Bit.ShiftLeft(Bit.And(Data(12), 0xFF), 8), Bit.And(Data(13), 0xFF)) / 1000
   
    '''let battHi = data[14] & 0xFF;
    '''let battLo = data[15] & 0xFF;
    Dim BattHi As Int  = Bit.And(Data(14), 0xFF)
    Dim BattLo As Int = Bit.And(Data(15), 0xFF)
   
    '''RuuviTag.voltage = (Double(BattHi) * 256.0 + Double(BattLo)) / 1000.0;
    RuuviTag.Voltage = Bit.Or(Bit.ShiftLeft(BattHi, 8), BattLo) / 1000
   
    '''RuuviTag.updatedAt = NSDate()
    RuuviTag.UpdatedAt = DateTime.Now
   
    Return RuuviTag
   
End Sub
 
Top