Mal eine allgemeine Anmerkung zu Datenübertragungen !

Hallo,

hier ist ja so einiges an Threads zu Thema serielle Datenübertragung entstanden.
Ich möchte dazu mal einige einfache Dinge sagen (ich hoffe das wird nicht als "Klugscheissern"
betrachtet.

Aaaaaalso :

Alles was wir hier so über die Serielle treiben oder auch was irgendwelche 433 Mhz Funkmodule machen
ist eine Datenübetragung ohne Framing.
Was heist das !?!
Das heist Daten die auf einer Seite abgeschickt werden haben keinen Datenrahmen.
Ein Datenrahmen enthält Daten die nichts mit dem zu tun haben was wir übertragen wollen.
Das können Längenbytes sein, Start- oder Stopzeichen, Checksummen e.t.c. .
Was bedeutet das für uns ?
Das bedeutet das z.B. ein Send über eine 433Mhz strecke von 8 Bytes beim Empfänger nicht als 8 Byte
in dem Moment ankommen (angekommen sein muß) wo er ein Receive aufruft.

Je nach Timing (wann rufe ich die available() oder entsprechende Funtion) kann es sein das beim
ersten Aufruf erst 2 Bytes da sind und die anderen 6 erst beim zweite Aufruf.

Gibt es Phasen mit gesperrten Interrupts können Zeichen (Bytes) auch ganz verloren gehen.
Außerdem verlassen sich viele hier auf den Gut-Fall. Aber jeder Art von Datenübertragung, gerade
über Funk, kann gestört sein. Deshalb muss man Vorkehrungen treffen - sofern notwendig.

Ich habe mir für einen selbstgebauten Plattenspielerumschalter eine (ziemlich sinnlose) Fernbedienung
über 433 MHz gebaut.
Da dort nichts zeitkritisches ist und mich auch sporadische Fehlübertragungen nicht stören habe ich
das sehr einfach realisert. Die Umschaltkommandos haben einfach die Form "PHONO 1" "PHONO 2" und so weiter. Da ich die Puffer relativ selten abhole kann ich eigentlich (nicht wirklich) davon ausgehen das
immer komplette Kommandos im Empfangspuffer stehen. Trotzdem wird erst mal die Länge gecheckt.
Ist irgendwann etwas nicht 7 Bytes lang kann es kein Umschaltkommando sein.
Dann wird noch gecheckt ob Byte 1 ein P ist und byte 5 ein O und ob Byte 7 eine Ziffer im richtigen Bereich ist.
Für diesen Fall funktioniert das, ABER das ist schon Katastrophenbetrieb und ist von mir auch nur
als Hack gedacht. Ich brauche nur n mal schnell auf die Fernbedienung drücken so können Puffer der
Form "PHONO 1PHON" "O 1PHONO 1" entstehen.
(Beide Strings falsche Länge und beim zweiten der erste Buchstabe kein P)
Obwohl das 3 gültige Strings sind würde es nicht funktionieren.
Da hilft nur ein eigenes Framing oder eine State-Maschine (Kann man googlen).

Sowas kann man sich als Template basteln und für jeden Fall wieder benuzten.
Ein einfaches Framing arbeitet z.b. mit einem Start und Ende Zeichen. Irgendwas das im Nutzstring
nicht vorkommen darf oder dort Escaped werden muss (z.B. durch Doppelübertragung).

Eine Statemaschine reisse ich nur mal kurz an :
Es werden i.A. (Sonderfälle mal weggelassen) nur einzelne Bytes verarbeitet.

Also der Form, das ist nur Beispielcode und kein korrektes Arduinobeispiel

while (serial.available())
{
  // getonebyte -> das nächste available ist um eins kleiner
  // CallStateMaschine mit diesem Byte

  if (CallStateMaschine(serial.readbyte()));
  {
     // Ich habe was erkannt  :-)
  }
}

..
..
..

#define NOSTATE 0
#define WAIT4START 0
#define WAIT4FOR_2ndO 1
#define WAIT4BLANK 2
#define WAIT4NUMBER 3

static int Maschinestate = NOSTATE;
static int internalCount;


bool CallStateMachine(uint8_t in_byte)
{
  bool RetVal = false;

  switch(MaschineState)
  {
      case WAIT4START:
         if (in_byte == 'P') // Start of PHONO
         {
             Maschinestate = WAITFOR2ndO;
             internalCount = 0;
         }
       break;

       case WAITFOR2ndO :
         {
             if (InternalCount == 3) // HON has passed
             {
                 if (in_byte == 'O')
                 {
                     MaschineState = WAIT4BLANK;
                  }
                  else
                  {
                      MaschineState = WAIT4START; // das war es nicht, noch mal von vorne
                   }
               }
               else
               {
                   InternalCount++;
                }
             break,

         case WAIT4BLANK:

Und so weiter. Ich denke das Prinzip ist klar.
Irgendwann wenn im Zustand WAIT4NUMBER eine Ziffer im passenden
Bereich gefunden wird, wird RetVal auf true gesetzt und dieser Wert zurück
gegeben. Dann hat man erfolgreich etwas gelesen und kennt den Wert.

Solche Statemaschines kann man natürlich in vielen Arten Programmieren, mit Tabellen,
Funktionspointer oder Mischformen von beiden.
Der Vorteil ist einfach, wenn sie korrekt gemacht sind kann man sie einfach erweitern und
sie finden in einem Datenstrom immer in den "Takt". Fehlende Bytes oder fehlerhafte Byte
könnes so natürlich auch nicht ersetzt werden.
Darf aber ruhig mal was verloren gehen und es muss nur wieder syncronisiert werden
ist das schon klasse und auch leicht erweiterbar.

Will man mehr Sicherheit kommt man natürlich um so Dinge wie Checksummen oder
Paritäten nicht herum.

Wenn Bytes natürlich gar nicht übertragen werden, durch gesperrte Interrupts oder so,
dann liegt ein systematischer Fehler vor den auch die geschickteste Programmierung
nicht ausbessern kann.

Ich denke mal das viele hier meinen, das klappt doch sonst ganz gut alles, so im Internet, oder
im lokalen Netz zu Hause. Das liegt daran das hier nur das obere Ende der Übertragung zu
Tage tritt. Unten im PC, in den Routern e.t.c. laufen Mechanissmen wie die hier beschriebenen
ab um Datensicherheit zu erzeugen.
Auf einem Microkontroller ist man "GANZ UNTEN" und für alles selber verantwortlich.
Sowas wie -> das ist ja instabil -> hat man immer mangeldem Verständniss, schlechter
Programmierung oder , ja , ab und zu defekter Hardware zu verdanken.

Ich denke es ist klar das ich das nicht für Fachleute geschrieben habe, sondern für Leute die
mal was mit dem Ardunio machen wollen.

Ich hoffe nicht generft zu haben.

Ulli