2015-01-19 7 views
15

Obwohl undokumentiert, konventionelle Weisheit mit dem Android BLE Apis ist, dass bestimmte Operationen wie Lesen/Schreiben Merkmale einzeln vorgenommen werden müssen (obwohl einige Geräte milder als andere sind) . Es ist mir jedoch nicht klar, ob diese Richtlinie nur für eine einzelne Verbindung oder für alle aktiven Verbindungen gelten soll.Robust kommunizieren mit mehreren BLE-Geräten gleichzeitig auf Android

Ich habe gehört, dass es am besten ist, Verbindungen zu Geräten einzeln zu initiieren. Dies könnte ein Beispiel für Operationen (connect/connectGatt) sein, die seriell zwischen allen Geräten ausgeführt werden sollten.

Aber für andere Operationen, wie Lesen und Schreiben Merkmale, ist es gut genug, wenn jede Verbindung Operationen seriell ausführt, oder brauche ich eine globale Operationswarteschlange zwischen allen Geräten, so dass zwischen allen Geräten nur eine Operation ausgeführt wird?

+0

Meine eigenen Tests bestätigen, dass die Lesevorgänge zumindest pro Verbindung seriell sein müssen, aber ich bin sehr daran interessiert, die Antwort auf Ihren letzten Absatz zu kennen. – stkent

Antwort

-1

BLE ist asynchron und ereignisgesteuert. Sie können die Befehle senden, wie Sie möchten, und Sie erhalten die Antworten in keiner bestimmten Reihenfolge zurück. Wenn Sie einen Befehl senden und erwarten, dass das nächste Paket die Antwort ist, werden Sie in Schwierigkeiten geraten.

Dies gesagt, ich bin mir nicht sicher, wie die Android-Bibliothek darum herum strukturiert ist.

+0

Während die vom Android-Bluetooth-Stack bereitgestellten APIs darauf hindeuten, dass Asynchronität unterstützt wird, ist dies in der Realität leider nicht der Fall. Wenn mehrere charakteristische Leseanforderungen schnell ausgelöst werden, führt dies beispielsweise nur zu einem einzigen Leseergebnis. Ich habe dies bestätigt, indem ich die Rate der Leseanforderungen künstlich verlangsamt habe. In diesem Fall geben alle ein Leseergebnis zurück. – stkent

2

Während ich nicht für die obere Schicht sprechen kann, kann ich mich darauf beziehen, was auf einer niedrigeren Hardware-Ebene passieren wird, und das könnte einige Einsichten für Ihr Design liefern.

Was auch immer der Stapel auf der oberen Schicht tut, am Ende muss die Operation vom Transceiver-Chip gehandhabt werden.

BLE arbeitet über 40 Kanalband, in denen 3 für Broadcast und andere für die Datenübertragung verwendet werden. Dies wird getan, um in der Lage zu sein, eine Vielzahl von Geräten miteinander kommunizieren zu lassen, die die Kollision begrenzen, indem sie sich auf anderen Frequenzbändern befinden.

Diese Bänder werden basierend auf dem mit dem geringsten Rauschen (oder Verkehr) ausgewählt.

Der Transceiver selbst kann nur in einem Band gleichzeitig kommunizieren (sprechen und hören) und muss zwischen Bändern wechseln, um andere Geräte zu erreichen. Dies geschieht durch ein sehr enges Timing der Kommunikation. Ein weiterer Fakt ist, dass ein drahtloser Transceiver im Grunde eine Art von Halbduplex-Kommunikation mit Kollisionserkennung ist, er kann nicht gleichzeitig senden und hören, noch können zwei Geräte gleichzeitig auf demselben Band senden. Es ist daher durch Design (und Naturgesetze) seriell oder sequentiell.

Wenn Sie eine Operationswarteschlange oder eine Threaded-Implementierung implementieren, muss am Ende alles vom Transceiver seriell/sequenziell behandelt werden.

Wenn Sie von verschiedenen Threads darauf zugreifen, muss der Transceiver möglicherweise die ganze Zeit zwischen den Kanälen springen oder vielleicht verwirrt werden, wenn er auf der oberen Ebene nicht gut gehandhabt wird.

