2017-02-09 9 views
0

У меня есть датчик TI. Тег как периферийное устройство, которое передает данные BLE в виде kCBAdvDataManufacturerData. Я хотел бы извлечь разные значения из этих данных в iOS.Извлечь данные из kCBAdvDataManufacturerData on Swift

Я выполнение следующих действий в 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() 
    } 
} 

И это то, что я вижу в консоли:

AdvertisementData: [ "kCBAdvDataIsConnectable": 0, "kCBAdvDataManufacturerData": < 0d00fe05 0c6f32> , "kCBAdvDataLocalName": CLIMBC]

Данные, которые меня интересуют в декодировании, это kCBAdvDataManufacturerData: < 0d00fe05 0c6f32> и отображение каждого поля на экране. В частности, это то, что числа представляют в моем случае:

  1. 0d00 - TI производитель ID
  2. FE - идентификатор узла, который я дал
  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, поэтому я нахожу некоторые трудности. Любой фрагмент кода будет приветствоваться.

+1

В псевдокоде 'вар manData = AdvertisementData [«kCBAdvDataManufacturerData»], как Data' Тогда вы можете позвонить' subdata (с диапазоном: NSRange) ', чтобы разделить ваши' manData' на каждую часть, которую вы хотите, и прочитать их. – Larme

ответ

1

Вот реализация быстрого метода 3 данных 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 
+0

@ Prientus. Это было очень полезно. Cheers :) – user3315702

2

Видя выход консоли , advertisementData["kCBAdvDataManufacturerData"] выглядит как NSData, содержащий 7 байт. Вы можете легко получить доступ к нему как 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 
} 
+0

Закодировано и уже проверено. Оно работает. Большой :) – user3315702