从字节获取字符串(Corebluetooth,Swift)

Getting a String from a byte (Corebluetooth, Swift)

只是想看看是否有人可以帮助我解决一些 BLE 问题。我正在尝试制作一个从我的划船机获取数据的应用程序,但我不知道如何将字节转换为字符串?很难解释,但这是我的 VC:

import UIKit
import CoreBluetooth


let rowerServiceCBUUID = CBUUID(string: "CE060000-43E5-11E4-916C-0800200C9A66")
let characteristic1CBUUID = CBUUID(string: "CE060031-43E5-11E4-916C-0800200C9A66")
let characteristic2CBUUID = CBUUID(string: "2AD1")
class HRMViewController: UIViewController {
  @IBOutlet weak var heartRateLabel: UILabel!
  @IBOutlet weak var bodySensorLocationLabel: UILabel!
  var centralManager: CBCentralManager!
  var pmPeripheral: CBPeripheral!
  var wattValue: Int!
  override func viewDidLoad() {
    super.viewDidLoad()
    centralManager = CBCentralManager(delegate: self, queue: nil)
    // Make the digits monospaces to avoid shifting when the numbers change
    heartRateLabel.font = UIFont.monospacedDigitSystemFont(ofSize: heartRateLabel.font!.pointSize, weight: .regular)
  }

  func onHeartRateReceived(_ heartRate: Int) {
    heartRateLabel.text = String(heartRate)
    print("BPM: \(heartRate)")
  }
}
extension HRMViewController: CBCentralManagerDelegate {
  func centralManagerDidUpdateState(_ central: CBCentralManager) {
      print("Central state update")
      if central.state != .poweredOn {
          print("Central is not powered on")
      } else {
          print("Central scanning for", rowerServiceCBUUID);
          centralManager.scanForPeripherals(withServices: [rowerServiceCBUUID],
                                            options: [CBCentralManagerScanOptionAllowDuplicatesKey : true])
      }
  }

  func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    print(peripheral)
    peripheral.delegate = self
    pmPeripheral = peripheral
    pmPeripheral.delegate = self
    centralManager.stopScan()
    centralManager.connect(pmPeripheral!)
  }
  func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    print("Connected!")
    pmPeripheral.discoverServices(nil)
  }

}
extension HRMViewController: CBPeripheralDelegate {
  func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    guard let services = peripheral.services else { return }
    for service in services {
      print(service)
      print(service.characteristics ?? "characteristics are nil")
      peripheral.discoverCharacteristics(nil, for: service)
    }
  }
  func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?){
    guard let characteristics = service.characteristics else { return }
    for characteristic in characteristics {
      print(characteristic)
      if characteristic.properties.contains(.read) {
        print("\(characteristic.uuid): properties contains .read")
      }
      if characteristic.properties.contains(.notify) {
        print("\(characteristic.uuid): properties contains .notify")
      }
      peripheral.readValue(for: characteristic)
    }
  }
  func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic,
                  error: Error?) {
    switch characteristic.uuid {
      case characteristic1CBUUID:
        let bodySensorLocation = bodyLocation(from: characteristic)
        bodySensorLocationLabel.text = bodySensorLocation
      default:
        print("Unhandled Characteristic UUID: \(characteristic.uuid)")
    }
  }
  private func bodyLocation(from characteristic: CBCharacteristic) -> String {
    guard let characteristicData = characteristic.value,
      let byte = characteristicData.first else { return "Error" }
    switch byte {
      case 0: return "0"
      case 1: return "1"
      case 2: return "2"
      case 3: return "3"
      case 4: return "4"
      case 5: return "5"
      case 6: return "6"
      case 7: return "7"
      case 8: return "8"
      default:
        return "Reserved for future use"
    }
  }
}

特别是最底部的文本是我卡住的地方,每个 Corebluetooth 指南都将数字交换为文本,但我的是一个字符串数组(如此处所示:https://youtu.be/rXDCBVQXdbg

我被困住了,不知道从这里去哪里。如有任何帮助,我们将不胜感激!

根据您正在使用的 UUID,您当前关注的是 C2 赛艇一般状态特征,记录在 Concept2 Performance Monitor Bluetooth Smart Communications Interface Definition.[=14 第 11 页=]

文档说消息将包含 19 个字节:

  • 字节 0:运行时间 Lo(0.01 秒 lsb)
  • 字节 1:中间经过的时间
  • 字节 2:经过时间高
  • 字节 3:距离 Lo (0.1 m lsb)
  • 字节 4:中距离
  • 字节 5:距离高
  • 字节 6:锻炼类型(枚举)
  • ...

经过的时间存储在3个字节中:字节0是最低有效字节(LSB),其次是中字节和高字节。单位为0.01s。所以要得到秒数,必须除以100。

距离的存储方式类似。单位是0.1m.

锻炼类型在字节 6 中作为枚举给出。所以不包含文本。只是一个数字代码。

要对其进行解码,请使用如下代码。函数 onRowingGeneralStatusUpdate(for:) 替换了你容易混淆的命名函数 bodyLocation(from:):

func onRowingGeneralStatusUpdate(characteristic: CBCharacteristic) {
    guard let data = characteristic.value else { return }

    // elapsed time in sec
    let elapsedTime: Double = Double(Int(data[0]) + 256 * Int(data[1]) + 65536 * Int(data[2])) / 100.0
    // distance in m
    let distance: Double = Double(Int(data[3]) + 256 * Int(data[4]) + 65536 * Int(data[5])) / 10.0
    let workout: String =  workoutType(for: data[6])
}

func workoutType(for code: UInt8) -> String {
    switch code {
    case 0:
        return "Just row, no splits"
    case 1:
        return "Just row, splits"
    case 2:
        return "Fixed dist, no splits"
    case 3:
        return "Fixed dist, splits"
    case 4:
        return "Fixed time, no splits"
    case 5:
        return "Fixed time, splits"
    case 6:
        return "Fixed time, interval"
    case 7:
        return "Fixed dist, interval"
    case 8:
        return "Variable, interval"
    case 9:
        return "Variable, undef rest, interval"
    case 10:
        return "Fixed, calorie"
    case 11:
        return "Fixed, watt-minutes"
    case 12:
        return "Fixed cals, interval"
    default:
        return ""
    }
}