Zoeken…


Invoering

Heet om gegevens te lezen en te schrijven naar een Bluetooth-apparaat met lage energie.

Opmerkingen

Enkele belangrijke punten

  • Er zijn geen mogelijkheden nodig.
  • iPhone-winkelbytes in Little Endian-indeling, controleer dus of Bluetooth-accessoires Little Endian gebruiken. Voorbeeld:
    • Intel CPU gebruikt meestal weinig endian.
    • De ARM-architectuur was little-endian vóór versie 3 toen deze big-endian werd.
  • Na een enkele of batchbewerking gaat de verbinding verloren, dus u moet opnieuw verbinding maken voordat u doorgaat.

Scannen op SERVICE UUID

func SearchBLE(){
    cb_manager.scanForPeripherals(withServices:[service_uuid], options: nil)
    StopSearchBLE()
}

Hoe SERVICE UUID te ontdekken zonder documentatie

func centralManager(_ central: CBCentralManager, didConnect peripheral:             
CBPeripheral) {
        peripheral.delegate = self
        peripheral.discoverServices(nil)
}

func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    for service in peripheral.services! {
        print("Service: \(service)\n error: \(error)")
    }
}
  • discoverServices (nil) - NIL betekent dat alle services worden geretourneerd, wat geen goede optie is. (LEES Opmerkingen 3)
  • Als u de SERVICE UUID niet hebt gevonden, voert u uw code uit en zoekt u in de console voer hier de afbeeldingsbeschrijving in
  • Ik vond 3 services: Batterij, Apparaatinformatie (Firmware) en FFF0
  • Deze uuid-service is niet standaard, een lijst met standaarden vindt u hier
  • FFF0 is in dit geval de SERVICEUUID

Converteer gegevens naar UInt16 en omgekeerd

Voeg deze extensies toe aan je klas

protocol DataConvertible {
    init?(data: Data)
    var data: Data { get }
}

extension DataConvertible {

    init?(data: Data) {
        guard data.count == MemoryLayout<Self>.size else { return nil }
        self = data.withUnsafeBytes { $0.pointee }
    }

    var data: Data {
        var value = self
        return Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
    }
}
extension UInt16 : DataConvertible {
    init?(data: Data) {
        guard data.count == MemoryLayout<UInt16>.size else { return nil }
        self = data.withUnsafeBytes { $0.pointee }
    }
    var data: Data {
        var value = CFSwapInt16HostToBig(self)
        return Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
    }
}

Namen weergeven van alle Bluetooth Low Energy (BLE)

  • Voor dit voorbeeld heb ik een gecontroleerde kamer met één BLE-apparaat inschakelen.
  • Je klas moet CBCentralManagerDelegate uitbreiden.
  • Implementeer de methode: centralManagerDidUpdateState (_ central: CBCentralManager).
  • Gebruik globale wachtrij om het scherm niet te bevriezen tijdens het zoeken naar een apparaat.
  • Instantiate CBCentralManager en wacht op callback centralManagerDidUpdateState reactie.
class BLEController: CBCentralManagerDelegate{

var cb_manager: CBCentralManager!
var bles : [CBPeripheral] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        cb_manager = CBCentralManager(delegate: self, queue: DispatchQueue.global())
    }

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        print("UPDATE STATE - \(central)")
    }
}

Terugbellen naar centralManagerDidUpdateState geeft aan dat CoreBluetooth gereed is, zodat u nu naar BLE kunt zoeken. Update centralManagerDidUpdateState-code om te zoeken naar alle BLE-apparaten wanneer deze gereed zijn.

func centralManagerDidUpdateState(_ central: CBCentralManager) {
    print("UPDATE STATE - \(central)")
    SearchBLE()
}

func SearchBLE(){
    cb_manager.scanForPeripherals(withServices: nil, options: nil)
    StopSearchBLE()
}

func StopSearchBLE() {
    let when = DispatchTime.now() + 5 // change 5 to desired number of seconds
    DispatchQueue.main.asyncAfter(deadline: when) {
        self.cb_manager.stopScan()
    }
}
  • SearchBLE () zoek naar BLE-apparaten en stop na 5 seconden met zoeken
  • cb_manager.scanForPeripherals (withServices: nil, options: nil) zoekt met u naar elke BLE die binnen bereik is.
  • StopSearchBLE () stopt het zoeken na 5 seconden.
  • Elke gevonden BLE roept callback func centralManager op (_ central: CBCentralManager, didDiscover perifeer: CBPeripheral, advertentie Data: [String: Any], rssi RSSI: NSNumber)
func centralManager(_ central: CBCentralManager, didDiscover peripheral:                                                             
    CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    guard let name = peripheral.name else {
        return
    }
    print(name)
    bles.append(peripheral)
}

Verbind en lees belangrijke waarde

  • Ik ben in een gecontroleerde ruimte met een enkel baken dat het IBEACON-protocol gebruikt.
  • BLEController moet CBPeripheralDelegate uitbreiden
  • Ik gebruik de eerste BLE om verbinding te maken nadat het zoeken is gestopt.
  • Wijzig de methode StopSearchBLE ()
