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

Wolli013

Well-Known Member
Licensed User
Longtime 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
    }
}
 

Wolli013

Well-Known Member
Licensed User
Longtime 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
)
 
Upvote 0

Wolli013

Well-Known Member
Licensed User
Longtime 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
 
Upvote 0

Wolli013

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

Wolli013

Well-Known Member
Licensed User
Longtime 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
)
 
Upvote 0

Wolli013

Well-Known Member
Licensed User
Longtime 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
 
Upvote 0

Wolli013

Well-Known Member
Licensed User
Longtime 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
)
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime 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.
 
Upvote 0

Wolli013

Well-Known Member
Licensed User
Longtime 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
 
Upvote 0

emexes

Expert
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
 
Upvote 0
Top