Forum: PC-Programmierung [Java] Serielle Daten kommen in 2 Packungen


von Frank Weigler (Gast)


Lesenswert?

Hallo,

Mir ist für folgendes Problem leider kein besserer Titel eingefallen.

Ich kommuniziere über die serielle Schnittstelle mit einem 
angeschlossenen Gerät. Die eingehenenden Daten werden wie in dem 
Beispiel hier auf der Seite [1] eingelesen.

Nach Absenden eines Befehls an das Gerät wird dieser immer mit einer 
Antwort quitiert. Funktioniert auch alles eigentlich wie es soll. Nur 
bekomme ich meine Antowrt mal in zwei Paketen, mal in einem Paket. Mit 
Paket meine ich dass der Eventhandler für DATA_AVAILABLE wohl zweimal 
aufgerufen wird.

Manchmal werden dann die 10 Bytes die als Antwort kommen im ersten 
Aufruf gelesen, aber macnhmal 2 Byte im ersten und die restlichen 8 im 
zweiten. Oder 8 im ersten und die restlichen 2 im zweiten.

Hat jemand spontan eine Idee woran das liegen könnte?

[1] 
http://www.mikrocontroller.net/articles/Serielle_Schnittstelle_unter_Java

Gruß

Frank

von Simon K. (simon) Benutzerseite


Lesenswert?

Bei read kann man doch angeben, wie viele Byte er lesen soll. 
Möglicherweise muss man noch irgendwo Timeouts anpassen.

von Rolf Magnus (Gast)


Lesenswert?

> Hat jemand spontan eine Idee woran das liegen könnte?

Vermutlich, weil das eben einfach so ist. Das System weiß ja nicht, daß 
deine Antwort genau 10 Bytes groß ist. Du bekommst halt Daten, wenn es 
meint, seinen Puffer leeren zu müssen.

von Frank Weigler (Gast)


Lesenswert?

> Bei read kann man doch angeben, wie viele Byte er lesen soll.

Also meine Lesebuffer ist 255 Byte gross. Habe jetzt testweise einfach 
mal diese Grösse verwendet, da keine Antwort gröser sein wird als 255. 
Diese Anzahl von Bytes versuche ich dann zu lesen.

byte[] receiveBuffer = new byte[255];

while (inputStream.available() > 0) {
  numBytes = inputStream.read(receiveBuffer, 0, receiveBuffer.length);
}
      }
> Möglicherweise muss man noch irgendwo Timeouts anpassen.

Kurioserweise scheint eine "Warteschleife" vor dem Lesen das Problem zu 
beheben. Finde ich jetzt aber irgendwie ziemlich unschön und verschafft 
nicht gerade ein gutes Gefühl. An welcher Stelle können denn "irgendwo 
Timeouts angepasst" werden.

for (int i = 0; i < 100000; i++){
  for (int j = 0; j < 1000; j++){}
}

> Vermutlich, weil das eben einfach so ist.

Ich weiss jetzt in dem speziellen Fall eben dass die Antwort 10 Byte 
gross sein muss. WIe oben zu lesen ist, ist der Buffer schon grösser.

von Markus V. (Gast)


Lesenswert?

Du solltes Dir mal Gedanken über ein (einfaches) Übertragungs-Protokoll 
machen. Einfach nur irgendwelche Bytes über die Leitung übertragen 
funktioniert schon. Aber wie Rolf schreibt, für das System sind das 
einfach nur Bytes, die es in beliebigen Portionen dem Aufrufer zur 
Verfügung stellt.

Es würde Dir schon helfen, wenn zu zunächst ein definierte Start-Zeichen 
und am Ende ein Stop-Zeichen sendest. Die empfangenen Daten pufferst Du 
über Deinen SerialPort-Event-Handler zwischen und erzeugtst ein eigenes 
Event, wenn eine Nachricht vollständig empfangen wurde. Alles ziemlich 
simpel...

Gruß
Markus

von Markus V. (Gast)


Lesenswert?

Wenn Du Dir übrigens mal die Doku zu InputStream.Read aus Java-Doc zu 
Gemüte führst, wirst Du auf eine Antwort zu Deiner Eingangsfrage stoßen.

Die "Lösung" mit einer Warteschleife (mir rollt es die Fußnägel auf!!!) 
ist keine. Das klappt mehr oder weniger zufällig. Die einzige saubere 
Lösung ist das Zwischenpuffern im Receive-Event-Handler, weil die 
serielle Übertragung so langsam ist, daß die ComPort-Software nicht 
weiß, ob Dein Paket schon übertragen ist und halt mal das zur Verfügung 
stellt, was sie bereits empfangen hat.

Gruß
Markus

von Frank Weigler (Gast)


Lesenswert?

Erstmal Danke für deine ausführlichen Antworten. Die "Lösung" mit der 
Schleife soll ja keine Lösung darstellen, sondern war nur ein Test um 
rauszubekommen was da vor sich geht.

Ich werde mir das Ganze mal nochmal durch den Kopf gehen lassen. Aber 
ich ging auch irgendwie davon aus dass InputStream.Read mir die Antwort 
durchgehend in "einem Fluss" liefert. Wenn das natürlich nicht der Fall 
ist, dann macht ja im Prinzip wirklich nur ein einfaches Protokoll Sinn, 
in dem dann definierte Anfangs- und Endzustände herrschen, bzw. ich 
diese dann auch überprüfen kann.

Ich denke ihr habt mir aufjedenfall einen Weg in die richtige Richtung 
gezeigt. Werde mir mal wieder ein paar Gedanken zu dem Thema machen.

Vorerst Danke euch beiden.

von Brutal Force (Gast)


Lesenswert?

Musst Du auf Geschwindigkeit optimieren?
Falls ja: Du kommst um das Puffern wohl nicht herum.

Falls nein:

Mach Dir die Sache doch einfach!
Rechne aus, wie lange die 10 Bytes brauchen, um übertragen zu werden.
Verdopple die Zeit.
Und warte solange, bevor Du read aufrufst...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.