class BLEController: CBCentralManagerDelegate, CBPeripheralDelegate{
//...
    func StopSearchMiniewBeacon() {
        let when = DispatchTime.now() + 5 // change 2 to desired number of seconds
        DispatchQueue.main.asyncAfter(deadline: when) {
            self.cb_manager.stopScan()
            self.cb_manager.connect(bles.first)
        }
    }
/...
}
  • In de documentatie van uw BLE-apparaat moet u zoeken naar de SERVICE UUID en GROTE UUID-KENMERKEN
var service_uuid =  CBUUID(string: "0000fff0-0000-1000-8000-00805f9b34fb")
var major_uuid =  CBUUID(string: "0000fff2-0000-1000-8000-00805f9b34fb")
func centralManager(_ central: CBCentralManager, didConnect peripheral:             
CBPeripheral) {
    peripheral.delegate = self
    peripheral.discoverServices([service_uuid])
}

func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    print("Service: \(service)\n error: \(error)")
    peripheral.discoverCharacteristics([major_uuid], for: (peripheral.services?[0])!)
}
  • Maak hierboven een variabele 'service_uuid' en 'major_uuid' zoals code. '-0000-1000-8000-00805f9b34fb' maakt deel uit van de standaard. 'fff0' is mijn SERVICE UUID, 'fff2' is mijn BELANGRIJKE UUID-kenmerk en '0000' zijn vereist om het 4 bytes uuid 1º blok te vullen.
  • discoverCharacteristics ([major_uuid], for: (perifere.services? cialis0])!) krijgt een belangrijk kenmerk van mijn apparaat gatt-server en heeft nu NIL als waarde.
  • (Peripheral.services?[0])! - 0 omdat ik een enkele waarde retourneer nadat ik perifere.discoverServices heb gedaan ([service_uuid])
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    for characteristic in service.characteristics! {
        print("Characteristic: \(characteristic)\n error: \(error)")
        if(characteristic.uuid.uuidString == "FFF2"){
            peripheral.readValue(for: characteristic)
        }
    }
}

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    print("Characteristic read: \(characteristic)\n error: \(error)")
    let major = UInt16.init(bigEndian: UInt16(data: characteristic.value!)!)
    print("major: \(major)")
}
  • Karakteristieke waarde is alleen leesbaar na aanroep perifere.readValue (voor: kenmerk)
  • readValue zal resulteren in func perifeer (_ perifeer: CBPeripheral, didUpdateValueFor kenmerk: CBCharacteristic, error: Error?) met waarde in gegevenstype.

Schrijf belangrijke waarde

  • U moet de diensten en het kenmerk ontdekken
  • U hebt geen leeswaarde van het kenmerk nodig voordat u eroverheen schrijft.
  • gaat door voor, bijvoorbeeld, na leeswaarde. Modify func perifeer (_ perifeer: CBPeripheral, didUpdateValueFor kenmerk: CBCharacteristic, error: Error?)
  • Voeg een variabele new_major en reset_characteristic toe
var reset_characteristic : CBCharacteristic!
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    for characteristic in service.characteristics! {
        print("Characteristic: \(characteristic)\n error: \(error)")
        if(characteristic.uuid.uuidString == "FFF2"){
            peripheral.readValue(for: characteristic)
        }
        if(characteristic.uuid.uuidString == "FFFF"){
            reset_characteristic = characteristic
        }
    }
}
let new_major : UInt16 = 100
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    print("Characteristic read: \(characteristic)\n error: \(error)")
    let major = UInt16.init(bigEndian: UInt16(data: characteristic.value!)!)
    print("major: \(major)")
    peripheral.writeValue(new_major.data, for: characteristic, type: CBCharacteristicWriteType.withResponse)
}
  • iPhone by deafult verzendt en ontvangt bytes in Little Endian-formaat, maar mijn apparaat MINEW met chipset NRF51822 heeft ARM archteture en heeft bytes in Big Endian-formaat nodig, dus ik moet het ruilen.
  • De documentatie van het BLE-apparaat geeft aan welk type invoer en uitvoer elk kenmerk zal hebben en of u het kunt lezen zoals hierboven (CBCharacteristicWriteType.withResponse).
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
    print("Characteristic write: \(characteristic)\n error: \(error)")
    if(characteristic.uuid.uuidString == "FFF2"){
            print("Resetting")
            peripheral.writeValue("minew123".data(using: String.Encoding.utf8)!, for: reset_characteristic, type: CBCharacteristicWriteType.withResponse)
        }
    if(characteristic.uuid.uuidString == "FFFF"){
        print("Reboot finish")
        cb_manager.cancelPeripheralConnection(peripheral)
    }
}
  • Om een GATT-serverinformatie bij te werken, moet u deze programmatisch opnieuw opstarten of gegevens opslaan en handmatig in- en uitschakelen.
  • FFFF is kenmerkend voor dit apparaat.
  • 'minew123' is het standaardwachtwoord voor opnieuw opstarten of informatie in dit geval opslaan.
  • voer je app uit en bekijk je console op fouten, ik hoop dat er geen fouten zijn, maar je zult de nieuwe waarde nog niet zien.
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    print("Characteristic read: \(characteristic)\n error: \(error)")
    let major = UInt16.init(bigEndian: UInt16(data: characteristic.value!)!)
    print("major: \(major)")
    //peripheral.writeValue(new_major.data, for: characteristic, type: CBCharacteristicWriteType.withResponse)

}

  • Laatste stap is om de laatste regel in de methode didUpdateValueFor te becommentariëren en de app opnieuw uit te voeren, nu krijgt u de nieuwe waarde.


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow