Die Prüfsummenberechnungs-Routine "wbus_checksum()"

Über das Prüfsummenbyte (CHK) am Ende einer Nachricht wird eine störungsfreie Übertragung am W-Bus sichergestellt. Die Prüfsumme besteht aus einem Byte und berechnet sich aus dem XOR aller Bytes einer Nachricht (mit Ausnahme des Prüfsummen-Bytes selbst). Das W-Bus Protokoll schreibt vor, das Nachrichten mit ungültiger Prüfsumme von den Empfängern ignoriert werden.

Wir realisieren das mit der Funktion namens wbus_checksum(). Als Parameter soll sie den Zeiger auf den Start einer W-Bus Nachricht im Arbeitsspeicher erhalten. Ihr Rückgabewert wird dann die berechnete Prüfsumme sein.

Mit Hilfe der Funktion können wir dann sowohl eingegangene Nachrichten überprüfen (hierbei muss dann die berechnete Prüfsumme mit der in der Nachricht übertragenen übereinstimmen) als auch selbst erzeugte Nachrichten mit einer korrekten Prüfsumme versehen.

Hier der Arduino C-Code der Funktion:

/**
 * Return checksum for frame
 *
 * @returns: Checksum
 * @param frame: Pointer to start of frame
 */
byte wbus_checksum(byte *frame) {
  byte chk = 0;
  unsigned int len = frame[1] + 1;
  for (;len!=0;len--) {
    chk ^= *frame++;
  }
  return(chk);
}

Anstelle der statisch hinterlegten Prüfsumme (hier im Beispiel 0xCA):

byte tx[5] = { 0xF4, 0x03, 0x23, 0x1E, 0xCA };  // start Zuheizer VW Touran

können wir dieses Byte nun berechnen und an die entsprechende Position im Frame setzen:

  byte tx[5] = { 0xF4, 0x03, 0x23, 0x1E, 0x00 };  // start Zuheizer VW Touran
  tx[4] = wbus_checksum(tx);  // Index [4] is the fifth byte in 'tx' array

Zeile 7

byte wbus_checksum(byte *frame)

Im Funktionskopf definieren wir den Rückgabewert der Funktion als byte (dies entspricht einem unsigned char). Der einzige Funktionsparameter ist ein Zeiger auf eine Bytestruktur byte *frame. Aber der Zeigerposition wird die Funktion die Bytes lesen und berechnen.

Zeile 8

byte chk = 0;

Hier initalisieren wir den Rückgabewert der Prüfsumme mit 0. Die Prüfsumme ist ein Ein-Byte Wert, daher die Deklaration von chk als Datentyp byte.

Zeile 9

unsigned int len = frame[1] + 1;

In len legen wir die Anzahl der zu berechnenden Bytes im Frame ab. Hierzu lesen wir das 2. Byte im Frame (Frameaufbau = ADDR LEN CMD [DATA..] CHK) mit dem Befehl frame[1]. Hier steht laut Protokoll das LEN-Byte, welches die Anzahl der Bytes enthält die ihm folgen.

Da frame ein Zeiger auf ein Array von Bytes ist, können wir hier mit der eckigen Klammer auf das gewünschte Byte in diesem Array zugreifen (HINWEIS: Dies ist ein 0-basierender Index).

Der gesamte Frame besteht also aus der Anzahl LEN Bytes zzgl. dem ADDR-Byte und dem LEN-Byte selbst. Als Formel wäre das: FRAMELEN = LEN + 2. Da wir jedoch das CHK (Prüfsummenbyte) nicht mitberechnen dürfen, kommen wir auf folgende Formel: FRAMELEN = LEN + 1.

Zeile 10

for (;len!=0;len--)

Mit Hilfe einer for-Schleife rufen wir nun den nachfolgenden Berechnungsbefehl für die zuvor ermittelte Anzahl Bytes aufgerufen.

Den ersten Parameter des for-Befehls können wir leer lassen, da wir die Schleifenvariable (len) bereits definiert und initialisiert haben.

In der Schleifen-Endbedigung (zweiter Parameter bei for) prüfen wir, ob der Wert von len ungleich (und damit größer als) 0 ist.

Als letzter Parameter in der for-Schleife wird der nach jedem Schleifendurchlauf auszuführende Befehl angegeben. In unserem Fall sorgen wir mit len– dafür, das der Wert von len um 1 verringert wird ().

Zeile 11

chk ^= *frame++;

Hier folgt nun die eigentliche Berechnung. Auf der rechten Seite wird über den Derefenzierungsbefehl *frame das Byte zurückgeliefert, welches an der durch frame angegebenen Speicherposition steht. Das nachfolgende ++ erhöht diesen Positionszeiger anschließend um den Wert 1. Damit zeigt die Variable frame auf die nächste Byteposition im Speicher.

Die Zuweisung ^= beinhaltet ein XOR des Wertes vor und hinter dem Gleichheitszeichen. Dies ist eine Kurzschreibweise für chk = chk ^ *frame++;.

Zeile 13

return(chk);

Als letztes geben wir den berechneten Prüfsummenwert als Funktionsergebnis mit return() zurück.