Sök…


Introduktion

Het att läsa och skriva data till en Bluetooth-lågenergienhet.

Anmärkningar

Några viktiga punkter

  • Inga funktioner behövs.
  • iPhone-butiker bytes i Little Endian-format, så kontrollera om Bluetooth-tillbehör använder Little Endian också. Exempel:
    • Intel CPU använder vanligtvis lite endian.
    • ARM-arkitekturen var lite-endian före version 3 när den blev big-endian.
  • Efter en enda eller batchoperation kommer förbindelsen att gå förlorad, så du måste ansluta igen innan du fortsätter.

Sök efter SERVICE UUID

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

Hur man upptäcker SERVICE UUID utan dokumentation

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 betyder att alla tjänster kommer att returneras, vilket inte är ett bra alternativ. (LÄS Anmärkningar 3)
  • Om du inte har hittat SERVICE UUID kör du din kod och letar efter i konsolen ange bildbeskrivning här
  • Jag hittade att jag har tre tjänster: Batteri, enhetsinformation (Firmware) och FFF0
  • Den här tysta tjänsten är inte en standard, en lista med standarder kan hittas här
  • FFF0 är SERVICE UUID i detta fall

Konvertera data till UInt16 och tvärtom

Lägg till tillägg till din klass

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

Visar namn på alla Bluetooth Low Energy (BLE)

  • I det här exemplet har jag ett kontrollerat rum med en enda BLE-enhet aktiverad.
  • Din klass bör utöka CBCentralManagerDelegate.
  • Implementera metoden: centralManagerDidUpdateState (_ central: CBCentralManager).
  • Använd global kö för att inte frysa skärmen när du söker efter en enhet.
  • Instantiate CBCentralManager och vänta på callback centralManagerDidUpdateState svar.
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)")
    }
}

Återuppringning till centralManagerDidUpdateState indikerar att CoreBluetooth är redo, så du kan söka efter BLE nu. Uppdatera centralManagerDidUpdateState-kod för att söka efter alla BLE-enheter när den är klar.

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()
    }
}
  • SökBLE () söka efter BLE-enheter och sluta söka efter 5s
  • cb_manager.scanForPeripherals (withServices: nil, option: nil) letar efter varje BLE i sortimentet med dig.
  • StopSearchBLE () stoppar sökningen efter 5s.
  • Varje BLE som hittas kommer återuppringning func centralManager (_ central: CBCentralManager, didDiscover perifera: CBPeripheral, reklamData: [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)
}

Anslut och läs huvudvärdet

  • Jag befinner mig i ett kontrollerat rum med ett enda gruvfyr som använder IBEACON-protokollet.
  • BLEController måste utöka CBPeripheralDelegate
  • Jag använder den första BLE för att ansluta efter att sökningen har upphört.
  • Ändra metoden 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)
        }
    }
/...
}
  • I dokumentationen av din BLE-enhet bör du leta efter SERVICE UUID- och MAJOR UUID-EGENSKAPER
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])!)
}
  • Skapa en variabel "service_uuid" och "major_uuid" som kod ovan. '-0000-1000-8000-00805f9b34fb' är en del av standarden. 'fff0' är min SERVICE UUID, 'fff2' är min STORA UUID-karakteristik och '0000' krävs för att fylla 4 bytes uuid 1º-blocket.
  • DiscoverCharacteristics ([major_uuid], för: (peripheral.services?vud0])!) kommer att få huvudkarakteristik från min enhetsgatt-server och den kommer att ha NIL som värde för nu.
  • (Peripheral.services?[0])! - 0 beacuse kommer att returnera ett enda värde när jag gjorde perifera.discoverServices ([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)")
}
  • Karakteristiskt värde kommer endast att läsas efter peripheral.readValue (för: karakteristik)
  • readValue kommer att resultera i func perifera (_ perifera: CBPeripher, didUpdateValueFor karakteristik: CBCharacteristic, error: Error?) med värde i Datatyp.

Skriv huvudvärde

  • Du måste upptäcka tjänsterna och kännetecknen
  • Du behöver inte läsvärde från karakteristiken innan du skriver om det.
  • fortsätter för detta exempel efter läsvärde. Ändra func perifera (_ perifera: CBPeripheral, didUpdateValueFör karakteristik: CBCharacteristic, error: Error?)
  • Lägg till en variabel new_major och reset_characteristic
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 av deafult skickar och tar emot byte i Little Endian-format, men min enhet MINEW-häxchipsuppsättning NRF51822 har ARM-arkiv och behöver byte i Big Endian-format, så jag måste byta den.
  • BLE Enhetsdokumentation säger vilken typ av inmatning och utdata varje karaktär har och om du kan läsa den som ovan (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)
    }
}
  • För att uppdatera en gatt-serverinformation måste du starta om den programmatiskt eller spara data till den och stänga av och slå på den manuellt.
  • FFFF är karakteristiskt som gör det i den här enheten.
  • 'minew123' är standardlösenordet för omstart o spara information i detta fall.
  • kör din app och se dig konsol för något fel, jag hoppas ingen, men du kommer inte att se det nya värdet än.
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)

}

  • Sista steget är att kommentera sista raden i metoden didUpdateValueFor och kör appen igen, nu kommer du att det nya värdet.


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow