2017-02-09 4 views
0

J'ai une étiquette de capteur TI en tant que périphérique qui diffuse des données BLE sous la forme de kCBAdvDataManufacturerData. Je voudrais extraire différentes valeurs de ces données dans iOS.Extraire des données de kCBAdvDataManufacturerData sur Swift

J'exécute ce qui suit à 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() 
    } 
} 

Et voici ce que je vois dans la console:

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

Les données que je suis intéressé par le décodage sont les suivantes: kCBAdvDataManufacturerData: < 0d00fe05 0c6f32> et l'affichage de chaque champ à l'écran. Plus précisément, c'est ce que les chiffres représentent dans mon cas:

  1. 0d00 - TI fabricant ID
  2. fe - l'ID de nœud que j'ai donné
  3. 05 - état du nœud (quelque chose qui reste constante
  4. C6F - est la tension de la batterie d'étiquette de détection
  5. 32- est le compteur de paquets BLE

Dans Android je peux. décoder comme suit:

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; 
    } 
    } 
}; 

Comment exactement puis-je y parvenir? Je suis nouveau à Swift c'est pourquoi je trouve quelques difficultés. Tout extrait de code sera le bienvenu.

+1

Dans le code pseudo 'var mandata = AdvertisementData [ « kCBAdvDataManufacturerData »] comme data' Ensuite, vous pouvez appeler' sous-données (avec range: NSRange) 'diviser votre' manData' en chaque partie que vous voulez, et les lire. – Larme

Répondre

1

Voici une implémentation de rapide 3 méthode des données subdata avec un exemple d'une chaîne convertie en données, puis diviser vers octets que vous pouvez reconvertir en chaînes:

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. C'était très utile. Bravo :) – user3315702

2

En voyant la sortie de la console , advertisementData["kCBAdvDataManufacturerData"] semble être un NSData contenant 7 octets. Vous pouvez facilement y accéder en tant que Swift Data, et chaque octet dans un Data est accessible avec l'indice:

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

Codé et déjà testé. Ça marche. Génial :) – user3315702