Value Blocks bearbeiten

Speicherorganisation eines Value Blocks:

Die 16-Byte großen Datenblöcke der RFID-Tags können wahlweise als Read/Write Blocks oder als Value Blocks verwendet werden. Als Read/Write Blocks können Blöcke nur mit Zeichen beschrieben werden und die Zeichen wieder gelesen werden.

Datenblöcke, die als Value Blocks definiert sind, können je einen Zahlenwert enthalten. Value Blocks können nicht nur gelesen und geschrieben werden, sondern auch inkrementiert, dekrementiert, in einen volatilen Speicher gelegt und von dort wieder zurückgespeichert werden.

Ob ein Datenblock ein Read/Write Block oder ein Value Block ist, wird durch die Access Bits im jeweiligen Sektor für jeden einzelnen Block definiert. Mit der werkseitigen Einstellung der Access Bits C1 C2 C3 = 0 0 0 können alle Datenblöcke sowohl als Read/Write Blocks oder als Value Blocks verwendet werden. Ansonsten sind Datenblöcke nur dann als Value Blocks verwendbar, wenn die Access Bits des jeweiligen Sektors für einen Block entweder C1 C2 C3 = 0 0 1 oder 1 1 0 ist (siehe Bild 4 unter Access Bits).

Der Aufbau eines Value Block ist im nachfolgenden Bild 1 ersichtlich. Der Zahlenwert (Value), der gespeichert werden soll, wird dabei als vorzeichenbehaftete 4 Byte Zahl, dreimal in einem Block gespeichert, zweimal nichtinvertiert (Byte 3 bis 0 und Byte 11 bis 8) und einmal invertiert (Byte 7 bis 4). Das niedrigste signifikante Byte der Zahl wird dabei im niedrigsten Byte gespeichert. Negative Zahlen werden als 2er-Komplement gespeichert. Der gültige Zahlenbereich dieser "int32_t"- bzw. "long"-Zahl erstreckt sich von -2.147.483.648 bis +2.147.483.647.

Die Bytes 12 bis 15 beinhalten zweimal nichtinvertiert und zweimal invertiert eine 1-Byte Adresse "A", wo die Adresse des jeweiligen Blocks gespeichert werden kann (z.B. für ein Backup-Management).


Bild 1: Aufbau eines Blocks als Value Block


Programmbeispiel 5: Die Anzahl von RFID-Betätigungen zählen

Funktionsbeschreibung:

Jedes Mal wenn eine Betätigung mit einem RFID-Tag erkannt wird, soll ein Zählwert in einem Value Block des RFID-Tags um "1" erhöht werden. Ist der im Deklarationsteil des Programms voreingestellte Block noch kein Value Block, so wird er als Value Block mit dem Anfangswert "0" eingerichtet. Inhalt des Blocks und Zählwert werden am Seriellen Monitor (Bild 2) angezeigt.


Hinweis: Das Programm funktioniert nur mit RFID-Tags mit 1 kByte Speicher, da Tags mit 4 kByte Speicher eine andere Speicherorganisation haben (32 Sektoren mit je 4 Blöcken und 8 Sektoren mit je 16 Blöcken).


Im Beispiel 4 finden folgende Funktionen der MFRC522-Library Verwendung:

(Es werden nur die neuen Funktionen gegenüber den Beispielen 1 bis 3 vorgestellt)

MFR.MIFARE_SetValue(byte, int32_t);

MFR.MIFARE_GetValue(byte, int32_t);

MFR.MIFARE_Increment(byte blockAdd, int32_t delta);

MFR.MIFARE_Transfer(byte));


Beschreibung der neuen Funktionen:


byte MIFARE_SetValue(byte blockAdd, int32_t value)

Funktion: Schreibt einen Wert in einen Value Block

Parameter: blockAdd: Blockadresse (0 <= blockAdd <= (Blockanzahl - 1))

                 value: Wert, der im Value Block gespeichert werden soll

                           (-2,147,483,648 >= value <= +2,147,483,647)

Rückgabe: StatusCode 0 bis 8 (= Aufzählungstyp enum in der Library), Bedeutung siehe Funktion "PCD_Authenticate()"

Beispiel:

int32_t value = 0; //Der Wert der gespeichert werden soll (= 0)

blockAdd = 22; //Blockadresse des Value Blocks

MFR.MIFARE_SetValue(blockAdd, value);


byte MIFARE_GetValue(byte blockAdd, int32_t *value)

Funktion: Liest einen Wert in einen Value Block

Parameter: blockAdd: Blockadresse (0 <= blockAdd <= (Blockanzahl - 1))

                 value: Zeiger auf eine Variable, in welcher der gelesene Wert gespeichert wird

                           (-2,147,483,648 >= value <= +2,147,483,647)