Der einzige gute Grund, den ich sehen könnte, um das auf Thread zu behandeln, würde sein, dass die Verarbeitungszeit des Transceivers bedeutend niedriger als der obere Stapel ist, den Sie ausführen müssen, und Sie Multi-Core-Prozessor nutzen würden.

Aber sonst, wenn sehr spezielle Software brauchen oder Architektur, ich glaube nicht, dass Sie erhebliche Vorteile haben eine andere Implementierung als seriell und ich würde auch mit den Sklaven eins nach dem anderen statt alle gleichzeitig für die Überlegungen oben erläutert.

+0

Danke, das war sehr interessant und hat mir geholfen zu verstehen, warum der Android-Stack so funktioniert wie er. – stkent

5

Auf Android pro BluetoothGatt Objekt Sie sollten nur eine Operation zu einem Zeitpunkt ausgeführt werden (Anfrage mtu, entdecken Sie Dienstleistungen, Lese-/Schreibcharakteristik/Schlagwort) sonst wird etwas schief geht. Sie müssen warten, bis der entsprechende Callback aufgerufen wird, bis Sie die nächste Operation ausführen können.

Wenn Sie ausstehende Verbindungen zu mehreren Geräten gleichzeitig haben, wenn Sie autoConnect = true verwenden, gibt es kein Problem, aber wenn Sie autoConnect = false verwenden, versucht der Android-Bluetooth-Stack nur eine Verbindung zu einem Gerät herzustellen. Das bedeutet, dass die Verbindungsanforderungen in die Warteschlange eingereiht werden, wenn mehr als eine ausstehende Verbindung vorhanden ist. Es gibt einen bestimmten Fehler, bei dem eine ausstehende Verbindung, die sich noch in der Warteschlange befindet (wenn Sie .disconnect() oder .close() aufrufen), jedoch kürzlich in Android behoben wurde.

Beachten Sie, dass es auch eine maximale Anzahl von Verbindungen/ausstehende Verbindungen/Gatt-Objekte gibt, für die das Verhalten völlig undokumentiert ist, was passiert, wenn Sie diese Grenzen überschreiten. Im besten Fall erhalten Sie einfach einen Rückruf mit Fehlerstatus, aber in einigen Fällen habe ich gesehen, dass der Android-Bluetooth-Stack in einer Endlosschleife stecken bleibt, in der er den Bluetooth-Controller anweist, sich mit einem Gerät zu verbinden der Fehlercode maximale Verbindungen erreicht.

+0

Danke! Zu Problemen wie "Es gibt einen bestimmten Fehler, bei dem eine ausstehende Verbindung, die sich noch in der Warteschlange befindet (wenn Sie .disconnect() oder .close()) aufrufen, nicht abgebrochen werden kann" - haben Sie einen Verweis auf dieses Problem? Ich bin gespannt, was die empfohlene Problemumgehung ist, bis dieser Fix veröffentlicht wird. – stkent

+0

Sicher. Siehe https://code.google.com/p/android/issues/detail?id=228633. Es gibt verschiedene Problemumgehungen: Verwenden Sie autoConnect = true, und stellen Sie sicher, dass Sie nie eine ausstehende gatt connect-Verbindung gleichzeitig haben (mit autoConnect = false), wenn Sie sie manchmal abbrechen, wenn Sie die Firmware-Peripheriegeräte steuern wenn auf dem Link nichts passiert, sagen wir mal 30 Sekunden. – Emil

+0

Wenn Sie sagen "Sie sollten nur einen Vorgang gleichzeitig ausführen", schließt dies auch den ersten Anruf zu "BluetoothGatt.connect" und den letzten Anruf zu "BluetoothGatt.disconnect" und "BluetoothGatt.close" ein? Ich versuche gerade, mich mit bis zu 6 Geräten gleichzeitig zu verbinden, und der Prozentsatz der fehlgeschlagenen Verbindungen scheint zuzunehmen, wenn die Anzahl der Zielgeräte zunimmt. – stkent