1

I'm trying to implement Bluetooth FTMS(Fitness Machine).

guard let characteristicData = characteristic.value else { return -1 }
let byteArray = [UInt8](characteristicData)
let nsdataStr = NSData.init(data: (characteristic.value)!)

print("pwrFTMS 2ACC Feature  Array:[\(byteArray.count)]\(byteArray) Hex:\(nsdataStr)")

Here is what's returned from the bleno server

PwrFTMS 2ACC Feature Array:[8][2, 64, 0, 0, 8, 32, 0, 0] Hex:{length = 8, bytes = 0x0240000008200000}

Based on the specs, the returned data has 2 characteristics, each of them 4 octet long. I'm having trouble getting the 4 octets split so I can get it converted to binary and get the relevant Bits for decoding.

enter image description here

Part of the problem is the swift will remove the leading zero. Hence, instead of getting 00 00 64 02, I'm getting 642. I tried the below to pad it with leading zero but since it's formatted to a string, I can't convert it to binary using radix:2

let FTMSFeature = String(format: "%02x", byteArray[3]) + String(format: "%02x", byteArray[2]) + String(format: "%02x", byteArray[1]) + String(format: "%02x", byteArray[0])

I've been banging my head on this for an entire day and went thru multiple SO and Google to no avail.

How Can I convert:

From - [HEX] 00 00 40 02
To   - [DEC] 16386
To   - [BIN] 0100 0000 0000 0010

then I can get to Bit1 = 1 and Bit14 = 1

app4g
  • 670
  • 4
  • 24

1 Answers1

2

How Can I convert:

From - [HEX] 00 00 40 02
To - [DEC] 16386
To - [BIN] 0100 0000 0000 0010

You can simply use ContiguousBytes withUnsafeBytes method to load your bytes as UInt32. Note that it will use only the same amount of bytes needed to create the resulting type (4 bytes)

let byteArray: [UInt8] = [2, 64, 0, 0, 8, 32, 0, 0]
let decimal = byteArray.withUnsafeBytes { $0.load(as: UInt32.self) }
decimal  // 16386

To convert from bytes to binary you just need to pad to left your resulting binary string. Note that your expected binary string has only 2 bytes when a 32-bit unsigned integer should have 4:

extension FixedWidthInteger {
    var binary: String {
        (0 ..< Self.bitWidth / 8).map {
            let byte = UInt8(truncatingIfNeeded: self >> ($0 * 8))
            let string = String(byte, radix: 2)
            return String(repeating: "0",
                          count: 8 - string.count) + string
        }.reversed().joined(separator: " ")
    }
}

let binary = decimal.binary  // "00000000 00000000 01000000 00000010"

To know if a specific bit is on or off you can do as follow:

extension UnsignedInteger {
    func bit<B: BinaryInteger>(at pos: B) -> Bool {
        precondition(0..<B(bitWidth) ~= pos, "invalid bit position")
        return (self & 1 << pos) > 0
    }
}

decimal.bit(at: 0)  // false
decimal.bit(at: 1)  // true
decimal.bit(at: 2)  // false
decimal.bit(at: 3)  // false
decimal.bit(at: 14) // true

If you need to get a value at a specific bytes position you can check this post

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • This is fantastic. Thanks a Lot. Tho I fail to understand the meaning of ```ContiguousBytes withUnsafeBytes``` (still googling and reading it). I also am struggling to understand why my previous decoding method does not work. I have posted that as a separate question here -> https://stackoverflow.com/q/68265831/14414215 Could you take a look as well. TQ – app4g Jul 06 '21 at 06:54