Arduino mit MFRC522-Reader

Arduino mit MFRC522-Reader

Funktionen der Value-Blöcke

Wir wollen uns jetzt einmal die Funktinalität der Value-Blöcke anschauen. Die Aufgabe soll lauten:

Block 0 von Sektor 1 (Block 4) soll als Value-Block genutzt werden. Es soll ein Wert dort eingeschrieben werden und dann wollen wir die Funktion "increment" testen.

Wir müssen zunächst die "Access-Bits" für Block 0 des 1. Sektors ändern, denn im Auslieferungszustand ist er als "read/write"-Block konfiguriert. Ein Blick ins Tutorial über den Sektor-Trailer-Block hilft uns dabei.

Die Kombination, die wir benötigen lautet: 110 (6 dezimal). Damit wird der Block zum Value-Block und wir können mithilfe des B-Schlüssels alle Funktionen ausführen.

Da wir keine einzelnen Bytes und schon gar keine Bits manipulieren können, müssen wir uns eine Datenstruktur basteln, die dem Trailer-Block entspricht:

byte bTrailerBuffer[] ={0xff,0xff,0xff,0xff,0xff,0xff,0,0,0,0,0xff,0xff,0xff,0xff,0xff,0xff};

Wir haben am Anfang und am Ende unsere beiden Schlüssel (6 x 0xff) und in der Mitte von links nach rechts die 3 Byte der "Access Bits" für Block 0, 1, 2 und den Sektor-Trailer-Block (Block 3). Das vierte Byte in der Mitte steht für User-Daten zur Verfügung. Wir belassen die Werte zunächst auf 0 und initialisieren sie gleich in einem nächsten Schritt. Diese Zeile fügen wir in unseren Variablenblock am Anfang des Programms ein. Außerdem ändern wir noch unsere "keyA" Variable auf den Namen "key" weil wir sie ja auch für den B-Schlüssel nutzen werden.



Gehen wir wieder Schritt für Schritt vor und schauen uns den ersten Teil unseres neuen Programms an. Im Setup-Teil kommt nichts neues hinzu, deshalb beginnen wir sofort in der Hauptschleife:



Nach der bekannten Selektierung und Kartentyp-Abfrage wollen wir zunächst einmal den Sektor 1 anzeigen. Dazu verwenden wir aber dieses Mal nicht den Read-Befehl, sondern eine spezielle Methode, die einen ganzen Sektor formatiert ausgibt:

mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, 1);

Wir übergeben der Methode die UID, den Schlüssel und die Sektor-Nummer. Die Anzeige sieht dann folgendermaßen aus:



Wir sehen die Werte, die wir vorher in den Block 4 geschrieben haben und den Zustand der Access Bits am Ende der Zeilen. Und wir können auch gut den Aufbau des Sektor-Trailer-Blocks erkennen. Key A kann niemals ausgelesen werden, Key B nur in Verbindung mit dem Schlüssel A oder B. Wir haben uns mit Schlüssel B angemeldet, deshalb erhalten wir hier eine Anzeige.

Schauen wir uns die nächsten beiden Zeilen an, mit dem wir die Access-Bits ändern:



Wir müssten jetzt eigentlich mühsam ein Bitmuster erstellen, um die neuen Access-Bits in eine hexadezimale oder dezimale Darstellung zu wandeln und in invertierter und nicht invertierter Form an die richtige Position in das Array "bTrailerBuffer" zu schreiben. Doch dafür gibt es in der MFRC522-Bibliothek eine Methode, die uns diese Arbeit abnimmt. Sie heißt:

mfrc522.MIFARE_SetAccessBits(&bTrailerBuffer[6], 6, 0 , 0, 1);

Wir sagen der Methode lediglich an welcher Stelle des Arrays der Eintrag erfolgt (7. Byte, Index = 6) und wie unsere Access-Bits lauten, nämlich "6" für den Value-Block (Block 0), "0" für die beiden Blöcke 1 und 2, die dann im Auslieferungszustand bleiben und der Sektor-Trailer-Block bleibt ebenfalls im Auslieferungszustand, also auf "1".

