iosswiftbluetooth-lowenergydata-conversionuint16

How to calculate Int value from Big-endian representation in Swift?


I'm working on transferring a UInt16 value via BLE. From what I read, for this purpose, I need to convert the UInt16 to UInt8 which will be converted to type Data. I have been referring to this thread. For example, I've used the code below:

extension Numeric {
    var data: Data {
        var source = self
        return Data(bytes: &source, count: MemoryLayout<Self>.size)
    }
}
extension Data {
    var array: [UInt8] { return Array(self) }
}

let arr = [16, 32, 80, 160, 288, 400, 800, 1600, 3200]

for x in arr {
    let lenghtByte = UInt16(x)
    let bytePtr = lenghtByte.bigEndian.data.array
    print(lenghtByte, ":", bytePtr)
}

What I can't quite understand is when I convert the UInt16 to a big-endian array, how the values will add up to the corresponding actual value. Hope This makes sense. The output of the above snippet is,

16 : [0, 16]
32 : [0, 32]
80 : [0, 80]
160 : [0, 160]
288 : [1, 32]
400 : [1, 144]
800 : [3, 32]
1600 : [6, 64]
3200 : [12, 128]

What I want to know is how every value after 160 can be calculated using the UInt8 values in a Big-endian array? (i.e. how does [12,128] equate to 3200, likewise).

Thank you in advance :)


Solution

  • What the data property does, is that it looks at the binary representation of the number, chops it up into bytes, and puts it into a Data buffer. For example, for 1600 in big endian, the binary representation look like this:

    0000011001000000
    

    Notice that there are two bytes in the integer - 00000110 ("6" in decimal) and 01000000 ("64" in decimal). This is where [6, 64] comes from.

    To get 1600 back from [6, 64], you just need to be aware that the "6" doesn't actually represent 6, just like how the "5" in 52 doesn't represent 5, but 5 * 10. Here, the "6" represents 6 * 256, or 6 << 8 (6 shifted 8 times to the left). Overall, to get the number back, you do

    a << 8 + b
    

    where a is the first array element, and b is the second.

    In general for a number with n bytes, you can calculate it like this:

    // this code is just to show you how the array and the number relates mathematically
    // if you want to convert the array to the number in code, see
    // https://stackoverflow.com/a/38024025/5133585
    var total = 0
    for (i, elem) in byteArray.enumerated() {
        total += Int(elem) << (8 * (byteArray.count - i - 1))
    }