I am writing a code in swift to get data from a BLE device (Omron BP7000). I am able to pair with it and get the other service and read the data. But I am unable to get the data of the blood pressure, in didUpdateValueFor characteristic:
. Other delegate of CoreBluetooth have been used and are working as expected. Just when it comes to read/write data to Current time and read data from the Blood pressure characteristic I get the issue. If anyone can post some suggest of how should I proceed will be helpful.
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
switch characteristic.uuid {
case batteryLevelCBUUID:
print("Battery level: (characteristic.value![0])")
let valueBattery = characteristic.value?[0]
batteryLabel.text = "Battery Level =" + " " + String(describing: characteristic.value! [0]) + "%"
centerView.isHidden = false
case currentTimeCBUUID:
peripheral.readValue(for: characteristic)
let currentDate = Date()
// Write the date and time to the characteristic
writeCurrentTime(to: characteristic, in: peripheral)
// print("(characteristic.value as Any) gives Current Time String ")
if let dateTime = extractDateTime(from: characteristic) {
print("Date and Time:", dateTime)
} else {
print("Unable to extract date and time from the characteristic.")
}
case bloodPressureMeasurementCBUUID:
decodeBloodPressureMeasurementData(from: characteristic)
print("(characteristic.value as Any) gives 2A35 ")
default:
print("")
}
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
// Handle write error
print("Error writing value: (error.localizedDescription)")
} else {
// Handle successful write
print("Value written successfully")
// Check if the characteristic supports notifications
if characteristic.properties.contains(.notify) {
peripheral.setNotifyValue(true, for: characteristic)
}
}
}
func writeCurrentTime(to characteristic: CBCharacteristic, in peripheral: CBPeripheral) {
// Get the current date and time
let currentDate = Date()
let calendar = Calendar.current
var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second, .weekday, .nanosecond], from: currentDate)
// Create the value to be written
var value = Data()
value.append(Data(bytes: &components.year!, count: 2)) // Year (2 bytes)
value.append(Data(bytes: "", count: 0))
value.append(UInt8(components.month!)) // Month (1 byte)
value.append(UInt8(components.day!)) // Day (1 byte)
value.append(UInt8(components.hour!)) // Hours (1 byte)
value.append(UInt8(components.minute!)) // Minutes (1 byte)
value.append(UInt8(components.second!)) // Seconds (1 byte)
value.append(UInt8(components.weekday!)) // Day of Week (1 byte)
value.append(contentsOf: components.nanosecond!.bytes(2)) // Fractions of a second (2 bytes)
// Write the value to the Current Time characteristic
peripheral.writeValue(value, for: characteristic, type: .withResponse)
}
func decodeBloodPressureMeasurementData(from characteristic: CBCharacteristic) {
guard let data = characteristic.value else {
print("No data available for decoding.")
return
}
let flags = data[0] // Flags byte
let unitFlags = (flags & 0b00000001) // Bit 0 indicates the unit of blood pressure values
let timestampFlags = (flags & 0b00000010) // Bit 1 indicates the presence of timestamp
// Decode systolic, diastolic, and mean arterial pressure values
let systolicPressure = (data[1] + (data[2] << 8))
let diastolicPressure = (data[3] + (data[4] << 8))
let meanArterialPressure = (data[5] + (data[6] << 8))
// Decode pulse rate value
let pulseRate = (data[7] + (data[8] << 8))
// Decode unit of blood pressure values
let unit: String = (unitFlags != 0) ? "kPa" : "mmHg"
// Process and use the decoded values as needed
print("Systolic Pressure: (systolicPressure) (unit)")
print("Diastolic Pressure: (diastolicPressure) (unit)")
print("Mean Arterial Pressure: (meanArterialPressure) (unit)")
print("Pulse Rate: (pulseRate) bpm")
}
[1]: https://i.stack.imgur.com/fYaxj.png
2
Answers
I have found the answer for this issue. I was using Data() and instead of that when I used NSMutableData() it started working and connected to the BLE device (Omron BP 7000). Following is the code for the answer I have used.
I’m assuming that your Current Time is part of the Current Time Service. Error code 128 (0x80) indicates "Data field ignored." So you’re either sending a field the device doesn’t support, or you’re sending something out of range. The docs also explain that all values are little-endian.
The specs note that Current Time may optionally be written (with response) and is not permitted to be written without response. So you’re correct to write with response. Since you’re getting 0x80 rather than a general write failure, I will assume the characteristic is writable on this device.
So, now turn to the GSS v9, section 3.62 for details on the Current Time characteristic. The structure is 10 octets, an Exact Time 256 (9 octets) followed by an Adjust Reason (1 octet).
Now, turn to Section 3.90 that defines Exact Time 256. It is a Day Date Time struct (section 3.71) followed by a Factions256 uint8.
You get the idea. Go step by step through the spec to build up the format. Do not guess. Never assume it’s obvious. Follow the spec. I’ll skip over some steps and assemble the whole format:
For convenience, I often use this extension on FixedWidthIntegers:
And the Bluetooth day-of-week is different than Foundation’s:
With those, I believe this would be the correct packet:
So then you’re decoding blood pressure. It looks like you’re treating them as integers, when they’re medfloat16, and you’re ignoring the documented scaling factors. Start with section 2.3 of the GSS, which explains how to interpret values generally, and particularly 2.3.2 about scalars. Then see section 3.31 that explains the Blood Pressure Measurement characteristic in detail. You may find the Personal Health Devices Transcoding white paper helpful. "medfloat16" is often referred to as SFLOAT, so you can read section 2.2.2 of the whitepaper for details and an example encoding.
If you have questions about blood pressure after reading the above, open a new question addressing the specific issue you’re having. What is the input? What should the output be? What output are you getting instead?