Search code examples
objective-cnsdatabluetooth-lowenergyuint8t

how to extract byte data from bluetooth heart rate monitor in objective c


Im having trouble understanding bytes and uint8_t values.

I am using the sample project created by apple that reads data from a Bluetooth 4.0 heart rate monitor via the heart rate service protocol. THe sample project gives out heart rate data as below:

- (void) updateWithHRMData:(NSData *)data 
{
const uint8_t *reportData = [data bytes];
uint16_t bpm = 0;

if ((reportData[0] & 0x01) == 0) 
{
    /* uint8 bpm */
    bpm = reportData[1];
} 
else 
{
    /* uint16 bpm */
    bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[1]));
}

I am assuming that (reportData[0] & 0x01) returns the first data bit in the data array reportData but I dont know how to access the second, (reportData[0] & 0x02) doesn't work like I thought it would. Ideally I would like to check all the data in reportData[0] and then based on that grab the rr interval data in reportData[4] or [5] dependant on where it is stored and iterate through it to get each value as I believe there can be multiple values stored there.

a newbie question I know but Im having trouble finding the answer, or indeed the search terms to establish the answer.


Solution

  • When you do reportData[0] you are getting the first byte (at index 0). When you combine that value with reportData[0] & 0x02, you are masking out all but the 2nd bit. This result will either be 0 (if bit 2 is not set) or it will be 2 (if the 2nd bit is set).

    if ((reportData[0] & 0x02) == 0) {
        // bit 2 of first byte is not set
    } else {
        // bit 2 of first byte is set
    }
    

    If you want to check all 8 bits then you could do:

    uint8_t byte = reportData[0];
    for (int i = 0; i < 8; i++) {
        int mask = 1 << i;
        if ((byte & mask) == 0) {
            bit i is not set
        } else {
            bit i is set
        }
    }
    

    Update: To extract a value that spans two bits you do something like this:

    uint8_t mask = 0x01 | 0x02; // Good for value stored in the first two bits
    uint8_t value = byte & mask; // value now has just value from first two bits
    

    If the value to extract is in higher bits then there is an extra step:

    uint8_t mask = 0x02 | 0x04; // Good for value in 2nd and 3rd bits
    uint8_t value = (byte & mask) >> 1; // need to shift value to convert to regular integer