Поиск…


Вступление

Горячая запись и запись данных на устройство с низким энергопотреблением.

замечания

Некоторые важные моменты

  • Никаких возможностей не требуется.
  • iPhone хранит байты в формате Little Endian, поэтому проверьте, использует ли bluetooth-аксессуар Little Endian. Пример:
    • Intel CPU обычно использует немного endian.
    • Архитектура ARM была миниатюрной до версии 3, когда она стала широкоформатной.
  • После однократной или пакетной операции соединение будет потеряно, поэтому перед продолжением необходимо снова подключиться.

Сканировать для SERVICE UUID

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

Как открыть SERVICE UUID без документации

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 означает, что все службы будут возвращены, что не является хорошим вариантом. (READ Remarks 3)
  • Если вы еще не обнаружили, что SERVICE UUID запускает ваш код и ищет консоль введите описание изображения здесь
  • Я обнаружил, что у меня есть 3 службы: Аккумулятор, Информация об устройстве (Firmware) и FFF0
  • Этот сервис uuid не является стандартным, список со стандартами можно найти здесь
  • FFF0 - это SERVICE UUID в этом случае

Преобразование данных в UInt16 и наоборот

Добавьте эти расширения в свой класс

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

Отображение имен всех Bluetooth Low Energy (BLE)

  • В этом примере у меня есть контролируемая комната с одним устройством BLE.
  • Ваш класс должен расширить CBCentralManagerDelegate.
  • Внедрите метод: centralManagerDidUpdateState (_ central: CBCentralManager).
  • Используйте глобальную очередь, чтобы не затормозить экран во время поиска устройства.
  • Выполните активацию CBCentralManager и дождитесь ответа callManagerDidUpdateState.
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)")
    }
}

Обратный вызов centralManagerDidUpdateState указывает, что CoreBluetooth готов, поэтому вы можете искать BLE сейчас. Обновите код centralManagerDidUpdateState для поиска всех устройств BLE, когда они будут готовы.

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 () выполняет поиск устройств BLE и прекращает поиск после 5 секунд
  • cb_manager.scanForPeripherals (withServices: nil, options: nil) ищет все BLE в диапазоне с вами.
  • StopSearchBLE () остановит поиск после 5 секунд.
  • Каждый найденный BLE будет callback func centralManager (_ central: CBCentralManager, didDiscover периферийное: CBPeripheral, advertData: [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)
}

Подключить и прочитать главное значение

  • Я в контролируемой комнате с одним маяком, который использует протокол IBEACON.
  • BLEController необходимо расширить CBPeripheralDelegate
  • Я буду использовать первый BLE для подключения после остановки поиска.
  • Измените метод 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)
        }
    }
/...
}
  • В документации вашего устройства BLE вы должны искать SERVICE UUID и MAJOR UUID ХАРАКТЕРИСТИКА
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])!)
}
  • Создайте переменную 'service_uuid' и 'major_uuid', как показано выше. '-0000-1000-8000-00805f9b34fb' является частью стандарта. 'fff0' - мой СЕРВИСНЫЙ UUID, 'fff2' - моя главная характеристика UUID, и '0000' необходимо заполнить блок размером 4 байта uuid 1º.
  • discoverCharacteristics ([major_uuid], для: (peripheral.services?[0])!) будет получать основные характеристики с моего gatt-сервера устройства, и на данный момент он будет иметь значение NIL.
  • (Peripheral.services?[0])! - 0 beacuse вернет одно значение после того, как я сделал периферийное. 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)")
}
  • Характеристическое значение будет читаемым только после вызова peripheral.readValue (для: характеристики)
  • readValue приведет к периферийной функции func (_ периферийная: CBPeripheral, didUpdateValueFor характеристика: CBCharacteristic, error: Error?) со значением в типе данных.

Напишите основное значение

  • Вам необходимо открыть службы и характеристики
  • Перед тем, как написать над ним, вам не нужно считывать значение с характеристики.
  • будет продолжен для этого примера после значения чтения. Изменить func периферийное (_ периферийное: CBPeripheral, didUpdateValueДля характеристики: CBCharacteristic, ошибка: ошибка?)
  • Добавьте переменную new_major и 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 by deafult отправит и получит байты в формате Little Endian, но мое устройство MINEW witch чипсет NRF51822 имеет ARM archteture и нуждается в байтах в формате Big Endian, поэтому мне нужно его поменять.
  • Документация BLE Device сообщит, какой тип ввода и вывода будет иметь каждый признак, и если вы можете прочитать его, как указано выше (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)
    }
}
  • Чтобы обновить информацию о gatt-сервере, вам необходимо перезагрузить его программным способом или сохранить данные на нем, выключить и включить вручную.
  • FFFF характерен для этого устройства.
  • «minew123» - это пароль по умолчанию для перезагрузки. o сохранение информации в этом случае.
  • запустите приложение и наблюдайте за консолью за любую ошибку, я надеюсь, что нет, но вы еще не увидите новое значение.
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)

}

  • Последний шаг - прокомментировать последнюю строку в методе didUpdateValueFor и повторно запустить приложение, теперь вы получите новое значение.


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow