繁体   English   中英

BLE节奏特征解析iOS蓝牙Swift

[英]BLE cadence characteristic parsing iOS bluetooth Swift

我正在尝试创建一个读取节奏传感器(Wahoo 健身节奏)的 iOS 应用程序。 这是蓝牙特性0x2A5B(CSC 测量) 在这个例子中,踏频是自行车上踏板旋转的速度。

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

当我打印 byteArray 时,我得到“[2, 1, 0, 152, 11]”。 “2”和“0”永远不会改变。 “1”位置增加并且从不减少。 “152”和“11”的位置似乎是完全随机的,永远不会变为0。当曲柄完全停止时,它们也不会改变。 在阅读文档时,我预计“11”是最后一个事件启动时间。 但不管我旋转传感器有多慢,它似乎都没有改变。

如何使用此数据从传感器获取节奏?

在 Paul 的帮助下,我对代码进行了更改,结果如下:

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

返回的 RPM 当前低于预期值,最高约为 53,最低为 3。 这些值与传感器开发人员的应用程序进行比较,该应用程序指示大约 50-70 rpm。

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

这就是我最终做的

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
  }

根据 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