【问题标题】:Extract data from kCBAdvDataManufacturerData on Swift在 Swift 上从 kCBAdvDataManufacturerData 中提取数据
【发布时间】:2017-06-27 16:40:51
【问题描述】:

我有一个 TI 传感器标签作为外围设备,它以 kCBAdvDataManufacturerData 的形式广播 BLE 数据。我想在 iOS 中从这些数据中提取不同的值。

我正在 Swift 中执行以下操作:

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){     
     for (index, foundPeripheral) in peripherals.enumerated(){
         if foundPeripheral.peripheral?.identifier == peripheral.identifier{
             peripherals[index].lastRSSI = RSSI
             print("AdvertisementData:\(advertisementData)")
             return

         }
     }  

     let isConnectable = advertisementData["kCBAdvDataIsConnectable"] as! Bool
     let displayPeripheral = DisplayPeripheral(peripheral: peripheral, lastRSSI: RSSI, isConnectable: isConnectable)
     peripherals.append(displayPeripheral)
     tableView.reloadData()
    }
}

这就是我在控制台中看到的:

广告数据:[“kCBAdvDataIsConnectable”:0,“kCBAdvDataManufacturerData”:,“kCBAdvDataLocalName”:CLIMBC]

我有兴趣解码的数据是 kCBAdvDataManufacturerData : 并在屏幕上显示每个字段。 具体来说,这就是我的例子中的数字:

  1. 0d00 - TI 制造商 ID
  2. fe - 我给的节点 ID
  3. 05 - 节点的状态(保持不变的东西
  4. c6f - 是传感器标签电池电压
  5. 32- 是 BLE 数据包计数器。

在 Android 中,我可以解码如下:

private static String getNodeIdFromRawPacket(byte[] manufSpecField) {
    if(manufSpecField != null && manufSpecField.length > 1) {
        return String.format("%02X", manufSpecField[0]);
    }else{
        return null;
    }
}
private static int getNodeBatteryVoltageFromRawPacket(byte[] manufSpecField){
    if(manufSpecField != null && manufSpecField.length > 4) {
        return (((((int) manufSpecField[manufSpecField.length - 3]) << 24) >>> 24) << 8) + ((((int) manufSpecField[manufSpecField.length - 2]) << 24) >>> 24);
    }else{
        return 0;
    }
}

private byte[] extractManufacturerSpecificData(byte[] scanRecord, int manufacturer_id){

     if(scanRecord != null) {
         int ptr = 0;
         while (ptr < scanRecord.length && scanRecord[ptr] != 0) {
             int field_length = scanRecord[ptr];
             if (scanRecord[ptr + 1] == (byte) (0xFF)) { //this is true when the manufacturer specific data field has been found
                 if (((scanRecord[ptr + 3] << 8) + scanRecord[ptr + 2]) == manufacturer_id) {
                    byte[] manufacturerSpecificData = new byte[field_length - 3];
                     System.arraycopy(scanRecord, ptr + 4, manufacturerSpecificData, 0, field_length - 3);
                     return manufacturerSpecificData;
                 }
             }
             ptr += (field_length + 1);
         }
         return null;
     }else{
        return null;
     }
  }
};

我究竟如何才能做到这一点?我是 Swift 的新手,这就是我发现一些困难的原因。任何代码 sn-p 都将受到欢迎。

【问题讨论】:

  • 在伪代码var manData = AdvertisementData["kCBAdvDataManufacturerData"] as Data 然后你可以调用subdata(with range: NSRange) 将你的manData 拆分成你想要的每个部分,然后阅读它们。

标签: ios iphone swift3 bluetooth-lowenergy core-bluetooth


【解决方案1】:

为 Swift 更新:

let yourServiceUUIDString = "FFF0"
if let mAdvData = advertisementData["kCBAdvDataServiceUUIDs"] as? [AnyObject], (mAdvData.contains { ($0 as? CBUUID)?.uuidString == yourServiceUUIDString}) {
    print("BLE device found..!")
}

【讨论】:

  • 这行得通,但由于某种原因,当 macOS 宣传这个时,它不包括在内
【解决方案2】:

看到控制台的输出,advertisementData["kCBAdvDataManufacturerData"] 似乎是一个包含 7 个字节的 NSData。您可以轻松地以 Swift Data 的形式访问它,Data 中的每个字节都可以通过下标访问:

if let manufacturerData = advertisementData["kCBAdvDataManufacturerData"] as? Data {
    assert(manufacturerData.count >= 7)
    //0d00 - TI manufacturer ID
    //Constructing 2-byte data as little endian (as TI's manufacturer ID is 000D)
    let manufactureID = UInt16(manufacturerData[0]) + UInt16(manufacturerData[1]) << 8
    print(String(format: "%04X", manufactureID)) //->000D
    //fe - the node ID that I have given
    let nodeID = manufacturerData[2]
    print(String(format: "%02X", nodeID)) //->FE
    //05 - state of the node (something that remains constant
    let state = manufacturerData[3]
    print(String(format: "%02X", state)) //->05
    //c6f - is the sensor tag battery voltage
    //Constructing 2-byte data as big endian (as shown in the Java code)
    let batteryVoltage = UInt16(manufacturerData[4]) << 8 + UInt16(manufacturerData[5])
    print(String(format: "%04X", batteryVoltage)) //->0C6F
    //32- is the BLE packet counter.
    let packetCounter = manufacturerData[6]
    print(String(format: "%02X", packetCounter)) //->32
}

【讨论】:

  • 我在这里得到了manufacturerData.count == 6。因此,Polar H10 设备无法访问最后一个。你有什么想法从manufacturerData这里获取人力资源数据吗?
【解决方案3】:

这里是 swift 3 Data 方法 subdata 的一个实现,其中包含一个将字符串转换为数据然后拆分为字节的示例,您可以将这些字节转换回字符串:

let input = "505450578"
let data = input.data(using: .utf8)

let manufacturerId:Range<Int> = 0..<2
let nodeId:Range<Int> = 2..<4
let nodeState:Range<Int> = 4..<5
let voltage:Range<Int> = 5..<6
let packetCounter:Range<Int> = 6..<9

let subdata1 = data?.subdata(in: manufacturerId)
let subdata2 = data?.subdata(in: nodeId)
let subdata3 = data?.subdata(in: nodeState)
let subdata4 = data?.subdata(in: voltage)
let subdata5 = data?.subdata(in: packetCounter)

//Results from original given string
let str1 = String(data: subdata1!, encoding:.utf8) //50
let str2 = String(data: subdata2!, encoding:.utf8) //54
let str3 = String(data: subdata3!, encoding:.utf8) //5
let str4 = String(data: subdata4!, encoding:.utf8) //0
let str5 = String(data: subdata5!, encoding:.utf8) //578

【讨论】:

  • @Prientus。这很有帮助。干杯:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
  • 1970-01-01
  • 2018-11-23
  • 2017-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多