Регистр IOBluetooth для уведомления об открытии канала не срабатывает при открытии канала

Я работаю над проектом, для которого требуется Bluetooth 2.1, и я пытаюсь сделать тестовый клиент для подключения к оборудованию.

Итак, я просматривал «документы» для IOBluetooth и сумел передать служебную запись SDP.

Открытие соединения на устройстве (Android) и запись данных на мой компьютер работает (в соответствии с удаленным устройством), но мой клиентский инструмент фактически не вызывает селектор для уведомления...

Это происходит до тех пор, пока я не остановлю клиентскую программу и не запущу ее снова, и в этом случае она сработает немедленно.

Также мало документации о том, как запускаются уведомления, независимо от того, являются ли они асинхронными или нет.

Уже неделю ломаю голову, мысли?

Фиктивный код клиента:

BTSocketSession.swift

class BTSocketSession {

    var lock : DispatchSemaphore = DispatchSemaphore(value: 0);
    var serviceRecord : IOBluetoothSDPServiceRecord? = nil;
    var channel : IOBluetoothRFCOMMChannel? = nil;
    var notification : IOBluetoothUserNotification? = nil;
    var serverID : BluetoothRFCOMMChannelID = 255;
    var done = false;

    init(serviceRecordPListPath: String) {
        print("Loading Service Dictionary...");
        let serviceDict : NSMutableDictionary = NSMutableDictionary(contentsOfFile: serviceRecordPListPath)!;
        print("Done.");
        print("Publishing service...");
        self.serviceRecord = IOBluetoothSDPServiceRecord.publishedServiceRecord(with: serviceDict as! [AnyHashable : Any]);
        print("Done.");
    }

    func listen() {
        var id = BluetoothRFCOMMChannelID();
        self.serviceRecord?.getRFCOMMChannelID(&id);
        self.serverID = id;
        print(serviceRecord ?? "Derp");
        print(id);
        self.notification = IOBluetoothRFCOMMChannel.register(forChannelOpenNotifications: self, selector: #selector(self.rfcommChannelOpen(notification:channel:)), withChannelID: id, direction: kIOBluetoothUserNotificationChannelDirectionIncoming);
        self.lock.wait();
    }

    func cancel() {
        print("Cancelling service advertisement...");
        if (self.serviceRecord == nil) {
            self.removeServiceRecord();
            self.lock.signal();
            print("Done.");
        } else {
            print("Error: No service broadcasting.");
        }
    }

    private func removeServiceRecord() {
        self.serviceRecord?.remove();
        self.serviceRecord = nil;
        self.notification?.unregister();
        self.notification = nil;
    }

    @objc func rfcommChannelOpen(notification: IOBluetoothUserNotification, channel: IOBluetoothRFCOMMChannel) {
        if (self.serverID != channel.getID()) {
            return;
        }
        print("Notification Recieved!!!");
        print(channel);
        print(notification);
        self.done = true;
        notification.unregister();
        self.removeServiceRecord();
        self.channel = channel;
        self.lock.signal();
    }

}

main.swift

func main() {
    let q = DispatchQueue(label: "Demo");
    let s = DispatchSemaphore(value: 0);
    let c = BTSocketSession(serviceRecordPListPath: "/path/to/plist");

    q.async {
        print("Waiting for connection event...");
        c.listen();
        print("Done.");
        print("Releasing main thread...");
        s.signal()
        print("Done.");
    }

    s.wait();
    print("Closing channel...");
    c.channel?.close();
    c.cancel();
    print("Done.");
    print("Exiting...");

}

main();
print("Wellp");

person TinfoilPancakes    schedule 16.05.2017    source источник


Ответы (1)


Решено:

Как оказалось, при создании приложения командной строки / безголового приложения в OSX вы должны использовать интерфейс RunLoop для правильной регистрации системных уведомлений, таких как уведомления об открытии канала Bluetooth.

Решение найдено здесь.

Изменения:

Следующее позволяет программе работать должным образом.

func main() {
    let q = DispatchQueue(label: "Demo");
    let c = BTSocketSession(serviceRecordPListPath: "/path/to/plist");

    q.async {
        print("Waiting for connection event...");
        c.listen();
        print("Done.");
        print("Releasing main thread...");
        c.channel.close();
        CFRunLoopStop(RunLoop.main.getCFRunLoop());
        print("Done.");
    }
    RunLoop.main.run();
    print("Exiting...");
}

main();
print("Wellp");

Жизнь снова прекрасна =) Желаю вам хорошего дня!

person TinfoilPancakes    schedule 18.05.2017