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


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.

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)

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)

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

End Sub

Hier noch ein Auszug aus dem SwiftCode

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


Licensed User
Einstein here just realised I could easily write the following without using a library:
Sub BytesToUint16(HiByte As Byte, LoByte As Byte) As Int

    Return Bit.Or(Bit.ShiftLeft(Bit.And(HiByte, 0xFF), 8), Bit.And(LoByte, 0xFF))

End Sub

Sub BytesToSint16(HiByte As Byte, LoByte As Byte) As Int

    Return Bit.Or(Bit.ShiftLeft(HiByte, 8), Bit.And(LoByte, 0xFF)

End Sub
and then the above example would reduce to stuff like:
'''let battHi = data[14] & 0xFF;
'''let battLo = data[15] & 0xFF;
'''RuuviTag.voltage = (Double(BattHi) * 256.0 + Double(BattLo)) / 1000.0;
RuuviTag.Voltage = BytesToUint16(Data(14), Data(15))
except now you don't have those intermediate temporaries BattHi and BattLo... is that good thing or bad ???
Upvote 0


Licensed User
I'd still check that temperature reading closely, though, given that all the other measurements are first converted to a 16-bit number, and then scaled.

It is like the temperature should either be:
- the divide by 100 (decimal) should really be divide by 0x100 (hexadecimal), or
- the divide by 100 (decimal) should be done *after* the two bytes are converted to a 16-bit number.
Upvote 0


Licensed User
In fact, if it's BLE then the packet is probably described by GATT, which tends towards the second interpretation (convert to 16-bit, then scale).

These are the defined GATT data types (sorry about the formatting: apparently a few months ago, decided it was too hard to update the human-readable spec):

<Enumeration key="0" value="Reserved For Future Use"/>
<Enumeration key="1" value="Boolean"/>
<Enumeration key="2" value="unsigned 2-bit integer"/>
<Enumeration key="3" value="unsigned 4-bit integer"/>
<Enumeration key="4" value="unsigned 8-bit integer"/>
<Enumeration key="5" value="unsigned 12-bit integer"/>
<Enumeration key="6" value="unsigned 16-bit integer"/>
<Enumeration key="7" value="unsigned 24-bit integer"/>
<Enumeration key="8" value="unsigned 32-bit integer"/>
<Enumeration key="9" value="unsigned 48-bit integer"/>
<Enumeration key="10" value="unsigned 64-bit integer"/>
<Enumeration key="11" value="unsigned 128-bit integer"/>
<Enumeration key="12" value="signed 8-bit integer"/>
<Enumeration key="13" value="signed 12-bit integer"/>
<Enumeration key="14" value="signed 16-bit integer"/>
<Enumeration key="15" value="signed 24-bit integer"/>
<Enumeration key="16" value="signed 32-bit integer"/>
<Enumeration key="17" value="signed 48-bit integer"/>
<Enumeration key="18" value="signed 64-bit integer"/>
<Enumeration key="19" value="signed 128-bit integer"/>
<Enumeration key="20" value="IEEE-754 32-bit floating point"/>
<Enumeration key="21" value="IEEE-754 64-bit floating point"/>
<Enumeration key="22" value="IEEE-11073 16-bit SFLOAT"/>
<Enumeration key="23" value="IEEE-11073 32-bit FLOAT"/>
<Enumeration key="24" value="IEEE-20601 format"/>
<Enumeration key="25" value="UTF-8 string"/>
<Enumeration key="26" value="UTF-16 string"/>
<Enumeration key="27" value="Opaque Structure"/>
Last edited:
Upvote 0


Licensed User
The BLE GATT units page is still readable:

But the previously-readable format presentation page is kaput:

Happily, has a copy:

The key takeaway from that page is that the descriptor specifies the numeric Format (type eg, uint16, sint32, float32) and Exponent (decimal scaling) and Unit, but I am not seeing anything that covers the half-and-half interpretation like with the Ruuvi temperature.
Upvote 0


Licensed User
Example of GATT descriptor:

- first byte = format = 0x04 = unsigned 8-bit integer
- second byte = exponent = 0x00 = scale/multiply by 10^0 ie 1.0
- third byte and fourth bytes = unit = 0x27AD = org.bluetooth.unit.percentage

Upvote 0