3 votes

Extraire les données de kCBAdvDataManufacturerData sur Swift

J'ai un capteur TI Tag comme 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.

J'exécute ce qui suit en 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 qui m'intéressent pour le décodage sont kCBAdvDataManufacturerData : <0d00fe05 0c6f32> et afficher chaque champ à l'écran. Plus précisément, voici ce que représentent les chiffres dans mon cas :

  1. 0d00 - ID du fabricant de TI
  2. fe - l'ID du noeud que j'ai donné
  3. 05 - état du nœud (quelque chose qui reste constant)
  4. c6f - est la tension de la batterie de la balise du capteur
  5. 32- est le compteur de paquets BLE.

Dans Android, je suis capable de 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 puis-je y parvenir exactement ? Je suis novice en Swift, c'est pourquoi je rencontre quelques difficultés. Tout extrait de code sera le bienvenu.

5voto

OOPer Points 33473

Voir la sortie de votre console, advertisementData["kCBAdvDataManufacturerData"] semble être un NSData contenant 7 octets. Vous pouvez facilement y accéder en tant que Swift Data et chaque octet d'un Data est accessible avec un 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
}

2voto

Prientus Points 628

Voici une mise en œuvre de la méthode Swift 3 Data subdata avec un exemple de chaîne convertie en données, puis divisée en 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X