Bluetooth: Fehler in Nachrichten

Hallo,
für mein Projekt nutze ich diesen BT-Shield von ITEAD STUDIO:
http://blog.iteadstudio.com/arduino-bluetooth-shield-upgrade-to-v2-2/

Ziel des Projekts:
Ich möchte Nachrichten, bzw Befehle vom Arduino zu einer Android App und wieder zurück schicken können.
Nach dem Durcharbeiten von vielen Anleitungen und Foren habe ich eine Kommunikation auch zustande bekommen. Nun habe ich aber folgendes Problem:

Was ich genau mache:
Im Java Code nutze ich folgenden Befehl: void java.io.OutputStream.write(byte[] buffer)

public void write(byte[] buffer) {
	try {
		mmOutStream.write(buffer);
	} catch (IOException e) {
		Log.e(TAG, "Exception during write", e);
	}
}

Das Objekt mmOutStream ist eine OutputStream Klasse und schickt mit write(bytearray) für mich ein Bytepaket raus. Dabei ist die Länge der Pakete zwischen 3 und 30 Byte. Hingegen kann die Zeit zwischen 2 Paketen variieren, Mindestabstand ist jedoch 15 msec.
Zum Lesen benutze ich:

int len, i; // len = anzahl bytes, i = counter
byte data[64]; // zum Speichern der Werte

for( i = 0 ; mySerial.available(); i++) {
	data[i] = (byte) mySerial.read();
	len++;
}

Mein Problem:
ca. 95% aller versandten Bytes der App kommen richtig beim Arduino an. Die restlichen 5% hingegen sind fehlerhaft: die angekommenen Bytes haben föllig falsche Werte. Das nächste ankommende Paket ist hingegen ganz richtig. Deutlich seltener kommt es vor, dass ein Byte ausgelassen/vergessen wird.

Zur Frage:
Nutzt das BT-Shield irgendwelche Protokolle, um Nachrichten gegen Fehler abzusichern? Denn wen dies so ist, liegt der Fehler einzig und allein in meinem Programm. Irgendwie habe ich noch keine Forumfrage gesehen, die Fehler in verschickten Daten behandeln - weiß jemand, was ich falsch mache?

Ich vermute mal den Fehler in der Schleife.

for( i = 0 ; mySerial.available(); i++) {
	data[i] = (byte) mySerial.read();
	len++;
}

Der Arduino ist nicht gerade langsam. Es kann also vorkommen, das irgendwann während der Abarbeitung der Schleife die Bedingung "mySerial.available()" ein "false" liefert, weil das nächste Byte einfach noch nicht da ist. Dann bricht die Schleife ab.
Da ich den umgebenden Code nicht kenne, kann ich jetzt nur noch Vermutungen anstellen. Aber ich denke relativ kurz danach landest Du wieder in der Schleife, fängst aber wieder bei i=0 an zu zählen. Damit werden die neuen Bytes wieder an den Anfang des Array geschrieben. Trotzdem wird aber mit dem "len++" der Gesamtzähler weiter erhöht und damit die korrekte Zahl an übertragenen Bytes gezählt. Da die zusätzlichen Bytes aber gar nicht an die richtige Stelle im Array geschrieben werden, liest Du an diesen Stellen vermutlich irgendwelche zufälligen Bytes, die halt gerade an dieser Stelle im Speicher stehen.
Um das zu prüfen, könntest Du nach jedem Paket das Array mit Null-Bytes füllen. Dann dürften im Fehlerfall auch nur noch Nullen im Array stehen und Du wärst sicher, das keine falschen Bytes übertragen werden.

Die Sache mit dem len++ setze ich bei der Ausgabe wieder auf 0, um beim nächsten Lesen wieder bei 0 anzufangen.

Dass Arduino gar nicht so langsam ist, ist mir erst vor einigen Tagen klar geworden, als ich als häufigsten Fehler eine 255 Ausgegeben bekommen hatte.
Später hatte ich gelesen, dass read(), im Falle, dass noch keine Bytes da sind, -1 liefert -> diese wird aber beim konvertieren zum byte zu 255.
Zu diesem Zeitpunkt waren auch ca 40% aller Nachrichten fehlerbehaftet

Macht es eigentlich einen Unterschied, ob man stop bit und parity nutzt? Im Moment nutze ich folgende Einstellung : AT+UART=38400,0,0 - und somit weder stop, noch parity bit.

Als ich gestern Abend mit dem UART befehl rumgespielt habe, ist mir aufgefallen, dass mit dem stopbit (38400,1,0) deutlich mehr Fehler aufgekommen sind, als ohne diesen bit.

Und noch etwas: kann man mit Bluetooth eig. gleichzeitig senden und empfangen? Ich meine ich schicke dand einem Thread alle 50 msec ein Datenpaket raus, empfange diese mit dem Arduino auf mySerial, gebe diese auf Serial aus und schicke das gleiche Paket über mySerial wieder ans Telefon, wo diese wieder angezeigt werden - kann es sein, dass das eintreffende Paket vom gerade losgeschickten gestört wird?

Stopbit 0 / 1 macht ca. 10% Geschwindigkeitsunterschied.

Ein einfacher Trick ist, aussen um deine for Schleife ein weiteres if und kleines Delay zu setzen.

if (mySerial.available() )
{
  delay (2); // 2 ms sollte reichen, damit alle max. 30 Zeichen da sind
  for (i=0; mySerial.available() ; i++) 
   { ... }
}

Mensch! dass die genialen Lösungen auch immer einfach sein müssen :grin:

Die Idee mit dem Delay hatte ich bereits, damals hatte ich aber wohl einen zu großen Wert genommen, diesen obendrein mit in die Schleife gebaut und kam bei größeren Datenmengen auf ewige Wartezeiten. Heute bin ich darauf gekommen, wie man dies evtl. optimieren und auch mehr, als 30 Byte erlauben kann. Vielleicht kann es einem anderen Suchenden helfen:

int i, len = 0;
byte data[64];
for (i = 0; mySerial.available(); i++) {
	data[i] = mySerial.read();
	len++;
	if (mySerial.available() == 0)
		delay(2);
}

Für alle anderen Fehler wird wohl ein Sicherungsverfahren herhalten müssen :smiley:

Danke an mkl0815 und michael_x