Android InputStream löscht die ersten zwei Bytes (modifiziertes BluetoothChat)

8

Ich habe Code aus dem Beispiel von BluetoothChat verwendet, um Byte-Daten von einer Bluetooth-Waage zu senden und zu empfangen. Die Waage empfängt den Befehl vom Gerät und sendet dann ein Byte-Array zurück. {2.198,48,48,48,48,199,3} Die 2 = STX und die 198 = Paketstart und 199 = Paketende und 3 = ETX in unserem Kommunikationsprotokoll.

Alles funktioniert gut, außer dass der folgende Code im BluetoothChatService.java merkwürdig reagiert, indem er die ersten zwei Bytes löscht.

%Vor%

Ich habe ein Problem speziell mit dem folgenden Codeabschnitt:

%Vor%

Beim Debuggen und Überprüfen des Inhalts des Puffers in mmInStream.read (Puffer) vor der Ausführung enthält der Puffer die korrekten Daten, die vom Waagengerät zurückgesendet wurden, zB:

%Vor%

Aber sobald der Code schrittweise geändert wurde, werden die ersten zwei Bytes des Puffers entfernt und es enthält nun fälschlicherweise:

%Vor%

und das ist es, was der Nachrichtenhandler dann schließlich an die Aktivität weitergibt.

Für mehr Klarheit muss ich hinzufügen, dass der Stream von Bytes, die von der Waage gesendet werden, Hexadezimalzeichen im Bereich von 00 bis FF sind. Aus irgendeinem seltsamen Grund sieht die Zeichenkette im Debugger so aus:

%Vor%

und dann die 2, -58 werden gelöscht.

Ich habe festgestellt, dass ich, wenn ich ein Byte-Array über einen Socket sende, folgendes tun muss:

%Vor%

Wenn der Inhalt dieses Arrays debuggt wird {2, -58,48,48,48,48,48, -57,3}

Bitte verstehe, dass ich neu bei Android bin - Java und viel zu lernen habe. Alle Hilfe wird geschätzt. Vielen Dank Adrian

Ich habe log.i-Einträge hinzugefügt, um besser zu verstehen, was passiert, basierend auf Radus Ratschlägen. Es scheint, dass, nachdem ich Daten über Bluetooth auf mein Gerät geschrieben habe, es antwortet und wir aus irgendeinem Grund nur die ersten zwei Bytes lesen, dann diese an den Nachrichtenhandler senden, dann den Rest des vom Gerät gesendeten Pakets lesen und dann senden Dies wird an den Message-Handler gesendet, aber bevor der Handler sogar das erste Mal geantwortet hat, wurde der Puffer bereits überschrieben. Wenn also der Handler versucht, die ersten beiden Bytes zu lesen, liest er das 3. und 4. Byte der Antwort Paket, dann sofort reagiert wieder und liest das gesamte Paket von 3-17. Also, wenn ich es einfach ausdrücken kann. Der Message-Handler antwortet nur auf den gesendeten Puffer, nachdem er überschrieben wurde. Siehe das Protokoll unten:

%Vor%

Mein neuer Code setzt auch den Puffer auf 0 zurück, bevor der letzte Datenstrom eingelesen wird, daher sieht der Nachrichten-Handler nur 0, bevor ich dies tat, erschien das Protokoll wie folgt:

%Vor%

Ich hoffe, dass das die Sache nicht durcheinander gebracht hat, sondern tatsächlich das Problem demonstriert, das viele Leute mit dem BluetoothChat-Demo-Code zu haben scheinen, wenn sie für ihren eigenen Gebrauch angepasst wurden. Irgendwie müssen wir verhindern, dass der Puffer überschrieben wird, bis der Nachrichten-Handler ihn gelesen hat. Grüße

Adrian Wreyford

Aktualisierter Code funktioniert besser wegen Schlaf!

%Vor%

Jetzt sehen die Protokolle wie folgt aus:

%Vor%

Beachten Sie, dass die mmInStream.available () 2 Bytes zurückgibt, dann auf der nächsten Zeile des Codes, wenn wir den Puffer lesen, werden 19 Bytes gelesen .. wirklich seltsam, wie es zwischen diesen beiden vermeintlich unmittelbaren Schritten füllt. Der Schlaf scheint genügend Zeit für den Handler zu erlauben, die Nachricht aus dem übergebenen Puffer zu lesen, bevor der Puffer neu geschrieben wird.

Ich hätte erwartet, dass die handler.obtainmessage ... einen eindeutigen Puffer sendet, aber scheinbar den Verweis auf den Thread-Puffer sendet, also den Ärger. Wie kann ich jedes Mal einen eindeutigen Puffer senden? Danke Adrian

    
Adrian Wreyford 02.09.2012, 20:55
quelle

5 Antworten

8

Ich habe Leute gesehen, die bei der Verwendung des Bluetooth-Chat-Beispiels auf dieses Problem gestoßen sind. Das Problem mit dem Beispielcode ist, dass das Nachrichtenobjekt, das an Handler gesendet wird, einfach einen Verweis auf das tatsächliche byte[] -Array enthält, das für jede nachfolgende read() -Operation verwendet wird. Das bedeutet, sobald der Handler die Nachricht erhält und das Array untersucht, hat der nachfolgende Vorgang read() im Bluetooth-Socket bereits die Möglichkeit, neuere Daten in dieses Array zu schreiben.

In dieser Codezeile:

%Vor%

Das Array wird nicht kopiert; Die Nachricht übermittelt lediglich eine Objektreferenz an dasselbe Array.

