CRC [cyclic redundancy check]

Um Fehler bei der Übertragung oder Duplizierung von Daten erkennen zu können, kann man die zyklische Redundanzprüfung anwenden.
Bei der FHZ oder IPScom hat dies Verfahren einen anderen wichtigen Grund: es dient dazu die gültigen Daten aus einem Datenstrom heraus zu filtern.
Problem: es werden keine Steuerzeichen (z.B. STX, ETX, CRLF) gesendet.
Außerdem werden nur reine Bytes übertragen kein Text. Dadurch ist eine Unterscheidung z.B. von CRLF (CHR(13) & CHR(10)) oder einem Zahlenwert von 13 oder 10 nicht möglich.
Beispiel: „blubb nix gut“, STX, "Temperatur: ", „12.5“, „Grad“, CRLF, „Blubber Müll“ > hier ist alles klar: 12.5 Grad
Aber hier: 12,03,232,128,12,51,53,12,55,218,128,23,65,26 - wo fängt es an, wo hört es auf :confused:
Darum verwenden wir folgenden „Trick“:
Ein Datenpaket geht immer mit 128 los (dass hilft nur bedingt, weil 128 auch für den Wert 128 stehen kann)
Dann folgt die Check-Summe (siehe Skript), diese wird wermittelt, indem man die folgenden Bytes mit XOR verknüpft.
Und wieviele Bytes kommen dann nun? Dass steht in dem 3. Byte und dann kommen die eigentlichen Daten.
Die Wahrscheinlichkeit, das hinter einer 128 eine gültige Check-Summe ist sehr gering. Darum ist dieses Verfahren für IPCcom ausreichend sicher.
Klingt kompliziert - ist es aber eigentlich nicht.

MST

// Hier zwei komplette Strings
$str = chr(128)."@".chr(4)."E".chr(0).chr(0).chr(1).chr(128).chr(6).chr(2)."OK";

// Hier ist der erste String nicht komplett
//                                         | <- hier fehlt ein chr(1);
//$str = chr(128)."@".chr(4)."E".chr(0).chr(0).chr(128).chr(6).chr(2)."OK";

// Hier fehlt die erste 128
//$str = "@".chr(4)."E".chr(0).chr(0).chr(1).chr(128).chr(6).chr(2)."OK";

// Hier ist die CRC falsch
//$str = chr(128)."X".chr(4)."E".chr(0).chr(0).chr(1).chr(128).chr(26).chr(2)."ERR";

$len = strlen($str);
echo "Länge: $len
";

if(($str == "") or ($len <= 3)){
  return;
}

$strposition = -1;                                 // Um zu sehen, ob er einen String gefunden hat
$fehler = "Kein Fehler";                           // Falls $fehler nicht unten beschrieben wird und als Debuginfo
$crc_calc = 0;                                     // muss hier initialisiert werden, falls nichts gefunden wird

for ($i = 0; $i < $len; $i++){                     // Alle Zeichen im String ansehen
if (ord(substr($str,$i)) == 128)                   // Wurde eine 128 gefunden?
    {
      $eintritt = $i;                              // Debuginfo; bei welcher Stelle wurde zuletzt eine 128 gefunden
      $crc_read = ord(substr($str,$i+1));          // Die vom Atmel im String mitgesendete Checksumme
      $anzahlbytes = ord(substr($str,$i+2));       // Die vom Atmel im String mitgesendete Anzahl nachfolgender Bytes

      if ($anzahlbytes+$i+2 >=  $len)              // Gibt es überhaupt genügend Bytes im String??
      {                                            // $anzahlbytes = folgende Anzahl Bytes; $i = hier steht der Zeiger im String;
        $fehler = "Zu wenige Zeichen";             // 2 = Bytes vor Anzahl (128 und CRC)
        break;                                     // Abbruch der Routine weil nicht genügend Zeichen
      }

      $crc_calc = 0;                               // hier initialisieren, weil evtl. mehrere 128 betrachtet werden!!
      for ($j = 0; $j < $anzahlbytes+1; $j++) {    // "Anzahl" und folgende Bytes zu Checksumme verrechnen
         $crc_calc = $crc_calc ^ ord(substr($str,$i+$j+2));// ACHTUNG!! xor liefert nur TRUE/FALSE!! Hochpfeil weil binäre Operation
      }
      if ($crc_calc == $crc_read) {                // Stimmen Checksummen überein? Ja? Sehr wahrscheinlicher Treffer
         $strposition = $i;                        // Hierin steht jetzt die erste Stelle des wahrscheinlich kompletten Strings
         break;                                    // Ende der Suche weil Fund.
       }else{
       $fehler = "CRC ERR";
      }
    }
}

echo "Stringposition (-1 wenn kein Fund): $strposition 
";
echo "CRC vom Atmel: $crc_read 
";
echo "CRC berechnet: $crc_calc 
";
echo "Anzahl Bytes: $anzahlbytes 
";
echo "Fund der 128: $eintritt 
";
echo "Fehler: $fehler  
";