2013-07-02 31 views

回答

7

你检查Bluetooth spec任何建议?下面的示例代码使用C#,但我认为它显示了解析每个心率数据包中数据的方式。

//first byte of heart rate record denotes flags 
byte flags = heartRateRecord[0]; 

ushort offset = 1; 

bool HRC2 = (flags & 1) == 1; 
if (HRC2) //this means the BPM is un uint16 
{ 
    short hr = BitConverter.ToInt16(heartRateRecord, offset); 
    offset += 2; 
} 
else //BPM is uint8 
{ 
    byte hr = heartRateRecord[offset]; 
    offset += 1; 
} 

//see if EE is available 
//if so, pull 2 bytes 
bool ee = (flags & (1 << 3)) != 0; 
if (ee) 
    offset += 2; 

//see if RR is present 
//if so, the number of RR values is total bytes left/2 (size of uint16) 
bool rr = (flags & (1 << 4)) != 0; 
if (rr) 
{ 
    int count = (heartRateRecord.Length - offset)/2; 
    for (int i = 0; i < count; i++) 
    { 
     //each existence of these values means an R-Wave was already detected 
     //the ushort means the time (1/1024 seconds) since last r-wave 
     ushort value = BitConverter.ToUInt16(heartRateRecord, offset); 

     double intervalLengthInSeconds = value/1024.0; 
     offset += 2; 
    } 
} 
+0

感谢您的详细代码示例中,+ 1给你。我已经在Objective-C中翻译并使用了整体。看到我对这篇文章的回答。 – Brabbeldas

+0

我的Wahoo Tickr传感器有关检测到的r波的数量的行为是相当奇怪的。大多数情况下,我只能得到一个似乎是正确的RR读数。但是当我得到2读数,这两个读数必须加以总结才能得到正确的RR值(bpm:48,rr [0]:0.58,rr [1]:0.62)..但有时它们几乎是两个单独的读数,但有些不太可能的价值。太大或太小.. – Chriz

0

编辑: 这个工作对我来说,我得到了正确的RR值: 在某些情况下,你可以在同一时间RR找到两个值。

- (void) updateWithHRMData:(NSData *)datas { 

    const uint8_t *reportData = [datas bytes]; 

    uint16_t bpm = 0; 
    uint16_t bpm2 = 0; 

    if ((reportData[0] & 0x04) == 0) 
    { 
     NSLog(@"%@", @"Data are not present"); 
    } 
    else 
    { 

     bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[2])); 

     bpm2 = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[4])); 

     if (bpm != 0 || bpm2 != 0) { 

       NSLog(@"%u", bpm); 

       if (bpm2 != 0) { 
        NSLog(@"%u", bpm2); 
       } 

     } 

    } 

} 
1

这篇文章有点老,但没有给出完整的答案。 当我遇到这篇文章,它最终帮助了我,我想分享我的最终代码。希望它能帮助别人。

Daniel Judge提供的代码其实是对的,但正如他已经写过的,它是C#。由于Daniel Judge的代码考虑到一条消息中可能存在两个以上的RR值,所以与Simon M在最后提出的代码相比,HI代码要好一些。 下面是实际的spec of the Heart_rate_measurement characteristic

我有翻译丹尼尔判断他的代码的Objective-C:

// 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); 

     } 

    } 

} 
+0

嗨!你可以向我解释* 1000从哪里来?我知道它与规格“1/1024秒的分辨率”相关,但我不明白操作* 1000 – darksider

0

在@Brabbeldas的解决方案,我不得不使用不同的标志来获得RRI值。但可能取决于使用的设备。

if ((reportData[0] & 0x10) == 0) 

代替

if ((reportData[0] & 0x04) == 0) 
0

解析在 “C” 心脏速率参数

我上传的示例应用程序的GitHub Heart-Rate-Bluegiga

void ble_evt_attclient_attribute_value(const struct ble_msg_attclient_attribute_value_evt_t *msg) 
{ 
    if (msg->value.len < 2) { 
     printf("Not enough fields in Heart Rate Measurement value"); 
     change_state(state_finish); 
    } 


    // Heart Rate Profile defined flags 
    const unsigned char HEART_RATE_VALUE_FORMAT = 0x01; 
    const unsigned char ENERGY_EXPENDED_STATUS = 0x08; 
    const unsigned char RR_INTERVAL = 0x10; 


    unsigned char current_offset = 0; 
    unsigned char flags = msg->value.data[current_offset]; 
    int is_heart_rate_value_size_long = ((flags & HEART_RATE_VALUE_FORMAT) != 0); 
    int has_expended_energy = ((flags & ENERGY_EXPENDED_STATUS) != 0); 
    int has_rr_intervals = ((flags & RR_INTERVAL) != 0); 


    current_offset++; 


    uint16 heart_rate_measurement_value = 0; 


    if (is_heart_rate_value_size_long) 
    { 
     heart_rate_measurement_value = (uint16)((msg->value.data[current_offset + 1] << 8) + 
      msg->value.data[current_offset]); 
     current_offset += 2; 
    } 
    else 
    { 
     heart_rate_measurement_value = msg->value.data[current_offset]; 
     current_offset++; 
    } 


    printf("Heart rate measurment value: %d ", heart_rate_measurement_value); 


    uint16 expended_energy_value = 0; 


    if (has_expended_energy) 
    { 
     expended_energy_value = (uint16)((msg->value.data[current_offset + 1] << 8) + 
      msg->value.data[current_offset]); 
     current_offset += 2; 


     printf(" Expended energy value: %d ", expended_energy_value); 
    } 


    uint16 rr_intervals[10] = {0}; 


    if (has_rr_intervals) 
    { 
     printf(" Rr intervals: "); 


     int rr_intervals_count = (msg->value.len - current_offset)/2; 


     for (int i = 0; i < rr_intervals_count; i++) 
     { 
      int raw_rr_interval = (uint16)((msg->value.data[current_offset + 1] << 8) + 
       msg->value.data[current_offset]); 
      rr_intervals[i] = ((double)raw_rr_interval/1024) * 1000; 
      current_offset += 2; 


      printf("%d ", rr_intervals[i]); 
     } 
     printf("\n"); 
    } 
}