Libelium's library

It is mandatory to include the RFID library when using this module. The following line must be introduced at the beginning of the code:

#include <WaspRFID13.h>

Waspmote's API RFID/NFC files:

  • WaspRFID13.cpp

  • WaspRFID13.h

API functions

  • Private functions:

    The following functions are executed inside the API functions. In normal conditions, the user must NOT manage or use them.

Function

Brief description

bool configureSAM(void);

set internal parameters of the PN532

sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength);

Send data stored in dataTX

getACK(void);

Wait for ACK response

waitResponse(void);*

Wait the response of the module

getData(uint8_t outLength);

Get data from the module

checkSum(uint8_t *dataTX);

Calculates the checksum

uint8_t lengthCheckSum(uint8_t *dataTX);

Calculates the length checksum

*To avoid the hang of the module this function will wait for 5 seconds approximately. If no tag is detected, the program will continue after this time. The waiting time can be configured in the library.

Library constructor

It is the class constructor. It is only executed inside the API's function init().

  • Public functions:

    The following functions are public and therefore they can be executed in the loop() or setup() functions. They provide the tools to perform all the features of the RFID/NFC module.

Function

Brief description

OFF()

switches the module off

ON(socket)

switches the module on, in one of the 2 sockets

init(UID, ATQ)

inits the module, configures it and searches for new cards

authenticate(UID, ad, key)

authenticates one card’s sector

bool getFirmware(void)

The PN532 sends back the version of the embedded firmware.

read(ad ,*data)

reads one card’s block

readWithAuth(UID, key, *data, ad)

authenticates one card's sector and reads one block

write(ad, *data)

writes one card’s block

writeWithAuth(UID, key, *data, ad)

authenticates one card's sector and writes one block

writeAndCheck(*data, ad)

writes one card's block and checks that

writeAndCheckWithAuth(UID, key, *data, ad)

authenticates one card's sector, writes one block and checks that

uint8_t powerDown(void)

put the module into Power Down mode

wakeUp(void)

wake up from power dowm mode.

print( *data, length)

print data stored in vectors

setKeys(UID, keyOld, keyA, keyB, cfg, data, ad

changes both keys and access conditions to one card's sector

equalUIDs(UID1, UID2)

compares 2 UIDs

searchUID(vCards, UID, nCards)

searches one UID inside one group of UIDs

string2vector(inp, outp)

converts from a string to a uint8_t vector

vector2int(*inp)

converts from a uint8_t vector to a integer

Switching the module on

This function takes the RFID/NFC module out of the power-down mode by starting the wake up procedure.

If you connected the RFID/NFC module into the usual XBee socket, please use SOCKET0; if you connected the RFID/NFC module into the Expansion Board, you must use SOCKET1.

Example of use:

{
RFID13.ON(SOCKET0); // switches the module on with the socket 0 (the normal socket, without
// using the Expansion Board)
}

Switching the module off

This function takes the RFID/NFC module to the software power-down mode.

Example of use:

{
RFID13.OFF(); // switches the module off
}

Initiating the module

This function initializes the necessary variables, requests if there is an ISO/IEC 14443-A card in the field, does the anti-collision loop and selects the card to operate.

This function is enough for those applications which just require to get the UID of cards, since most of the ISO/IEC 14443-A processes are executed inside.

It is highly advised to execute this function in the beginning of each loop, just as shown in any of the examples. Even if the module is already initialized, it is good to start from the same point every time.

This function initializes many internal registers and variables. All the settings are optimized for the best operation. Changing those settings may result in a defective operation.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t ATQ[2]; // stores the ATQ-A (answer to request, type 14443- A). Generally stored in a
// bigger buffer (16B)
uint8_t UID[4]; // stores the UID (unique identification) of a card
...
state = RFID13.init(UID, ATQ); // The goal of this command is to detect as many targets // (maximum MaxTg) as possible in passive mode.
}

Authenticating a sector

This function authenticates a sector of the card thanks to the key or password. It is important to remark that before doing any read or write in a block, it is mandatory to authenticate us in it.

The only exception is the UID, which can be read without authentication; it is returned by the init() function.

One authentication is enough to validate all the 4 blocks in a sector.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t ATQ[2]; // stores the ATQ-A
uint8_t UID[4]; // stores the UID (unique identification) of a card
uint8_t key[6]; // stores the key or password
...
memset(key, 0xFF, 6); // the key by default, edit if needed
state = RFID13.init(UID, ATQ); // inits systems and look for cards
state = RFID13.authenticate(UID, 2, key); // authenticates block number 2 (all sector 0
// actually)of the selected card. State of the executed
// function is stored.
}