Rückgabe: StatusCode 0 bis 8 (= Aufzählungstyp enum in der Library), Bedeutung siehe Funktion "PCD_Authenticate()"

Beispiel:

int32_t value; //Variable, in die der ausgelesene Wert gespeichert werden soll

blockAdd = 22; //Blockadresse des Value Blocks

MFR.MIFARE_GetValue(blockAdd, &value);


byte MIFARE_Increment(byte blockAdd, int32_t delta)

Funktion: Inkrementiert den im Value Block gespeicherten Wert um den Wert "delta" und speichert das Ergebnis im volatilen Speicher des RFID-Tags

Parameter: blockAdd: Blockadresse (0 <= blockAdd <= (Blockanzahl - 1))

                 delta: Wert, um den der im Value Block gespeicherte Wert erhöht werden soll

                           (-2,147,483,648 >= delta <= +2,147,483,647)

Rückgabe: StatusCode 0 bis 8 (= Aufzählungstyp enum in der Library), Bedeutung siehe Funktion "PCD_Authenticate()"

Achtung: Die Funktion erhöht nicht den Wert im Value Block, sondern speichert das Ergebnis nur im volatilen Speicher des RFID-Tags. Um den Wert im Value Block zu erhöhen, muss der Inhalt des volatilen Speichers in den Value Block mit der nachfolgend beschriebenen "Transfer"-Funktion übertragen werden.

Bemerkung: Die Beschreibung ist sinngemäß auch auf die "Decrement"-Funktion anzuwenden!

Beispiel:

int32_t delta; //Variable, um die der Wert des Value Blocks erhöht werden soll

blockAdd = 22; //Blockadresse des Value Blocks

MFR.MIFARE_Increment(blockAdd, delta);

MFR.MIFARE_Transfer(blockAdd);


byte MIFARE_Transfer(byte blockAdd)

Funktion: Transferiert einen Wert, aus dem volatilen Speicher des RFID-Tags in einen Value Block

Parameter: blockAdd: Blockadresse (0 <= blockAdd <= (Blockanzahl - 1))

Rückgabe: StatusCode 0 bis 8 (= Aufzählungstyp enum in der Library), Bedeutung siehe Funktion "PCD_Authenticate()"

Beispiel: Siehe "Increment"-Funktion


Hier nun das vollständige Programm:

Hinweis: Es werden bei den MFRC522-Library-Funktionen nicht alle möglichen StatusCode-Rückgaben im Programm ausgewertet und/oder angezeigt.

//RFID Programm 5
//Zaehlen von RFID-Betaetigungen
//Code fuer Arduino
//Author Retian
//Version 1.0


//Prototyp
void zeigeBlock(void);


#include <MFRC522.h>
#include <SPI.h>


#define rstPin 9
#define ssPin 10


MFRC522 MFR(ssPin, rstPin);
MFRC522::MIFARE_Key key;


byte blockAdresse = 20; //Hier wird die Blockadresse des Value Blocks angegeben