Der einzige Grund, warum das Bluetooth-Chat-Beispiel für seinen ursprünglichen Zweck funktioniert, ist, weil es kurze Buchstabenbündel mit menschlicher Schreibgeschwindigkeit übermitteln soll. Wenn Sie etwas schneller als das senden, wird die Handler liest aus dem Array zu Müll.

Die Antwort ist, eine Kopie des Arrays zu senden (z. B. System.arraycopy() ) oder einen einfachen Ringpuffer zu verwenden, was meine eigene Bluetooth-Anwendung verwendet.

Die Tatsache, dass die ersten zwei Bytes manipuliert werden, ist eine seltsame, aber es könnte nur auf die spezifische Implementierung der zugrunde liegenden Leseoperation im Bluetooth-Stack auf Ihrem speziellen Gerät zurückzuführen sein. Die einfache Tatsache ist, dass Sie, wenn Sie read() mit diesem Puffer aufgerufen haben, diesen Puffer in der Zwischenzeit nicht mehr berühren sollten oder sich darum kümmern, was darin enthalten ist. Vielleicht tut die bestimmte Bluetooth-Socket-Lese-Implementierung auf Ihrem Gerät etwas mit diesen ersten paar Bytes im Puffer wegen etwas, das mit seiner internen Operation zu tun hat. Aber es sollte dir egal sein, in welchem ​​komischen Zwischenzustand sich der Puffer befindet, während read() blockiert, weil kein anderer Thread versuchen sollte, zu dieser Zeit einen Sinn daraus zu machen. Alles, was Ihnen wichtig ist, ist, dass der Puffer in einem gültigen Zustand mit gültigen Daten ist, wenn read() zurückgibt.

Der Grund, warum die sleep() -Operation das Problem anscheinend teilweise "heilt", ist, weil es eine grobe Methode ist, dem Handler Zeit zu geben, das Array zu betrachten, bevor die nachfolgende read() -Operation das Array bekommt . Dies ist jedoch keine gute Lösung.

Das zweite Problem, das Sie haben, liegt daran, dass in% byte in Java signiert ist. Aus diesem Grund zeigt der Debugger die Bytes als signierte Werte an. Wenn Sie in Ihrer Anwendung mit einem gegebenen Byte als int arbeiten müssen und das Byte ursprünglich nicht signiert ist, tun Sie etwas wie:

%Vor%     
Trevor 05.09.2012, 20:08
quelle
1

Ich denke, das Problem, das Sie sehen mit z. Das 198, das zu -58 wird, ist, weil Java signierte Bytes verwendet, also alles über 127 eine negative Zahl ist. Also wird 198 binary als - (256 - 198) = -58 gesehen.
Die Lösung besteht darin, sie mit einem Code wie dem folgenden in ein int zu konvertieren:

%Vor%     
Oli Glaser 13.10.2012 23:36
quelle
1

Wie bereits erwähnt, ist Bluetooth kein offener Datenstrom wie UDP.

Ich nehme an, dass ein Verständnis von RS232 erforderlich ist, um zu wissen, wann Bytes zusammen verpackt oder einzeln gesendet werden.

mit einem Mikrocontroller-Projekt, stellen Sie sich etwas wie:

vor %Vor%

mit PIC-Mikrochips sind die resultierenden Daten etwa wie folgt:

%Vor%

Mit dem Android zu Mikrocontroller-Projekt, an dem ich gerade arbeite, mache ich so etwas wie:

%Vor%

Ich habe festgestellt, dass Sie beim Lesen eines Bluetooth-Datenstroms effizient mit Ihrem Code arbeiten müssen. Mit anderen Inputstream-Methoden als read () würde ich fast immer das erste Byte verpassen.

Ich habe gerade mit bluetooth smart begonnen, was meiner Meinung nach ganz anders ist, da Daten nur gesendet werden, wenn sie verfügbar sind.

    
Christian Lacdael 23.05.2015 06:51
quelle
0

Nicht sicher, warum das passiert, aber es kann eine seltsame Race-Bedingung sein. Eines der Probleme mit Ihrem Code ist, dass er alle Zeitdaten lesen möchte! Auch wenn keine Daten vorhanden sind.

Vielleicht liest man also die ersten 2 Bytes, dann liest man bei einer nachfolgenden Iteration den Eingangspuffer wieder ohne die ersten 2 Bytes (der Debugger zeigt Ihnen in diesem Fall das falsche Bild).

Was Sie verbessern können, ist, indem Sie diese Zeilen hinzufügen (versuchen Sie nicht, die Paste zu kopieren, ich passe den Code an Ihre vorherige an - es funktioniert vielleicht oder auch nicht):

%Vor%

Beachten Sie, dass ich Log.i anstelle des Debuggers verwende. Es ist besser für Multi-Thread-Sachen, wenn Sie die Protokolle implementieren können und sie Sie nicht stören - und es ist schneller auszuführen und einfacher zu debuggen.

    
Radu 04.09.2012 13:26
quelle
0

Ich war vor ein paar Wochen in der gleichen Position wie du.

Ich habe festgestellt, dass die Lesezählung zufällig ist, wenn Lese (Puffer) verwendet wird. Also wirst du niemals wirklich vorhersagen  wie groß das nächste Datenpaket sein wird.

Die einfache Lösung für mich war, ein einzelnes Byte mit read () zu lesen und es in einen lokalen Puffer einzufügen, bis jedes Byte empfangen wurde.

Hoffe, das hilft.

    
user2046976 06.02.2013 13:16
quelle