简体   繁体   English

BLE节奏特征解析iOS蓝牙Swift

[英]BLE cadence characteristic parsing iOS bluetooth Swift

I am trying to create an iOS app that reads a cadence sensor (Wahoo fitness cadence).我正在尝试创建一个读取节奏传感器(Wahoo 健身节奏)的 iOS 应用程序。 This is bluetooth characteristic 0x2A5B (CSC Measurement) .这是蓝牙特性0x2A5B(CSC 测量) In this example, cadence is how fast the pedals rotate on a bike.在这个例子中,踏频是自行车上踏板旋转的速度。

I am using the code below in Swift to read the characteristic from the sensor: Version 1:我在 Swift 中使用下面的代码从传感器读取特性:版本 1:

private func cadence(from characteristic: CBCharacteristic) -> Int {

    guard let characteristicData = characteristic.value else {return -1 }
    let byteArray = [UInt8](characteristicData)
    print(byteArray)

    let firstBitValue = byteArray[1] & 0x01 //set bit 1 (not 0)
    if firstBitValue == 1 { //IF crank revolution data is present, 1==true
        return Int(byteArray[2])
    } else {
        return 0
    }
}

When I print byteArray, I get "[2, 1, 0, 152, 11]".当我打印 byteArray 时,我得到“[2, 1, 0, 152, 11]”。 the "2" and "0" never change. “2”和“0”永远不会改变。 the "1" position increases and never decreases. “1”位置增加并且从不减少。 The "152" and "11" positions seem to be completely random, never changing to 0. They do not change either when the crank is completely stopped. “152”和“11”的位置似乎是完全随机的,永远不会变为0。当曲柄完全停止时,它们也不会改变。 When reading the documentation, I expected the "11" to be the last event crank time.在阅读文档时,我预计“11”是最后一个事件启动时间。 But it appears to not change despite how slow I spin the sensor.但不管我旋转传感器有多慢,它似乎都没有改变。

How can I use this data to get the cadence from the sensor?如何使用此数据从传感器获取节奏?

After working with Paul's help, I have made changes to the code and ended up at the result below:在 Paul 的帮助下,我对代码进行了更改,结果如下:

Version 2版本 2

    func cadence(from characteristic:CBCharacteristic, previousRotations:Int = 0) -> (rpm:Double, rotations:Int)? {
        guard let characteristicData = characteristic.value else {
            return nil
        }

        let byteArray = [UInt8](characteristicData)
        if  byteArray[0] & 0x02 == 2 {
            // contains cadence data
            let rotations = (Int(byteArray[2]) << 8) + Int(byteArray[1])
            var deltaRotations = rotations - previousRotations
            if deltaRotations < 0 {
                deltaRotations += 65535
            }
            let timeInt = (Int(byteArray[4]) << 8) + Int(byteArray[3])
            let timeMins =  Double(timeInt) / 1024.0 / 60.0
            let rpm = Double(deltaRotations) / timeMins

            return (rpm:rpm, rotations: rotations)
        }
        return nil
}

The RPM's being returned are currently below expected values, at around 53 being the highest, and 3 being the lowest.返回的 RPM 当前低于预期值,最高约为 53,最低为 3。 These values are compared to the sensor developer's app which indicates around 50-70 rpm.这些值与传感器开发人员的应用程序进行比较,该应用程序指示大约 50-70 rpm。

Version 3:版本 3:

func cadence(from characteristic:CBCharacteristic, previousTime: Int=0, previousRotations:Int = 0) -> (rpm:Double, time: Int, rotations:Int)? {
            guard let characteristicData = characteristic.value else {
                return nil
            }

            let byteArray = [UInt8](characteristicData)
            if  byteArray[0] & 0x02 == 2 {
                // contains cadence data
                let rotations = Int(byteArray[2])<<8 + Int(byteArray[1])
                var deltaRotations = rotations - previousRotations
                if deltaRotations < 0 {
                    deltaRotations += 65535
                }
                let timeInt = Int(byteArray[4])<<8 + Int(byteArray[3])
                var timeDelta = timeInt - previousTime
                if (timeDelta < 0) {
                    timeDelta += 65535
                }

                let timeMins =  Double(timeDelta) / 1024.0 / 60
                let rpm = Double(deltaRotations) / timeMins

                return (rpm:rpm, time: timeInt, rotations: rotations)
            }
            return nil
        }

This is what I ended up doing这就是我最终做的

func onCSC(from characteristic: CBCharacteristic) -> Double{
    guard let characteristicData = characteristic.value else { return -1 }
    let byteArray = [UInt8](characteristicData)
    let firstBitValue  = byteArray[0] & 0x01 // Bit1 [2] == 0010 & 0000 == 0000 == 0 (Dec) Wheel Rev FALSE (For Spd)
    let secondBitValue = byteArray[0] & 0x02 // Bit2 [2] == 0010 & 0010 == 0010 == 2 (Dec) Crank Rev TRUE  (For Cad)
    
    if firstBitValue > 0 {
      // Since using Wahoo RPM cadence only sensor. (Revisit Later)
    }
    
    if secondBitValue > 0 {
      let cumCrankRev   = Int(byteArray[2])<<8 + Int(byteArray[1])
      let lastCrankTime = Int(byteArray[4])<<8 + Int(byteArray[3])
      
      var deltaRotations = cumCrankRev - prevCumCrankRev
      if deltaRotations < 0 { deltaRotations += 65535 }
      
      var timeDelta = lastCrankTime - prevCrankTime
      if (timeDelta < 0) { timeDelta += 65535 }
      // In Case Cad Drops, we use PrevRPM 
      // to substitute (up to 2 seconds before reporting 0)
      if (timeDelta != 0) {
        prevCrankStaleness = 0
        let timeMins =  Double(timeDelta) / 1024.0 / 60
        rpm = Double(deltaRotations) / timeMins
        prevRPM = rpm
      } else if (timeDelta == 0 && prevCrankStaleness < 2 ) {
        rpm = prevRPM
        prevCrankStaleness += 1
      } else if (prevCrankStaleness >= 2) {
        rpm = 0.0
      }

      prevCumCrankRev = cumCrankRev
      prevCrankTime = lastCrankTime
      return rpm
    }
    return -1
  }

According to the specs from bluetooth.com根据 bluetooth.com 的规格

  //  byte1 uint8: flags
  //   bit 0 = 1: Wheel Revolution Data is present
  //   bit 1 = 1: Crank Revolution Data is present
  //
  //   byte2/3 The next two fields are present only if bit 0 above is 1:
  //    uint32: Cumulative Wheel Revolutions
  //    uint16: Last Wheel Event Time, in 1024ths of a second
  //
  //   byte 3/4 The next two fields are present only if bit 10 above is 1:
  //    uint16: Cumulative Crank Revolutions
  //    uint16: Last Crank Event Time, in 1024ths of a second

  //    Flag       : 2 (0x2)
  //    CumWheel   : 6 (0x6)
  //    LastWheel  : 0 (0x0)
  //    CumCrank   : 231 (0xe7)
  //    LastCrankTm: 30 (0x1e)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM