从 BLE 血糖仪检索血糖数据 - Swift

问题描述 投票:0回答:1

我正在尝试通过 CoreBluetooth 从 Accucheck 即时血糖仪获取血糖数据,这是从我的 didUpdateValueFor 特征方法中调用的方法 -

private func glucoseValue(from characteristic: CBCharacteristic) -> Int {
  guard let characteristicData = characteristic.value else { return -1 }
  let byteArray = [UInt8](characteristicData)

  let firstBitValue = byteArray[0] & 0x01
  if firstBitValue == 0 {
    // Glucose Value Format is in the 2nd byte
    return Int(byteArray[1])
  } else {
    // Glucose Value Format is in the 2nd and 3rd bytes
    return (Int(byteArray[1]) << 8) + Int(byteArray[2])
  }
}

但是我没有得到正确的数据,并且得到了错误的值。 您能帮我解决我做错了什么以及如何正确格式化数据以获得预期结果吗?

这是我的控制台中针对不同 UUID 打印的内容 -

特点====

特点====

特点====

特点====

提前致谢!

swift bluetooth bluetooth-lowenergy core-bluetooth ios-bluetooth
1个回答
0
投票

既然@Sudhanshu问我是怎么解决的,虽然这个问题有点老了,但我想分享我的解决方案来帮助他/她/其他人。

我没有时间记住代码的细节,现在我发现我应该就我的做法写下详细的注释。

过去 3 个小时以来,我一直在与 Bard 交谈,无法帮助我解释足够的解决方案,但我得到了以下有趣的观点:

  • 使用正确的葡萄糖数据特征。
  • 实现准确的 SFLOAT 解析以正确提取值。
  • 根据血糖仪读数验证解析值。
  • 利用RCAP进行同步,确保捕获最新的数据。

我可以确认它与 RCAP 有关,但记得不够。所以,伙计们,你们可以乱搞我的代码,直到你们完全掌握它为止。我希望你们中的任何人都可以回来编辑我的答案,并提供代码注释和更清晰的解释。

extension AccuChekInstantReadingVC: CBPeripheralDelegate {

    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        printDebug("didDiscoverServicesFor: \(peripheral.name ?? "Unknown device name")")

        guard let services = peripheral.services else {
            if let error = error as? NSError {
                printError(error)
            }
            return
        }

        Task { @MainActor in
            // Search for the Glucose Service specifically
            if let service = services.first(where: { $0.uuid == GlucoseService_CBUUID }) {
                // Initiate discovery of necessary characteristics within the Glucose Service
                peripheral.discoverCharacteristics(
                    [
                        RecordAccessControlPoint_CBUUID,
                        MeasurementCharacteristic_CBUUID
                    ],
                    for: service
                )
            }
        }
    }
    
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        printDebug("didDiscoverCharacteristicsFor: \(String(describing: service.description))")

        // Ensure discovered characteristics are available
        guard let characteristics = service.characteristics else {
            return
        }

        printDebug("Found \(characteristics.count) characteristics.")

        Task { @MainActor in
            // Prioritize enabling notifications for the Measurement Characteristic
            if let characteristic = characteristics.first(
                where: { $0.uuid.isEqual(MeasurementCharacteristic_CBUUID) }
            ) {
                peripheral.setNotifyValue(true, for: characteristic)
            }
        }
    }
    
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        hideLoading()

        // Handle Measurement Characteristic updates
        if characteristic.service?.uuid == GlucoseService_CBUUID,
           characteristic.uuid == MeasurementCharacteristic_CBUUID {
            if let data = characteristic.value {
                let numberOfBytes = data.count
                var byteArray: [UInt8] = .init(repeating: 0, count: numberOfBytes)
                (data as NSData).getBytes(&byteArray, length: numberOfBytes)
                let floatValue: Float = [byteArray[12], byteArray[13]].extractSFloat()

                measurementValue = Int(round(floatValue * 100000))

                printDebug("Measurement Data: ", measurementValue ?? 0)

            } else {
                printDebug("Data: nil")
            }
        }

        // Handle RCAP Characteristic updates
        if characteristic.service?.uuid == GlucoseService_CBUUID,
           characteristic.uuid == RecordAccessControlPoint_CBUUID {
            if let data = characteristic.value {
                let numberOfBytes = data.count
                var byteArray: [UInt8] = .init(repeating: 0, count: numberOfBytes)
                (data as NSData).getBytes(&byteArray, length: numberOfBytes)

                if let measurementValue = measurementValue,
                   let lastBit = byteArray.last,
                   lastBit == 1 {
                    onReceivedReadingFromDevice(measurementValue)
                }

                printDebug("RCAP:", byteArray)

            } else {
                printDebug("RCAP: nil")
            }
        }
    }
    
    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
        printDebug("didUpdateNotificationStateFor: \(characteristic.uuid)")
        
        guard error == nil else {
            if let error = error as? NSError {
                printError(error)
            }
            
            return
        }
        
        Task { @MainActor in
            if characteristic.uuid == MeasurementCharacteristic_CBUUID,
               let characteristics = characteristic.service?.characteristics {
                if let characteristic = characteristics.first(
                    where: { $0.uuid.isEqual(RecordAccessControlPoint_CBUUID) }
                ) {
                    try await Task.sleep(nanoseconds: 1500_000_000)

                    peripheral.setNotifyValue(true, for: characteristic)
                    
                    try await Task.sleep(nanoseconds: 200_000_000)
                    
                    peripheral.writeValue(Data([0x01, 0x06]), for: characteristic, type: .withResponse)
                }
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.