Как отправлять и получать данные через CBL2CAPChannel - PullRequest
0 голосов
/ 19 декабря 2018

Я пытаюсь открыть канал L2CAP между двумя устройствами iOS и передавать данные в обе стороны.Одно из устройств действует как центральное, а другое - как периферийное.

На периферийной стороне:

Я публикую L2CAPChannel следующим образом:

func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
    if peripheral.state == .poweredOn {
        peripheral.publishL2CAPChannel(withEncryption: false)
    }
}

Пробовал оба значения true и false для шифрования.

Затем, после публикации канала, я получаю PSM из метода делегата didPublishL2CAPChannel и создаю сервис с характеристикой, содержащей PSM в качестве значения, и начинаю рекламировать его..

На центральной стороне:

Я сканирую периферийные устройства, нахожу подходящую, подключаюсь к ней, начинаю обнаруживать службы, затем, когда служба обнаруживается, я обнаруживаюхарактеристики.Я нахожу характеристику, читаю ее значение и получаю PSM.Затем я делаю это:

self.peripheral.openL2CAPChannel(psm)

Затем я получаю вызов в методе делегата, что канал открыт, и делаю это:

func peripheral(_ peripheral: CBPeripheral, didOpen channel: CBL2CAPChannel?, error: Error?) {
    guard error == nil else {
        print("Couldn't open channel. Error: \(error!.localizedDescription)")
        return
    }
    self.l2capChannel = channel
    self.l2capChannel?.inputStream.delegate = self
    self.l2capChannel?.outputStream.delegate = self
    print("L2CAP channel opened with \(peripheral.name ?? "unknown")")
}

Это печатает:

L2CAP channel opened with mrsta’s iPad

На периферийной стороне снова:

Я получаю обратный вызов в методе делегата:

func peripheralManager(_ peripheral: CBPeripheralManager, didOpen channel: CBL2CAPChannel?, error: Error?) {
    guard error == nil else {
        print("Couldn't open channel. Error: \(error!.localizedDescription)")
        return
    }
    self.l2capChannel = channel
    self.l2capChannel?.inputStream.delegate = self
    self.l2capChannel?.outputStream.delegate = self
    print("L2CAP channel opened")
}

Это печатает:

[CoreBluetooth] No central present! Creating a new object. This shouldn't happen.
L2CAP channel opened

Пока что похоже, что канал открыт с обеих сторон.Мне просто интересно, что это за сообщение на вышеприведенном принте "... Нет централизованного присутствия! ..."

Через некоторое время я начинаю получать подобные сообщения в консоли:

[CoreBluetooth] WARNING: Unknown error: 436
[CoreBluetooth] No known channel matching peer <CBPeripheral: 0x2829de120, identifier = 241BAA6F-0BFD-9F5A-1EC9-35A4FD246DF5, name = mrsta’s iPad, state = connected> with psm 192
[CoreBluetooth] WARNING: Unknown error: 431

Я понятия не имею, что это значит.Любые предложения?

Я также реализовал метод StreamDelegate с обеих сторон:

func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
    print("Stream Event occurred: \(eventCode)")
    if eventCode == .hasSpaceAvailable {
        self.tryToWrite()
    }
}

Но вышеупомянутый метод делегата никогда не вызывается.Я пытаюсь записать в выходной поток, как это (tryToWrite вызывается из метода делегата канала didOpen на центральной стороне):

func tryToWrite() {
    let string = "Hello"
    let stringData = Data(from: string)
    let _ = stringData.withUnsafeBytes { write(stuff: $0, to: self.l2capChannel, withMaxLength: stringData.count) }
}

func write(stuff: UnsafePointer<UInt8>, to channel: CBL2CAPChannel?, withMaxLength maxLength: Int) {
    let result = channel?.outputStream.write(stuff, maxLength: maxLength)
    print("Write result: \(String(describing: result))")
}

И результат:

Write result: Optional(-1)

На основе которогов документации означает, что запись не удалась.

Скажите, пожалуйста, что мне не хватает?Что это за ошибки, которые я получаю после открытия канала, и как правильно писать и читать данные?

1 Ответ

0 голосов
/ 08 апреля 2019

Я использую L2CAP, и он работает.В обеих функциях didOpen я делаю

self.l2capChannel = channel

self.l2capChannel?.inputStream.delegate = self 
self.l2capChannel?.inputStream.schedule(in: .main, forMode: .defaultRunLoopMode)
self.l2capChannel?.inputStream.open()

self.l2capChannel?.outputStream.delegate = self
self.l2capChannel?.outputStream.schedule(in: .main, forMode: .defaultRunLoopMode)
self.l2capChannel?.outputStream.open()

, а когда они мне больше не нужны, я закрываю их

self.l2capChannel?.inputStream.close()
self.l2capChannel?.inputStream.remove(from: .main, forMode: .defaultRunLoopMode)

self.l2capChannel?.outputStream.close()
self.l2capChannel?.outputStream.remove(from: .main, forMode: .defaultRunLoopMode)

self.l2capChannel? = nil
...