Auch wenn der Name der Methode es vielleicht suggeriert, die Access-Bits werden damit noch nicht gesetzt, sondern es wird lediglich das Arrray korrekt erstellt. Deshalb schreiben wir im folgenden Befehl das Array in den Kartenchip.

Um zu prüfen, ob auch alles richtig gelaufen ist, geben wir den Sektor erneut aus:



und schauen uns das Ergebnis an:



Wundern Sie sich nicht über den Inhalt von Block 4, ich habe lediglich einen anderen Chip verwendet, auf dem ich diese Werte gespeichert hatte. Wichtig ist aber, dass sich die Access-Bits von "000" auf "110" geändert haben. Wir haben es jetzt mit einem Value-Block zu tun.

Um mit dem Write-Befehl einen Wert in diesem Block zu schreiben, müssten wir das korrekte Format einhalten, also:

Sie ahnen es vielleicht schon: auch dafür gibt es eine Methode in unserer Bibliothek und die lautet sinnigerweise:

mfrc522.MIFARE_SetValue(block, value);

Die Methode nimmt die Blocknummer und den Wert entgegen und beschreibt den Block dann in der korrekten Formatierung. Fügen wir also die folgenden Zeilen hinzu:



Aus Sicherheitsgründen wird vor bestimmten Abläufen eine erneute Authentifikation erforderlich und das ist auch vor dem Einschreiben eines neuen Values so. Das ist auch sinnvoll, denn damit kann ja z. B. der Kontostand geändert werden. Danach schreiben wir den Wert "10" in den Value-Block und geben den gesamten Sektor noch einmal aus, um auch hier wieder den Erfolg zu kontrollieren.



Wir sehen, dass wir im Value-Block zweimal den Wert "0x0A" (also 10) finden und in der Mitte der Wert "f5 ff ff ff", was der invertierten Darstellung enspricht. Auch die Adresse des Block (4) wird zweimal nicht invertiert und zweimal invertiert angezeigt.

Kommen wir zum letzten Schritt, dem Inkrementieren:



Auch hier wird logischerweise wieder eine Authentifizierung notwendig, weil der Kontostand geändert wird. Im Anschluss rufen wir die Increment-Methode auf und übergeben die Blockadresse und den Wert, um den wir den Value erhöhen wollen, in unserem Fall 1.

Der Inkrement- oder auch Dekrement-Befehl verändert aber nicht den Block selbst, sondern er kopiert den Wert aus dem Value-Block in den internen Datenspeicher und dort wird er dann erhöht oder verringert. Danach müssen wir ihn mit dem Transfer-Befehl wieder in den Block zurückschreiben. Im Anschluss erfolgt auch hier wieder die Ausgabe des kompletten Sektors. Hier jetzt die komplette Ausgabe des Programm mit einem frischen Chip und wir sehen, dass sich der Value von 0x0A (10) auf 0x0B (11) verändert hat:



Später bei einer konkreten Anwendung wollen Sie natürlich nicht den gesamten Block oder gar Sektor auslesen, um ihn dann umzuformatieren. Das brauchen Sie auch nicht, denn es gibt die Methode:

mfrc522.MIFARE_GetValue(valueBlock, &value); Dazu übergeben Sie lediglich die Nummer des Blocks, den Sie auslesen möchten und die Adresse einer Variablen vom Typ "long".

Damit wären wir am Ende dieses Kapitels angelangt. Auch wenn sich die Abläufe auf den MFRC522-Reader-Chip und gerade am Schluss lediglich auf die Tag-Chips der MIFARE-Familie beschränken, so haben wir doch ein sehr tiefes Verständnis für die zugrunde liegende Technik erhalten. Prinzipiell arbeiten die meisten Produkte nach einem ähnlichen Muster.