как извлечь байтовые данные из монитора сердечного ритма Bluetooth в объективе c

У меня проблемы с пониманием байтов и значений uint8_t.

Я использую образец проекта, созданный Apple, который считывает данные с монитора сердечного ритма Bluetooth 4.0 через протокол службы сердечного ритма. Пример проекта выдает данные о частоте сердечных сокращений, как показано ниже:

- (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]));
}

Я предполагаю, что (reportData[0] & 0x01) возвращает первый бит данных в массиве данных reportData, но я не знаю, как получить доступ ко второму (reportData[0] & 0x02) не работает, как я думал. В идеале я хотел бы проверить все данные в reportData[0], а затем на основе этого получить данные интервала rr в reportData[4] или [5] в зависимости от того, где они хранятся, и выполнить итерацию по ним, чтобы получить каждое значение, как я считаю там может храниться несколько значений.

вопрос новичка, который я знаю, но у меня проблемы с поиском ответа или поисковыми запросами, чтобы установить ответ.


person skeg0    schedule 18.03.2013    source источник


Ответы (3)


Когда вы делаете reportData[0], вы получаете первый байт (с индексом 0). Когда вы объединяете это значение с reportData[0] & 0x02, вы маскируете все, кроме 2-го бита. Этот результат будет либо 0 (если бит 2 не установлен), либо 2 (если установлен 2-й бит).

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

Если вы хотите проверить все 8 бит, вы можете сделать:

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
    }
}

Обновление: чтобы извлечь значение, которое охватывает два бита, вы делаете что-то вроде этого:

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

Если значение для извлечения находится в старших битах, то есть дополнительный шаг:

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
person rmaddy    schedule 18.03.2013
comment
Большое спасибо за ваш ответ, мне было интересно, что, если значение распределено по 2 битам, например. биты хранят числа 1,2,3 или 4? Я предполагаю, что для хранения 3 или 4 необходимо использовать 2 бита, но как посмотреть на эти два бита в целом, а затем извлечь из них одно число и сохранить, например, в int? - person skeg0; 19.03.2013

Проверьте этот пост для обсуждения примера кода. Сообщение также ссылается на Спецификация Bluetooth, которая должна помочь вам понять, почему выполняется проверка порядка следования байтов (по сути, Apple обеспечивает максимальную переносимость). По сути, первый байт представляет собой битовое поле, описывающее формат данных HRV и наличие/отсутствие данных интервалов EE и RR. Так:

reportData[0] & 0x03

сообщает вам, присутствуют ли данные EE (1 = да, 0 = нет), и

reportData[0] & 0x04

сообщает вам, присутствуют ли данные интервала RR (1 = да, 0 = нет)

Затем вы можете получить данные интервала RR с помощью

uint16_t rrinterval;
rrinterval = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[idx]));

где idx определяется проведенными вами тестами на наличие/отсутствие. Я предполагаю, что смещения не являются фиксированными, кстати, как это то, что вы указываете (т.е. динамические смещения, основанные на наличии/отсутствии) - я не знаком со спецификацией BT. Если формат фиксирован, в этом случае данные RR будут со смещением 7.

person jstevenco    schedule 18.03.2013

Часть исходного вопроса еще не решена. Рори также хочет знать, как анализировать все данные RR-интервалов, поскольку в одном сообщении может быть несколько значений (я видел до трех). Данные RR-интервала не всегда располагаются в одних и тех же байтах. Это зависит от нескольких вещей:

  • BPM записывается в один байт или два?
  • есть ли данные ЭЭ?
  • рассчитать количество значений RR-интервала

Вот фактическая спецификация Характеристика Heart_rate_measurement

// Instance method to get the heart rate BPM information
- (void) getHeartBPMData:(CBCharacteristic *)characteristic error:(NSError *)error
{
    // Get the BPM //
    // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml //

    // Convert the contents of the characteristic value to a data-object //
    NSData *data = [characteristic value];

    // Get the byte sequence of the data-object //
    const uint8_t *reportData = [data bytes];

    // Initialise the offset variable //
    NSUInteger offset = 1;
    // Initialise the bpm variable //
    uint16_t bpm = 0;


    // Next, obtain the first byte at index 0 in the array as defined by reportData[0] and mask out all but the 1st bit //
    // The result returned will either be 0, which means that the 2nd bit is not set, or 1 if it is set //
    // If the 2nd bit is not set, retrieve the BPM value at the second byte location at index 1 in the array //
    if ((reportData[0] & 0x01) == 0) {
        // Retrieve the BPM value for the Heart Rate Monitor
        bpm = reportData[1];

        offset = offset + 1; // Plus 1 byte //
    }
    else {
        // If the second bit is set, retrieve the BPM value at second byte location at index 1 in the array and //
        // convert this to a 16-bit value based on the host’s native byte order //
        bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[1]));

        offset =  offset + 2; // Plus 2 bytes //
    }
    NSLog(@"bpm: %i", bpm);



    // Determine if EE data is present //
    // If the 3rd bit of the first byte is 1 this means there is EE data //
    // If so, increase offset with 2 bytes //
    if ((reportData[0] & 0x03) == 1) {
        offset =  offset + 2; // Plus 2 bytes //
    }



    // Determine if RR-interval data is present //
    // If the 4th bit of the first byte is 1 this means there is RR data //
    if ((reportData[0] & 0x04) == 0)
    {
        NSLog(@"%@", @"Data are not present");
    }
    else
    {
        // The number of RR-interval values is total bytes left / 2 (size of uint16) //

        NSUInteger length = [data length];
        NSUInteger count = (length - offset)/2;
        NSLog(@"RR count: %lu", (unsigned long)count);

        for (int i = 0; i < count; i++) {

            // The unit for RR interval is 1/1024 seconds //
            uint16_t value = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[offset]));
            value = ((double)value / 1024.0 ) * 1000.0;

            offset = offset + 2; // Plus 2 bytes //

            NSLog(@"RR value %lu: %u", (unsigned long)i, value);

        }

    }

}
person Brabbeldas    schedule 28.10.2014
comment
Код, который вы разместили, кажется неверным. В соответствии со спецификацией битовый индекс 3 говорит вам, присутствует ли EE, что означает, что ваш чек будет (поскольку мы начинаем считать с 0) reportData[0] & pow(2,2) или просто 0x04, а для RR (битовый индекс 4) ваша маска будет 0x08 или pow(2,3). - person jaaq; 22.07.2019