byte sectorTrailer;
byte readBuf[18];
byte sizeOfreadBuf = sizeof(readBuf);
byte myKey[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
byte status;

int32_t wert; //Zahlenwert des Value Blocks


void setup() {
  Serial.begin(115200);
  SPI.begin();
  MFR.PCD_Init();

  for (byte i = 0; i < 6; i++) key.keyByte[i] = myKey[i];
  Serial.print(F("Vorgegebnen Blockadresse des Value Blocks: "));
  Serial.println(blockAdresse);


  //Pruefe, ob "blockAdresse" eine gueltige Blockadresse ist
  //(kein Sector Trailer und nicht Block 0)
  if ((blockAdresse + 1) % 4 == 0 || blockAdresse == 0 || blockAdresse > 63)
  {
     Serial.print(blockAdresse);
     if (blockAdresse == 0) Serial.println(F(" ist ungueltig, weil Herstellerdaten-Block!"));
     else if (blockAdresse > 63) Serial.println(F(" ist ungueltig, weil ausserhalb Bereich!"));
     else Serial.println(F(" ist ungueltig, weil SectorTrailer!"));
     Serial.println(F("Blockadresse für Value Block im Deklarationsteil des Programms aendern!!"));
     while(1); //Wenn if-Bedingung erfuellt, dann geht's hier nicht mehr weiter!
   }


   //Ermittle den zugehoerigen SectorTrailer zur "blockAdresse"
   sectorTrailer = blockAdresse + 3 - (blockAdresse % 4);

}


void loop() {
  //Warte auf neuen RFID-Tag
  Serial.print(F("Warte auf RFID-Tag ... "));
  while (!MFR.PICC_IsNewCardPresent() || !MFR.PICC_ReadCardSerial());
  Serial.println(F("gelesen!"));


  //Authendifiziere den neuen RFID-Tag
  status = MFR.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, sectorTrailer, &key, &(MFR.uid));
  Serial.print(F("Status Authentifizierung: "));
  Serial.println(MFR.GetStatusCodeName(status));


  //Pruefe, ob blockAdresse bereits ein Value Block ist
  //Wenn nicht, dann erzeuge eine Value Block mit Wert 0
  Serial.print(F("Block "));
  Serial.print(blockAdresse);
  MFR.MIFARE_Read(blockAdresse, readBuf, &sizeOfreadBuf);
  if (readBuf[0] != readBuf[8] ||
      readBuf[1] != readBuf[9] ||
      readBuf[2] != readBuf[10] ||
      readBuf[3] != readBuf[11] ||
      readBuf[0] != (byte)~readBuf[4] ||
      readBuf[1] != (byte)~readBuf[5] ||
      readBuf[2] != (byte)~readBuf[6] ||
      readBuf[3] != (byte)~readBuf[7] ||
      readBuf[12] != readBuf[14] ||
      readBuf[12] != (byte)~readBuf[13] ||
      readBuf[12] != (byte)~readBuf[15])
  {
    Serial.println(F(" ist noch kein Value Block => Erzeuge Value Block"));
    MFR.MIFARE_SetValue(blockAdresse, (int32_t)0);
  }
  else Serial.println(F(" ist bereits ein Value Block!"));


  //Zeige den Blockinhalt vor dem Inkrementieren
  zeigeBlock();


  //Inkrementiere den Value Block
  Serial.print(F("Inkrementiere Block "));
  Serial.println(blockAdresse);
  status = MFR.MIFARE_Increment(blockAdresse, (int32_t)1);
  Serial.print(F("Status Inkrementieren: "));
  Serial.println(MFR.GetStatusCodeName(status));


  //Uebertrage das Ergebnis der Inkrementierung in den Value Block
  MFR.MIFARE_Transfer(blockAdresse);


  //Zeige den Blockinhalt nach dem Inkrementieren
  zeigeBlock();


  //Gebe den Inhalt des Value Blocks als Zahlenwert aus
  MFR.MIFARE_GetValue(blockAdresse, &wert);
  Serial.print(F("Wert (Hex) = ")); Serial.println(wert, HEX);
  Serial.print(F("Wert (Dez) = ")); Serial.println(wert);
  Serial.println();


  //Beende Authentifizierung des RFID-Tags
  MFR.PICC_HaltA();
  MFR.PCD_StopCrypto1();
}


void zeigeBlock()
{
  Serial.print(F("Lese Block "));
  Serial.print(blockAdresse);
  Serial.print(F(":   "));
  status = MFR.MIFARE_Read(blockAdresse, readBuf, &sizeOfreadBuf);
  if (status == MFRC522::STATUS_OK)
  {
    if (blockAdresse < 10) Serial.print("0"); //Fuehrende Null anzeigen
    for (byte i = 0; i < 16; i++)
    {
      if (readBuf[i] < 16) Serial.print("0"); //Fuehrende Null anzeigen
      Serial.print(readBuf[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
  else
  {
    Serial.print(F("Lesefehler: "));
    Serial.println(MFR.GetStatusCodeName(status));
  }
}

Ausgabe am Seriellen Monitor:

Im Deklarationsteil des Programms ist der Block 20 als Value Block angegeben. Nach Erkennen eines RFID-Tags ergibt die erste Überprüfung, dass Block 20 noch kein Value Block ist, daher wird er durch Beschreiben des Blocks mit der Funktion "MFR.MIFARE_SetValue(blockAdresse, (int32_t)0);" zu einem Value Block mit dem Wert "0" gemacht. Der Block 20 hat danach folgendes Aussehen:

Byte  0 bis  3: 00 00 00 00 -> Zahlenwert 0

Byte  4 bis  7: FF FF FF  FF -> Zahlenwert 0 invertiert

Byte  8 bis 11: 00 00 00 00 -> Zahlenwert 0

Byte 12 u. 14: 14 -> Adresse des Blocks (14 HEX = 20 DEZ)

Byte 13 u. 15: EB -> Adresse des Blocks invertiert

Nach dem Inkrementieren wird der Blockinhalt des Value Blocks nochmals ausgegeben und auch der gespeicherte Zahlenwert angezeigt.

Beim nächsten Erkennen des gleichen RFID-Tags ergibt die Überprüfung, dass Block 20 bereits ein Value Block ist und somit sofort inkrementiert werden kann, usw.

Bild 2: Ausgabe am Seriellen Monitor


Zurück zu Access Bits

Wird fortgesetzt .....