Reading a block

This function reads the 16 bytes stored in a block. This block must have been authenticated before reading.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t aux[16]; // auxiliar buffer
uint8_t UID[4]; // stores the UID (unique identification) of a card
uint8_t key[6]; // stores the key or password
...
memset(key, 0xFF, 6); // the key by default, edit if needed
state = RFID13.init(UID, aux); // inits systems and look for cards
state = RFID13.authenticate(UID, 2, key);// authenticates block 2
state = RFID13.read(2, aux);// reads the block 2. Data is stored in aux.
}

Reading a block with authentication

This function authenticates a block of the card first, and then reads the 16 bytes stored in a block. This function is useful to do these 2 steps in just one.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t aux[16]; // auxiliar buffer
uint8_t UID[4]; // stores the UID (unique identification) of a card
uint8_t key[6]; // stores the key or password
...
memset(key, 0xFF, 6); // the key by default, edit if needed
state = RFID13.init(UID, aux); // inits systems and look for cards
state = RFID13.readWithAuth(UID, key, aux, 2); // authenticates block 2, then reads it. Data
// is stored in aux.
}

Writing in a block

This function writes 16 bytes in a block. This block must have been authenticated before writing.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t aux[16]; // auxiliar buffer
uint8_t UID[4]; // stores the UID (unique identification) of a card
uint8_t key[6]; // stores the key or password
...
memset(key, 0xFF, 6); // the key by default, edit if needed
state = RFID13.init(UID, aux); // inits systems and look for cards
state = RFID13.authenticate(UID, 2, key);// authenticates block 2
memset(aux, 0x00, 16); // stores 0\'s in aux, 16 bytes
state = RFID13.write(2, aux); // writes the content of aux in block number 2
}

Writing in a block with authentication

This function authenticates a block of the card first, and then writes 16 bytes in the block. This function is useful to do these 2 steps in just one.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t aux[16]; // auxiliar buffer
uint8_t UID[4]; // stores the UID (unique identification) of a card
uint8_t key[6]; // stores the key or password
...
memset(key, 0xFF, 6); // the key by default, edit if needed
state = RFID13.init(UID, aux); // inits systems and look for cards
memset(aux, 0x00, 16); // stores 0\'s in aux, 16 bytes
state = RFID13.writeWithAuth(UID, key, aux, 2); // authenticates block 2, then writes the
// content of aux in it
}

Writing in a block and checking it

This function writes 16 bytes in a block, and then checks the correct data was written. This block must be authenticated before writing. This function is useful to do these 2 steps in just one.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t aux[16]; // auxiliar buffer
uint8_t UID[4]; // stores the UID (unique identification) of a card
uint8_t key[6]; // stores the key or password
...
memset(key, 0xFF, 6); // the key by default, edit if needed
state = RFID13.init(UID, aux); // inits systems and look for cards
state = RFID13.authenticate(UID, 2, key);// authenticates block 2
memset(aux, 0x00, 16); // stores 0\'s in aux, 16 bytes
state = RFID13.writeAndCheck(aux, 2); // writes the content of aux in block 2, then checks // its content is OK
}

Writing in a block with authentication and checking it

This function authenticates a block of the card first, then writes 16 bytes in the block, and then checks the correct data was written. It is useful to do these 3 steps in just one.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t aux[16]; // auxiliar buffer
uint8_t UID[4]; // stores the UID (unique identification) of a card
uint8_t key[6]; // stores the key or password
...
memset(key, 0xFF, 6); // the key by default, edit if needed
state = RFID13.init(UID, aux); // inits systems and look for cards
state = RFID13.authenticate(UID, 2, key);// authenticates block 2
memset(aux, 0x00, 16); // stores 0\'s in aux, 16 bytes
writeAndCheckWithAuth(UID, key, aux, 2); // authenticates block 2, then writes the content of
// aux in it and checks its content is OK
}

Setting keys in a sector

This function authenticates a block of the card first, then sets the new keys A and B, and the access bits for a sector. After that, it authenticates again and reads the trailer block. This function is useful to do these 4 steps in just one.

This function should be executed with care because if any of the internal functions is not successfully executed, then the sector could be damaged or left unaccessible. That is why it is highly recommended to read the output status in order to check if all the process was completed. Please place the card still and close distance from the RFID/NFC module's antenna when setting new keys; if the whole process is not properly completed, the access to that sector might be lost forever.

There are many options for the configuration of the access bits. We suggest to use the same options that the card has by default: {0xFF, 0x07, 0x80, 0x69}. With this configuration:

  • data blocks must be authenticated with the key A, and then can be read/written

  • key A can only be changed (written) after an authentication with key A

  • access bits can be read or written after an authentication with key A

  • in the sector trailer, the key B has no use and can be read/written after an authentication with key A. It can be used as additional storage space, for instance.

