2

我无法理解字节和 uint8_t 值。

我正在使用苹果创建的示例项目,它通过心率服务协议从蓝牙 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] 中的所有数据,然后根据它获取 reportData[4] 或 [5] 中的 rr 间隔数据,具体取决于它的存储位置并遍历它以获得我相信的每个值那里可以存储多个值。

一个我知道的新手问题,但我无法找到答案,或者确实找不到建立答案的搜索词。

4

3 回答 3

2

当您这样做时,reportData[0]您将获得第一个字节(在索引 0 处)。当您将该值与 结合时reportData[0] & 0x02,您将屏蔽除第二位以外的所有内容。该结果将是 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
于 2013-03-18T21:49:54.247 回答
1

查看这篇文章以讨论示例代码。该帖子还链接到蓝牙规范,该规范应该可以帮助您了解为什么要执行字节顺序检查(基本上是 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由您执行的存在/不存在测试确定。我假设偏移量不是固定的 BTW,因为这就是您所指示的(即,基于存在/不存在的动态偏移量)——我不熟悉 BT 规范。如果格式固定的,在这种情况下,RR 数据将位于偏移量 7。

于 2013-03-18T22:13:56.307 回答
1

部分原始问题尚未得到解答。Rory 还想知道如何解析所有 RR 间隔数据,因为在一条消息中可以有多个值(我见过最多三个)。RR 间隔数据并不总是位于相同的字节内。这取决于几件事:

  • BPM 是写入一个字节还是两个字节?
  • 有EE数据吗?
  • 计算 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);

        }

    }

}
于 2014-10-28T08:50:36.033 回答