I am trying to create an iOS app that reads a cadence sensor (Wahoo fitness cadence). This is bluetooth characteristic 0x2A5B (CSC Measurement). 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:
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]". the "2" and "0" never change. the "1" position increases and never decreases. 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. When reading the documentation, I expected the "11" to be the last event crank time. 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:
Version 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. These values are compared to the sensor developer's app which indicates around 50-70 rpm.
Version 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
}