CS_LEVEL_17_SOLUTION - OnlyCook/abitur-elite-code GitHub Wiki

Level 17 – Musterlösung: RFID-Scanner (Serielle Schnittstelle)

Lösung

public class RFIDReader
{
    private Serial serial;
 
    public RFIDReader(Serial s)
    {
        this.serial = s;
        this.serial.Open();
    }
 
    public bool IsCardAvailable()
    {
        return serial.DataAvailable() > 0;
    }
 
    public string ReadCard()
    {
        if (serial.Read() != 0x02) return "";
 
        char[] data = new char[6];
        int xor = 0;
        for (int i = 0; i < 6; i++)
        {
            data[i] = (char)serial.Read();
            xor ^= data[i];
        }
 
        if (serial.Read() != xor) return "";
 
        if (serial.Read() != 0x03) return "";
 
        return new string(data);
    }
}

Erklärung

Die serielle Schnittstelle öffnen

Im Abitur ist es eine häufige Fehlerquelle, die serielle Schnittstelle vor der Nutzung nicht zu öffnen. Der Konstruktor ist der richtige Ort dafür:

public RFIDReader(Serial s)
{
    this.serial = s;
    this.serial.Open();
}

Das Serial-Objekt wird von außen übergeben (nicht intern erstellt) – das Klassendiagramm zeigt dies über die Assoziation. Open() muss direkt im Konstruktor aufgerufen werden, damit die Schnittstelle sofort nach der Erstellung des RFIDReader-Objekts betriebsbereit ist.


IsCardAvailable() – eine einfache Abfrage

public bool IsCardAvailable()
{
    return serial.DataAvailable() > 0;
}

DataAvailable() gibt zurück, wie viele Bytes an der Schnittstelle bereitstehen. Jede positive Zahl bedeutet: Es ist etwas da. Der Rückgabewert des Vergleichs > 0 ist direkt ein bool – kein if nötig.


ReadCard() – Protokoll Schritt für Schritt

Das Herzstück des Levels. Die Methode liest das Paket Byte für Byte und bricht bei jedem Protokollverstoß sofort mit return "" ab. Diese Technik nennt man Early Return – statt tief verschachtelter if/else-Blöcke wird bei einem Fehler direkt zurückgekehrt, was den Code flach und lesbar hält.

Schritt 1: STX prüfen

if (serial.Read() != 0x02) return "";

0x02 ist der hexadezimale Wert für das Start-Byte STX (Start of Text). serial.Read() gibt einen int zurück. Stimmt das erste gelesene Byte nicht mit STX überein, ist das Paket ungültig – sofortiger Abbruch.

Schritt 2: 6 Datenbytes lesen und XOR berechnen

char[] data = new char[6];
int xor = 0;
for (int i = 0; i < 6; i++)
{
    data[i] = (char)serial.Read();
    xor ^= data[i];
}

Hier passieren zwei Dinge gleichzeitig in der Schleife:

Casting von int zu char: serial.Read() liefert einen int (den Zahlenwert des Bytes). Ein char in C# repräsentiert ein Zeichen als Zahl (Unicode). Mit (char) wird der int-Wert explizit in das entsprechende Zeichen umgewandelt – das nennt man Explicit Casting. Am Ende kann das char-Array mit new string(data) direkt in einen String umgewandelt werden.

XOR-Prüfsumme akkumulieren: Der XOR-Operator ^ verknüpft zwei Werte bitweise. Die Kurzform ^= funktioniert wie +=: xor ^= data[i] ist dasselbe wie xor = xor ^ data[i]. Startet man bei xor = 0 und verknüpft jeden Byte-Wert nacheinander, erhält man am Ende die XOR-Prüfsumme aller 6 Bytes. XOR hat die nützliche Eigenschaft, dass Bitfehler in der Übertragung das Ergebnis verändern – daher eignet es sich gut zur einfachen Fehlererkennung.

Schritt 3: Prüfsumme vergleichen

if (serial.Read() != xor) return "";

Das nächste Byte nach den Nutzdaten ist die gesendete Prüfsumme. Diese wird direkt mit dem selbst berechneten xor-Wert verglichen. Stimmen sie nicht überein, wurde das Paket fehlerhaft übertragen – Abbruch.

Schritt 4: ETX prüfen

if (serial.Read() != 0x03) return "";

0x03 ist ETX (End of Text), das End-Byte des Protokolls. Es bestätigt, dass das Paket vollständig und korrekt abgeschlossen wurde.

Schritt 5: String zurückgeben

return new string(data);

new string(char[]) ist der Standardweg in C#, um aus einem char-Array einen String zu bauen. Alle 6 Zeichen werden zu einem fertigen String zusammengesetzt und zurückgegeben.