Search code examples
swiftbit-manipulationbytecore-bluetooth

How to read 19bits out of 3 bytes in Swift?


I have a Data object with 20 bytes that I'm getting from a BLE device.

This is an example when I po the data in the CBCharacteristic:

▿ 20 bytes
  - count : 20
  ▿ pointer : 0x0000000282889ab0
    - pointerValue : 10779925168
  ▿ bytes : 20 elements
    - 0 : 16
    - 1 : 0
    - 2 : 0
    - 3 : 21
    - 4 : 0
    - 5 : 0
    - 6 : 20
    - 7 : 3
    - 8 : 87
    - 9 : 154
    - 10 : 3
    - 11 : 88
    - 12 : 204
    - 13 : 20
    - 14 : 255
    - 15 : 197
    - 16 : 7
    - 17 : 159
    - 18 : 56
    - 19 : 122 

Now I have instructions that tell me that on Byte 1,2,3 there is the signal that I'm looking for as 19 bits (0-524288)

So how can I get that signal value?

I would appreciate reading material on how to get this on my own if necessary. I don't have a proper CS background and I'm lost on how/where to even look for this.

Thank you

EDIT (in response to @Sweeper):

These are instructions for Byte 0

General state / configuration. Contains following bits:
7 (highest) – Error state, reads 0 normally and 1 if any error in hardware side
6 – button pressed (’1’ – button is pressed, ’0’ – button is not pressed)
5 – USB connected (’1’ – USB is connected, ’0’ – USB is not connected)
4 – Charging/charged (’1’ – Charging, ’0’ – not charging)
3 – Gain of channel A. 2 gains (0 is slower, 1 is higher)
2 – Gain of channel B. 2 gains (0 is slower, 1 is higher)
1 – Gain of channel C. 2 gains (0 is slower, 1 is higher)
0 – Gain of channel D. 2 gains (0 is slower, 1 is higher)

And by doing this I can get the expected data for the first byte:

guard let data = characteristic.value else { return }
guard data.count == 20 else { return }
let val = [UInt8](data)
let general:UInt8 = val[0]
let error = general >> 7 & 1
let buttonPressed = general >> 6 & 1
let usbConnected = general >> 5 & 1
let charging = general >> 4 & 1
let gainChannelA = general >> 3 & 1
let gainChannelB = general >> 2 & 1
let gainChannelC = general >> 1 & 1
let gainChannelD = general >> 0 & 1

Does this help in knowing the endianness of the protocol?


Solution

  • Since the data comes from multiple bytes, the answer depends on the endianness implied by the protocol. These 19 bits use two full bytes and three bits in a third byte.

    If these three bytes are stored in unsigned 8-bit variables a, b, and c, the value would be either

    Int(a) << 11 + Int(b) << 3 + Int(c) & 0x07
    

    or

    Int(c) << 11 + Int(b) << 3 + Int(a) & 0x07
    

    values for a b and c would come either from bytes 1, 2, and 3 or bytes 3, 2, 1, depending on the order specified in the protocol.

    Note: Expression x & 0x07 means "three lower bits", because 0x07 hex is 00000111 in binary.