With any configuration, the key A can never be read (the module returns 0's instead of the key) for security reasons. As we can see, the key A of each RFID/NFC card is the master key and we must avoid losing or sharing this information.

Any new card is delivered with the same A and B keys by default: 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF. That is to say, 48 logic 1's.

As shown, the key length is 6 bytes so there are more than 2.8·10¹⁴ different possible passwords.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t aux[16]; // auxiliar buffer
uint8_t UID[4]; // stores the UID (unique identification) of a card
uint8_t keyA_old[6]; // stores the old key A
uint8_t keyA_new[6]; // stores the new key A
uint8_t keyB_new[6]; // stores the new key B
uint8_t config_new[4] = {0xFF, 0x07, 0x80, 0x00}; // same cfg
...
memset(keyA_old, 0xFF, 6); // the key by default, edit if needed
memset(keyA_new, 0x88, 6); // the new key A, edit if needed
memset(keyB_new, 0x99, 6); // the new key B, edit if needed
state = RFID13.init(UID, aux); // inits systems and look for cards
state = RFID13.setKeys(UID, keyA_old, keyA_new, keyB_new, config_new, aux, 2); //
// authenticates block 2, then writes the new trailer block, with new key A
// and B. The access bits are the same.
}

Powering down

This function puts the module into Power Down mode in order to save power consumption.

Example of use:

{
RFID.powerDown(); // After this function you must wake up the module.
}

Waking up

This function wakes up the module from power down mode.

Example of use:

{
RFID.wakeUp(); //Wake Up from Power Down mode.
}

Printing data

This function is very useful for viewing data content in vectors when you are debugging the code.

Example of use:

{
RFID.print(readData , 16); // Print data read and stored in readData vector in the serial monitor
}

Comparing UIDs

This function compares 2 UIDs to check if they are equal. It is useful to check if the UID we have just detected is the same than a predetermined UID. One logic application could be access control for a single person.

Example of use:

{
uint8_t state; // stores the status of the executed command
uint8_t ATQ[2]; // stores the ATQ-A
uint8_t UID[4]; // stores the UID (unique identification) of a card
uint8_t card[] = {0xXY, 0xXY, 0xXY, 0xXY}; // the UID of the card that we want to find
boolean tr = false;
...
state = RFID13.init(UID, ATQ); // inits systems and look for cards
tr = RFID13.equalUIDs(card, UID); // if the read UID is the same than the original card, tr
// will be true
}

Searching a UID among a group of UIDs

This function tests if a certain UID is contained in a set or vector of UIDs. It is useful to check if the UID we have just detected is inside a predetermined set or group of UIDs. One logic application could be access control for a group of people.

Example of use:

{
#define nCards 3 // edit: number of possible cards
uint8_t state; // stores the status of the executed command
uint8_t ATQ[2]; // stores the ATQ-A
uint8_t UID[4]; // stores the UID (unique identification) of a card
// edit: vector with the UIDs of all the cards
uint8_t vCards [nCards*4] = {0xXY, 0xXY, 0xXY, 0xXY,
0xXY, 0xXY, 0xXY, 0xXY,
0xXY, 0xXY, 0xXY, 0xXY};
int card = -1; // stores the index of the present card
...
state = RFID13.init(UID, ATQ); // inits systems and look for cards
card = RFID13.searchUID(vCards, UID, nCards); // looks for the read card inside the data
// base. If so, it returns its index in the vector.
// If not, -1.
}

Converting from a string to a uint8_t pointer

This function converts from a string to a pointer to uint8_t's. When we want to write a word or phrase in an RFID card, this function is useful to convert from ASCII code to the format the RFID/NFC module can understand.

Example of use:

{
uint8_t aux[16]; // auxiliar uint8_t pointer
char text [16]; // auxiliar string
int number = 3; // stores numbers
...
sprintf(text ,\"Its a test %d \", number*4); // add a number to a string (dynamic !! )
RFID13.string2vector(text, aux); // converts from string to a uint8_t pointer
}

Converting from a uint8_t pointer to an integer

This function converts from a pointer to uint8_t's to an integer. When we want to read a number from an RFID card, this function is useful to convert from ASCII code to the format we can understand, an integer.

Example of use:

{
uint8_t aux[16] = {0x51, 0x52, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // auxiliar uint8_t pointer
int number = 0; // stores numbers
...
number = vector2int(aux); // converts from a uint8_t pointer to an integer
}