├── .gitignore ├── doc ├── rfidmifare.doc ├── rfidmifare.pdf └── fritzing │ ├── RFID-RC522-v2.fzpz │ ├── RFID-RC522-v2.png │ ├── RFID-RC522 - Pin Layout.png │ ├── Arduino-Uno-r3-with-RFID-RC522.fzz │ └── Arduino-Uno-r3-with-RFID-RC522.png ├── library.properties ├── library.json ├── Makefile ├── UNLICENSE ├── examples ├── FixBrickedUID │ └── FixBrickedUID.ino ├── Ntag216_AUTH │ └── Ntag216_AUTH.ino ├── firmware_check │ └── firmware_check.ino ├── DumpInfo │ └── DumpInfo.ino ├── ReadUidMultiReader │ └── ReadUidMultiReader.ino ├── ChangeUID │ └── ChangeUID.ino ├── ReadNUID │ └── ReadNUID.ino ├── MinimalInterrupt │ └── MinimalInterrupt.ino ├── rfid_default_keys │ └── rfid_default_keys.ino ├── rfid_write_personal_data │ └── rfid_write_personal_data.ino ├── ReadAndWrite │ └── ReadAndWrite.ino ├── RFID-Cloner │ └── RFID-Cloner.ino ├── MifareClassicValueBlock │ └── MifareClassicValueBlock.ino └── servo_motor │ └── servo_motor.ino ├── .travis.yml ├── changes.txt ├── keywords.txt ├── README.rst ├── MFRC522.h └── MFRC522.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | MFRC522.zip 2 | -------------------------------------------------------------------------------- /doc/rfidmifare.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gandhi-wibowo/rfid/master/doc/rfidmifare.doc -------------------------------------------------------------------------------- /doc/rfidmifare.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gandhi-wibowo/rfid/master/doc/rfidmifare.pdf -------------------------------------------------------------------------------- /doc/fritzing/RFID-RC522-v2.fzpz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gandhi-wibowo/rfid/master/doc/fritzing/RFID-RC522-v2.fzpz -------------------------------------------------------------------------------- /doc/fritzing/RFID-RC522-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gandhi-wibowo/rfid/master/doc/fritzing/RFID-RC522-v2.png -------------------------------------------------------------------------------- /doc/fritzing/RFID-RC522 - Pin Layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gandhi-wibowo/rfid/master/doc/fritzing/RFID-RC522 - Pin Layout.png -------------------------------------------------------------------------------- /doc/fritzing/Arduino-Uno-r3-with-RFID-RC522.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gandhi-wibowo/rfid/master/doc/fritzing/Arduino-Uno-r3-with-RFID-RC522.fzz -------------------------------------------------------------------------------- /doc/fritzing/Arduino-Uno-r3-with-RFID-RC522.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gandhi-wibowo/rfid/master/doc/fritzing/Arduino-Uno-r3-with-RFID-RC522.png -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=MFRC522 2 | version=1.1.8 3 | author=GithubCommunity 4 | maintainer=miguelbalboa 5 | sentence=Arduino RFID Library for MFRC522 (SPI) 6 | paragraph=Read/Write a RFID Card or Tag using the ISO/IEC 14443A/MIFARE interface. 7 | category=Communication 8 | url=https://github.com/miguelbalboa/rfid 9 | architectures=avr,STM32F1,teensy 10 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MFRC522", 3 | "keywords": "rfid, spi", 4 | "description": "Read a card using a MFRC522 reader on your SPI interface", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/miguelbalboa/rfid.git" 9 | }, 10 | "version": "1.1.8", 11 | "exclude": "doc", 12 | "frameworks": "arduino", 13 | "platforms": ["atmelavr", "ststm32", "teensy"] 14 | } 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for MFRC522 library 2 | # 3 | 4 | all: package 5 | 6 | help: 7 | @echo "Please use \`make ' where is one of" 8 | @echo " clean to clean the project (e.g. remove process files)" 9 | @echo " package to package the library (into a zip file)" 10 | 11 | clean: 12 | rm ./MFRC522.zip 13 | @echo 14 | @echo "Clean finished." 15 | 16 | package: 17 | zip -o ./MFRC522.zip ./MFRC522.h ./MFRC522.cpp 18 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /examples/FixBrickedUID/FixBrickedUID.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example sketch/program to fix a broken UID changeable MIFARE cards. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * This sample shows how to fix a broken UID changeable MIFARE cards that have a corrupted sector 0. 8 | * 9 | * @author Tom Clement 10 | * @license Released into the public domain. 11 | * 12 | * Typical pin layout used: 13 | * ----------------------------------------------------------------------------------------- 14 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 15 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 16 | * Signal Pin Pin Pin Pin Pin Pin 17 | * ----------------------------------------------------------------------------------------- 18 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 19 | * SPI SS SDA(SS) 10 53 D10 10 10 20 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 21 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 22 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #define RST_PIN 9 // Configurable, see typical pin layout above 29 | #define SS_PIN 10 // Configurable, see typical pin layout above 30 | 31 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 32 | 33 | MFRC522::MIFARE_Key key; 34 | 35 | void setup() { 36 | Serial.begin(9600); // Initialize serial communications with the PC 37 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 38 | SPI.begin(); // Init SPI bus 39 | mfrc522.PCD_Init(); // Init MFRC522 card 40 | Serial.println(F("Warning: this example clears your mifare UID, use with care!")); 41 | 42 | // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory. 43 | for (byte i = 0; i < 6; i++) { 44 | key.keyByte[i] = 0xFF; 45 | } 46 | } 47 | 48 | void loop() { 49 | if ( mfrc522.MIFARE_UnbrickUidSector(false) ) { 50 | Serial.println(F("Cleared sector 0, set UID to 1234. Card should be responsive again now.")); 51 | } 52 | delay(1000); 53 | } 54 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | 5 | # Cache PlatformIO packages using Travis CI container-based infrastructure 6 | sudo: false 7 | cache: 8 | directories: 9 | - "~/.platformio" 10 | 11 | env: 12 | # add examples here and define which boards should be tested (only compile test) 13 | - PLATFORMIO_CI_SRC=examples/ChangeUID/ChangeUID.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 14 | - PLATFORMIO_CI_SRC=examples/DumpInfo/DumpInfo.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 15 | - PLATFORMIO_CI_SRC=examples/firmware_check/firmware_check.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 16 | - PLATFORMIO_CI_SRC=examples/FixBrickedUID/FixBrickedUID.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 17 | - PLATFORMIO_CI_SRC=examples/MifareClassicValueBlock/MifareClassicValueBlock.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 18 | - PLATFORMIO_CI_SRC=examples/MinimalInterrupt/MinimalInterrupt.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 19 | - PLATFORMIO_CI_SRC=examples/ReadAndWrite/ReadAndWrite.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 20 | - PLATFORMIO_CI_SRC=examples/ReadUidMultiReader/ReadUidMultiReader.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 21 | - PLATFORMIO_CI_SRC=examples/rfid_default_keys/rfid_default_keys.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 22 | - PLATFORMIO_CI_SRC=examples/rfid_write_personal_data/rfid_write_personal_data.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 23 | - PLATFORMIO_CI_SRC=examples/Ntag216_AUTH/Ntag216_AUTH.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 24 | - PLATFORMIO_CI_SRC=examples/ReadNUID/ReadNUID.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 25 | - PLATFORMIO_CI_SRC=examples/servo_motor/servo_motor.ino TESTBOARD=arduino_avr,teensy 26 | - PLATFORMIO_CI_SRC=examples/RFID-Cloner/RFID-Cloner.ino TESTBOARD=arduino_avr,arduino_arm,teensy,esp 27 | 28 | install: 29 | - pip install -U platformio 30 | 31 | script: 32 | # short the string comparison 33 | - stringContain() { [ -z "${2##*$1*}" ]; } 34 | # selectable board tests @Rotzbua 35 | - board="arduino_avr"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; platformio ci --lib=. --board=uno --board=megaatmega1280; else echo "skip board test of $board"; fi 36 | - board="arduino_arm"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; platformio ci --lib=. --board=due --board=zero; else echo "skip board test of $board"; fi 37 | - board="teensy"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; platformio ci --lib=. --board=teensy31; else echo "skip board test of $board"; fi 38 | - board="esp"; if stringContain "$board" "$TESTBOARD"; then echo "check board $board"; platformio ci --lib=. --board=d1_mini; else echo "skip board test of $board"; fi 39 | -------------------------------------------------------------------------------- /examples/Ntag216_AUTH/Ntag216_AUTH.ino: -------------------------------------------------------------------------------- 1 | //This example show how you can get Authenticated by the NTAG213,215,216 by default the tags are unprotected in order to protect them we need to write 4 different values: 2 | // Using mfrc522.MIFARE_Ultralight_Write(PageNum, Data, #Databytes)) 3 | //1.- we need to write the 32bit passWord to page 0xE5 !for ntag 213 and 215 page is different refer to nxp documentation! 4 | //2.- Now Write the 16 bits pACK to the page 0xE6 use the 2 high bytes like this: pACKH + pACKL + 00 + 00 after an authentication the tag will return this secret bytes 5 | //3.- Now we need to write the first page we want to protect this is a 1 byte data in page 0xE3 we need to write 00 + 00 + 00 + firstPage all pages after this one are write protected 6 | // Now WRITE protection is ACTIVATED so we need to get authenticated in order to write the last data 7 | //4.- Finally we need to write an access record in order to READ protect the card this step is optional only if you want to read protect also write 80 + 00 + 00 + 00 to 0xE4 8 | //After completeing all these steps you will nee to authentiate first in order to read or write ant page after the first page you selected to protect 9 | //To disengage proection just write the page (0xE3) to 00 + 00 + 00 + FF that going to remove all protection 10 | //Made by GARGANTUA from RoboCreators.com & paradoxalabs.com 11 | 12 | #include 13 | #include 14 | 15 | #define RST_PIN 9 // 16 | #define SS_PIN 10 // 17 | 18 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 19 | 20 | void setup() { 21 | Serial.begin(9600); // Initialize serial communications with the PC 22 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 23 | SPI.begin(); // Init SPI bus 24 | mfrc522.PCD_Init(); // Init MFRC522 25 | Serial.println(F("Scan PICC to see UID, type, and data blocks...")); 26 | } 27 | 28 | void loop() { 29 | // Look for new cards 30 | if ( ! mfrc522.PICC_IsNewCardPresent()) { 31 | return; 32 | } 33 | 34 | // Select one of the cards 35 | if ( ! mfrc522.PICC_ReadCardSerial()) { 36 | return; 37 | } 38 | 39 | byte PSWBuff[] = {0xFF, 0xFF, 0xFF, 0xFF}; //32 bit PassWord default FFFFFFFF 40 | byte pACK[] = {0, 0}; //16 bit PassWord ACK returned by the NFCtag 41 | 42 | Serial.print("Auth: "); 43 | Serial.println(mfrc522.PCD_NTAG216_AUTH(&PSWBuff[0], pACK)); //Request Authentification if return STATUS_OK we are good 44 | 45 | //Print PassWordACK 46 | Serial.print(pACK[0], HEX); 47 | Serial.println(pACK[1], HEX); 48 | 49 | byte WBuff[] = {0x00, 0x00, 0x00, 0x04}; 50 | byte RBuff[18]; 51 | 52 | //Serial.print("CHG BLK: "); 53 | //Serial.println(mfrc522.MIFARE_Ultralight_Write(0xE3, WBuff, 4)); //How to write to a page 54 | 55 | mfrc522.PICC_DumpMifareUltralightToSerial(); //This is a modifier dunp just cghange the for cicle to < 232 instead of < 16 in order to see all the pages on NTAG216 56 | 57 | delay(3000); 58 | } -------------------------------------------------------------------------------- /changes.txt: -------------------------------------------------------------------------------- 1 | 11 Feb 2016, v1.1.8 2 | - Added examples/MinimalInterrupt/MinimalInterrupt.ino example, Interrupt example @lmmeng 3 | - Added .gitignore file allows the project to be more easily used as a subproject. @BenWiederhake 4 | - Added Added Teensy 2.0 & Tensy++ 2.0 pinouts to README.rst @jkutianski 5 | 6 | 16 Jan 2016, v1.1.7 7 | - README.rst Spelling and Grammar Tweak @cuthbertnibbles 8 | - Added examples/servo_motor/servo_motor.ino example, Arduino RFID Access Control with a Servo Motor @techied 9 | - Added examples/RFID-Cloner/RFID-Cloner.ino Copy from rfid cards with standard authentication @stefanblommaert 10 | - Fix compile error at examples/RFID-Cloner/RFID-Cloner.ino, using MFRC522:::PICC_Type, @Rotzbua 11 | 12 | 06 Jan 2016, v1.1.6 13 | - Fixed compilation error for examples/ReadNUID/ReadNUID.ino example. @Rotzbua 14 | 15 | 04 Jan 2016, v1.1.5 16 | - Use settings functions on SPI libraries, setSPIConfig was deleted, now the library use SPI.beginTransaction() and SPI.endTransaction() @sophiekovalevsky 17 | - Added examples/ReadNUID/ReadNUID.ino example, showing how to read new NUID from a PICC to serial. @sophiekovalevsky 18 | 19 | 03 Jan 2016, v1.1.4 20 | - Added Authentication with Ntag 213,215,216 returns the pACK MFRC522::PCD_NTAG216_AUTH @Gargantuanman 21 | - Starting to use versions http://semver.org/ 22 | - Continuous Integration @ivankravets 23 | - functions return MFRC522::StatusCode and MFRC522::PICC_Type instead of generic byte @rotzbua 24 | - removed int-values of MFRC522::StatusCode and MFRC522::PICC_Type @rotzbua 25 | 26 | 05 Dec 2015 27 | - recognize infineon cards correctly @mayatforest 28 | - added multi reader support, see example @lmmeng 29 | 30 | 10 Nov 2014 31 | - Updated the changelog. 32 | - Added makefile. 33 | 34 | 24 Oct 2014 35 | - Added PlatformIO-based manifest file. 36 | 37 | 17 Jul 2014 38 | - Written documentation for the library. 39 | - Added rfid_default_keys example. 40 | 41 | 11 Jun 2014 42 | - Updated example: ReadAndWrite. 43 | 44 | 14 Apr 2014 45 | - Updated examples: DumpInfo, MifareClassicValueBlock, and ReadAndWrite. 46 | 47 | 12 Feb 2014 48 | - Fixed resetPowerDownPin initial state. 49 | 50 | 29 Jan 2014 51 | - Fixed chipSelectPin initial state. 52 | 53 | 30 Nov 2013 54 | - Examples put in their own folders. 55 | - Updated the keywords.txt file. 56 | 57 | 12 Nov 2013 58 | - Updated examples: DumpInfo, MifareClassicValueBlock, and ReadAndWrite. 59 | 60 | 20 Oct 2013 61 | - All constants, functions and parameters are now commented in English. 62 | - Code refactored, most function names have changed. 63 | - Support ISO-14443-3 anti collission and 4/7/10 byte UIDs (cascade levels). 64 | - Added functions for MIFARE Classic Decrement/Increment/Restore/Transfer 65 | and MIFARE Ultralight Write. 66 | - New examples written. 67 | 68 | 19 Oct 2013 69 | - Renamed library from RFID to MFRC522 (RFID seemed to generic). 70 | - Register names changed to comply with datasheet. 71 | - Global defines moved into class. 72 | 73 | 24 Sep 2013 74 | - Turn off encryption when tag is halted. 75 | 76 | 27 Jan 2013 77 | - Added README and small TODO list. 78 | - Added example to show Serial on LCD display. 79 | 80 | 09 Sep 2012 81 | - Initial commit to GitHub. 82 | -------------------------------------------------------------------------------- /examples/firmware_check/firmware_check.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example sketch/program to test your firmware. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * This example test the firmware of your MFRC522 reader module, only known version can be checked. If the test passed 8 | * it do not mean that your module is faultless! Some modules have bad or broken antennas or the PICC is broken. 9 | * NOTE: for more informations read the README.rst 10 | * 11 | * @author Rotzbua 12 | * @license Released into the public domain. 13 | * 14 | * Typical pin layout used: 15 | * ----------------------------------------------------------------------------------------- 16 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 17 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 18 | * Signal Pin Pin Pin Pin Pin Pin 19 | * ----------------------------------------------------------------------------------------- 20 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 21 | * SPI SS SDA(SS) 10 53 D10 10 10 22 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 23 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 24 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | #define RST_PIN 9 // Configurable, see typical pin layout above 31 | #define SS_PIN 10 // Configurable, see typical pin layout above 32 | 33 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 34 | 35 | /** 36 | * Check firmware only once at startup 37 | */ 38 | void setup() { 39 | Serial.begin(9600); // Initialize serial communications with the PC 40 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 41 | SPI.begin(); // Init SPI bus 42 | mfrc522.PCD_Init(); // Init MFRC522 module 43 | 44 | Serial.println(F("*****************************")); 45 | Serial.println(F("MFRC522 Digital self test")); 46 | Serial.println(F("*****************************")); 47 | mfrc522.PCD_DumpVersionToSerial(); // Show version of PCD - MFRC522 Card Reader 48 | Serial.println(F("-----------------------------")); 49 | Serial.println(F("Only known versions supported")); 50 | Serial.println(F("-----------------------------")); 51 | Serial.println(F("Performing test...")); 52 | bool result = mfrc522.PCD_PerformSelfTest(); // perform the test 53 | Serial.println(F("-----------------------------")); 54 | Serial.print(F("Result: ")); 55 | if (result) 56 | Serial.println(F("OK")); 57 | else 58 | Serial.println(F("DEFECT or UNKNOWN")); 59 | Serial.println(); 60 | } 61 | 62 | void loop() {} // nothing to do 63 | -------------------------------------------------------------------------------- /examples/DumpInfo/DumpInfo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example sketch/program showing how to read data from a PICC to serial. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * Example sketch/program showing how to read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID 8 | * Reader on the Arduino SPI interface. 9 | * 10 | * When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE 11 | * then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When 12 | * you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output 13 | * will show the ID/UID, type and any data blocks it can read. Note: you may see "Timeout in communication" messages 14 | * when removing the PICC from reading distance too early. 15 | * 16 | * If your reader supports it, this sketch/program will read all the PICCs presented (that is: multiple tag reading). 17 | * So if you stack two or more PICCs on top of each other and present them to the reader, it will first output all 18 | * details of the first and then the next PICC. Note that this may take some time as all data blocks are dumped, so 19 | * keep the PICCs at reading distance until complete. 20 | * 21 | * @license Released into the public domain. 22 | * 23 | * Typical pin layout used: 24 | * ----------------------------------------------------------------------------------------- 25 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 26 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 27 | * Signal Pin Pin Pin Pin Pin Pin 28 | * ----------------------------------------------------------------------------------------- 29 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 30 | * SPI SS SDA(SS) 10 53 D10 10 10 31 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 32 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 33 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 34 | */ 35 | 36 | #include 37 | #include 38 | 39 | #define RST_PIN 9 // Configurable, see typical pin layout above 40 | #define SS_PIN 10 // Configurable, see typical pin layout above 41 | 42 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 43 | 44 | void setup() { 45 | Serial.begin(9600); // Initialize serial communications with the PC 46 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 47 | SPI.begin(); // Init SPI bus 48 | mfrc522.PCD_Init(); // Init MFRC522 49 | mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details 50 | Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks...")); 51 | } 52 | 53 | void loop() { 54 | // Look for new cards 55 | if ( ! mfrc522.PICC_IsNewCardPresent()) { 56 | return; 57 | } 58 | 59 | // Select one of the cards 60 | if ( ! mfrc522.PICC_ReadCardSerial()) { 61 | return; 62 | } 63 | 64 | // Dump debug info about the card; PICC_HaltA() is automatically called 65 | mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); 66 | } 67 | -------------------------------------------------------------------------------- /examples/ReadUidMultiReader/ReadUidMultiReader.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * This sample shows how to read and write data blocks on a MIFARE Classic PICC 11 | * (= card/tag). 12 | * 13 | * BEWARE: Data will be written to the PICC, in sector #1 (blocks #4 to #7). 14 | * 15 | * 16 | * Typical pin layout used: 17 | * ----------------------------------------------------------------------------------------- 18 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 19 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 20 | * Signal Pin Pin Pin Pin Pin Pin 21 | * ----------------------------------------------------------------------------------------- 22 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 23 | * SPI SS 1 SDA(SS) 10 53 D10 10 10 24 | * SPI SS 2 SDA(SS) 2 53 D10 10 10 25 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 26 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 27 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 28 | * 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #define RST_PIN 10 // Configurable, see typical pin layout above 35 | #define SS_1_PIN 5 // Configurable, see typical pin layout above 36 | #define SS_2_PIN 3 // Configurable, see typical pin layout above 37 | 38 | #define NR_OF_READERS 2 39 | 40 | byte ssPins[] = {SS_1_PIN, SS_2_PIN}; 41 | 42 | MFRC522 mfrc522[NR_OF_READERS]; // Create MFRC522 instance. 43 | 44 | /** 45 | * Initialize. 46 | */ 47 | void setup() { 48 | 49 | Serial.begin(115200); // Initialize serial communications with the PC 50 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 51 | 52 | SPI.begin(); // Init SPI bus 53 | 54 | for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) { 55 | mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN); // Init each MFRC522 card 56 | } 57 | } 58 | 59 | /** 60 | * Main loop. 61 | */ 62 | void loop() { 63 | 64 | for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) { 65 | // Look for new cards 66 | 67 | if (mfrc522[reader].PICC_IsNewCardPresent() && mfrc522[reader].PICC_ReadCardSerial()) { 68 | Serial.print(F("Reader: ")); 69 | Serial.print(reader); 70 | // Show some details of the PICC (that is: the tag/card) 71 | Serial.print(F(" Card UID:")); 72 | dump_byte_array(mfrc522[reader].uid.uidByte, mfrc522[reader].uid.size); 73 | Serial.println(); 74 | Serial.print(F("PICC type: ")); 75 | MFRC522::PICC_Type piccType = mfrc522[reader].PICC_GetType(mfrc522[reader].uid.sak); 76 | Serial.println(mfrc522[reader].PICC_GetTypeName(piccType)); 77 | 78 | // Halt PICC 79 | mfrc522[reader].PICC_HaltA(); 80 | // Stop encryption on PCD 81 | mfrc522[reader].PCD_StopCrypto1(); 82 | } //if (mfrc522[reader].PICC_IsNewC 83 | } //for(uint8_t reader 84 | } 85 | 86 | /** 87 | * Helper routine to dump a byte array as hex values to Serial. 88 | */ 89 | void dump_byte_array(byte *buffer, byte bufferSize) { 90 | for (byte i = 0; i < bufferSize; i++) { 91 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 92 | Serial.print(buffer[i], HEX); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /examples/ChangeUID/ChangeUID.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example to change UID of changeable MIFARE card. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * This sample shows how to set the UID on a UID changeable MIFARE card. 8 | * NOTE: for more informations read the README.rst 9 | * 10 | * @author Tom Clement 11 | * @license Released into the public domain. 12 | * 13 | * Typical pin layout used: 14 | * ----------------------------------------------------------------------------------------- 15 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 16 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 17 | * Signal Pin Pin Pin Pin Pin Pin 18 | * ----------------------------------------------------------------------------------------- 19 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 20 | * SPI SS SDA(SS) 10 53 D10 10 10 21 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 22 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 23 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #define RST_PIN 9 // Configurable, see typical pin layout above 30 | #define SS_PIN 10 // Configurable, see typical pin layout above 31 | 32 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 33 | 34 | /* Set your new UID here! */ 35 | #define NEW_UID {0xDE, 0xAD, 0xBE, 0xEF} 36 | 37 | MFRC522::MIFARE_Key key; 38 | 39 | void setup() { 40 | Serial.begin(9600); // Initialize serial communications with the PC 41 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 42 | SPI.begin(); // Init SPI bus 43 | mfrc522.PCD_Init(); // Init MFRC522 card 44 | Serial.println(F("Warning: this example overwrites the UID of your UID changeable card, use with care!")); 45 | 46 | // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory. 47 | for (byte i = 0; i < 6; i++) { 48 | key.keyByte[i] = 0xFF; 49 | } 50 | } 51 | 52 | // Setting the UID can be as simple as this: 53 | //void loop() { 54 | // byte newUid[] = NEW_UID; 55 | // if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) { 56 | // Serial.println("Wrote new UID to card."); 57 | // } 58 | // delay(1000); 59 | //} 60 | 61 | // But of course this is a more proper approach 62 | void loop() { 63 | 64 | // Look for new cards, and select one if present 65 | if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) { 66 | delay(50); 67 | return; 68 | } 69 | 70 | // Now a card is selected. The UID and SAK is in mfrc522.uid. 71 | 72 | // Dump UID 73 | Serial.print(F("Card UID:")); 74 | for (byte i = 0; i < mfrc522.uid.size; i++) { 75 | Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); 76 | Serial.print(mfrc522.uid.uidByte[i], HEX); 77 | } 78 | Serial.println(); 79 | 80 | // Dump PICC type 81 | // MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 82 | // Serial.print(F("PICC type: ")); 83 | // Serial.print(mfrc522.PICC_GetTypeName(piccType)); 84 | // Serial.print(F(" (SAK ")); 85 | // Serial.print(mfrc522.uid.sak); 86 | // Serial.print(")\r\n"); 87 | // if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI 88 | // && piccType != MFRC522::PICC_TYPE_MIFARE_1K 89 | // && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { 90 | // Serial.println(F("This sample only works with MIFARE Classic cards.")); 91 | // return; 92 | // } 93 | 94 | // Set new UID 95 | byte newUid[] = NEW_UID; 96 | if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) { 97 | Serial.println(F("Wrote new UID to card.")); 98 | } 99 | 100 | // Halt PICC and re-select it so DumpToSerial doesn't get confused 101 | mfrc522.PICC_HaltA(); 102 | if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) { 103 | return; 104 | } 105 | 106 | // Dump the new memory contents 107 | Serial.println(F("New UID and contents:")); 108 | mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); 109 | 110 | delay(2000); 111 | } 112 | -------------------------------------------------------------------------------- /examples/ReadNUID/ReadNUID.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * -------------------------------------------------------------------------------------------------------------------- 3 | * Example sketch/program showing how to read new NUID from a PICC to serial. 4 | * -------------------------------------------------------------------------------------------------------------------- 5 | * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid 6 | * 7 | * Example sketch/program showing how to the read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID 8 | * Reader on the Arduino SPI interface. 9 | * 10 | * When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE 11 | * then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When 12 | * you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output 13 | * will show the type, and the NUID if a new card has been detected. Note: you may see "Timeout in communication" messages 14 | * when removing the PICC from reading distance too early. 15 | * 16 | * @license Released into the public domain. 17 | * 18 | * Typical pin layout used: 19 | * ----------------------------------------------------------------------------------------- 20 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 21 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 22 | * Signal Pin Pin Pin Pin Pin Pin 23 | * ----------------------------------------------------------------------------------------- 24 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 25 | * SPI SS SDA(SS) 10 53 D10 10 10 26 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 27 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 28 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #define SS_PIN 10 35 | #define RST_PIN 9 36 | 37 | MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class 38 | 39 | MFRC522::MIFARE_Key key; 40 | 41 | // Init array that will store new NUID 42 | byte nuidPICC[3]; 43 | 44 | void setup() { 45 | Serial.begin(9600); 46 | SPI.begin(); // Init SPI bus 47 | rfid.PCD_Init(); // Init MFRC522 48 | 49 | for (byte i = 0; i < 6; i++) { 50 | key.keyByte[i] = 0xFF; 51 | } 52 | 53 | Serial.println(F("This code scan the MIFARE Classsic NUID.")); 54 | Serial.print(F("Using the following key:")); 55 | printHex(key.keyByte, MFRC522::MF_KEY_SIZE); 56 | } 57 | 58 | void loop() { 59 | 60 | // Look for new cards 61 | if ( ! rfid.PICC_IsNewCardPresent()) 62 | return; 63 | 64 | // Verify if the NUID has been readed 65 | if ( ! rfid.PICC_ReadCardSerial()) 66 | return; 67 | 68 | Serial.print(F("PICC type: ")); 69 | MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak); 70 | Serial.println(rfid.PICC_GetTypeName(piccType)); 71 | 72 | // Check is the PICC of Classic MIFARE type 73 | if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI && 74 | piccType != MFRC522::PICC_TYPE_MIFARE_1K && 75 | piccType != MFRC522::PICC_TYPE_MIFARE_4K) { 76 | Serial.println(F("Your tag is not of type MIFARE Classic.")); 77 | return; 78 | } 79 | 80 | if (rfid.uid.uidByte[0] != nuidPICC[0] || 81 | rfid.uid.uidByte[1] != nuidPICC[1] || 82 | rfid.uid.uidByte[2] != nuidPICC[2] || 83 | rfid.uid.uidByte[3] != nuidPICC[3] ) { 84 | Serial.println(F("A new card has been detected.")); 85 | 86 | // Store NUID into nuidPICC array 87 | for (byte i = 0; i < 4; i++) { 88 | nuidPICC[i] = rfid.uid.uidByte[i]; 89 | } 90 | 91 | Serial.println(F("The NUID tag is:")); 92 | Serial.print(F("In hex: ")); 93 | printHex(rfid.uid.uidByte, rfid.uid.size); 94 | Serial.println(); 95 | Serial.print(F("In dec: ")); 96 | printDec(rfid.uid.uidByte, rfid.uid.size); 97 | Serial.println(); 98 | } 99 | else Serial.println(F("Card read previously.")); 100 | 101 | // Halt PICC 102 | rfid.PICC_HaltA(); 103 | 104 | // Stop encryption on PCD 105 | rfid.PCD_StopCrypto1(); 106 | } 107 | 108 | 109 | /** 110 | * Helper routine to dump a byte array as hex values to Serial. 111 | */ 112 | void printHex(byte *buffer, byte bufferSize) { 113 | for (byte i = 0; i < bufferSize; i++) { 114 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 115 | Serial.print(buffer[i], HEX); 116 | } 117 | } 118 | 119 | /** 120 | * Helper routine to dump a byte array as dec values to Serial. 121 | */ 122 | void printDec(byte *buffer, byte bufferSize) { 123 | for (byte i = 0; i < bufferSize; i++) { 124 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 125 | Serial.print(buffer[i], DEC); 126 | } 127 | } -------------------------------------------------------------------------------- /examples/MinimalInterrupt/MinimalInterrupt.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * Minimal example how to use the interrupts to read the UID of a MIFARE Classic PICC 11 | * (= card/tag). 12 | * 13 | * 14 | * Typical pin layout used: 15 | * ----------------------------------------------------------------------------------------- 16 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 17 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 18 | * Signal Pin Pin Pin Pin Pin Pin 19 | * ----------------------------------------------------------------------------------------- 20 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 21 | * SPI SS SDA(SS) 10 53 D10 3 10 22 | * IRQ ? ? ? ? 2 10 23 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 24 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 25 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 26 | * 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | #define RST_PIN 9 // Configurable, see typical pin layout above 33 | #define SS_PIN 3 // Configurable, see typical pin layout above 34 | #define IRQ_PIN 2 35 | 36 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 37 | 38 | MFRC522::MIFARE_Key key; 39 | 40 | volatile boolean bNewInt = false; 41 | unsigned char regVal = 0x7F; 42 | void activateRec(MFRC522 mfrc522); 43 | void clearInt(MFRC522 mfrc522); 44 | 45 | /** 46 | * Initialize. 47 | */ 48 | void setup() { 49 | Serial.begin(115200); // Initialize serial communications with the PC 50 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 51 | SPI.begin(); // Init SPI bus 52 | 53 | mfrc522.PCD_Init(); // Init MFRC522 card 54 | 55 | /* read and printout the MFRC522 version (valid values 0x91 & 0x92)*/ 56 | Serial.print("Ver: 0x"); 57 | byte readReg = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); 58 | Serial.println(readReg, HEX); 59 | 60 | /* setup the IRQ pin*/ 61 | pinMode(IRQ_PIN, INPUT_PULLUP); 62 | 63 | /* 64 | * Allow the ... irq to be propagated to the IRQ pin 65 | * For test purposes propagate the IdleIrq and loAlert 66 | */ 67 | regVal = 0xA0; //rx irq 68 | mfrc522.PCD_WriteRegister(mfrc522.ComIEnReg,regVal); 69 | 70 | bNewInt = false; //interrupt flag 71 | 72 | /*Activate the interrupt*/ 73 | attachInterrupt(digitalPinToInterrupt(IRQ_PIN), readCard, FALLING); 74 | 75 | Serial.println("End setup"); 76 | 77 | do{ //clear a spourious interrupt at start 78 | ; 79 | }while(!bNewInt); 80 | bNewInt = false; 81 | } 82 | 83 | /** 84 | * Main loop. 85 | */ 86 | void loop() { 87 | 88 | if(bNewInt){ //new read interrupt 89 | bNewInt = false; 90 | Serial.print("Interrupt. "); 91 | mfrc522.PICC_ReadCardSerial(); //read the tag data 92 | // Show some details of the PICC (that is: the tag/card) 93 | Serial.print(F("Card UID:")); 94 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 95 | Serial.println(); 96 | 97 | clearInt(mfrc522); 98 | } 99 | 100 | // The receiving block needs regular retriggering (tell the tag it should transmit??) 101 | // (mfrc522.PCD_WriteRegister(mfrc522.FIFODataReg,mfrc522.PICC_CMD_REQA);) 102 | activateRec(mfrc522); 103 | delay(100); 104 | } //loop() 105 | 106 | /** 107 | * Helper routine to dump a byte array as hex values to Serial. 108 | */ 109 | void dump_byte_array(byte *buffer, byte bufferSize) { 110 | for (byte i = 0; i < bufferSize; i++) { 111 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 112 | Serial.print(buffer[i], HEX); 113 | } 114 | } 115 | /** 116 | * MFRC522 interrupt serving routine 117 | */ 118 | void readCard(){ 119 | bNewInt = true; 120 | } 121 | 122 | /* 123 | * The function sending to the MFRC522 the needed commands to activate the reception 124 | */ 125 | void activateRec(MFRC522 mfrc522){ 126 | mfrc522.PCD_WriteRegister(mfrc522.FIFODataReg,mfrc522.PICC_CMD_REQA); 127 | mfrc522.PCD_WriteRegister(mfrc522.CommandReg,mfrc522.PCD_Transceive); 128 | mfrc522.PCD_WriteRegister(mfrc522.BitFramingReg, 0x87); 129 | } 130 | 131 | /* 132 | * The function to clear the pending interrupt bits after interrupt serving routine 133 | */ 134 | void clearInt(MFRC522 mfrc522){ 135 | mfrc522.PCD_WriteRegister(mfrc522.ComIrqReg,0x7F); 136 | } 137 | 138 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for library MFRC522 3 | ####################################### 4 | 5 | ####################################### 6 | # KEYWORD1 Classes, datatypes, and C++ keywords 7 | ####################################### 8 | MFRC522 KEYWORD1 9 | PCD_Register KEYWORD1 10 | PCD_Command KEYWORD1 11 | PCD_RxGain KEYWORD1 12 | PICC_Command KEYWORD1 13 | MIFARE_Misc KEYWORD1 14 | PICC_Type KEYWORD1 15 | StatusCode KEYWORD1 16 | Uid KEYWORD1 17 | MIFARE_Key KEYWORD1 18 | 19 | ####################################### 20 | # KEYWORD2 Methods and functions 21 | ####################################### 22 | 23 | # Basic interface functions for communicating with the MFRC522 24 | PCD_WriteRegister KEYWORD2 25 | PCD_WriteRegister KEYWORD2 26 | PCD_ReadRegister KEYWORD2 27 | PCD_ReadRegister KEYWORD2 28 | setBitMask KEYWORD2 29 | PCD_SetRegisterBitMask KEYWORD2 30 | PCD_ClearRegisterBitMask KEYWORD2 31 | PCD_CalculateCRC KEYWORD2 32 | 33 | # Functions for manipulating the MFRC522 34 | PCD_Init KEYWORD2 35 | PCD_Reset KEYWORD2 36 | PCD_AntennaOn KEYWORD2 37 | PCD_AntennaOff KEYWORD2 38 | PCD_GetAntennaGain KEYWORD2 39 | PCD_SetAntennaGain KEYWORD2 40 | PCD_PerformSelfTest KEYWORD2 41 | 42 | # Functions for communicating with PICCs 43 | PCD_TransceiveData KEYWORD2 44 | PCD_CommunicateWithPICC KEYWORD2 45 | PICC_RequestA KEYWORD2 46 | PICC_WakeupA KEYWORD2 47 | PICC_REQA_or_WUPA KEYWORD2 48 | PICC_Select KEYWORD2 49 | PICC_HaltA KEYWORD2 50 | 51 | # Functions for communicating with MIFARE PICCs 52 | PCD_Authenticate KEYWORD2 53 | PCD_StopCrypto1 KEYWORD2 54 | MIFARE_Read KEYWORD2 55 | MIFARE_Write KEYWORD2 56 | MIFARE_Increment KEYWORD2 57 | MIFARE_Ultralight_Write KEYWORD2 58 | MIFARE_GetValue KEYWORD2 59 | MIFARE_SetValue KEYWORD2 60 | PCD_NTAG216_AUTH KEYWORD2 61 | 62 | # Support functions 63 | PCD_MIFARE_Transceive KEYWORD2 64 | GetStatusCodeName KEYWORD2 65 | PICC_GetType KEYWORD2 66 | PICC_GetTypeName KEYWORD2 67 | 68 | # Support functions for debuging 69 | PCD_DumpVersionToSerial KEYWORD2 70 | PICC_DumpToSerial KEYWORD2 71 | PICC_DumpDetailsToSerial KEYWORD2 72 | PICC_DumpMifareClassicToSerial KEYWORD2 73 | PICC_DumpMifareClassicSectorToSerial KEYWORD2 74 | PICC_DumpMifareUltralightToSerial KEYWORD2 75 | 76 | # Advanced functions for MIFARE 77 | MIFARE_SetAccessBits KEYWORD2 78 | MIFARE_OpenUidBackdoor KEYWORD2 79 | MIFARE_SetUid KEYWORD2 80 | MIFARE_UnbrickUidSector KEYWORD2 81 | 82 | # Convenience functions - does not add extra functionality 83 | PICC_IsNewCardPresent KEYWORD2 84 | PICC_ReadCardSerial KEYWORD2 85 | 86 | ####################################### 87 | # KEYWORD3 setup and loop functions, as well as the Serial keywords 88 | ####################################### 89 | 90 | ####################################### 91 | LITERAL1 Constants 92 | ####################################### 93 | CommandReg LITERAL1 94 | ComIEnReg LITERAL1 95 | DivIEnReg LITERAL1 96 | ComIrqReg LITERAL1 97 | DivIrqReg LITERAL1 98 | ErrorReg LITERAL1 99 | Status1Reg LITERAL1 100 | Status2Reg LITERAL1 101 | FIFODataReg LITERAL1 102 | FIFOLevelReg LITERAL1 103 | WaterLevelReg LITERAL1 104 | ControlReg LITERAL1 105 | BitFramingReg LITERAL1 106 | CollReg LITERAL1 107 | ModeReg LITERAL1 108 | TxModeReg LITERAL1 109 | RxModeReg LITERAL1 110 | TxControlReg LITERAL1 111 | TxASKReg LITERAL1 112 | TxSelReg LITERAL1 113 | RxSelReg LITERAL1 114 | RxThresholdReg LITERAL1 115 | DemodReg LITERAL1 116 | MfTxReg LITERAL1 117 | MfRxReg LITERAL1 118 | SerialSpeedReg LITERAL1 119 | CRCResultRegH LITERAL1 120 | CRCResultRegL LITERAL1 121 | ModWidthReg LITERAL1 122 | RFCfgReg LITERAL1 123 | GsNReg LITERAL1 124 | CWGsPReg LITERAL1 125 | ModGsPReg LITERAL1 126 | TModeReg LITERAL1 127 | TPrescalerReg LITERAL1 128 | TReloadRegH LITERAL1 129 | TReloadRegL LITERAL1 130 | TCounterValueRegH LITERAL1 131 | TCounterValueRegL LITERAL1 132 | TestSel1Reg LITERAL1 133 | TestSel2Reg LITERAL1 134 | TestPinEnReg LITERAL1 135 | TestPinValueReg LITERAL1 136 | TestBusReg LITERAL1 137 | AutoTestReg LITERAL1 138 | VersionReg LITERAL1 139 | AnalogTestReg LITERAL1 140 | TestDAC1Reg LITERAL1 141 | TestDAC2Reg LITERAL1 142 | TestADCReg LITERAL1 143 | PCD_Idle LITERAL1 144 | PCD_Mem LITERAL1 145 | PCD_GenerateRandomID LITERAL1 146 | PCD_CalcCRC LITERAL1 147 | PCD_Transmit LITERAL1 148 | PCD_NoCmdChange LITERAL1 149 | PCD_Receive LITERAL1 150 | PCD_Transceive LITERAL1 151 | PCD_MFAuthent LITERAL1 152 | PCD_SoftReset LITERAL1 153 | RxGain_18dB LITERAL1 154 | RxGain_23dB LITERAL1 155 | RxGain_18dB_2 LITERAL1 156 | RxGain_23dB_2 LITERAL1 157 | RxGain_33dB LITERAL1 158 | RxGain_38dB LITERAL1 159 | RxGain_43dB LITERAL1 160 | RxGain_48dB LITERAL1 161 | RxGain_min LITERAL1 162 | RxGain_avg LITERAL1 163 | RxGain_max LITERAL1 164 | PICC_CMD_REQA LITERAL1 165 | PICC_CMD_WUPA LITERAL1 166 | PICC_CMD_CT LITERAL1 167 | PICC_CMD_SEL_CL1 LITERAL1 168 | PICC_CMD_SEL_CL2 LITERAL1 169 | PICC_CMD_SEL_CL3 LITERAL1 170 | PICC_CMD_HLTA LITERAL1 171 | PICC_CMD_MF_AUTH_KEY_A LITERAL1 172 | PICC_CMD_MF_AUTH_KEY_B LITERAL1 173 | PICC_CMD_MF_READ LITERAL1 174 | PICC_CMD_MF_WRITE LITERAL1 175 | PICC_CMD_MF_DECREMENT LITERAL1 176 | PICC_CMD_MF_INCREMENT LITERAL1 177 | PICC_CMD_MF_RESTORE LITERAL1 178 | PICC_CMD_MF_TRANSFER LITERAL1 179 | PICC_CMD_UL_WRITE LITERAL1 180 | MF_ACK LITERAL1 181 | MF_KEY_SIZE LITERAL1 182 | PICC_TYPE_UNKNOWN LITERAL1 183 | PICC_TYPE_ISO_14443_4 LITERAL1 184 | PICC_TYPE_ISO_18092 LITERAL1 185 | PICC_TYPE_MIFARE_MINI LITERAL1 186 | PICC_TYPE_MIFARE_1K LITERAL1 187 | PICC_TYPE_MIFARE_4K LITERAL1 188 | PICC_TYPE_MIFARE_UL LITERAL1 189 | PICC_TYPE_MIFARE_PLUS LITERAL1 190 | PICC_TYPE_TNP3XXX LITERAL1 191 | PICC_TYPE_NOT_COMPLETE LITERAL1 192 | STATUS_OK LITERAL1 193 | STATUS_ERROR LITERAL1 194 | STATUS_COLLISION LITERAL1 195 | STATUS_TIMEOUT LITERAL1 196 | STATUS_NO_ROOM LITERAL1 197 | STATUS_INTERNAL_ERROR LITERAL1 198 | STATUS_INVALID LITERAL1 199 | STATUS_CRC_WRONG LITERAL1 200 | STATUS_MIFARE_NACK LITERAL1 201 | FIFO_SIZE LITERAL1 202 | -------------------------------------------------------------------------------- /examples/rfid_default_keys/rfid_default_keys.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * Example sketch/program which will try the most used default keys listed in 11 | * https://code.google.com/p/mfcuk/wiki/MifareClassicDefaultKeys to dump the 12 | * block 0 of a MIFARE RFID card using a RFID-RC522 reader. 13 | * 14 | * Typical pin layout used: 15 | * ----------------------------------------------------------------------------------------- 16 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 17 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 18 | * Signal Pin Pin Pin Pin Pin Pin 19 | * ----------------------------------------------------------------------------------------- 20 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 21 | * SPI SS SDA(SS) 10 53 D10 10 10 22 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 23 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 24 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #define RST_PIN 9 // Configurable, see typical pin layout above 32 | #define SS_PIN 10 // Configurable, see typical pin layout above 33 | 34 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 35 | 36 | // Number of known default keys (hard-coded) 37 | // NOTE: Synchronize the NR_KNOWN_KEYS define with the defaultKeys[] array 38 | #define NR_KNOWN_KEYS 8 39 | // Known keys, see: https://code.google.com/p/mfcuk/wiki/MifareClassicDefaultKeys 40 | byte knownKeys[NR_KNOWN_KEYS][MFRC522::MF_KEY_SIZE] = { 41 | {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // FF FF FF FF FF FF = factory default 42 | {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, // A0 A1 A2 A3 A4 A5 43 | {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5}, // B0 B1 B2 B3 B4 B5 44 | {0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd}, // 4D 3A 99 C3 51 DD 45 | {0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a}, // 1A 98 2C 7E 45 9A 46 | {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}, // D3 F7 D3 F7 D3 F7 47 | {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, // AA BB CC DD EE FF 48 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // 00 00 00 00 00 00 49 | }; 50 | 51 | /* 52 | * Initialize. 53 | */ 54 | void setup() { 55 | Serial.begin(9600); // Initialize serial communications with the PC 56 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 57 | SPI.begin(); // Init SPI bus 58 | mfrc522.PCD_Init(); // Init MFRC522 card 59 | Serial.println(F("Try the most used default keys to print block 0 of a MIFARE PICC.")); 60 | } 61 | 62 | /* 63 | * Helper routine to dump a byte array as hex values to Serial. 64 | */ 65 | void dump_byte_array(byte *buffer, byte bufferSize) { 66 | for (byte i = 0; i < bufferSize; i++) { 67 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 68 | Serial.print(buffer[i], HEX); 69 | } 70 | } 71 | 72 | /* 73 | * Try using the PICC (the tag/card) with the given key to access block 0. 74 | * On success, it will show the key details, and dump the block data on Serial. 75 | * 76 | * @return true when the given key worked, false otherwise. 77 | */ 78 | boolean try_key(MFRC522::MIFARE_Key *key) 79 | { 80 | boolean result = false; 81 | byte buffer[18]; 82 | byte block = 0; 83 | MFRC522::StatusCode status; 84 | 85 | // Serial.println(F("Authenticating using key A...")); 86 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, key, &(mfrc522.uid)); 87 | if (status != MFRC522::STATUS_OK) { 88 | // Serial.print(F("PCD_Authenticate() failed: ")); 89 | // Serial.println(mfrc522.GetStatusCodeName(status)); 90 | return false; 91 | } 92 | 93 | // Read block 94 | byte byteCount = sizeof(buffer); 95 | status = mfrc522.MIFARE_Read(block, buffer, &byteCount); 96 | if (status != MFRC522::STATUS_OK) { 97 | // Serial.print(F("MIFARE_Read() failed: ")); 98 | // Serial.println(mfrc522.GetStatusCodeName(status)); 99 | } 100 | else { 101 | // Successful read 102 | result = true; 103 | Serial.print(F("Success with key:")); 104 | dump_byte_array((*key).keyByte, MFRC522::MF_KEY_SIZE); 105 | Serial.println(); 106 | // Dump block data 107 | Serial.print(F("Block ")); Serial.print(block); Serial.print(F(":")); 108 | dump_byte_array(buffer, 16); 109 | Serial.println(); 110 | } 111 | Serial.println(); 112 | 113 | mfrc522.PICC_HaltA(); // Halt PICC 114 | mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD 115 | return result; 116 | } 117 | 118 | /* 119 | * Main loop. 120 | */ 121 | void loop() { 122 | // Look for new cards 123 | if ( ! mfrc522.PICC_IsNewCardPresent()) 124 | return; 125 | 126 | // Select one of the cards 127 | if ( ! mfrc522.PICC_ReadCardSerial()) 128 | return; 129 | 130 | // Show some details of the PICC (that is: the tag/card) 131 | Serial.print(F("Card UID:")); 132 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 133 | Serial.println(); 134 | Serial.print(F("PICC type: ")); 135 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 136 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 137 | 138 | // Try the known default keys 139 | MFRC522::MIFARE_Key key; 140 | for (byte k = 0; k < NR_KNOWN_KEYS; k++) { 141 | // Copy the known key into the MIFARE_Key structure 142 | for (byte i = 0; i < MFRC522::MF_KEY_SIZE; i++) { 143 | key.keyByte[i] = knownKeys[k][i]; 144 | } 145 | // Try the key 146 | if (try_key(&key)) { 147 | // Found and reported on the key and block, 148 | // no need to try other keys for this PICC 149 | break; 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /examples/rfid_write_personal_data/rfid_write_personal_data.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Write personal data of a MIFARE RFID card using a RFID-RC522 reader 3 | * Uses MFRC522 - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 4 | * ----------------------------------------------------------------------------------------- 5 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 6 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 7 | * Signal Pin Pin Pin Pin Pin Pin 8 | * ----------------------------------------------------------------------------------------- 9 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 10 | * SPI SS SDA(SS) 10 53 D10 10 10 11 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 12 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 13 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 14 | * 15 | * Hardware required: 16 | * Arduino 17 | * PCD (Proximity Coupling Device): NXP MFRC522 Contactless Reader IC 18 | * PICC (Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203. 19 | * The reader can be found on eBay for around 5 dollars. Search for "mf-rc522" on ebay.com. 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #define RST_PIN 9 // Configurable, see typical pin layout above 26 | #define SS_PIN 10 // Configurable, see typical pin layout above 27 | 28 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance 29 | 30 | void setup() { 31 | Serial.begin(9600); // Initialize serial communications with the PC 32 | SPI.begin(); // Init SPI bus 33 | mfrc522.PCD_Init(); // Init MFRC522 card 34 | Serial.println(F("Write personal data on a MIFARE PICC ")); 35 | } 36 | 37 | void loop() { 38 | 39 | // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory. 40 | MFRC522::MIFARE_Key key; 41 | for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; 42 | 43 | // Look for new cards 44 | if ( ! mfrc522.PICC_IsNewCardPresent()) { 45 | return; 46 | } 47 | 48 | // Select one of the cards 49 | if ( ! mfrc522.PICC_ReadCardSerial()) return; 50 | 51 | Serial.print(F("Card UID:")); //Dump UID 52 | for (byte i = 0; i < mfrc522.uid.size; i++) { 53 | Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); 54 | Serial.print(mfrc522.uid.uidByte[i], HEX); 55 | } 56 | Serial.print(F(" PICC type: ")); // Dump PICC type 57 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 58 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 59 | 60 | byte buffer[34]; 61 | byte block; 62 | MFRC522::StatusCode status; 63 | byte len; 64 | 65 | Serial.setTimeout(20000L) ; // wait until 20 seconds for input from serial 66 | // Ask personal data: Family name 67 | Serial.println(F("Type Family name, ending with #")); 68 | len=Serial.readBytesUntil('#', (char *) buffer, 30) ; // read family name from serial 69 | for (byte i = len; i < 30; i++) buffer[i] = ' '; // pad with spaces 70 | 71 | block = 1; 72 | //Serial.println(F("Authenticating using key A...")); 73 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 74 | if (status != MFRC522::STATUS_OK) { 75 | Serial.print(F("PCD_Authenticate() failed: ")); 76 | Serial.println(mfrc522.GetStatusCodeName(status)); 77 | return; 78 | } 79 | else Serial.println(F("PCD_Authenticate() success: ")); 80 | 81 | // Write block 82 | status = mfrc522.MIFARE_Write(block, buffer, 16); 83 | if (status != MFRC522::STATUS_OK) { 84 | Serial.print(F("MIFARE_Write() failed: ")); 85 | Serial.println(mfrc522.GetStatusCodeName(status)); 86 | return; 87 | } 88 | else Serial.println(F("MIFARE_Write() success: ")); 89 | 90 | block = 2; 91 | //Serial.println(F("Authenticating using key A...")); 92 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 93 | if (status != MFRC522::STATUS_OK) { 94 | Serial.print(F("PCD_Authenticate() failed: ")); 95 | Serial.println(mfrc522.GetStatusCodeName(status)); 96 | return; 97 | } 98 | 99 | // Write block 100 | status = mfrc522.MIFARE_Write(block, &buffer[16], 16); 101 | if (status != MFRC522::STATUS_OK) { 102 | Serial.print(F("MIFARE_Write() failed: ")); 103 | Serial.println(mfrc522.GetStatusCodeName(status)); 104 | return; 105 | } 106 | else Serial.println(F("MIFARE_Write() success: ")); 107 | 108 | // Ask personal data: First name 109 | Serial.println(F("Type First name, ending with #")); 110 | len=Serial.readBytesUntil('#', (char *) buffer, 20) ; // read first name from serial 111 | for (byte i = len; i < 20; i++) buffer[i] = ' '; // pad with spaces 112 | 113 | block = 4; 114 | //Serial.println(F("Authenticating using key A...")); 115 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 116 | if (status != MFRC522::STATUS_OK) { 117 | Serial.print(F("PCD_Authenticate() failed: ")); 118 | Serial.println(mfrc522.GetStatusCodeName(status)); 119 | return; 120 | } 121 | 122 | // Write block 123 | status = mfrc522.MIFARE_Write(block, buffer, 16); 124 | if (status != MFRC522::STATUS_OK) { 125 | Serial.print(F("MIFARE_Write() failed: ")); 126 | Serial.println(mfrc522.GetStatusCodeName(status)); 127 | return; 128 | } 129 | else Serial.println(F("MIFARE_Write() success: ")); 130 | 131 | block = 5; 132 | //Serial.println(F("Authenticating using key A...")); 133 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 134 | if (status != MFRC522::STATUS_OK) { 135 | Serial.print(F("PCD_Authenticate() failed: ")); 136 | Serial.println(mfrc522.GetStatusCodeName(status)); 137 | return; 138 | } 139 | 140 | // Write block 141 | status = mfrc522.MIFARE_Write(block, &buffer[16], 16); 142 | if (status != MFRC522::STATUS_OK) { 143 | Serial.print(F("MIFARE_Write() failed: ")); 144 | Serial.println(mfrc522.GetStatusCodeName(status)); 145 | return; 146 | } 147 | else Serial.println(F("MIFARE_Write() success: ")); 148 | 149 | 150 | Serial.println(" "); 151 | mfrc522.PICC_HaltA(); // Halt PICC 152 | mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD 153 | 154 | } 155 | -------------------------------------------------------------------------------- /examples/ReadAndWrite/ReadAndWrite.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * This sample shows how to read and write data blocks on a MIFARE Classic PICC 11 | * (= card/tag). 12 | * 13 | * BEWARE: Data will be written to the PICC, in sector #1 (blocks #4 to #7). 14 | * 15 | * 16 | * Typical pin layout used: 17 | * ----------------------------------------------------------------------------------------- 18 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 19 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 20 | * Signal Pin Pin Pin Pin Pin Pin 21 | * ----------------------------------------------------------------------------------------- 22 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 23 | * SPI SS SDA(SS) 10 53 D10 10 10 24 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 25 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 26 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 27 | * 28 | */ 29 | 30 | #include 31 | #include 32 | 33 | #define RST_PIN 9 // Configurable, see typical pin layout above 34 | #define SS_PIN 10 // Configurable, see typical pin layout above 35 | 36 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 37 | 38 | MFRC522::MIFARE_Key key; 39 | 40 | /** 41 | * Initialize. 42 | */ 43 | void setup() { 44 | Serial.begin(9600); // Initialize serial communications with the PC 45 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 46 | SPI.begin(); // Init SPI bus 47 | mfrc522.PCD_Init(); // Init MFRC522 card 48 | 49 | // Prepare the key (used both as key A and as key B) 50 | // using FFFFFFFFFFFFh which is the default at chip delivery from the factory 51 | for (byte i = 0; i < 6; i++) { 52 | key.keyByte[i] = 0xFF; 53 | } 54 | 55 | Serial.println(F("Scan a MIFARE Classic PICC to demonstrate read and write.")); 56 | Serial.print(F("Using key (for A and B):")); 57 | dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE); 58 | Serial.println(); 59 | 60 | Serial.println(F("BEWARE: Data will be written to the PICC, in sector #1")); 61 | } 62 | 63 | /** 64 | * Main loop. 65 | */ 66 | void loop() { 67 | // Look for new cards 68 | if ( ! mfrc522.PICC_IsNewCardPresent()) 69 | return; 70 | 71 | // Select one of the cards 72 | if ( ! mfrc522.PICC_ReadCardSerial()) 73 | return; 74 | 75 | // Show some details of the PICC (that is: the tag/card) 76 | Serial.print(F("Card UID:")); 77 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 78 | Serial.println(); 79 | Serial.print(F("PICC type: ")); 80 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 81 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 82 | 83 | // Check for compatibility 84 | if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI 85 | && piccType != MFRC522::PICC_TYPE_MIFARE_1K 86 | && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { 87 | Serial.println(F("This sample only works with MIFARE Classic cards.")); 88 | return; 89 | } 90 | 91 | // In this sample we use the second sector, 92 | // that is: sector #1, covering block #4 up to and including block #7 93 | byte sector = 1; 94 | byte blockAddr = 4; 95 | byte dataBlock[] = { 96 | 0x01, 0x02, 0x03, 0x04, // 1, 2, 3, 4, 97 | 0x05, 0x06, 0x07, 0x08, // 5, 6, 7, 8, 98 | 0x08, 0x09, 0xff, 0x0b, // 9, 10, 255, 12, 99 | 0x0c, 0x0d, 0x0e, 0x0f // 13, 14, 15, 16 100 | }; 101 | byte trailerBlock = 7; 102 | MFRC522::StatusCode status; 103 | byte buffer[18]; 104 | byte size = sizeof(buffer); 105 | 106 | // Authenticate using key A 107 | Serial.println(F("Authenticating using key A...")); 108 | status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid)); 109 | if (status != MFRC522::STATUS_OK) { 110 | Serial.print(F("PCD_Authenticate() failed: ")); 111 | Serial.println(mfrc522.GetStatusCodeName(status)); 112 | return; 113 | } 114 | 115 | // Show the whole sector as it currently is 116 | Serial.println(F("Current data in sector:")); 117 | mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); 118 | Serial.println(); 119 | 120 | // Read data from the block 121 | Serial.print(F("Reading data from block ")); Serial.print(blockAddr); 122 | Serial.println(F(" ...")); 123 | status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size); 124 | if (status != MFRC522::STATUS_OK) { 125 | Serial.print(F("MIFARE_Read() failed: ")); 126 | Serial.println(mfrc522.GetStatusCodeName(status)); 127 | } 128 | Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":")); 129 | dump_byte_array(buffer, 16); Serial.println(); 130 | Serial.println(); 131 | 132 | // Authenticate using key B 133 | Serial.println(F("Authenticating again using key B...")); 134 | status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid)); 135 | if (status != MFRC522::STATUS_OK) { 136 | Serial.print(F("PCD_Authenticate() failed: ")); 137 | Serial.println(mfrc522.GetStatusCodeName(status)); 138 | return; 139 | } 140 | 141 | // Write data to the block 142 | Serial.print(F("Writing data into block ")); Serial.print(blockAddr); 143 | Serial.println(F(" ...")); 144 | dump_byte_array(dataBlock, 16); Serial.println(); 145 | status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, dataBlock, 16); 146 | if (status != MFRC522::STATUS_OK) { 147 | Serial.print(F("MIFARE_Write() failed: ")); 148 | Serial.println(mfrc522.GetStatusCodeName(status)); 149 | } 150 | Serial.println(); 151 | 152 | // Read data from the block (again, should now be what we have written) 153 | Serial.print(F("Reading data from block ")); Serial.print(blockAddr); 154 | Serial.println(F(" ...")); 155 | status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size); 156 | if (status != MFRC522::STATUS_OK) { 157 | Serial.print(F("MIFARE_Read() failed: ")); 158 | Serial.println(mfrc522.GetStatusCodeName(status)); 159 | } 160 | Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":")); 161 | dump_byte_array(buffer, 16); Serial.println(); 162 | 163 | // Check that data in block is what we have written 164 | // by counting the number of bytes that are equal 165 | Serial.println(F("Checking result...")); 166 | byte count = 0; 167 | for (byte i = 0; i < 16; i++) { 168 | // Compare buffer (= what we've read) with dataBlock (= what we've written) 169 | if (buffer[i] == dataBlock[i]) 170 | count++; 171 | } 172 | Serial.print(F("Number of bytes that match = ")); Serial.println(count); 173 | if (count == 16) { 174 | Serial.println(F("Success :-)")); 175 | } else { 176 | Serial.println(F("Failure, no match :-(")); 177 | Serial.println(F(" perhaps the write didn't work properly...")); 178 | } 179 | Serial.println(); 180 | 181 | // Dump the sector data 182 | Serial.println(F("Current data in sector:")); 183 | mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); 184 | Serial.println(); 185 | 186 | // Halt PICC 187 | mfrc522.PICC_HaltA(); 188 | // Stop encryption on PCD 189 | mfrc522.PCD_StopCrypto1(); 190 | } 191 | 192 | /** 193 | * Helper routine to dump a byte array as hex values to Serial. 194 | */ 195 | void dump_byte_array(byte *buffer, byte bufferSize) { 196 | for (byte i = 0; i < bufferSize; i++) { 197 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 198 | Serial.print(buffer[i], HEX); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | MFRC522 2 | ======= 3 | 4 | .. image:: https://travis-ci.org/miguelbalboa/rfid.svg?branch=master 5 | :target: https://travis-ci.org/miguelbalboa/rfid 6 | 7 | Arduino library for MFRC522 and other RFID RC522 based modules. 8 | 9 | Read and write different types of Radio-Frequency IDentification (RFID) cards 10 | on your Arduino using a RC522 based reader connected via the Serial Peripheral 11 | Interface (SPI) interface. 12 | 13 | Set the UID, write to sector 0, and unbrick Chinese UID changeable MIFARE cards. 14 | 15 | 16 | .. _compatible boards: 17 | Compatible boards 18 | ---------- 19 | 20 | This library is compatible to Teensy and ESP8266, but not all examples are available for every board. Also you have to change pins, see `pin layout`_. 21 | 22 | 23 | .. _pin layout: 24 | Pin Layout 25 | ---------- 26 | 27 | The following table shows the typical pin layout used: 28 | 29 | +-----------+----------+---------------------------------------------------------------+--------------------------+ 30 | | | PCD | Arduino | Teensy | 31 | | +----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 32 | | | MFRC522 | Uno | Mega | Nano v3 |Leonardo / Micro | Pro Micro | 2.0 | ++ 2.0 | 3.1 | 33 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 34 | | Signal | Pin | Pin | Pin | Pin | Pin | Pin | Pin | Pin | Pin | 35 | +===========+==========+=============+=========+=========+=================+===========+========+========+========+ 36 | | RST/Reset | RST | 9 [1]_ | 5 [1]_ | D9 | RESET / ICSP-5 | RST | 7 | 4 | 9 | 37 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 38 | | SPI SS | SDA [3]_ | 10 [2]_ | 53 [2]_ | D10 | 10 | 10 | 0 | 20 | 10 | 39 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 40 | | SPI MOSI | MOSI | 11 / ICSP-4 | 51 | D11 | ICSP-4 | 16 | 2 | 22 | 11 | 41 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 42 | | SPI MISO | MISO | 12 / ICSP-1 | 50 | D12 | ICSP-1 | 14 | 3 | 23 | 12 | 43 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 44 | | SPI SCK | SCK | 13 / ICSP-3 | 52 | D13 | ICSP-3 | 15 | 1 | 21 | 13 | 45 | +-----------+----------+-------------+---------+---------+-----------------+-----------+--------+--------+--------+ 46 | 47 | .. [1] Configurable, typically defined as RST_PIN in sketch/program. 48 | .. [2] Configurable, typically defined as SS_PIN in sketch/program. 49 | .. [3] The SDA pin might be labeled SS on some/older MFRC522 boards. 50 | 51 | 52 | .. _hardware: 53 | Hardware 54 | -------- 55 | 56 | There are three hardware components involved: 57 | 58 | 1. **Micro Controller**: 59 | 60 | * An `Arduino`_ or compatible executing the Sketch using this library. 61 | 62 | * Prices vary from USD 7 for clones, to USD 75 for "starter kits" (which 63 | might be a good choice if this is your first exposure to Arduino; 64 | check if such kit already includes the Arduino, Reader, and some Tags). 65 | 66 | 2. **Proximity Coupling Device (PCD)**: 67 | 68 | * The PCD is the actual RFID **Reader** based on `NXP MFRC522`_ Contactless 69 | Reader Integrated Circuit). 70 | 71 | * Readers can be found on `eBay`_ for around USD 5: search for *"rc522"*. 72 | 73 | * You can also find them at several web stores, they are often included in 74 | *"starter kits"*; so check your favourite electronics provider as well. 75 | 76 | 3. **Proximity Integrated Circuit Card (PICC)**: 77 | 78 | * The PICC is the RFID **Card** or **Tag** using the `ISO/IEC 14443A`_ 79 | interface, for example Mifare or NTAG203. 80 | 81 | * One or two might be included with the Reader or *"starter kit"* already. 82 | 83 | 84 | .. _protocol: 85 | Protocols 86 | --------- 87 | 88 | 1. The micro controller and the reader use SPI for communication. 89 | 90 | * The protocol is described in the `NXP MFRC522`_ datasheet. 91 | 92 | * See the `Pin Layout`_ section for details on connecting the pins. 93 | 94 | 2. The reader and the tags communicate using a 13.56 MHz electromagnetic field. 95 | 96 | * The protocol is defined in ISO/IEC 14443-3:2011 Part 3 Type A. 97 | 98 | * Details are found in chapter 6 *"Type A – Initialization and anticollision"*. 99 | 100 | * See http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf for a free version 101 | of the final draft (which might be outdated in some areas). 102 | 103 | * The reader does not support ISO/IEC 14443-3 Type B. 104 | 105 | 106 | .. _security: 107 | Security 108 | ------- 109 | This library only supports crypto1-encrypted communication. Crypto1 has been known as `broken`_ for a few years, so it does NOT offer ANY security, it is virtually unencrypted communication. **Do not use it for any security related applications!** 110 | This library does not offer 3DES or AES authentication used by cars like the Mifare DESFire, it may be possible to be implemented because the datasheet says there is support. We hope for pull requests :). 111 | 112 | 113 | .. _troubleshooting: 114 | Troubleshooting 115 | ------- 116 | 117 | * **I don't get input from reader** or **WARNING: Communication failure, is the MFRC522 properly connected?** 118 | 119 | #. Check your connection, see `Pin Layout`_ . 120 | #. Check voltage. Most breakouts work with 3.3V. 121 | #. SPI only works with 3.3V, most breakouts seem 5V tollerant, but try a level shifter. 122 | #. According to reports #101, #126 and #131, there may be a problem with the soldering on the MFRC522 breakout. You could fix this on your own. 123 | 124 | 125 | * **Sometimes I get timeouts** or **sometimes tag/card does not work.** 126 | 127 | #. Try other side of the antenna. 128 | #. Try to decrease distance between MFRC522. 129 | #. Increase antenna gain per firmware: ``mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);`` 130 | #. Use better power supply. 131 | #. Hardware may be corrupted, most products are from china and sometimes the quality is really poor. Contact your seller. 132 | 133 | 134 | * **My tag/card doesn't work.** 135 | 136 | #. Distance between antenna and token too large (>1cm). 137 | #. You got the wrong type PICC. Is it really 13.56 MHz? Is it really a Mifare Type A? 138 | #. NFC tokens are not supported. Some may work. 139 | #. Animal RFID tags are not supported. They use a different frequency (125 kHz). 140 | #. Hardware may be corrupted, most products are from china and sometimes the quality is really poor. Contact your seller. 141 | #. Newer versions of Mifare cards like DESFire/Ultralight maybe not work according to missing authentification, see `security`_ or different `protocol`_. 142 | 143 | 144 | * **My mobile phone doesn't recognize the MFRC522** or **my MFRC522 can't read data from other MFRC522** 145 | 146 | #. Card simmulation is not supported. 147 | #. Communication with mobile phones is not supported. 148 | #. Peer to peer communication is not supported. 149 | 150 | 151 | * **I need more features.** 152 | 153 | #. If software: code it and make a pull request. 154 | #. If hardware: buy a more expensive like PN532 (supports NFC and many more, but costs about $15) 155 | 156 | 157 | .. _license: 158 | License 159 | ------- 160 | This is free and unencumbered software released into the public domain. 161 | 162 | Anyone is free to copy, modify, publish, use, compile, sell, or 163 | distribute this software, either in source code form or as a compiled 164 | binary, for any purpose, commercial or non-commercial, and by any 165 | means. 166 | 167 | In jurisdictions that recognize copyright laws, the author or authors 168 | of this software dedicate any and all copyright interest in the 169 | software to the public domain. We make this dedication for the benefit 170 | of the public at large and to the detriment of our heirs and 171 | successors. We intend this dedication to be an overt act of 172 | relinquishment in perpetuity of all present and future rights to this 173 | software under copyright law. 174 | 175 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 176 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 177 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 178 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 179 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 180 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 181 | OTHER DEALINGS IN THE SOFTWARE. 182 | 183 | For more information, please refer to http://unlicense.org/ 184 | 185 | 186 | History 187 | ------- 188 | 189 | The MFRC522 library was first created in Jan 2012 by Miguel Balboa (from 190 | http://circuitito.com) based on code by Dr. Leong (from http://B2CQSHOP.com) 191 | for *"Arduino RFID module Kit 13.56 Mhz with Tags SPI W and R By COOQRobot"*. 192 | 193 | It was translated into English and rewritten/refactored in the fall of 2013 194 | by Søren Thing Andersen (from http://access.thing.dk). 195 | 196 | It has been extended with functionality to alter sector 0 on Chinese UID changeable MIFARE card in Oct 2014 by Tom Clement (from http://tomclement.nl). 197 | 198 | 199 | .. _arduino: https://arduino.cc/ 200 | .. _ebay: http://www.ebay.com/ 201 | .. _iso/iec 14443a: https://en.wikipedia.org/wiki/ISO/IEC_14443 202 | .. _iso/iec 14443-3\:2011 part 3: 203 | .. _nxp mfrc522: http://www.nxp.com/documents/data_sheet/MFRC522.pdf 204 | .. _broken: http://eprint.iacr.org/2008/166 205 | -------------------------------------------------------------------------------- /examples/RFID-Cloner/RFID-Cloner.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Copy the RFID card data into variables and then 3 | * scan the second empty card to copy all the date 4 | * ---------------------------------------------------------------------------- 5 | * Example sketch/program which will try the most used default keys listed in 6 | * https://code.google.com/p/mfcuk/wiki/MifareClassicDefaultKeys to dump the 7 | * block 0 of a MIFARE RFID card using a RFID-RC522 reader. 8 | * 9 | * Typical pin layout used: 10 | * ----------------------------------------------------------------------------------------- 11 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 12 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 13 | * Signal Pin Pin Pin Pin Pin Pin 14 | * ----------------------------------------------------------------------------------------- 15 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 16 | * SPI SS SDA(SS) 10 53 D10 10 10 17 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 18 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 19 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #define RST_PIN 9 // Configurable, see typical pin layout above 27 | #define SS_PIN 10 // Configurable, see typical pin layout above 28 | 29 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 30 | 31 | byte buffer[18]; 32 | byte block; 33 | byte waarde[64][16]; 34 | MFRC522::StatusCode status; 35 | 36 | MFRC522::MIFARE_Key key; 37 | 38 | // Number of known default keys (hard-coded) 39 | // NOTE: Synchronize the NR_KNOWN_KEYS define with the defaultKeys[] array 40 | #define NR_KNOWN_KEYS 8 41 | // Known keys, see: https://code.google.com/p/mfcuk/wiki/MifareClassicDefaultKeys 42 | byte knownKeys[NR_KNOWN_KEYS][MFRC522::MF_KEY_SIZE] = { 43 | {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // FF FF FF FF FF FF = factory default 44 | {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, // A0 A1 A2 A3 A4 A5 45 | {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5}, // B0 B1 B2 B3 B4 B5 46 | {0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd}, // 4D 3A 99 C3 51 DD 47 | {0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a}, // 1A 98 2C 7E 45 9A 48 | {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}, // D3 F7 D3 F7 D3 F7 49 | {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, // AA BB CC DD EE FF 50 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // 00 00 00 00 00 00 51 | }; 52 | 53 | char choice; 54 | /* 55 | * Initialize. 56 | */ 57 | void setup() { 58 | Serial.begin(9600); // Initialize serial communications with the PC 59 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 60 | SPI.begin(); // Init SPI bus 61 | mfrc522.PCD_Init(); // Init MFRC522 card 62 | Serial.println(F("Try the most used default keys to print block 0 to 63 of a MIFARE PICC.")); 63 | Serial.println("1.Read card \n2.Write to card \n3.Copy the data."); 64 | 65 | for (byte i = 0; i < 6; i++) { 66 | key.keyByte[i] = 0xFF; 67 | } 68 | } 69 | 70 | 71 | 72 | //Via seriele monitor de bytes uitlezen in hexadecimaal 73 | 74 | void dump_byte_array(byte *buffer, byte bufferSize) { 75 | for (byte i = 0; i < bufferSize; i++) { 76 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 77 | Serial.print(buffer[i], HEX); 78 | } 79 | } 80 | //Via seriele monitor de bytes uitlezen in ASCI 81 | 82 | void dump_byte_array1(byte *buffer, byte bufferSize) { 83 | for (byte i = 0; i < bufferSize; i++) { 84 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 85 | Serial.write(buffer[i]); 86 | } 87 | } 88 | 89 | /* 90 | * Try using the PICC (the tag/card) with the given key to access block 0 to 63. 91 | * On success, it will show the key details, and dump the block data on Serial. 92 | * 93 | * @return true when the given key worked, false otherwise. 94 | */ 95 | 96 | boolean try_key(MFRC522::MIFARE_Key *key) 97 | { 98 | boolean result = false; 99 | 100 | for(byte block = 0; block < 64; block++){ 101 | 102 | // Serial.println(F("Authenticating using key A...")); 103 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, key, &(mfrc522.uid)); 104 | if (status != MFRC522::STATUS_OK) { 105 | Serial.print(F("PCD_Authenticate() failed: ")); 106 | Serial.println(mfrc522.GetStatusCodeName(status)); 107 | return false; 108 | } 109 | 110 | // Read block 111 | byte byteCount = sizeof(buffer); 112 | status = mfrc522.MIFARE_Read(block, buffer, &byteCount); 113 | if (status != MFRC522::STATUS_OK) { 114 | Serial.print(F("MIFARE_Read() failed: ")); 115 | Serial.println(mfrc522.GetStatusCodeName(status)); 116 | } 117 | else { 118 | // Successful read 119 | result = true; 120 | Serial.print(F("Success with key:")); 121 | dump_byte_array((*key).keyByte, MFRC522::MF_KEY_SIZE); 122 | Serial.println(); 123 | 124 | // Dump block data 125 | Serial.print(F("Block ")); Serial.print(block); Serial.print(F(":")); 126 | dump_byte_array1(buffer, 16); //omzetten van hex naar ASCI 127 | Serial.println(); 128 | 129 | for (int p = 0; p < 16; p++) //De 16 bits uit de block uitlezen 130 | { 131 | waarde [block][p] = buffer[p]; 132 | Serial.print(waarde[block][p]); 133 | Serial.print(" "); 134 | } 135 | 136 | } 137 | } 138 | Serial.println(); 139 | 140 | Serial.println("1.Read card \n2.Write to card \n3.Copy the data."); 141 | 142 | mfrc522.PICC_HaltA(); // Halt PICC 143 | mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD 144 | return result; 145 | 146 | start(); 147 | } 148 | 149 | /* 150 | * Main loop. 151 | */ 152 | void loop() { 153 | start(); 154 | 155 | } 156 | 157 | void start(){ 158 | choice = Serial.read(); 159 | 160 | if(choice == '1') 161 | { 162 | Serial.println("Read the card"); 163 | keuze1(); 164 | 165 | } 166 | else if(choice == '2') 167 | { 168 | Serial.println("See what is in the variables"); 169 | keuze2(); 170 | } 171 | else if(choice == '3') 172 | { 173 | Serial.println("Copying the data on to the new card"); 174 | keuze3(); 175 | } 176 | } 177 | 178 | void keuze2(){ //Test waardes in blokken 179 | 180 | for(block = 4; block <= 62; block++){ 181 | if(block == 7 || block == 11 || block == 15 || block == 19 || block == 23 || block == 27 || block == 31 || block == 35 || block == 39 || block == 43 || block == 47 || block == 51 || block == 55 || block == 59){ 182 | block ++; 183 | } 184 | 185 | Serial.print(F("Writing data into block ")); 186 | Serial.print(block); 187 | Serial.println("\n"); 188 | 189 | for(int j = 0; j < 16; j++){ 190 | Serial.print(waarde[block][j]); 191 | Serial.print(" "); 192 | } 193 | Serial.println("\n"); 194 | 195 | } 196 | 197 | Serial.println("1.Read card \n2.Write to card \n3.Copy the data."); 198 | start(); 199 | } 200 | 201 | void keuze3(){ //Copy the data in the new card 202 | Serial.println("Insert new card..."); 203 | // Look for new cards 204 | if ( ! mfrc522.PICC_IsNewCardPresent()) 205 | return; 206 | 207 | // Select one of the cards 208 | if ( ! mfrc522.PICC_ReadCardSerial()) 209 | return; 210 | 211 | // Show some details of the PICC (that is: the tag/card) 212 | Serial.print(F("Card UID:")); 213 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 214 | Serial.println(); 215 | Serial.print(F("PICC type: ")); 216 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 217 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 218 | 219 | // Try the known default keys 220 | /*MFRC522::MIFARE_Key key; 221 | for (byte k = 0; k < NR_KNOWN_KEYS; k++) { 222 | // Copy the known key into the MIFARE_Key structure 223 | for (byte i = 0; i < MFRC522::MF_KEY_SIZE; i++) { 224 | key.keyByte[i] = knownKeys[k][i]; 225 | } 226 | }*/ 227 | for (byte i = 0; i < 6; i++) { 228 | key.keyByte[i] = 0xFF; 229 | } 230 | 231 | for(int i = 4; i <= 62; i++){ //De blocken 4 tot 62 kopieren, behalve al deze onderstaande blocken (omdat deze de authenticatie blokken zijn) 232 | if(i == 7 || i == 11 || i == 15 || i == 19 || i == 23 || i == 27 || i == 31 || i == 35 || i == 39 || i == 43 || i == 47 || i == 51 || i == 55 || i == 59){ 233 | i++; 234 | } 235 | block = i; 236 | 237 | // Authenticate using key A 238 | Serial.println(F("Authenticating using key A...")); 239 | status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); 240 | if (status != MFRC522::STATUS_OK) { 241 | Serial.print(F("PCD_Authenticate() failed: ")); 242 | Serial.println(mfrc522.GetStatusCodeName(status)); 243 | return; 244 | } 245 | 246 | // Authenticate using key B 247 | Serial.println(F("Authenticating again using key B...")); 248 | status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, block, &key, &(mfrc522.uid)); 249 | if (status != MFRC522::STATUS_OK) { 250 | Serial.print(F("PCD_Authenticate() failed: ")); 251 | Serial.println(mfrc522.GetStatusCodeName(status)); 252 | return; 253 | } 254 | 255 | // Write data to the block 256 | Serial.print(F("Writing data into block ")); 257 | Serial.print(block); 258 | Serial.println("\n"); 259 | 260 | dump_byte_array(waarde[block], 16); 261 | 262 | 263 | status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(block, waarde[block], 16); 264 | if (status != MFRC522::STATUS_OK) { 265 | Serial.print(F("MIFARE_Write() failed: ")); 266 | Serial.println(mfrc522.GetStatusCodeName(status)); 267 | } 268 | 269 | 270 | Serial.println("\n"); 271 | 272 | } 273 | mfrc522.PICC_HaltA(); // Halt PICC 274 | mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD 275 | 276 | Serial.println("1.Read card \n2.Write to card \n3.Copy the data."); 277 | start(); 278 | } 279 | 280 | void keuze1(){ //Read card 281 | Serial.println("Insert card..."); 282 | // Look for new cards 283 | if ( ! mfrc522.PICC_IsNewCardPresent()) 284 | return; 285 | 286 | // Select one of the cards 287 | if ( ! mfrc522.PICC_ReadCardSerial()) 288 | return; 289 | 290 | // Show some details of the PICC (that is: the tag/card) 291 | Serial.print(F("Card UID:")); 292 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 293 | Serial.println(); 294 | Serial.print(F("PICC type: ")); 295 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 296 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 297 | 298 | // Try the known default keys 299 | MFRC522::MIFARE_Key key; 300 | for (byte k = 0; k < NR_KNOWN_KEYS; k++) { 301 | // Copy the known key into the MIFARE_Key structure 302 | for (byte i = 0; i < MFRC522::MF_KEY_SIZE; i++) { 303 | key.keyByte[i] = knownKeys[k][i]; 304 | } 305 | // Try the key 306 | if (try_key(&key)) { 307 | // Found and reported on the key and block, 308 | // no need to try other keys for this PICC 309 | break; 310 | } 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /examples/MifareClassicValueBlock/MifareClassicValueBlock.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ---------------------------------------------------------------------------- 3 | * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid 4 | * for further details and other examples. 5 | * 6 | * NOTE: The library file MFRC522.h has a lot of useful info. Please read it. 7 | * 8 | * Released into the public domain. 9 | * ---------------------------------------------------------------------------- 10 | * This sample shows how to setup blocks on a MIFARE Classic PICC (= card/tag) 11 | * to be in "Value Block" mode: in this mode the operations Increment/Decrement, 12 | * Restore and Transfer can be used. 13 | * 14 | * BEWARE: Data will be written to the PICC, in sector #1 (blocks #4 to #7). 15 | * 16 | * 17 | * Typical pin layout used: 18 | * ----------------------------------------------------------------------------------------- 19 | * MFRC522 Arduino Arduino Arduino Arduino Arduino 20 | * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro 21 | * Signal Pin Pin Pin Pin Pin Pin 22 | * ----------------------------------------------------------------------------------------- 23 | * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST 24 | * SPI SS SDA(SS) 10 53 D10 10 10 25 | * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 26 | * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 27 | * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 28 | * 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #define RST_PIN 9 // Configurable, see typical pin layout above 35 | #define SS_PIN 10 // Configurable, see typical pin layout above 36 | 37 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 38 | 39 | MFRC522::MIFARE_Key key; 40 | 41 | /** 42 | * Initialize. 43 | */ 44 | void setup() { 45 | Serial.begin(9600); // Initialize serial communications with the PC 46 | while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) 47 | SPI.begin(); // Init SPI bus 48 | mfrc522.PCD_Init(); // Init MFRC522 card 49 | 50 | // Prepare the key (used both as key A and as key B) 51 | // using FFFFFFFFFFFFh which is the default at chip delivery from the factory 52 | for (byte i = 0; i < 6; i++) { 53 | key.keyByte[i] = 0xFF; 54 | } 55 | 56 | Serial.println(F("Scan a MIFARE Classic PICC to demonstrate Value Block mode.")); 57 | Serial.print(F("Using key (for A and B):")); 58 | dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE); 59 | Serial.println(); 60 | 61 | Serial.println(F("BEWARE: Data will be written to the PICC, in sector #1")); 62 | } 63 | 64 | /** 65 | * Main loop. 66 | */ 67 | void loop() { 68 | // Look for new cards 69 | if ( ! mfrc522.PICC_IsNewCardPresent()) 70 | return; 71 | 72 | // Select one of the cards 73 | if ( ! mfrc522.PICC_ReadCardSerial()) 74 | return; 75 | 76 | // Show some details of the PICC (that is: the tag/card) 77 | Serial.print(F("Card UID:")); 78 | dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); 79 | Serial.println(); 80 | Serial.print(F("PICC type: ")); 81 | MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); 82 | Serial.println(mfrc522.PICC_GetTypeName(piccType)); 83 | 84 | // Check for compatibility 85 | if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI 86 | && piccType != MFRC522::PICC_TYPE_MIFARE_1K 87 | && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { 88 | Serial.println(F("This sample only works with MIFARE Classic cards.")); 89 | return; 90 | } 91 | 92 | // In this sample we use the second sector, 93 | // that is: sector #1, covering block #4 up to and including block #7 94 | byte sector = 1; 95 | byte valueBlockA = 5; 96 | byte valueBlockB = 6; 97 | byte trailerBlock = 7; 98 | MFRC522::StatusCode status; 99 | byte buffer[18]; 100 | byte size = sizeof(buffer); 101 | long value; 102 | 103 | // Authenticate using key A 104 | Serial.println(F("Authenticating using key A...")); 105 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid)); 106 | if (status != MFRC522::STATUS_OK) { 107 | Serial.print(F("PCD_Authenticate() failed: ")); 108 | Serial.println(mfrc522.GetStatusCodeName(status)); 109 | return; 110 | } 111 | 112 | // Show the whole sector as it currently is 113 | Serial.println(F("Current data in sector:")); 114 | mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); 115 | Serial.println(); 116 | 117 | // We need a sector trailer that defines blocks 5 and 6 as Value Blocks and enables key B 118 | // The last block in a sector (block #3 for Mifare Classic 1K) is the Sector Trailer. 119 | // See http://www.nxp.com/documents/data_sheet/MF1S503x.pdf sections 8.6 and 8.7: 120 | // Bytes 0-5: Key A 121 | // Bytes 6-8: Access Bits 122 | // Bytes 9: User data 123 | // Bytes 10-15: Key B (or user data) 124 | byte trailerBuffer[] = { 125 | 255, 255, 255, 255, 255, 255, // Keep default key A 126 | 0, 0, 0, 127 | 0, 128 | 255, 255, 255, 255, 255, 255}; // Keep default key B 129 | // The access bits are stored in a peculiar fashion. 130 | // There are four groups: 131 | // g[0] Access bits for block 0 (for sectors 0-31) 132 | // or blocks 0-4 (for sectors 32-39) 133 | // g[1] Access bits for block 1 (for sectors 0-31) 134 | // or blocks 5-9 (for sectors 32-39) 135 | // g[2] Access bits for block 2 (for sectors 0-31) 136 | // or blocks 10-14 (for sectors 32-39) 137 | // g[3] Access bits for the Sector Trailer: block 3 (for sectors 0-31) 138 | // or block 15 (for sectors 32-39) 139 | // Each group has access bits [C1 C2 C3], in this code C1 is MSB and C3 is LSB. 140 | // Determine the bit pattern needed using MIFARE_SetAccessBits: 141 | // g0=0 access bits for block 0 (of this sector) using [0 0 0] = 000b = 0 142 | // which means key A|B have r/w for block 0 of this sector 143 | // which (in this example) translates to block #4 within sector #1; 144 | // this is the transport configuration (at factory delivery). 145 | // g1=6 access bits for block 1 (of this sector) using [1 1 0] = 110b = 6 146 | // which means block 1 (of this sector) is used as a value block, 147 | // which (in this example) translates to block #5 within sector #1; 148 | // where key A|B have r, key B has w, key B can increment, 149 | // and key A|B can decrement, transfer, and restore. 150 | // g2=6 same thing for block 2 (of this sector): set it to a value block; 151 | // which (in this example) translates to block #6 within sector #1; 152 | // g3=3 access bits for block 3 (of this sector): the Sector Trailer here; 153 | // using [0 1 1] = 011b = 3 which means only key B has r/w access 154 | // to the Sector Trailer (block 3 of this sector) from now on 155 | // which (in this example) translates to block #7 within sector #1; 156 | mfrc522.MIFARE_SetAccessBits(&trailerBuffer[6], 0, 6, 6, 3); 157 | 158 | // Read the sector trailer as it is currently stored on the PICC 159 | Serial.println(F("Reading sector trailer...")); 160 | status = mfrc522.MIFARE_Read(trailerBlock, buffer, &size); 161 | if (status != MFRC522::STATUS_OK) { 162 | Serial.print(F("MIFARE_Read() failed: ")); 163 | Serial.println(mfrc522.GetStatusCodeName(status)); 164 | return; 165 | } 166 | // Check if it matches the desired access pattern already; 167 | // because if it does, we don't need to write it again... 168 | if ( buffer[6] != trailerBuffer[6] 169 | && buffer[7] != trailerBuffer[7] 170 | && buffer[8] != trailerBuffer[8]) { 171 | // They don't match (yet), so write it to the PICC 172 | Serial.println(F("Writing new sector trailer...")); 173 | status = mfrc522.MIFARE_Write(trailerBlock, trailerBuffer, 16); 174 | if (status != MFRC522::STATUS_OK) { 175 | Serial.print(F("MIFARE_Write() failed: ")); 176 | Serial.println(mfrc522.GetStatusCodeName(status)); 177 | return; 178 | } 179 | } 180 | 181 | // Authenticate using key B 182 | Serial.println(F("Authenticating again using key B...")); 183 | status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid)); 184 | if (status != MFRC522::STATUS_OK) { 185 | Serial.print(F("PCD_Authenticate() failed: ")); 186 | Serial.println(mfrc522.GetStatusCodeName(status)); 187 | return; 188 | } 189 | 190 | // A value block has a 32 bit signed value stored three times 191 | // and an 8 bit address stored 4 times. Make sure that valueBlockA 192 | // and valueBlockB have that format (note that it will only format 193 | // the block when it doesn't comply to the expected format already). 194 | formatValueBlock(valueBlockA); 195 | formatValueBlock(valueBlockB); 196 | 197 | // Add 1 to the value of valueBlockA and store the result in valueBlockA. 198 | Serial.print("Adding 1 to value of block "); Serial.println(valueBlockA); 199 | status = mfrc522.MIFARE_Increment(valueBlockA, 1); 200 | if (status != MFRC522::STATUS_OK) { 201 | Serial.print(F("MIFARE_Increment() failed: ")); 202 | Serial.println(mfrc522.GetStatusCodeName(status)); 203 | return; 204 | } 205 | status = mfrc522.MIFARE_Transfer(valueBlockA); 206 | if (status != MFRC522::STATUS_OK) { 207 | Serial.print(F("MIFARE_Transfer() failed: ")); 208 | Serial.println(mfrc522.GetStatusCodeName(status)); 209 | return; 210 | } 211 | // Show the new value of valueBlockA 212 | status = mfrc522.MIFARE_GetValue(valueBlockA, &value); 213 | if (status != MFRC522::STATUS_OK) { 214 | Serial.print(F("mifare_GetValue() failed: ")); 215 | Serial.println(mfrc522.GetStatusCodeName(status)); 216 | return; 217 | } 218 | Serial.print("New value of value block "); Serial.print(valueBlockA); 219 | Serial.print(" = "); Serial.println(value); 220 | 221 | // Decrement 10 from the value of valueBlockB and store the result in valueBlockB. 222 | Serial.print("Subtracting 10 from value of block "); Serial.println(valueBlockB); 223 | status = mfrc522.MIFARE_Decrement(valueBlockB, 10); 224 | if (status != MFRC522::STATUS_OK) { 225 | Serial.print(F("MIFARE_Decrement() failed: ")); 226 | Serial.println(mfrc522.GetStatusCodeName(status)); 227 | return; 228 | } 229 | status = mfrc522.MIFARE_Transfer(valueBlockB); 230 | if (status != MFRC522::STATUS_OK) { 231 | Serial.print(F("MIFARE_Transfer() failed: ")); 232 | Serial.println(mfrc522.GetStatusCodeName(status)); 233 | return; 234 | } 235 | // Show the new value of valueBlockB 236 | status = mfrc522.MIFARE_GetValue(valueBlockB, &value); 237 | if (status != MFRC522::STATUS_OK) { 238 | Serial.print(F("mifare_GetValue() failed: ")); 239 | Serial.println(mfrc522.GetStatusCodeName(status)); 240 | return; 241 | } 242 | Serial.print(F("New value of value block ")); Serial.print(valueBlockB); 243 | Serial.print(F(" = ")); Serial.println(value); 244 | // Check some boundary... 245 | if (value <= -100) { 246 | Serial.println(F("Below -100, so resetting it to 255 = 0xFF just for fun...")); 247 | status = mfrc522.MIFARE_SetValue(valueBlockB, 255); 248 | if (status != MFRC522::STATUS_OK) { 249 | Serial.print(F("mifare_SetValue() failed: ")); 250 | Serial.println(mfrc522.GetStatusCodeName(status)); 251 | return; 252 | } 253 | } 254 | 255 | // Dump the sector data 256 | mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); 257 | Serial.println(); 258 | 259 | // Halt PICC 260 | mfrc522.PICC_HaltA(); 261 | // Stop encryption on PCD 262 | mfrc522.PCD_StopCrypto1(); 263 | } 264 | 265 | /** 266 | * Helper routine to dump a byte array as hex values to Serial. 267 | */ 268 | void dump_byte_array(byte *buffer, byte bufferSize) { 269 | for (byte i = 0; i < bufferSize; i++) { 270 | Serial.print(buffer[i] < 0x10 ? " 0" : " "); 271 | Serial.print(buffer[i], HEX); 272 | } 273 | } 274 | 275 | /** 276 | * Ensure that a given block is formatted as a Value Block. 277 | */ 278 | void formatValueBlock(byte blockAddr) { 279 | byte buffer[18]; 280 | byte size = sizeof(buffer); 281 | MFRC522::StatusCode status; 282 | 283 | Serial.print(F("Reading block ")); Serial.println(blockAddr); 284 | status = mfrc522.MIFARE_Read(blockAddr, buffer, &size); 285 | if (status != MFRC522::STATUS_OK) { 286 | Serial.print(F("MIFARE_Read() failed: ")); 287 | Serial.println(mfrc522.GetStatusCodeName(status)); 288 | return; 289 | } 290 | 291 | if ( (buffer[0] == (byte)~buffer[4]) 292 | && (buffer[1] == (byte)~buffer[5]) 293 | && (buffer[2] == (byte)~buffer[6]) 294 | && (buffer[3] == (byte)~buffer[7]) 295 | 296 | && (buffer[0] == buffer[8]) 297 | && (buffer[1] == buffer[9]) 298 | && (buffer[2] == buffer[10]) 299 | && (buffer[3] == buffer[11]) 300 | 301 | && (buffer[12] == (byte)~buffer[13]) 302 | && (buffer[12] == buffer[14]) 303 | && (buffer[12] == (byte)~buffer[15])) { 304 | Serial.println(F("Block has correct Value Block format.")); 305 | } 306 | else { 307 | Serial.println(F("Formatting as Value Block...")); 308 | byte valueBlock[] = { 309 | 0, 0, 0, 0, 310 | 255, 255, 255, 255, 311 | 0, 0, 0, 0, 312 | blockAddr, ~blockAddr, blockAddr, ~blockAddr }; 313 | status = mfrc522.MIFARE_Write(blockAddr, valueBlock, 16); 314 | if (status != MFRC522::STATUS_OK) { 315 | Serial.print(F("MIFARE_Write() failed: ")); 316 | Serial.println(mfrc522.GetStatusCodeName(status)); 317 | } 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /examples/servo_motor/servo_motor.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino RFID Access Control 3 | 4 | Security ! 5 | 6 | To keep it simple we are going to use Tag's Unique IDs 7 | as only method of Authenticity. It's simple and not hacker proof. 8 | If you need security, don't use it unless you modify the code 9 | 10 | Copyright (C) 2015 Omer Siar Baysal 11 | 12 | This program is free software; you can redistribute it and/or modify 13 | it under the terms of the GNU General Public License as published by 14 | the Free Software Foundation; either version 2 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License along 23 | with this program; if not, write to the Free Software Foundation, Inc., 24 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 25 | 26 | */ 27 | 28 | #include // We are going to read and write PICC's UIDs from/to EEPROM 29 | #include // RC522 Module uses SPI protocol 30 | #include // Library for Mifare RC522 Devices 31 | /* 32 | Instead of a Relay maybe you want to use a servo 33 | Servos can lock and unlock door locks too 34 | There are examples out there. 35 | */ 36 | 37 | #include 38 | Servo daServo; 39 | /* 40 | For visualizing whats going on hardware 41 | we need some leds and 42 | to control door lock a relay and a wipe button 43 | (or some other hardware) 44 | Used common anode led,digitalWriting HIGH turns OFF led 45 | Mind that if you are going to use common cathode led or 46 | just seperate leds, simply comment out #define COMMON_ANODE, 47 | */ 48 | 49 | #define COMMON_ANODE 50 | 51 | #ifdef COMMON_ANODE 52 | #define LED_ON LOW 53 | #define LED_OFF HIGH 54 | #else 55 | #define LED_ON HIGH 56 | #define LED_OFF LOW 57 | #endif 58 | 59 | #define redLed 7 // Set Led Pins 60 | #define greenLed 6 61 | #define blueLed 5 62 | 63 | #define relay 4 // Set Relay Pin 64 | #define wipeB 3 // Button pin for WipeMode 65 | 66 | boolean match = false; // initialize card match to false 67 | boolean programMode = false; // initialize programming mode to false 68 | 69 | int successRead; // Variable integer to keep if we have Successful Read from Reader 70 | 71 | byte storedCard[4]; // Stores an ID read from EEPROM 72 | byte readCard[4]; // Stores scanned ID read from RFID Module 73 | byte masterCard[4]; // Stores master card's ID read from EEPROM 74 | 75 | /* 76 | We need to define MFRC522's pins and create instance 77 | Pin layout should be as follows (on Arduino Uno): 78 | MOSI: Pin 11 / ICSP-4 79 | MISO: Pin 12 / ICSP-1 80 | SCK : Pin 13 / ICSP-3 81 | SS : Pin 10 (Configurable) 82 | RST : Pin 9 (Configurable) 83 | look MFRC522 Library for 84 | other Arduinos' pin configuration 85 | */ 86 | 87 | #define SS_PIN 10 88 | #define RST_PIN 9 89 | MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. 90 | 91 | ///////////////////////////////////////// Setup /////////////////////////////////// 92 | void setup() { 93 | daServo.attach(relay); 94 | //Arduino Pin Configuration 95 | pinMode(redLed, OUTPUT); 96 | pinMode(greenLed, OUTPUT); 97 | pinMode(blueLed, OUTPUT); 98 | pinMode(wipeB, INPUT_PULLUP); // Enable pin's pull up resistor 99 | pinMode(relay, OUTPUT); 100 | //Be careful how relay circuit behave on while resetting or power-cycling your Arduino 101 | servo(50); // Make sure door is locked 102 | digitalWrite(redLed, LED_OFF); // Make sure led is off 103 | digitalWrite(greenLed, LED_OFF); // Make sure led is off 104 | digitalWrite(blueLed, LED_OFF); // Make sure led is off 105 | 106 | //Protocol Configuration 107 | Serial.begin(9600); // Initialize serial communications with PC 108 | SPI.begin(); // MFRC522 Hardware uses SPI protocol 109 | mfrc522.PCD_Init(); // Initialize MFRC522 Hardware 110 | 111 | //If you set Antenna Gain to Max it will increase reading distance 112 | //mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); 113 | 114 | Serial.println(F("Access Control v3.3")); // For debugging purposes 115 | ShowReaderDetails(); // Show details of PCD - MFRC522 Card Reader details 116 | 117 | //Wipe Code if Button Pressed while setup run (powered on) it wipes EEPROM 118 | if (digitalRead(wipeB) == LOW) { // when button pressed pin should get low, button connected to ground 119 | digitalWrite(redLed, LED_ON); // Red Led stays on to inform user we are going to wipe 120 | Serial.println(F("Wipe Button Pressed")); 121 | Serial.println(F("You have 5 seconds to Cancel")); 122 | Serial.println(F("This will be remove all records and cannot be undone")); 123 | delay(5000); // Give user enough time to cancel operation 124 | if (digitalRead(wipeB) == LOW) { // If button still be pressed, wipe EEPROM 125 | Serial.println(F("Starting Wiping EEPROM")); 126 | for (int x = 0; x < EEPROM.length(); x = x + 1) { //Loop end of EEPROM address 127 | if (EEPROM.read(x) == 0) { //If EEPROM address 0 128 | // do nothing, already clear, go to the next address in order to save time and reduce writes to EEPROM 129 | } 130 | else { 131 | EEPROM.write(x, 0); // if not write 0 to clear, it takes 3.3mS 132 | } 133 | } 134 | Serial.println(F("EEPROM Successfully Wiped")); 135 | digitalWrite(redLed, LED_OFF); // visualize successful wipe 136 | delay(200); 137 | digitalWrite(redLed, LED_ON); 138 | delay(200); 139 | digitalWrite(redLed, LED_OFF); 140 | delay(200); 141 | digitalWrite(redLed, LED_ON); 142 | delay(200); 143 | digitalWrite(redLed, LED_OFF); 144 | } 145 | else { 146 | Serial.println(F("Wiping Cancelled")); 147 | digitalWrite(redLed, LED_OFF); 148 | } 149 | } 150 | // Check if master card defined, if not let user choose a master card 151 | // This also useful to just redefine Master Card 152 | // You can keep other EEPROM records just write other than 143 to EEPROM address 1 153 | // EEPROM address 1 should hold magical number which is '143' 154 | if (EEPROM.read(1) != 143) { 155 | Serial.println(F("No Master Card Defined")); 156 | Serial.println(F("Scan A PICC to Define as Master Card")); 157 | do { 158 | successRead = getID(); // sets successRead to 1 when we get read from reader otherwise 0 159 | digitalWrite(blueLed, LED_ON); // Visualize Master Card need to be defined 160 | delay(200); 161 | digitalWrite(blueLed, LED_OFF); 162 | delay(200); 163 | } 164 | while (!successRead); // Program will not go further while you not get a successful read 165 | for ( int j = 0; j < 4; j++ ) { // Loop 4 times 166 | EEPROM.write( 2 + j, readCard[j] ); // Write scanned PICC's UID to EEPROM, start from address 3 167 | } 168 | EEPROM.write(1, 143); // Write to EEPROM we defined Master Card. 169 | Serial.println(F("Master Card Defined")); 170 | } 171 | Serial.println(F("-------------------")); 172 | Serial.println(F("Master Card's UID")); 173 | for ( int i = 0; i < 4; i++ ) { // Read Master Card's UID from EEPROM 174 | masterCard[i] = EEPROM.read(2 + i); // Write it to masterCard 175 | Serial.print(masterCard[i], HEX); 176 | } 177 | Serial.println(""); 178 | Serial.println(F("-------------------")); 179 | Serial.println(F("Everything Ready")); 180 | Serial.println(F("Waiting PICCs to be scanned")); 181 | cycleLeds(); // Everything ready lets give user some feedback by cycling leds 182 | } 183 | 184 | 185 | ///////////////////////////////////////// Main Loop /////////////////////////////////// 186 | void loop () { 187 | do { 188 | successRead = getID(); // sets successRead to 1 when we get read from reader otherwise 0 189 | if (programMode) { 190 | cycleLeds(); // Program Mode cycles through RGB waiting to read a new card 191 | } 192 | else { 193 | normalModeOn(); // Normal mode, blue Power LED is on, all others are off 194 | } 195 | } 196 | while (!successRead); //the program will not go further while you not get a successful read 197 | if (programMode) { 198 | if ( isMaster(readCard) ) { //If master card scanned again exit program mode 199 | Serial.println(F("Master Card Scanned")); 200 | Serial.println(F("Exiting Program Mode")); 201 | Serial.println(F("-----------------------------")); 202 | programMode = false; 203 | return; 204 | } 205 | else { 206 | if ( findID(readCard) ) { // If scanned card is known delete it 207 | Serial.println(F("I know this PICC, removing...")); 208 | deleteID(readCard); 209 | Serial.println("-----------------------------"); 210 | } 211 | else { // If scanned card is not known add it 212 | Serial.println(F("I do not know this PICC, adding...")); 213 | writeID(readCard); 214 | Serial.println(F("-----------------------------")); 215 | } 216 | } 217 | } 218 | else { 219 | if ( isMaster(readCard) ) { // If scanned card's ID matches Master Card's ID enter program mode 220 | programMode = true; 221 | Serial.println(F("Hello Master - Entered Program Mode")); 222 | int count = EEPROM.read(0); // Read the first Byte of EEPROM that 223 | Serial.print(F("I have ")); // stores the number of ID's in EEPROM 224 | Serial.print(count); 225 | Serial.print(F(" record(s) on EEPROM")); 226 | Serial.println(""); 227 | Serial.println(F("Scan a PICC to ADD or REMOVE")); 228 | Serial.println(F("-----------------------------")); 229 | } 230 | else { 231 | if ( findID(readCard) ) { // If not, see if the card is in the EEPROM 232 | Serial.println(F("Welcome, You shall pass")); 233 | granted(300); // Open the door lock for 300 ms 234 | } 235 | else { // If not, show that the ID was not valid 236 | Serial.println(F("You shall not pass")); 237 | denied(); 238 | } 239 | } 240 | } 241 | } 242 | 243 | ///////////////////////////////////////// Access Granted /////////////////////////////////// 244 | void granted (int setDelay) { 245 | digitalWrite(blueLed, LED_OFF); // Turn off blue LED 246 | digitalWrite(redLed, LED_OFF); // Turn off red LED 247 | digitalWrite(greenLed, LED_ON); // Turn on green LED 248 | servo(150); // Unlock door! 249 | delay(setDelay); // Hold door lock open for given seconds 250 | servo(50); // Relock door 251 | delay(1000); // Hold green LED on for a second 252 | } 253 | 254 | ///////////////////////////////////////// Access Denied /////////////////////////////////// 255 | void denied() { 256 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 257 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 258 | digitalWrite(redLed, LED_ON); // Turn on red LED 259 | delay(1000); 260 | } 261 | 262 | 263 | ///////////////////////////////////////// Get PICC's UID /////////////////////////////////// 264 | int getID() { 265 | // Getting ready for Reading PICCs 266 | if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue 267 | return 0; 268 | } 269 | if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue 270 | return 0; 271 | } 272 | // There are Mifare PICCs which have 4 byte or 7 byte UID care if you use 7 byte PICC 273 | // I think we should assume every PICC as they have 4 byte UID 274 | // Until we support 7 byte PICCs 275 | Serial.println(F("Scanned PICC's UID:")); 276 | for (int i = 0; i < 4; i++) { // 277 | readCard[i] = mfrc522.uid.uidByte[i]; 278 | Serial.print(readCard[i], HEX); 279 | } 280 | Serial.println(""); 281 | mfrc522.PICC_HaltA(); // Stop reading 282 | return 1; 283 | } 284 | 285 | void ShowReaderDetails() { 286 | // Get the MFRC522 software version 287 | byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); 288 | Serial.print(F("MFRC522 Software Version: 0x")); 289 | Serial.print(v, HEX); 290 | if (v == 0x91) 291 | Serial.print(F(" = v1.0")); 292 | else if (v == 0x92) 293 | Serial.print(F(" = v2.0")); 294 | else 295 | Serial.print(F(" (unknown)")); 296 | Serial.println(""); 297 | // When 0x00 or 0xFF is returned, communication probably failed 298 | if ((v == 0x00) || (v == 0xFF)) { 299 | Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?")); 300 | while(true); // do not go further 301 | } 302 | } 303 | 304 | ///////////////////////////////////////// Cycle Leds (Program Mode) /////////////////////////////////// 305 | void cycleLeds() { 306 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 307 | digitalWrite(greenLed, LED_ON); // Make sure green LED is on 308 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 309 | delay(200); 310 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 311 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 312 | digitalWrite(blueLed, LED_ON); // Make sure blue LED is on 313 | delay(200); 314 | digitalWrite(redLed, LED_ON); // Make sure red LED is on 315 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 316 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 317 | delay(200); 318 | } 319 | 320 | //////////////////////////////////////// Normal Mode Led /////////////////////////////////// 321 | void normalModeOn () { 322 | digitalWrite(blueLed, LED_ON); // Blue LED ON and ready to read card 323 | digitalWrite(redLed, LED_OFF); // Make sure Red LED is off 324 | digitalWrite(greenLed, LED_OFF); // Make sure Green LED is off 325 | digitalWrite(relay, HIGH); // Make sure Door is Locked 326 | } 327 | 328 | //////////////////////////////////////// Read an ID from EEPROM ////////////////////////////// 329 | void readID( int number ) { 330 | int start = (number * 4 ) + 2; // Figure out starting position 331 | for ( int i = 0; i < 4; i++ ) { // Loop 4 times to get the 4 Bytes 332 | storedCard[i] = EEPROM.read(start + i); // Assign values read from EEPROM to array 333 | } 334 | } 335 | 336 | ///////////////////////////////////////// Add ID to EEPROM /////////////////////////////////// 337 | void writeID( byte a[] ) { 338 | if ( !findID( a ) ) { // Before we write to the EEPROM, check to see if we have seen this card before! 339 | int num = EEPROM.read(0); // Get the numer of used spaces, position 0 stores the number of ID cards 340 | int start = ( num * 4 ) + 6; // Figure out where the next slot starts 341 | num++; // Increment the counter by one 342 | EEPROM.write( 0, num ); // Write the new count to the counter 343 | for ( int j = 0; j < 4; j++ ) { // Loop 4 times 344 | EEPROM.write( start + j, a[j] ); // Write the array values to EEPROM in the right position 345 | } 346 | successWrite(); 347 | Serial.println(F("Succesfully added ID record to EEPROM")); 348 | } 349 | else { 350 | failedWrite(); 351 | Serial.println(F("Failed! There is something wrong with ID or bad EEPROM")); 352 | } 353 | } 354 | 355 | ///////////////////////////////////////// Remove ID from EEPROM /////////////////////////////////// 356 | void deleteID( byte a[] ) { 357 | if ( !findID( a ) ) { // Before we delete from the EEPROM, check to see if we have this card! 358 | failedWrite(); // If not 359 | Serial.println(F("Failed! There is something wrong with ID or bad EEPROM")); 360 | } 361 | else { 362 | int num = EEPROM.read(0); // Get the numer of used spaces, position 0 stores the number of ID cards 363 | int slot; // Figure out the slot number of the card 364 | int start; // = ( num * 4 ) + 6; // Figure out where the next slot starts 365 | int looping; // The number of times the loop repeats 366 | int j; 367 | int count = EEPROM.read(0); // Read the first Byte of EEPROM that stores number of cards 368 | slot = findIDSLOT( a ); // Figure out the slot number of the card to delete 369 | start = (slot * 4) + 2; 370 | looping = ((num - slot) * 4); 371 | num--; // Decrement the counter by one 372 | EEPROM.write( 0, num ); // Write the new count to the counter 373 | for ( j = 0; j < looping; j++ ) { // Loop the card shift times 374 | EEPROM.write( start + j, EEPROM.read(start + 4 + j)); // Shift the array values to 4 places earlier in the EEPROM 375 | } 376 | for ( int k = 0; k < 4; k++ ) { // Shifting loop 377 | EEPROM.write( start + j + k, 0); 378 | } 379 | successDelete(); 380 | Serial.println(F("Succesfully removed ID record from EEPROM")); 381 | } 382 | } 383 | 384 | ///////////////////////////////////////// Check Bytes /////////////////////////////////// 385 | boolean checkTwo ( byte a[], byte b[] ) { 386 | if ( a[0] != NULL ) // Make sure there is something in the array first 387 | match = true; // Assume they match at first 388 | for ( int k = 0; k < 4; k++ ) { // Loop 4 times 389 | if ( a[k] != b[k] ) // IF a != b then set match = false, one fails, all fail 390 | match = false; 391 | } 392 | if ( match ) { // Check to see if if match is still true 393 | return true; // Return true 394 | } 395 | else { 396 | return false; // Return false 397 | } 398 | } 399 | 400 | ///////////////////////////////////////// Find Slot /////////////////////////////////// 401 | int findIDSLOT( byte find[] ) { 402 | int count = EEPROM.read(0); // Read the first Byte of EEPROM that 403 | for ( int i = 1; i <= count; i++ ) { // Loop once for each EEPROM entry 404 | readID(i); // Read an ID from EEPROM, it is stored in storedCard[4] 405 | if ( checkTwo( find, storedCard ) ) { // Check to see if the storedCard read from EEPROM 406 | // is the same as the find[] ID card passed 407 | return i; // The slot number of the card 408 | break; // Stop looking we found it 409 | } 410 | } 411 | } 412 | 413 | ///////////////////////////////////////// Find ID From EEPROM /////////////////////////////////// 414 | boolean findID( byte find[] ) { 415 | int count = EEPROM.read(0); // Read the first Byte of EEPROM that 416 | for ( int i = 1; i <= count; i++ ) { // Loop once for each EEPROM entry 417 | readID(i); // Read an ID from EEPROM, it is stored in storedCard[4] 418 | if ( checkTwo( find, storedCard ) ) { // Check to see if the storedCard read from EEPROM 419 | return true; 420 | break; // Stop looking we found it 421 | } 422 | else { // If not, return false 423 | } 424 | } 425 | return false; 426 | } 427 | 428 | ///////////////////////////////////////// Write Success to EEPROM /////////////////////////////////// 429 | // Flashes the green LED 3 times to indicate a successful write to EEPROM 430 | void successWrite() { 431 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 432 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 433 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is on 434 | delay(200); 435 | digitalWrite(greenLed, LED_ON); // Make sure green LED is on 436 | delay(200); 437 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 438 | delay(200); 439 | digitalWrite(greenLed, LED_ON); // Make sure green LED is on 440 | delay(200); 441 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 442 | delay(200); 443 | digitalWrite(greenLed, LED_ON); // Make sure green LED is on 444 | delay(200); 445 | } 446 | 447 | ///////////////////////////////////////// Write Failed to EEPROM /////////////////////////////////// 448 | // Flashes the red LED 3 times to indicate a failed write to EEPROM 449 | void failedWrite() { 450 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 451 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 452 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 453 | delay(200); 454 | digitalWrite(redLed, LED_ON); // Make sure red LED is on 455 | delay(200); 456 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 457 | delay(200); 458 | digitalWrite(redLed, LED_ON); // Make sure red LED is on 459 | delay(200); 460 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 461 | delay(200); 462 | digitalWrite(redLed, LED_ON); // Make sure red LED is on 463 | delay(200); 464 | } 465 | 466 | ///////////////////////////////////////// Success Remove UID From EEPROM /////////////////////////////////// 467 | // Flashes the blue LED 3 times to indicate a success delete to EEPROM 468 | void successDelete() { 469 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 470 | digitalWrite(redLed, LED_OFF); // Make sure red LED is off 471 | digitalWrite(greenLed, LED_OFF); // Make sure green LED is off 472 | delay(200); 473 | digitalWrite(blueLed, LED_ON); // Make sure blue LED is on 474 | delay(200); 475 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 476 | delay(200); 477 | digitalWrite(blueLed, LED_ON); // Make sure blue LED is on 478 | delay(200); 479 | digitalWrite(blueLed, LED_OFF); // Make sure blue LED is off 480 | delay(200); 481 | digitalWrite(blueLed, LED_ON); // Make sure blue LED is on 482 | delay(200); 483 | } 484 | 485 | ////////////////////// Check readCard IF is masterCard /////////////////////////////////// 486 | // Check to see if the ID passed is the master programing card 487 | boolean isMaster( byte test[] ) { 488 | if ( checkTwo( test, masterCard ) ) 489 | return true; 490 | else 491 | return false; 492 | } 493 | /////////////////////Servo Method/////////////////////////////////////// 494 | void servo(int datPos) 495 | { 496 | daServo.write(datPos); 497 | delay(15); 498 | } 499 | -------------------------------------------------------------------------------- /MFRC522.h: -------------------------------------------------------------------------------- 1 | /** 2 | * MFRC522.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 3 | * Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) 4 | * Created by Miguel Balboa (circuitito.com), Jan, 2012. 5 | * Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.) 6 | * Extended by Tom Clement with functionality to write to sector 0 of UID changeable Mifare cards. 7 | * Released into the public domain. 8 | * 9 | * Please read this file for an overview and then MFRC522.cpp for comments on the specific functions. 10 | * Search for "mf-rc522" on ebay.com to purchase the MF-RC522 board. 11 | * 12 | * There are three hardware components involved: 13 | * 1) The micro controller: An Arduino 14 | * 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC 15 | * 3) The PICC (short for Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203. 16 | * 17 | * The microcontroller and card reader uses SPI for communication. 18 | * The protocol is described in the MFRC522 datasheet: http://www.nxp.com/documents/data_sheet/MFRC522.pdf 19 | * 20 | * The card reader and the tags communicate using a 13.56MHz electromagnetic field. 21 | * The protocol is defined in ISO/IEC 14443-3 Identification cards -- Contactless integrated circuit cards -- Proximity cards -- Part 3: Initialization and anticollision". 22 | * A free version of the final draft can be found at http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf 23 | * Details are found in chapter 6, Type A – Initialization and anticollision. 24 | * 25 | * If only the PICC UID is wanted, the above documents has all the needed information. 26 | * To read and write from MIFARE PICCs, the MIFARE protocol is used after the PICC has been selected. 27 | * The MIFARE Classic chips and protocol is described in the datasheets: 28 | * 1K: http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf 29 | * 4K: http://datasheet.octopart.com/MF1S7035DA4,118-NXP-Semiconductors-datasheet-11046188.pdf 30 | * Mini: http://www.idcardmarket.com/download/mifare_S20_datasheet.pdf 31 | * The MIFARE Ultralight chip and protocol is described in the datasheets: 32 | * Ultralight: http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf 33 | * Ultralight C: http://www.nxp.com/documents/short_data_sheet/MF0ICU2_SDS.pdf 34 | * 35 | * MIFARE Classic 1K (MF1S503x): 36 | * Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. 37 | * The blocks are numbered 0-63. 38 | * Block 3 in each sector is the Sector Trailer. See http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf sections 8.6 and 8.7: 39 | * Bytes 0-5: Key A 40 | * Bytes 6-8: Access Bits 41 | * Bytes 9: User data 42 | * Bytes 10-15: Key B (or user data) 43 | * Block 0 is read-only manufacturer data. 44 | * To access a block, an authentication using a key from the block's sector must be performed first. 45 | * Example: To read from block 10, first authenticate using a key from sector 3 (blocks 8-11). 46 | * All keys are set to FFFFFFFFFFFFh at chip delivery. 47 | * Warning: Please read section 8.7 "Memory Access". It includes this text: if the PICC detects a format violation the whole sector is irreversibly blocked. 48 | * To use a block in "value block" mode (for Increment/Decrement operations) you need to change the sector trailer. Use PICC_SetAccessBits() to calculate the bit patterns. 49 | * MIFARE Classic 4K (MF1S703x): 50 | * Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. 51 | * The blocks are numbered 0-255. 52 | * The last block in each sector is the Sector Trailer like above. 53 | * MIFARE Classic Mini (MF1 IC S20): 54 | * Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. 55 | * The blocks are numbered 0-19. 56 | * The last block in each sector is the Sector Trailer like above. 57 | * 58 | * MIFARE Ultralight (MF0ICU1): 59 | * Has 16 pages of 4 bytes = 64 bytes. 60 | * Pages 0 + 1 is used for the 7-byte UID. 61 | * Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) 62 | * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. 63 | * Pages 4-15 are read/write unless blocked by the lock bytes in page 2. 64 | * MIFARE Ultralight C (MF0ICU2): 65 | * Has 48 pages of 4 bytes = 192 bytes. 66 | * Pages 0 + 1 is used for the 7-byte UID. 67 | * Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) 68 | * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. 69 | * Pages 4-39 are read/write unless blocked by the lock bytes in page 2. 70 | * Page 40 Lock bytes 71 | * Page 41 16 bit one way counter 72 | * Pages 42-43 Authentication configuration 73 | * Pages 44-47 Authentication key 74 | */ 75 | #ifndef MFRC522_h 76 | #define MFRC522_h 77 | 78 | #include 79 | #include 80 | 81 | // Firmware data for self-test 82 | // Reference values based on firmware version 83 | // Hint: if needed, you can remove unused self-test data to save flash memory 84 | // 85 | // Version 0.0 (0x90) 86 | // Philips Semiconductors; Preliminary Specification Revision 2.0 - 01 August 2005; 16.1 Sefttest 87 | const byte MFRC522_firmware_referenceV0_0[] PROGMEM = { 88 | 0x00, 0x87, 0x98, 0x0f, 0x49, 0xFF, 0x07, 0x19, 89 | 0xBF, 0x22, 0x30, 0x49, 0x59, 0x63, 0xAD, 0xCA, 90 | 0x7F, 0xE3, 0x4E, 0x03, 0x5C, 0x4E, 0x49, 0x50, 91 | 0x47, 0x9A, 0x37, 0x61, 0xE7, 0xE2, 0xC6, 0x2E, 92 | 0x75, 0x5A, 0xED, 0x04, 0x3D, 0x02, 0x4B, 0x78, 93 | 0x32, 0xFF, 0x58, 0x3B, 0x7C, 0xE9, 0x00, 0x94, 94 | 0xB4, 0x4A, 0x59, 0x5B, 0xFD, 0xC9, 0x29, 0xDF, 95 | 0x35, 0x96, 0x98, 0x9E, 0x4F, 0x30, 0x32, 0x8D 96 | }; 97 | // Version 1.0 (0x91) 98 | // NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test 99 | const byte MFRC522_firmware_referenceV1_0[] PROGMEM = { 100 | 0x00, 0xC6, 0x37, 0xD5, 0x32, 0xB7, 0x57, 0x5C, 101 | 0xC2, 0xD8, 0x7C, 0x4D, 0xD9, 0x70, 0xC7, 0x73, 102 | 0x10, 0xE6, 0xD2, 0xAA, 0x5E, 0xA1, 0x3E, 0x5A, 103 | 0x14, 0xAF, 0x30, 0x61, 0xC9, 0x70, 0xDB, 0x2E, 104 | 0x64, 0x22, 0x72, 0xB5, 0xBD, 0x65, 0xF4, 0xEC, 105 | 0x22, 0xBC, 0xD3, 0x72, 0x35, 0xCD, 0xAA, 0x41, 106 | 0x1F, 0xA7, 0xF3, 0x53, 0x14, 0xDE, 0x7E, 0x02, 107 | 0xD9, 0x0F, 0xB5, 0x5E, 0x25, 0x1D, 0x29, 0x79 108 | }; 109 | // Version 2.0 (0x92) 110 | // NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test 111 | const byte MFRC522_firmware_referenceV2_0[] PROGMEM = { 112 | 0x00, 0xEB, 0x66, 0xBA, 0x57, 0xBF, 0x23, 0x95, 113 | 0xD0, 0xE3, 0x0D, 0x3D, 0x27, 0x89, 0x5C, 0xDE, 114 | 0x9D, 0x3B, 0xA7, 0x00, 0x21, 0x5B, 0x89, 0x82, 115 | 0x51, 0x3A, 0xEB, 0x02, 0x0C, 0xA5, 0x00, 0x49, 116 | 0x7C, 0x84, 0x4D, 0xB3, 0xCC, 0xD2, 0x1B, 0x81, 117 | 0x5D, 0x48, 0x76, 0xD5, 0x71, 0x61, 0x21, 0xA9, 118 | 0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B, 0x6D, 119 | 0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F 120 | }; 121 | // Clone 122 | // Fudan Semiconductor FM17522 (0x88) 123 | const byte FM17522_firmware_reference[] PROGMEM = { 124 | 0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18, 125 | 0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B, 126 | 0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7, 127 | 0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B, 128 | 0x7C, 0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7, 129 | 0xC1, 0x5B, 0x00, 0x2A, 0xD0, 0x75, 0xDE, 0x9E, 130 | 0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB, 131 | 0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62 132 | }; 133 | 134 | class MFRC522 { 135 | public: 136 | // MFRC522 registers. Described in chapter 9 of the datasheet. 137 | // When using SPI all addresses are shifted one bit left in the "SPI address byte" (section 8.1.2.3) 138 | enum PCD_Register { 139 | // Page 0: Command and status 140 | // 0x00 // reserved for future use 141 | CommandReg = 0x01 << 1, // starts and stops command execution 142 | ComIEnReg = 0x02 << 1, // enable and disable interrupt request control bits 143 | DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits 144 | ComIrqReg = 0x04 << 1, // interrupt request bits 145 | DivIrqReg = 0x05 << 1, // interrupt request bits 146 | ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed 147 | Status1Reg = 0x07 << 1, // communication status bits 148 | Status2Reg = 0x08 << 1, // receiver and transmitter status bits 149 | FIFODataReg = 0x09 << 1, // input and output of 64 byte FIFO buffer 150 | FIFOLevelReg = 0x0A << 1, // number of bytes stored in the FIFO buffer 151 | WaterLevelReg = 0x0B << 1, // level for FIFO underflow and overflow warning 152 | ControlReg = 0x0C << 1, // miscellaneous control registers 153 | BitFramingReg = 0x0D << 1, // adjustments for bit-oriented frames 154 | CollReg = 0x0E << 1, // bit position of the first bit-collision detected on the RF interface 155 | // 0x0F // reserved for future use 156 | 157 | // Page 1: Command 158 | // 0x10 // reserved for future use 159 | ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving 160 | TxModeReg = 0x12 << 1, // defines transmission data rate and framing 161 | RxModeReg = 0x13 << 1, // defines reception data rate and framing 162 | TxControlReg = 0x14 << 1, // controls the logical behavior of the antenna driver pins TX1 and TX2 163 | TxASKReg = 0x15 << 1, // controls the setting of the transmission modulation 164 | TxSelReg = 0x16 << 1, // selects the internal sources for the antenna driver 165 | RxSelReg = 0x17 << 1, // selects internal receiver settings 166 | RxThresholdReg = 0x18 << 1, // selects thresholds for the bit decoder 167 | DemodReg = 0x19 << 1, // defines demodulator settings 168 | // 0x1A // reserved for future use 169 | // 0x1B // reserved for future use 170 | MfTxReg = 0x1C << 1, // controls some MIFARE communication transmit parameters 171 | MfRxReg = 0x1D << 1, // controls some MIFARE communication receive parameters 172 | // 0x1E // reserved for future use 173 | SerialSpeedReg = 0x1F << 1, // selects the speed of the serial UART interface 174 | 175 | // Page 2: Configuration 176 | // 0x20 // reserved for future use 177 | CRCResultRegH = 0x21 << 1, // shows the MSB and LSB values of the CRC calculation 178 | CRCResultRegL = 0x22 << 1, 179 | // 0x23 // reserved for future use 180 | ModWidthReg = 0x24 << 1, // controls the ModWidth setting? 181 | // 0x25 // reserved for future use 182 | RFCfgReg = 0x26 << 1, // configures the receiver gain 183 | GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation 184 | CWGsPReg = 0x28 << 1, // defines the conductance of the p-driver output during periods of no modulation 185 | ModGsPReg = 0x29 << 1, // defines the conductance of the p-driver output during periods of modulation 186 | TModeReg = 0x2A << 1, // defines settings for the internal timer 187 | TPrescalerReg = 0x2B << 1, // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg. 188 | TReloadRegH = 0x2C << 1, // defines the 16-bit timer reload value 189 | TReloadRegL = 0x2D << 1, 190 | TCounterValueRegH = 0x2E << 1, // shows the 16-bit timer value 191 | TCounterValueRegL = 0x2F << 1, 192 | 193 | // Page 3: Test Registers 194 | // 0x30 // reserved for future use 195 | TestSel1Reg = 0x31 << 1, // general test signal configuration 196 | TestSel2Reg = 0x32 << 1, // general test signal configuration 197 | TestPinEnReg = 0x33 << 1, // enables pin output driver on pins D1 to D7 198 | TestPinValueReg = 0x34 << 1, // defines the values for D1 to D7 when it is used as an I/O bus 199 | TestBusReg = 0x35 << 1, // shows the status of the internal test bus 200 | AutoTestReg = 0x36 << 1, // controls the digital self test 201 | VersionReg = 0x37 << 1, // shows the software version 202 | AnalogTestReg = 0x38 << 1, // controls the pins AUX1 and AUX2 203 | TestDAC1Reg = 0x39 << 1, // defines the test value for TestDAC1 204 | TestDAC2Reg = 0x3A << 1, // defines the test value for TestDAC2 205 | TestADCReg = 0x3B << 1 // shows the value of ADC I and Q channels 206 | // 0x3C // reserved for production tests 207 | // 0x3D // reserved for production tests 208 | // 0x3E // reserved for production tests 209 | // 0x3F // reserved for production tests 210 | }; 211 | 212 | // MFRC522 commands. Described in chapter 10 of the datasheet. 213 | enum PCD_Command { 214 | PCD_Idle = 0x00, // no action, cancels current command execution 215 | PCD_Mem = 0x01, // stores 25 bytes into the internal buffer 216 | PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number 217 | PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self test 218 | PCD_Transmit = 0x04, // transmits data from the FIFO buffer 219 | PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit 220 | PCD_Receive = 0x08, // activates the receiver circuits 221 | PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission 222 | PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader 223 | PCD_SoftReset = 0x0F // resets the MFRC522 224 | }; 225 | 226 | // MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD). 227 | // Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf 228 | enum PCD_RxGain { 229 | RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum 230 | RxGain_23dB = 0x01 << 4, // 001b - 23 dB 231 | RxGain_18dB_2 = 0x02 << 4, // 010b - 18 dB, it seems 010b is a duplicate for 000b 232 | RxGain_23dB_2 = 0x03 << 4, // 011b - 23 dB, it seems 011b is a duplicate for 001b 233 | RxGain_33dB = 0x04 << 4, // 100b - 33 dB, average, and typical default 234 | RxGain_38dB = 0x05 << 4, // 101b - 38 dB 235 | RxGain_43dB = 0x06 << 4, // 110b - 43 dB 236 | RxGain_48dB = 0x07 << 4, // 111b - 48 dB, maximum 237 | RxGain_min = 0x00 << 4, // 000b - 18 dB, minimum, convenience for RxGain_18dB 238 | RxGain_avg = 0x04 << 4, // 100b - 33 dB, average, convenience for RxGain_33dB 239 | RxGain_max = 0x07 << 4 // 111b - 48 dB, maximum, convenience for RxGain_48dB 240 | }; 241 | 242 | // Commands sent to the PICC. 243 | enum PICC_Command { 244 | // The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4) 245 | PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. 246 | PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. 247 | PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision. 248 | PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1 249 | PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2 250 | PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3 251 | PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT. 252 | // The commands used for MIFARE Classic (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9) 253 | // Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. 254 | // The read/write commands can also be used for MIFARE Ultralight. 255 | PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A 256 | PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B 257 | PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight. 258 | PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight. 259 | PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register. 260 | PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register. 261 | PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register. 262 | PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block. 263 | // The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) 264 | // The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight. 265 | PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC. 266 | }; 267 | 268 | // MIFARE constants that does not fit anywhere else 269 | enum MIFARE_Misc { 270 | MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK. 271 | MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes. 272 | }; 273 | 274 | // PICC types we can detect. Remember to update PICC_GetTypeName() if you add more. 275 | // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered 276 | enum PICC_Type : byte { 277 | PICC_TYPE_UNKNOWN , 278 | PICC_TYPE_ISO_14443_4 , // PICC compliant with ISO/IEC 14443-4 279 | PICC_TYPE_ISO_18092 , // PICC compliant with ISO/IEC 18092 (NFC) 280 | PICC_TYPE_MIFARE_MINI , // MIFARE Classic protocol, 320 bytes 281 | PICC_TYPE_MIFARE_1K , // MIFARE Classic protocol, 1KB 282 | PICC_TYPE_MIFARE_4K , // MIFARE Classic protocol, 4KB 283 | PICC_TYPE_MIFARE_UL , // MIFARE Ultralight or Ultralight C 284 | PICC_TYPE_MIFARE_PLUS , // MIFARE Plus 285 | PICC_TYPE_TNP3XXX , // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure 286 | PICC_TYPE_NOT_COMPLETE = 0xff // SAK indicates UID is not complete. 287 | }; 288 | 289 | // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. 290 | // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered 291 | enum StatusCode : byte { 292 | STATUS_OK , // Success 293 | STATUS_ERROR , // Error in communication 294 | STATUS_COLLISION , // Collission detected 295 | STATUS_TIMEOUT , // Timeout in communication. 296 | STATUS_NO_ROOM , // A buffer is not big enough. 297 | STATUS_INTERNAL_ERROR , // Internal error in the code. Should not happen ;-) 298 | STATUS_INVALID , // Invalid argument. 299 | STATUS_CRC_WRONG , // The CRC_A does not match 300 | STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK. 301 | }; 302 | 303 | // A struct used for passing the UID of a PICC. 304 | typedef struct { 305 | byte size; // Number of bytes in the UID. 4, 7 or 10. 306 | byte uidByte[10]; 307 | byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection. 308 | } Uid; 309 | 310 | // A struct used for passing a MIFARE Crypto1 key 311 | typedef struct { 312 | byte keyByte[MF_KEY_SIZE]; 313 | } MIFARE_Key; 314 | 315 | // Member variables 316 | Uid uid; // Used by PICC_ReadCardSerial(). 317 | 318 | // Size of the MFRC522 FIFO 319 | static const byte FIFO_SIZE = 64; // The FIFO is 64 bytes. 320 | 321 | ///////////////////////////////////////////////////////////////////////////////////// 322 | // Functions for setting up the Arduino 323 | ///////////////////////////////////////////////////////////////////////////////////// 324 | MFRC522(); 325 | MFRC522(byte chipSelectPin, byte resetPowerDownPin); 326 | 327 | ///////////////////////////////////////////////////////////////////////////////////// 328 | // Basic interface functions for communicating with the MFRC522 329 | ///////////////////////////////////////////////////////////////////////////////////// 330 | void PCD_WriteRegister(byte reg, byte value); 331 | void PCD_WriteRegister(byte reg, byte count, byte *values); 332 | byte PCD_ReadRegister(byte reg); 333 | void PCD_ReadRegister(byte reg, byte count, byte *values, byte rxAlign = 0); 334 | void setBitMask(unsigned char reg, unsigned char mask); 335 | void PCD_SetRegisterBitMask(byte reg, byte mask); 336 | void PCD_ClearRegisterBitMask(byte reg, byte mask); 337 | StatusCode PCD_CalculateCRC(byte *data, byte length, byte *result); 338 | 339 | ///////////////////////////////////////////////////////////////////////////////////// 340 | // Functions for manipulating the MFRC522 341 | ///////////////////////////////////////////////////////////////////////////////////// 342 | void PCD_Init(); 343 | void PCD_Init(byte chipSelectPin, byte resetPowerDownPin); 344 | void PCD_Reset(); 345 | void PCD_AntennaOn(); 346 | void PCD_AntennaOff(); 347 | byte PCD_GetAntennaGain(); 348 | void PCD_SetAntennaGain(byte mask); 349 | bool PCD_PerformSelfTest(); 350 | 351 | ///////////////////////////////////////////////////////////////////////////////////// 352 | // Functions for communicating with PICCs 353 | ///////////////////////////////////////////////////////////////////////////////////// 354 | StatusCode PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false); 355 | StatusCode PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData = NULL, byte *backLen = NULL, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false); 356 | StatusCode PICC_RequestA(byte *bufferATQA, byte *bufferSize); 357 | StatusCode PICC_WakeupA(byte *bufferATQA, byte *bufferSize); 358 | StatusCode PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize); 359 | StatusCode PICC_Select(Uid *uid, byte validBits = 0); 360 | StatusCode PICC_HaltA(); 361 | 362 | ///////////////////////////////////////////////////////////////////////////////////// 363 | // Functions for communicating with MIFARE PICCs 364 | ///////////////////////////////////////////////////////////////////////////////////// 365 | StatusCode PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid); 366 | void PCD_StopCrypto1(); 367 | StatusCode MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize); 368 | StatusCode MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize); 369 | StatusCode MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize); 370 | StatusCode MIFARE_Decrement(byte blockAddr, long delta); 371 | StatusCode MIFARE_Increment(byte blockAddr, long delta); 372 | StatusCode MIFARE_Restore(byte blockAddr); 373 | StatusCode MIFARE_Transfer(byte blockAddr); 374 | StatusCode MIFARE_GetValue(byte blockAddr, long *value); 375 | StatusCode MIFARE_SetValue(byte blockAddr, long value); 376 | StatusCode PCD_NTAG216_AUTH(byte *passWord, byte pACK[]); 377 | 378 | ///////////////////////////////////////////////////////////////////////////////////// 379 | // Support functions 380 | ///////////////////////////////////////////////////////////////////////////////////// 381 | StatusCode PCD_MIFARE_Transceive(byte *sendData, byte sendLen, bool acceptTimeout = false); 382 | // old function used too much memory, now name moved to flash; if you need char, copy from flash to memory 383 | //const char *GetStatusCodeName(byte code); 384 | static const __FlashStringHelper *GetStatusCodeName(StatusCode code); 385 | static PICC_Type PICC_GetType(byte sak); 386 | // old function used too much memory, now name moved to flash; if you need char, copy from flash to memory 387 | //const char *PICC_GetTypeName(byte type); 388 | static const __FlashStringHelper *PICC_GetTypeName(PICC_Type type); 389 | 390 | // Support functions for debuging 391 | void PCD_DumpVersionToSerial(); 392 | void PICC_DumpToSerial(Uid *uid); 393 | void PICC_DumpDetailsToSerial(Uid *uid); 394 | void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key); 395 | void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector); 396 | void PICC_DumpMifareUltralightToSerial(); 397 | 398 | // Advanced functions for MIFARE 399 | void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3); 400 | bool MIFARE_OpenUidBackdoor(bool logErrors); 401 | bool MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors); 402 | bool MIFARE_UnbrickUidSector(bool logErrors); 403 | 404 | ///////////////////////////////////////////////////////////////////////////////////// 405 | // Convenience functions - does not add extra functionality 406 | ///////////////////////////////////////////////////////////////////////////////////// 407 | bool PICC_IsNewCardPresent(); 408 | bool PICC_ReadCardSerial(); 409 | 410 | private: 411 | byte _chipSelectPin; // Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) 412 | byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) 413 | StatusCode MIFARE_TwoStepHelper(byte command, byte blockAddr, long data); 414 | }; 415 | 416 | #endif 417 | -------------------------------------------------------------------------------- /MFRC522.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MFRC522.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 3 | * NOTE: Please also check the comments in MFRC522.h - they provide useful hints and background information. 4 | * Released into the public domain. 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | ///////////////////////////////////////////////////////////////////////////////////// 11 | // Functions for setting up the Arduino 12 | ///////////////////////////////////////////////////////////////////////////////////// 13 | /** 14 | * Constructor. 15 | */ 16 | MFRC522::MFRC522() { 17 | } // End constructor 18 | 19 | /** 20 | * Constructor. 21 | * Prepares the output pins. 22 | */ 23 | MFRC522::MFRC522( byte chipSelectPin, ///< Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) 24 | byte resetPowerDownPin ///< Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) 25 | ) { 26 | _chipSelectPin = chipSelectPin; 27 | _resetPowerDownPin = resetPowerDownPin; 28 | } // End constructor 29 | 30 | ///////////////////////////////////////////////////////////////////////////////////// 31 | // Basic interface functions for communicating with the MFRC522 32 | ///////////////////////////////////////////////////////////////////////////////////// 33 | 34 | /** 35 | * Writes a byte to the specified register in the MFRC522 chip. 36 | * The interface is described in the datasheet section 8.1.2. 37 | */ 38 | void MFRC522::PCD_WriteRegister( byte reg, ///< The register to write to. One of the PCD_Register enums. 39 | byte value ///< The value to write. 40 | ) { 41 | SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE0)); // Set the settings to work with SPI bus 42 | digitalWrite(_chipSelectPin, LOW); // Select slave 43 | SPI.transfer(reg & 0x7E); // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3. 44 | SPI.transfer(value); 45 | digitalWrite(_chipSelectPin, HIGH); // Release slave again 46 | SPI.endTransaction(); // Stop using the SPI bus 47 | } // End PCD_WriteRegister() 48 | 49 | /** 50 | * Writes a number of bytes to the specified register in the MFRC522 chip. 51 | * The interface is described in the datasheet section 8.1.2. 52 | */ 53 | void MFRC522::PCD_WriteRegister( byte reg, ///< The register to write to. One of the PCD_Register enums. 54 | byte count, ///< The number of bytes to write to the register 55 | byte *values ///< The values to write. Byte array. 56 | ) { 57 | SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE0)); // Set the settings to work with SPI bus 58 | digitalWrite(_chipSelectPin, LOW); // Select slave 59 | SPI.transfer(reg & 0x7E); // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3. 60 | for (byte index = 0; index < count; index++) { 61 | SPI.transfer(values[index]); 62 | } 63 | digitalWrite(_chipSelectPin, HIGH); // Release slave again 64 | SPI.endTransaction(); // Stop using the SPI bus 65 | } // End PCD_WriteRegister() 66 | 67 | /** 68 | * Reads a byte from the specified register in the MFRC522 chip. 69 | * The interface is described in the datasheet section 8.1.2. 70 | */ 71 | byte MFRC522::PCD_ReadRegister( byte reg ///< The register to read from. One of the PCD_Register enums. 72 | ) { 73 | byte value; 74 | SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE0)); // Set the settings to work with SPI bus 75 | digitalWrite(_chipSelectPin, LOW); // Select slave 76 | SPI.transfer(0x80 | (reg & 0x7E)); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. 77 | value = SPI.transfer(0); // Read the value back. Send 0 to stop reading. 78 | digitalWrite(_chipSelectPin, HIGH); // Release slave again 79 | SPI.endTransaction(); // Stop using the SPI bus 80 | return value; 81 | } // End PCD_ReadRegister() 82 | 83 | /** 84 | * Reads a number of bytes from the specified register in the MFRC522 chip. 85 | * The interface is described in the datasheet section 8.1.2. 86 | */ 87 | void MFRC522::PCD_ReadRegister( byte reg, ///< The register to read from. One of the PCD_Register enums. 88 | byte count, ///< The number of bytes to read 89 | byte *values, ///< Byte array to store the values in. 90 | byte rxAlign ///< Only bit positions rxAlign..7 in values[0] are updated. 91 | ) { 92 | if (count == 0) { 93 | return; 94 | } 95 | //Serial.print(F("Reading ")); Serial.print(count); Serial.println(F(" bytes from register.")); 96 | byte address = 0x80 | (reg & 0x7E); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. 97 | byte index = 0; // Index in values array. 98 | SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE0)); // Set the settings to work with SPI bus 99 | digitalWrite(_chipSelectPin, LOW); // Select slave 100 | count--; // One read is performed outside of the loop 101 | SPI.transfer(address); // Tell MFRC522 which address we want to read 102 | while (index < count) { 103 | if (index == 0 && rxAlign) { // Only update bit positions rxAlign..7 in values[0] 104 | // Create bit mask for bit positions rxAlign..7 105 | byte mask = 0; 106 | for (byte i = rxAlign; i <= 7; i++) { 107 | mask |= (1 << i); 108 | } 109 | // Read value and tell that we want to read the same address again. 110 | byte value = SPI.transfer(address); 111 | // Apply mask to both current value of values[0] and the new data in value. 112 | values[0] = (values[index] & ~mask) | (value & mask); 113 | } 114 | else { // Normal case 115 | values[index] = SPI.transfer(address); // Read value and tell that we want to read the same address again. 116 | } 117 | index++; 118 | } 119 | values[index] = SPI.transfer(0); // Read the final byte. Send 0 to stop reading. 120 | digitalWrite(_chipSelectPin, HIGH); // Release slave again 121 | SPI.endTransaction(); // Stop using the SPI bus 122 | } // End PCD_ReadRegister() 123 | 124 | /** 125 | * Sets the bits given in mask in register reg. 126 | */ 127 | void MFRC522::PCD_SetRegisterBitMask( byte reg, ///< The register to update. One of the PCD_Register enums. 128 | byte mask ///< The bits to set. 129 | ) { 130 | byte tmp; 131 | tmp = PCD_ReadRegister(reg); 132 | PCD_WriteRegister(reg, tmp | mask); // set bit mask 133 | } // End PCD_SetRegisterBitMask() 134 | 135 | /** 136 | * Clears the bits given in mask from register reg. 137 | */ 138 | void MFRC522::PCD_ClearRegisterBitMask( byte reg, ///< The register to update. One of the PCD_Register enums. 139 | byte mask ///< The bits to clear. 140 | ) { 141 | byte tmp; 142 | tmp = PCD_ReadRegister(reg); 143 | PCD_WriteRegister(reg, tmp & (~mask)); // clear bit mask 144 | } // End PCD_ClearRegisterBitMask() 145 | 146 | 147 | /** 148 | * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A. 149 | * 150 | * @return STATUS_OK on success, STATUS_??? otherwise. 151 | */ 152 | MFRC522::StatusCode MFRC522::PCD_CalculateCRC( byte *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. 153 | byte length, ///< In: The number of bytes to transfer. 154 | byte *result ///< Out: Pointer to result buffer. Result is written to result[0..1], low byte first. 155 | ) { 156 | PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. 157 | PCD_WriteRegister(DivIrqReg, 0x04); // Clear the CRCIRq interrupt request bit 158 | PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization 159 | PCD_WriteRegister(FIFODataReg, length, data); // Write data to the FIFO 160 | PCD_WriteRegister(CommandReg, PCD_CalcCRC); // Start the calculation 161 | 162 | // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73�s. 163 | word i = 5000; 164 | byte n; 165 | while (1) { 166 | n = PCD_ReadRegister(DivIrqReg); // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved 167 | if (n & 0x04) { // CRCIRq bit set - calculation done 168 | break; 169 | } 170 | if (--i == 0) { // The emergency break. We will eventually terminate on this one after 89ms. Communication with the MFRC522 might be down. 171 | return STATUS_TIMEOUT; 172 | } 173 | } 174 | PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. 175 | 176 | // Transfer the result from the registers to the result buffer 177 | result[0] = PCD_ReadRegister(CRCResultRegL); 178 | result[1] = PCD_ReadRegister(CRCResultRegH); 179 | return STATUS_OK; 180 | } // End PCD_CalculateCRC() 181 | 182 | 183 | ///////////////////////////////////////////////////////////////////////////////////// 184 | // Functions for manipulating the MFRC522 185 | ///////////////////////////////////////////////////////////////////////////////////// 186 | 187 | /** 188 | * Initializes the MFRC522 chip. 189 | */ 190 | void MFRC522::PCD_Init() { 191 | // Set the chipSelectPin as digital output, do not select the slave yet 192 | pinMode(_chipSelectPin, OUTPUT); 193 | digitalWrite(_chipSelectPin, HIGH); 194 | 195 | // Set the resetPowerDownPin as digital output, do not reset or power down. 196 | pinMode(_resetPowerDownPin, OUTPUT); 197 | 198 | if (digitalRead(_resetPowerDownPin) == LOW) { //The MFRC522 chip is in power down mode. 199 | digitalWrite(_resetPowerDownPin, HIGH); // Exit power down mode. This triggers a hard reset. 200 | // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74�s. Let us be generous: 50ms. 201 | delay(50); 202 | } 203 | else { // Perform a soft reset 204 | PCD_Reset(); 205 | } 206 | 207 | // When communicating with a PICC we need a timeout if something goes wrong. 208 | // f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo]. 209 | // TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg. 210 | PCD_WriteRegister(TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds 211 | PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25�s. 212 | PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout. 213 | PCD_WriteRegister(TReloadRegL, 0xE8); 214 | 215 | PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting 216 | PCD_WriteRegister(ModeReg, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4) 217 | PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) 218 | } // End PCD_Init() 219 | 220 | /** 221 | * Initializes the MFRC522 chip. 222 | */ 223 | void MFRC522::PCD_Init( byte chipSelectPin, ///< Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) 224 | byte resetPowerDownPin ///< Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) 225 | ) { 226 | _chipSelectPin = chipSelectPin; 227 | _resetPowerDownPin = resetPowerDownPin; 228 | // Set the chipSelectPin as digital output, do not select the slave yet 229 | PCD_Init(); 230 | } // End PCD_Init() 231 | 232 | /** 233 | * Performs a soft reset on the MFRC522 chip and waits for it to be ready again. 234 | */ 235 | void MFRC522::PCD_Reset() { 236 | PCD_WriteRegister(CommandReg, PCD_SoftReset); // Issue the SoftReset command. 237 | // The datasheet does not mention how long the SoftRest command takes to complete. 238 | // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg) 239 | // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74�s. Let us be generous: 50ms. 240 | delay(50); 241 | // Wait for the PowerDown bit in CommandReg to be cleared 242 | while (PCD_ReadRegister(CommandReg) & (1<<4)) { 243 | // PCD still restarting - unlikely after waiting 50ms, but better safe than sorry. 244 | } 245 | } // End PCD_Reset() 246 | 247 | /** 248 | * Turns the antenna on by enabling pins TX1 and TX2. 249 | * After a reset these pins are disabled. 250 | */ 251 | void MFRC522::PCD_AntennaOn() { 252 | byte value = PCD_ReadRegister(TxControlReg); 253 | if ((value & 0x03) != 0x03) { 254 | PCD_WriteRegister(TxControlReg, value | 0x03); 255 | } 256 | } // End PCD_AntennaOn() 257 | 258 | /** 259 | * Turns the antenna off by disabling pins TX1 and TX2. 260 | */ 261 | void MFRC522::PCD_AntennaOff() { 262 | PCD_ClearRegisterBitMask(TxControlReg, 0x03); 263 | } // End PCD_AntennaOff() 264 | 265 | /** 266 | * Get the current MFRC522 Receiver Gain (RxGain[2:0]) value. 267 | * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf 268 | * NOTE: Return value scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. 269 | * 270 | * @return Value of the RxGain, scrubbed to the 3 bits used. 271 | */ 272 | byte MFRC522::PCD_GetAntennaGain() { 273 | return PCD_ReadRegister(RFCfgReg) & (0x07<<4); 274 | } // End PCD_GetAntennaGain() 275 | 276 | /** 277 | * Set the MFRC522 Receiver Gain (RxGain) to value specified by given mask. 278 | * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf 279 | * NOTE: Given mask is scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. 280 | */ 281 | void MFRC522::PCD_SetAntennaGain(byte mask) { 282 | if (PCD_GetAntennaGain() != mask) { // only bother if there is a change 283 | PCD_ClearRegisterBitMask(RFCfgReg, (0x07<<4)); // clear needed to allow 000 pattern 284 | PCD_SetRegisterBitMask(RFCfgReg, mask & (0x07<<4)); // only set RxGain[2:0] bits 285 | } 286 | } // End PCD_SetAntennaGain() 287 | 288 | /** 289 | * Performs a self-test of the MFRC522 290 | * See 16.1.1 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf 291 | * 292 | * @return Whether or not the test passed. Or false if no firmware reference is available. 293 | */ 294 | bool MFRC522::PCD_PerformSelfTest() { 295 | // This follows directly the steps outlined in 16.1.1 296 | // 1. Perform a soft reset. 297 | PCD_Reset(); 298 | 299 | // 2. Clear the internal buffer by writing 25 bytes of 00h 300 | byte ZEROES[25] = {0x00}; 301 | PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // flush the FIFO buffer 302 | PCD_WriteRegister(FIFODataReg, 25, ZEROES); // write 25 bytes of 00h to FIFO 303 | PCD_WriteRegister(CommandReg, PCD_Mem); // transfer to internal buffer 304 | 305 | // 3. Enable self-test 306 | PCD_WriteRegister(AutoTestReg, 0x09); 307 | 308 | // 4. Write 00h to FIFO buffer 309 | PCD_WriteRegister(FIFODataReg, 0x00); 310 | 311 | // 5. Start self-test by issuing the CalcCRC command 312 | PCD_WriteRegister(CommandReg, PCD_CalcCRC); 313 | 314 | // 6. Wait for self-test to complete 315 | word i; 316 | byte n; 317 | for (i = 0; i < 0xFF; i++) { 318 | n = PCD_ReadRegister(DivIrqReg); // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved 319 | if (n & 0x04) { // CRCIRq bit set - calculation done 320 | break; 321 | } 322 | } 323 | PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. 324 | 325 | // 7. Read out resulting 64 bytes from the FIFO buffer. 326 | byte result[64]; 327 | PCD_ReadRegister(FIFODataReg, 64, result, 0); 328 | 329 | // Auto self-test done 330 | // Reset AutoTestReg register to be 0 again. Required for normal operation. 331 | PCD_WriteRegister(AutoTestReg, 0x00); 332 | 333 | // Determine firmware version (see section 9.3.4.8 in spec) 334 | byte version = PCD_ReadRegister(VersionReg); 335 | 336 | // Pick the appropriate reference values 337 | const byte *reference; 338 | switch (version) { 339 | case 0x88: // Fudan Semiconductor FM17522 clone 340 | reference = FM17522_firmware_reference; 341 | break; 342 | case 0x90: // Version 0.0 343 | reference = MFRC522_firmware_referenceV0_0; 344 | break; 345 | case 0x91: // Version 1.0 346 | reference = MFRC522_firmware_referenceV1_0; 347 | break; 348 | case 0x92: // Version 2.0 349 | reference = MFRC522_firmware_referenceV2_0; 350 | break; 351 | default: // Unknown version 352 | return false; // abort test 353 | } 354 | 355 | // Verify that the results match up to our expectations 356 | for (i = 0; i < 64; i++) { 357 | if (result[i] != pgm_read_byte(&(reference[i]))) { 358 | return false; 359 | } 360 | } 361 | 362 | // Test passed; all is good. 363 | return true; 364 | } // End PCD_PerformSelfTest() 365 | 366 | ///////////////////////////////////////////////////////////////////////////////////// 367 | // Functions for communicating with PICCs 368 | ///////////////////////////////////////////////////////////////////////////////////// 369 | 370 | /** 371 | * Executes the Transceive command. 372 | * CRC validation can only be done if backData and backLen are specified. 373 | * 374 | * @return STATUS_OK on success, STATUS_??? otherwise. 375 | */ 376 | MFRC522::StatusCode MFRC522::PCD_TransceiveData( byte *sendData, ///< Pointer to the data to transfer to the FIFO. 377 | byte sendLen, ///< Number of bytes to transfer to the FIFO. 378 | byte *backData, ///< NULL or pointer to buffer if data should be read back after executing the command. 379 | byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. 380 | byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. Default NULL. 381 | byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. 382 | bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. 383 | ) { 384 | byte waitIRq = 0x30; // RxIRq and IdleIRq 385 | return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign, checkCRC); 386 | } // End PCD_TransceiveData() 387 | 388 | /** 389 | * Transfers data to the MFRC522 FIFO, executes a command, waits for completion and transfers data back from the FIFO. 390 | * CRC validation can only be done if backData and backLen are specified. 391 | * 392 | * @return STATUS_OK on success, STATUS_??? otherwise. 393 | */ 394 | MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The command to execute. One of the PCD_Command enums. 395 | byte waitIRq, ///< The bits in the ComIrqReg register that signals successful completion of the command. 396 | byte *sendData, ///< Pointer to the data to transfer to the FIFO. 397 | byte sendLen, ///< Number of bytes to transfer to the FIFO. 398 | byte *backData, ///< NULL or pointer to buffer if data should be read back after executing the command. 399 | byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. 400 | byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. 401 | byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. 402 | bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. 403 | ) { 404 | byte n, _validBits; 405 | unsigned int i; 406 | 407 | // Prepare values for BitFramingReg 408 | byte txLastBits = validBits ? *validBits : 0; 409 | byte bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] 410 | 411 | PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. 412 | PCD_WriteRegister(ComIrqReg, 0x7F); // Clear all seven interrupt request bits 413 | PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization 414 | PCD_WriteRegister(FIFODataReg, sendLen, sendData); // Write sendData to the FIFO 415 | PCD_WriteRegister(BitFramingReg, bitFraming); // Bit adjustments 416 | PCD_WriteRegister(CommandReg, command); // Execute the command 417 | if (command == PCD_Transceive) { 418 | PCD_SetRegisterBitMask(BitFramingReg, 0x80); // StartSend=1, transmission of data starts 419 | } 420 | 421 | // Wait for the command to complete. 422 | // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops transmitting. 423 | // Each iteration of the do-while-loop takes 17.86�s. 424 | i = 2000; 425 | while (1) { 426 | n = PCD_ReadRegister(ComIrqReg); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq 427 | if (n & waitIRq) { // One of the interrupts that signal success has been set. 428 | break; 429 | } 430 | if (n & 0x01) { // Timer interrupt - nothing received in 25ms 431 | return STATUS_TIMEOUT; 432 | } 433 | if (--i == 0) { // The emergency break. If all other conditions fail we will eventually terminate on this one after 35.7ms. Communication with the MFRC522 might be down. 434 | return STATUS_TIMEOUT; 435 | } 436 | } 437 | 438 | // Stop now if any errors except collisions were detected. 439 | byte errorRegValue = PCD_ReadRegister(ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr 440 | if (errorRegValue & 0x13) { // BufferOvfl ParityErr ProtocolErr 441 | return STATUS_ERROR; 442 | } 443 | 444 | // If the caller wants data back, get it from the MFRC522. 445 | if (backData && backLen) { 446 | n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO 447 | if (n > *backLen) { 448 | return STATUS_NO_ROOM; 449 | } 450 | *backLen = n; // Number of bytes returned 451 | PCD_ReadRegister(FIFODataReg, n, backData, rxAlign); // Get received data from FIFO 452 | _validBits = PCD_ReadRegister(ControlReg) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last received byte. If this value is 000b, the whole byte is valid. 453 | if (validBits) { 454 | *validBits = _validBits; 455 | } 456 | } 457 | 458 | // Tell about collisions 459 | if (errorRegValue & 0x08) { // CollErr 460 | return STATUS_COLLISION; 461 | } 462 | 463 | // Perform CRC_A validation if requested. 464 | if (backData && backLen && checkCRC) { 465 | // In this case a MIFARE Classic NAK is not OK. 466 | if (*backLen == 1 && _validBits == 4) { 467 | return STATUS_MIFARE_NACK; 468 | } 469 | // We need at least the CRC_A value and all 8 bits of the last byte must be received. 470 | if (*backLen < 2 || _validBits != 0) { 471 | return STATUS_CRC_WRONG; 472 | } 473 | // Verify CRC_A - do our own calculation and store the control in controlBuffer. 474 | byte controlBuffer[2]; 475 | MFRC522::StatusCode status = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]); 476 | if (status != STATUS_OK) { 477 | return status; 478 | } 479 | if ((backData[*backLen - 2] != controlBuffer[0]) || (backData[*backLen - 1] != controlBuffer[1])) { 480 | return STATUS_CRC_WRONG; 481 | } 482 | } 483 | 484 | return STATUS_OK; 485 | } // End PCD_CommunicateWithPICC() 486 | 487 | /** 488 | * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. 489 | * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. 490 | * 491 | * @return STATUS_OK on success, STATUS_??? otherwise. 492 | */ 493 | MFRC522::StatusCode MFRC522::PICC_RequestA( byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in 494 | byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. 495 | ) { 496 | return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize); 497 | } // End PICC_RequestA() 498 | 499 | /** 500 | * Transmits a Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. 501 | * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. 502 | * 503 | * @return STATUS_OK on success, STATUS_??? otherwise. 504 | */ 505 | MFRC522::StatusCode MFRC522::PICC_WakeupA( byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in 506 | byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. 507 | ) { 508 | return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize); 509 | } // End PICC_WakeupA() 510 | 511 | /** 512 | * Transmits REQA or WUPA commands. 513 | * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. 514 | * 515 | * @return STATUS_OK on success, STATUS_??? otherwise. 516 | */ 517 | MFRC522::StatusCode MFRC522::PICC_REQA_or_WUPA( byte command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA 518 | byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in 519 | byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. 520 | ) { 521 | byte validBits; 522 | MFRC522::StatusCode status; 523 | 524 | if (bufferATQA == NULL || *bufferSize < 2) { // The ATQA response is 2 bytes long. 525 | return STATUS_NO_ROOM; 526 | } 527 | PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. 528 | validBits = 7; // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0] 529 | status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits); 530 | if (status != STATUS_OK) { 531 | return status; 532 | } 533 | if (*bufferSize != 2 || validBits != 0) { // ATQA must be exactly 16 bits. 534 | return STATUS_ERROR; 535 | } 536 | return STATUS_OK; 537 | } // End PICC_REQA_or_WUPA() 538 | 539 | /** 540 | * Transmits SELECT/ANTICOLLISION commands to select a single PICC. 541 | * Before calling this function the PICCs must be placed in the READY(*) state by calling PICC_RequestA() or PICC_WakeupA(). 542 | * On success: 543 | * - The chosen PICC is in state ACTIVE(*) and all other PICCs have returned to state IDLE/HALT. (Figure 7 of the ISO/IEC 14443-3 draft.) 544 | * - The UID size and value of the chosen PICC is returned in *uid along with the SAK. 545 | * 546 | * A PICC UID consists of 4, 7 or 10 bytes. 547 | * Only 4 bytes can be specified in a SELECT command, so for the longer UIDs two or three iterations are used: 548 | * UID size Number of UID bytes Cascade levels Example of PICC 549 | * ======== =================== ============== =============== 550 | * single 4 1 MIFARE Classic 551 | * double 7 2 MIFARE Ultralight 552 | * triple 10 3 Not currently in use? 553 | * 554 | * @return STATUS_OK on success, STATUS_??? otherwise. 555 | */ 556 | MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally output, but can also be used to supply a known UID. 557 | byte validBits ///< The number of known UID bits supplied in *uid. Normally 0. If set you must also supply uid->size. 558 | ) { 559 | bool uidComplete; 560 | bool selectDone; 561 | bool useCascadeTag; 562 | byte cascadeLevel = 1; 563 | MFRC522::StatusCode result; 564 | byte count; 565 | byte index; 566 | byte uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level. 567 | int8_t currentLevelKnownBits; // The number of known UID bits in the current Cascade Level. 568 | byte buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A 569 | byte bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO. 570 | byte rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received. 571 | byte txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte. 572 | byte *responseBuffer; 573 | byte responseLength; 574 | 575 | // Description of buffer structure: 576 | // Byte 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3 577 | // Byte 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete bytes, Low nibble: Extra bits. 578 | // Byte 2: UID-data or CT See explanation below. CT means Cascade Tag. 579 | // Byte 3: UID-data 580 | // Byte 4: UID-data 581 | // Byte 5: UID-data 582 | // Byte 6: BCC Block Check Character - XOR of bytes 2-5 583 | // Byte 7: CRC_A 584 | // Byte 8: CRC_A 585 | // The BCC and CRC_A are only transmitted if we know all the UID bits of the current Cascade Level. 586 | // 587 | // Description of bytes 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels) 588 | // UID size Cascade level Byte2 Byte3 Byte4 Byte5 589 | // ======== ============= ===== ===== ===== ===== 590 | // 4 bytes 1 uid0 uid1 uid2 uid3 591 | // 7 bytes 1 CT uid0 uid1 uid2 592 | // 2 uid3 uid4 uid5 uid6 593 | // 10 bytes 1 CT uid0 uid1 uid2 594 | // 2 CT uid3 uid4 uid5 595 | // 3 uid6 uid7 uid8 uid9 596 | 597 | // Sanity checks 598 | if (validBits > 80) { 599 | return STATUS_INVALID; 600 | } 601 | 602 | // Prepare MFRC522 603 | PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. 604 | 605 | // Repeat Cascade Level loop until we have a complete UID. 606 | uidComplete = false; 607 | while (!uidComplete) { 608 | // Set the Cascade Level in the SEL byte, find out if we need to use the Cascade Tag in byte 2. 609 | switch (cascadeLevel) { 610 | case 1: 611 | buffer[0] = PICC_CMD_SEL_CL1; 612 | uidIndex = 0; 613 | useCascadeTag = validBits && uid->size > 4; // When we know that the UID has more than 4 bytes 614 | break; 615 | 616 | case 2: 617 | buffer[0] = PICC_CMD_SEL_CL2; 618 | uidIndex = 3; 619 | useCascadeTag = validBits && uid->size > 7; // When we know that the UID has more than 7 bytes 620 | break; 621 | 622 | case 3: 623 | buffer[0] = PICC_CMD_SEL_CL3; 624 | uidIndex = 6; 625 | useCascadeTag = false; // Never used in CL3. 626 | break; 627 | 628 | default: 629 | return STATUS_INTERNAL_ERROR; 630 | break; 631 | } 632 | 633 | // How many UID bits are known in this Cascade Level? 634 | currentLevelKnownBits = validBits - (8 * uidIndex); 635 | if (currentLevelKnownBits < 0) { 636 | currentLevelKnownBits = 0; 637 | } 638 | // Copy the known bits from uid->uidByte[] to buffer[] 639 | index = 2; // destination index in buffer[] 640 | if (useCascadeTag) { 641 | buffer[index++] = PICC_CMD_CT; 642 | } 643 | byte bytesToCopy = currentLevelKnownBits / 8 + (currentLevelKnownBits % 8 ? 1 : 0); // The number of bytes needed to represent the known bits for this level. 644 | if (bytesToCopy) { 645 | byte maxBytes = useCascadeTag ? 3 : 4; // Max 4 bytes in each Cascade Level. Only 3 left if we use the Cascade Tag 646 | if (bytesToCopy > maxBytes) { 647 | bytesToCopy = maxBytes; 648 | } 649 | for (count = 0; count < bytesToCopy; count++) { 650 | buffer[index++] = uid->uidByte[uidIndex + count]; 651 | } 652 | } 653 | // Now that the data has been copied we need to include the 8 bits in CT in currentLevelKnownBits 654 | if (useCascadeTag) { 655 | currentLevelKnownBits += 8; 656 | } 657 | 658 | // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations. 659 | selectDone = false; 660 | while (!selectDone) { 661 | // Find out how many bits and bytes to send and receive. 662 | if (currentLevelKnownBits >= 32) { // All UID bits in this Cascade Level are known. This is a SELECT. 663 | //Serial.print(F("SELECT: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); 664 | buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole bytes 665 | // Calculate BCC - Block Check Character 666 | buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; 667 | // Calculate CRC_A 668 | result = PCD_CalculateCRC(buffer, 7, &buffer[7]); 669 | if (result != STATUS_OK) { 670 | return result; 671 | } 672 | txLastBits = 0; // 0 => All 8 bits are valid. 673 | bufferUsed = 9; 674 | // Store response in the last 3 bytes of buffer (BCC and CRC_A - not needed after tx) 675 | responseBuffer = &buffer[6]; 676 | responseLength = 3; 677 | } 678 | else { // This is an ANTICOLLISION. 679 | //Serial.print(F("ANTICOLLISION: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); 680 | txLastBits = currentLevelKnownBits % 8; 681 | count = currentLevelKnownBits / 8; // Number of whole bytes in the UID part. 682 | index = 2 + count; // Number of whole bytes: SEL + NVB + UIDs 683 | buffer[1] = (index << 4) + txLastBits; // NVB - Number of Valid Bits 684 | bufferUsed = index + (txLastBits ? 1 : 0); 685 | // Store response in the unused part of buffer 686 | responseBuffer = &buffer[index]; 687 | responseLength = sizeof(buffer) - index; 688 | } 689 | 690 | // Set bit adjustments 691 | rxAlign = txLastBits; // Having a separate variable is overkill. But it makes the next line easier to read. 692 | PCD_WriteRegister(BitFramingReg, (rxAlign << 4) + txLastBits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] 693 | 694 | // Transmit the buffer and receive the response. 695 | result = PCD_TransceiveData(buffer, bufferUsed, responseBuffer, &responseLength, &txLastBits, rxAlign); 696 | if (result == STATUS_COLLISION) { // More than one PICC in the field => collision. 697 | byte valueOfCollReg = PCD_ReadRegister(CollReg); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0] 698 | if (valueOfCollReg & 0x20) { // CollPosNotValid 699 | return STATUS_COLLISION; // Without a valid collision position we cannot continue 700 | } 701 | byte collisionPos = valueOfCollReg & 0x1F; // Values 0-31, 0 means bit 32. 702 | if (collisionPos == 0) { 703 | collisionPos = 32; 704 | } 705 | if (collisionPos <= currentLevelKnownBits) { // No progress - should not happen 706 | return STATUS_INTERNAL_ERROR; 707 | } 708 | // Choose the PICC with the bit set. 709 | currentLevelKnownBits = collisionPos; 710 | count = (currentLevelKnownBits - 1) % 8; // The bit to modify 711 | index = 1 + (currentLevelKnownBits / 8) + (count ? 1 : 0); // First byte is index 0. 712 | buffer[index] |= (1 << count); 713 | } 714 | else if (result != STATUS_OK) { 715 | return result; 716 | } 717 | else { // STATUS_OK 718 | if (currentLevelKnownBits >= 32) { // This was a SELECT. 719 | selectDone = true; // No more anticollision 720 | // We continue below outside the while. 721 | } 722 | else { // This was an ANTICOLLISION. 723 | // We now have all 32 bits of the UID in this Cascade Level 724 | currentLevelKnownBits = 32; 725 | // Run loop again to do the SELECT. 726 | } 727 | } 728 | } // End of while (!selectDone) 729 | 730 | // We do not check the CBB - it was constructed by us above. 731 | 732 | // Copy the found UID bytes from buffer[] to uid->uidByte[] 733 | index = (buffer[2] == PICC_CMD_CT) ? 3 : 2; // source index in buffer[] 734 | bytesToCopy = (buffer[2] == PICC_CMD_CT) ? 3 : 4; 735 | for (count = 0; count < bytesToCopy; count++) { 736 | uid->uidByte[uidIndex + count] = buffer[index++]; 737 | } 738 | 739 | // Check response SAK (Select Acknowledge) 740 | if (responseLength != 3 || txLastBits != 0) { // SAK must be exactly 24 bits (1 byte + CRC_A). 741 | return STATUS_ERROR; 742 | } 743 | // Verify CRC_A - do our own calculation and store the control in buffer[2..3] - those bytes are not needed anymore. 744 | result = PCD_CalculateCRC(responseBuffer, 1, &buffer[2]); 745 | if (result != STATUS_OK) { 746 | return result; 747 | } 748 | if ((buffer[2] != responseBuffer[1]) || (buffer[3] != responseBuffer[2])) { 749 | return STATUS_CRC_WRONG; 750 | } 751 | if (responseBuffer[0] & 0x04) { // Cascade bit set - UID not complete yes 752 | cascadeLevel++; 753 | } 754 | else { 755 | uidComplete = true; 756 | uid->sak = responseBuffer[0]; 757 | } 758 | } // End of while (!uidComplete) 759 | 760 | // Set correct uid->size 761 | uid->size = 3 * cascadeLevel + 1; 762 | 763 | return STATUS_OK; 764 | } // End PICC_Select() 765 | 766 | /** 767 | * Instructs a PICC in state ACTIVE(*) to go to state HALT. 768 | * 769 | * @return STATUS_OK on success, STATUS_??? otherwise. 770 | */ 771 | MFRC522::StatusCode MFRC522::PICC_HaltA() { 772 | MFRC522::StatusCode result; 773 | byte buffer[4]; 774 | 775 | // Build command buffer 776 | buffer[0] = PICC_CMD_HLTA; 777 | buffer[1] = 0; 778 | // Calculate CRC_A 779 | result = PCD_CalculateCRC(buffer, 2, &buffer[2]); 780 | if (result != STATUS_OK) { 781 | return result; 782 | } 783 | 784 | // Send the command. 785 | // The standard says: 786 | // If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the 787 | // HLTA command, this response shall be interpreted as 'not acknowledge'. 788 | // We interpret that this way: Only STATUS_TIMEOUT is a success. 789 | result = PCD_TransceiveData(buffer, sizeof(buffer), NULL, 0); 790 | if (result == STATUS_TIMEOUT) { 791 | return STATUS_OK; 792 | } 793 | if (result == STATUS_OK) { // That is ironically NOT ok in this case ;-) 794 | return STATUS_ERROR; 795 | } 796 | return result; 797 | } // End PICC_HaltA() 798 | 799 | 800 | ///////////////////////////////////////////////////////////////////////////////////// 801 | // Functions for communicating with MIFARE PICCs 802 | ///////////////////////////////////////////////////////////////////////////////////// 803 | 804 | /** 805 | * Executes the MFRC522 MFAuthent command. 806 | * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card. 807 | * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1. 808 | * For use with MIFARE Classic PICCs. 809 | * The PICC must be selected - ie in state ACTIVE(*) - before calling this function. 810 | * Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start. 811 | * 812 | * All keys are set to FFFFFFFFFFFFh at chip delivery. 813 | * 814 | * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key. 815 | */ 816 | MFRC522::StatusCode MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B 817 | byte blockAddr, ///< The block number. See numbering in the comments in the .h file. 818 | MIFARE_Key *key, ///< Pointer to the Crypteo1 key to use (6 bytes) 819 | Uid *uid ///< Pointer to Uid struct. The first 4 bytes of the UID is used. 820 | ) { 821 | byte waitIRq = 0x10; // IdleIRq 822 | 823 | // Build command buffer 824 | byte sendData[12]; 825 | sendData[0] = command; 826 | sendData[1] = blockAddr; 827 | for (byte i = 0; i < MF_KEY_SIZE; i++) { // 6 key bytes 828 | sendData[2+i] = key->keyByte[i]; 829 | } 830 | for (byte i = 0; i < 4; i++) { // The first 4 bytes of the UID 831 | sendData[8+i] = uid->uidByte[i]; 832 | } 833 | 834 | // Start the authentication. 835 | return PCD_CommunicateWithPICC(PCD_MFAuthent, waitIRq, &sendData[0], sizeof(sendData)); 836 | } // End PCD_Authenticate() 837 | 838 | /** 839 | * Used to exit the PCD from its authenticated state. 840 | * Remember to call this function after communicating with an authenticated PICC - otherwise no new communications can start. 841 | */ 842 | void MFRC522::PCD_StopCrypto1() { 843 | // Clear MFCrypto1On bit 844 | PCD_ClearRegisterBitMask(Status2Reg, 0x08); // Status2Reg[7..0] bits are: TempSensClear I2CForceHS reserved reserved MFCrypto1On ModemState[2:0] 845 | } // End PCD_StopCrypto1() 846 | 847 | /** 848 | * Reads 16 bytes (+ 2 bytes CRC_A) from the active PICC. 849 | * 850 | * For MIFARE Classic the sector containing the block must be authenticated before calling this function. 851 | * 852 | * For MIFARE Ultralight only addresses 00h to 0Fh are decoded. 853 | * The MF0ICU1 returns a NAK for higher addresses. 854 | * The MF0ICU1 responds to the READ command by sending 16 bytes starting from the page address defined by the command argument. 855 | * For example; if blockAddr is 03h then pages 03h, 04h, 05h, 06h are returned. 856 | * A roll-back is implemented: If blockAddr is 0Eh, then the contents of pages 0Eh, 0Fh, 00h and 01h are returned. 857 | * 858 | * The buffer must be at least 18 bytes because a CRC_A is also returned. 859 | * Checks the CRC_A before returning STATUS_OK. 860 | * 861 | * @return STATUS_OK on success, STATUS_??? otherwise. 862 | */ 863 | MFRC522::StatusCode MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from. 864 | byte *buffer, ///< The buffer to store the data in 865 | byte *bufferSize ///< Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK. 866 | ) { 867 | MFRC522::StatusCode result; 868 | 869 | // Sanity check 870 | if (buffer == NULL || *bufferSize < 18) { 871 | return STATUS_NO_ROOM; 872 | } 873 | 874 | // Build command buffer 875 | buffer[0] = PICC_CMD_MF_READ; 876 | buffer[1] = blockAddr; 877 | // Calculate CRC_A 878 | result = PCD_CalculateCRC(buffer, 2, &buffer[2]); 879 | if (result != STATUS_OK) { 880 | return result; 881 | } 882 | 883 | // Transmit the buffer and receive the response, validate CRC_A. 884 | return PCD_TransceiveData(buffer, 4, buffer, bufferSize, NULL, 0, true); 885 | } // End MIFARE_Read() 886 | 887 | /** 888 | * Writes 16 bytes to the active PICC. 889 | * 890 | * For MIFARE Classic the sector containing the block must be authenticated before calling this function. 891 | * 892 | * For MIFARE Ultralight the operation is called "COMPATIBILITY WRITE". 893 | * Even though 16 bytes are transferred to the Ultralight PICC, only the least significant 4 bytes (bytes 0 to 3) 894 | * are written to the specified address. It is recommended to set the remaining bytes 04h to 0Fh to all logic 0. 895 | * * 896 | * @return STATUS_OK on success, STATUS_??? otherwise. 897 | */ 898 | MFRC522::StatusCode MFRC522::MIFARE_Write( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to. 899 | byte *buffer, ///< The 16 bytes to write to the PICC 900 | byte bufferSize ///< Buffer size, must be at least 16 bytes. Exactly 16 bytes are written. 901 | ) { 902 | MFRC522::StatusCode result; 903 | 904 | // Sanity check 905 | if (buffer == NULL || bufferSize < 16) { 906 | return STATUS_INVALID; 907 | } 908 | 909 | // Mifare Classic protocol requires two communications to perform a write. 910 | // Step 1: Tell the PICC we want to write to block blockAddr. 911 | byte cmdBuffer[2]; 912 | cmdBuffer[0] = PICC_CMD_MF_WRITE; 913 | cmdBuffer[1] = blockAddr; 914 | result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. 915 | if (result != STATUS_OK) { 916 | return result; 917 | } 918 | 919 | // Step 2: Transfer the data 920 | result = PCD_MIFARE_Transceive(buffer, bufferSize); // Adds CRC_A and checks that the response is MF_ACK. 921 | if (result != STATUS_OK) { 922 | return result; 923 | } 924 | 925 | return STATUS_OK; 926 | } // End MIFARE_Write() 927 | 928 | /** 929 | * Writes a 4 byte page to the active MIFARE Ultralight PICC. 930 | * 931 | * @return STATUS_OK on success, STATUS_??? otherwise. 932 | */ 933 | MFRC522::StatusCode MFRC522::MIFARE_Ultralight_Write( byte page, ///< The page (2-15) to write to. 934 | byte *buffer, ///< The 4 bytes to write to the PICC 935 | byte bufferSize ///< Buffer size, must be at least 4 bytes. Exactly 4 bytes are written. 936 | ) { 937 | MFRC522::StatusCode result; 938 | 939 | // Sanity check 940 | if (buffer == NULL || bufferSize < 4) { 941 | return STATUS_INVALID; 942 | } 943 | 944 | // Build commmand buffer 945 | byte cmdBuffer[6]; 946 | cmdBuffer[0] = PICC_CMD_UL_WRITE; 947 | cmdBuffer[1] = page; 948 | memcpy(&cmdBuffer[2], buffer, 4); 949 | 950 | // Perform the write 951 | result = PCD_MIFARE_Transceive(cmdBuffer, 6); // Adds CRC_A and checks that the response is MF_ACK. 952 | if (result != STATUS_OK) { 953 | return result; 954 | } 955 | return STATUS_OK; 956 | } // End MIFARE_Ultralight_Write() 957 | 958 | /** 959 | * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory. 960 | * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. 961 | * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. 962 | * Use MIFARE_Transfer() to store the result in a block. 963 | * 964 | * @return STATUS_OK on success, STATUS_??? otherwise. 965 | */ 966 | MFRC522::StatusCode MFRC522::MIFARE_Decrement( byte blockAddr, ///< The block (0-0xff) number. 967 | long delta ///< This number is subtracted from the value of block blockAddr. 968 | ) { 969 | return MIFARE_TwoStepHelper(PICC_CMD_MF_DECREMENT, blockAddr, delta); 970 | } // End MIFARE_Decrement() 971 | 972 | /** 973 | * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory. 974 | * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. 975 | * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. 976 | * Use MIFARE_Transfer() to store the result in a block. 977 | * 978 | * @return STATUS_OK on success, STATUS_??? otherwise. 979 | */ 980 | MFRC522::StatusCode MFRC522::MIFARE_Increment( byte blockAddr, ///< The block (0-0xff) number. 981 | long delta ///< This number is added to the value of block blockAddr. 982 | ) { 983 | return MIFARE_TwoStepHelper(PICC_CMD_MF_INCREMENT, blockAddr, delta); 984 | } // End MIFARE_Increment() 985 | 986 | /** 987 | * MIFARE Restore copies the value of the addressed block into a volatile memory. 988 | * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. 989 | * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. 990 | * Use MIFARE_Transfer() to store the result in a block. 991 | * 992 | * @return STATUS_OK on success, STATUS_??? otherwise. 993 | */ 994 | MFRC522::StatusCode MFRC522::MIFARE_Restore( byte blockAddr ///< The block (0-0xff) number. 995 | ) { 996 | // The datasheet describes Restore as a two step operation, but does not explain what data to transfer in step 2. 997 | // Doing only a single step does not work, so I chose to transfer 0L in step two. 998 | return MIFARE_TwoStepHelper(PICC_CMD_MF_RESTORE, blockAddr, 0L); 999 | } // End MIFARE_Restore() 1000 | 1001 | /** 1002 | * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. 1003 | * 1004 | * @return STATUS_OK on success, STATUS_??? otherwise. 1005 | */ 1006 | MFRC522::StatusCode MFRC522::MIFARE_TwoStepHelper( byte command, ///< The command to use 1007 | byte blockAddr, ///< The block (0-0xff) number. 1008 | long data ///< The data to transfer in step 2 1009 | ) { 1010 | MFRC522::StatusCode result; 1011 | byte cmdBuffer[2]; // We only need room for 2 bytes. 1012 | 1013 | // Step 1: Tell the PICC the command and block address 1014 | cmdBuffer[0] = command; 1015 | cmdBuffer[1] = blockAddr; 1016 | result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. 1017 | if (result != STATUS_OK) { 1018 | return result; 1019 | } 1020 | 1021 | // Step 2: Transfer the data 1022 | result = PCD_MIFARE_Transceive( (byte *)&data, 4, true); // Adds CRC_A and accept timeout as success. 1023 | if (result != STATUS_OK) { 1024 | return result; 1025 | } 1026 | 1027 | return STATUS_OK; 1028 | } // End MIFARE_TwoStepHelper() 1029 | 1030 | /** 1031 | * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. 1032 | * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. 1033 | * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. 1034 | * 1035 | * @return STATUS_OK on success, STATUS_??? otherwise. 1036 | */ 1037 | MFRC522::StatusCode MFRC522::MIFARE_Transfer( byte blockAddr ///< The block (0-0xff) number. 1038 | ) { 1039 | MFRC522::StatusCode result; 1040 | byte cmdBuffer[2]; // We only need room for 2 bytes. 1041 | 1042 | // Tell the PICC we want to transfer the result into block blockAddr. 1043 | cmdBuffer[0] = PICC_CMD_MF_TRANSFER; 1044 | cmdBuffer[1] = blockAddr; 1045 | result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. 1046 | if (result != STATUS_OK) { 1047 | return result; 1048 | } 1049 | return STATUS_OK; 1050 | } // End MIFARE_Transfer() 1051 | 1052 | /** 1053 | * Helper routine to read the current value from a Value Block. 1054 | * 1055 | * Only for MIFARE Classic and only for blocks in "value block" mode, that 1056 | * is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing 1057 | * the block must be authenticated before calling this function. 1058 | * 1059 | * @param[in] blockAddr The block (0x00-0xff) number. 1060 | * @param[out] value Current value of the Value Block. 1061 | * @return STATUS_OK on success, STATUS_??? otherwise. 1062 | */ 1063 | MFRC522::StatusCode MFRC522::MIFARE_GetValue(byte blockAddr, long *value) { 1064 | MFRC522::StatusCode status; 1065 | byte buffer[18]; 1066 | byte size = sizeof(buffer); 1067 | 1068 | // Read the block 1069 | status = MIFARE_Read(blockAddr, buffer, &size); 1070 | if (status == STATUS_OK) { 1071 | // Extract the value 1072 | *value = (long(buffer[3])<<24) | (long(buffer[2])<<16) | (long(buffer[1])<<8) | long(buffer[0]); 1073 | } 1074 | return status; 1075 | } // End MIFARE_GetValue() 1076 | 1077 | /** 1078 | * Helper routine to write a specific value into a Value Block. 1079 | * 1080 | * Only for MIFARE Classic and only for blocks in "value block" mode, that 1081 | * is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing 1082 | * the block must be authenticated before calling this function. 1083 | * 1084 | * @param[in] blockAddr The block (0x00-0xff) number. 1085 | * @param[in] value New value of the Value Block. 1086 | * @return STATUS_OK on success, STATUS_??? otherwise. 1087 | */ 1088 | MFRC522::StatusCode MFRC522::MIFARE_SetValue(byte blockAddr, long value) { 1089 | byte buffer[18]; 1090 | 1091 | // Translate the long into 4 bytes; repeated 2x in value block 1092 | buffer[0] = buffer[ 8] = (value & 0xFF); 1093 | buffer[1] = buffer[ 9] = (value & 0xFF00) >> 8; 1094 | buffer[2] = buffer[10] = (value & 0xFF0000) >> 16; 1095 | buffer[3] = buffer[11] = (value & 0xFF000000) >> 24; 1096 | // Inverse 4 bytes also found in value block 1097 | buffer[4] = ~buffer[0]; 1098 | buffer[5] = ~buffer[1]; 1099 | buffer[6] = ~buffer[2]; 1100 | buffer[7] = ~buffer[3]; 1101 | // Address 2x with inverse address 2x 1102 | buffer[12] = buffer[14] = blockAddr; 1103 | buffer[13] = buffer[15] = ~blockAddr; 1104 | 1105 | // Write the whole data block 1106 | return MIFARE_Write(blockAddr, buffer, 16); 1107 | } // End MIFARE_SetValue() 1108 | 1109 | /** 1110 | * Authenticate with a NTAG216. 1111 | * 1112 | * Only for NTAG216. First implemented by Gargantuanman. 1113 | * 1114 | * @param[in] passWord password. 1115 | * @param[in] pACK result success???. 1116 | * @return STATUS_OK on success, STATUS_??? otherwise. 1117 | */ 1118 | MFRC522::StatusCode MFRC522::PCD_NTAG216_AUTH(byte* passWord, byte pACK[]) //Authenticate with 32bit password 1119 | { 1120 | MFRC522::StatusCode result; 1121 | byte cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A. 1122 | 1123 | cmdBuffer[0] = 0x1B; //Comando de autentificacion 1124 | 1125 | for (byte i = 0; i<4; i++) 1126 | cmdBuffer[i+1] = passWord[i]; 1127 | 1128 | result = PCD_CalculateCRC(cmdBuffer, 5, &cmdBuffer[5]); 1129 | 1130 | if (result!=STATUS_OK) { 1131 | return result; 1132 | } 1133 | 1134 | // Transceive the data, store the reply in cmdBuffer[] 1135 | byte waitIRq = 0x30; // RxIRq and IdleIRq 1136 | byte cmdBufferSize = sizeof(cmdBuffer); 1137 | byte validBits = 0; 1138 | byte rxlength = 5; 1139 | result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, 7, cmdBuffer, &rxlength, &validBits); 1140 | 1141 | pACK[0] = cmdBuffer[0]; 1142 | pACK[1] = cmdBuffer[1]; 1143 | 1144 | if (result!=STATUS_OK) { 1145 | return result; 1146 | } 1147 | 1148 | return STATUS_OK; 1149 | } // End PCD_NTAG216_AUTH() 1150 | 1151 | 1152 | ///////////////////////////////////////////////////////////////////////////////////// 1153 | // Support functions 1154 | ///////////////////////////////////////////////////////////////////////////////////// 1155 | 1156 | /** 1157 | * Wrapper for MIFARE protocol communication. 1158 | * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout. 1159 | * 1160 | * @return STATUS_OK on success, STATUS_??? otherwise. 1161 | */ 1162 | MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointer to the data to transfer to the FIFO. Do NOT include the CRC_A. 1163 | byte sendLen, ///< Number of bytes in sendData. 1164 | bool acceptTimeout ///< True => A timeout is also success 1165 | ) { 1166 | MFRC522::StatusCode result; 1167 | byte cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A. 1168 | 1169 | // Sanity check 1170 | if (sendData == NULL || sendLen > 16) { 1171 | return STATUS_INVALID; 1172 | } 1173 | 1174 | // Copy sendData[] to cmdBuffer[] and add CRC_A 1175 | memcpy(cmdBuffer, sendData, sendLen); 1176 | result = PCD_CalculateCRC(cmdBuffer, sendLen, &cmdBuffer[sendLen]); 1177 | if (result != STATUS_OK) { 1178 | return result; 1179 | } 1180 | sendLen += 2; 1181 | 1182 | // Transceive the data, store the reply in cmdBuffer[] 1183 | byte waitIRq = 0x30; // RxIRq and IdleIRq 1184 | byte cmdBufferSize = sizeof(cmdBuffer); 1185 | byte validBits = 0; 1186 | result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, sendLen, cmdBuffer, &cmdBufferSize, &validBits); 1187 | if (acceptTimeout && result == STATUS_TIMEOUT) { 1188 | return STATUS_OK; 1189 | } 1190 | if (result != STATUS_OK) { 1191 | return result; 1192 | } 1193 | // The PICC must reply with a 4 bit ACK 1194 | if (cmdBufferSize != 1 || validBits != 4) { 1195 | return STATUS_ERROR; 1196 | } 1197 | if (cmdBuffer[0] != MF_ACK) { 1198 | return STATUS_MIFARE_NACK; 1199 | } 1200 | return STATUS_OK; 1201 | } // End PCD_MIFARE_Transceive() 1202 | 1203 | /** 1204 | * Returns a __FlashStringHelper pointer to a status code name. 1205 | * 1206 | * @return const __FlashStringHelper * 1207 | */ 1208 | const __FlashStringHelper *MFRC522::GetStatusCodeName(MFRC522::StatusCode code ///< One of the StatusCode enums. 1209 | ) { 1210 | switch (code) { 1211 | case STATUS_OK: return F("Success."); 1212 | case STATUS_ERROR: return F("Error in communication."); 1213 | case STATUS_COLLISION: return F("Collission detected."); 1214 | case STATUS_TIMEOUT: return F("Timeout in communication."); 1215 | case STATUS_NO_ROOM: return F("A buffer is not big enough."); 1216 | case STATUS_INTERNAL_ERROR: return F("Internal error in the code. Should not happen."); 1217 | case STATUS_INVALID: return F("Invalid argument."); 1218 | case STATUS_CRC_WRONG: return F("The CRC_A does not match."); 1219 | case STATUS_MIFARE_NACK: return F("A MIFARE PICC responded with NAK."); 1220 | default: return F("Unknown error"); 1221 | } 1222 | } // End GetStatusCodeName() 1223 | 1224 | /** 1225 | * Translates the SAK (Select Acknowledge) to a PICC type. 1226 | * 1227 | * @return PICC_Type 1228 | */ 1229 | MFRC522::PICC_Type MFRC522::PICC_GetType(byte sak ///< The SAK byte returned from PICC_Select(). 1230 | ) { 1231 | // http://www.nxp.com/documents/application_note/AN10833.pdf 1232 | // 3.2 Coding of Select Acknowledge (SAK) 1233 | // ignore 8-bit (iso14443 starts with LSBit = bit 1) 1234 | // fixes wrong type for manufacturer Infineon (http://nfc-tools.org/index.php?title=ISO14443A) 1235 | sak &= 0x7F; 1236 | switch (sak) { 1237 | case 0x04: return PICC_TYPE_NOT_COMPLETE; // UID not complete 1238 | case 0x09: return PICC_TYPE_MIFARE_MINI; 1239 | case 0x08: return PICC_TYPE_MIFARE_1K; 1240 | case 0x18: return PICC_TYPE_MIFARE_4K; 1241 | case 0x00: return PICC_TYPE_MIFARE_UL; 1242 | case 0x10: 1243 | case 0x11: return PICC_TYPE_MIFARE_PLUS; 1244 | case 0x01: return PICC_TYPE_TNP3XXX; 1245 | case 0x20: return PICC_TYPE_ISO_14443_4; 1246 | case 0x40: return PICC_TYPE_ISO_18092; 1247 | default: return PICC_TYPE_UNKNOWN; 1248 | } 1249 | } // End PICC_GetType() 1250 | 1251 | /** 1252 | * Returns a __FlashStringHelper pointer to the PICC type name. 1253 | * 1254 | * @return const __FlashStringHelper * 1255 | */ 1256 | const __FlashStringHelper *MFRC522::PICC_GetTypeName(PICC_Type piccType ///< One of the PICC_Type enums. 1257 | ) { 1258 | switch (piccType) { 1259 | case PICC_TYPE_ISO_14443_4: return F("PICC compliant with ISO/IEC 14443-4"); 1260 | case PICC_TYPE_ISO_18092: return F("PICC compliant with ISO/IEC 18092 (NFC)"); 1261 | case PICC_TYPE_MIFARE_MINI: return F("MIFARE Mini, 320 bytes"); 1262 | case PICC_TYPE_MIFARE_1K: return F("MIFARE 1KB"); 1263 | case PICC_TYPE_MIFARE_4K: return F("MIFARE 4KB"); 1264 | case PICC_TYPE_MIFARE_UL: return F("MIFARE Ultralight or Ultralight C"); 1265 | case PICC_TYPE_MIFARE_PLUS: return F("MIFARE Plus"); 1266 | case PICC_TYPE_TNP3XXX: return F("MIFARE TNP3XXX"); 1267 | case PICC_TYPE_NOT_COMPLETE: return F("SAK indicates UID is not complete."); 1268 | case PICC_TYPE_UNKNOWN: 1269 | default: return F("Unknown type"); 1270 | } 1271 | } // End PICC_GetTypeName() 1272 | 1273 | /** 1274 | * Dumps debug info about the connected PCD to Serial. 1275 | * Shows all known firmware versions 1276 | */ 1277 | void MFRC522::PCD_DumpVersionToSerial() { 1278 | // Get the MFRC522 firmware version 1279 | byte v = PCD_ReadRegister(VersionReg); 1280 | Serial.print(F("Firmware Version: 0x")); 1281 | Serial.print(v, HEX); 1282 | // Lookup which version 1283 | switch(v) { 1284 | case 0x88: Serial.println(F(" = (clone)")); break; 1285 | case 0x90: Serial.println(F(" = v0.0")); break; 1286 | case 0x91: Serial.println(F(" = v1.0")); break; 1287 | case 0x92: Serial.println(F(" = v2.0")); break; 1288 | default: Serial.println(F(" = (unknown)")); 1289 | } 1290 | // When 0x00 or 0xFF is returned, communication probably failed 1291 | if ((v == 0x00) || (v == 0xFF)) 1292 | Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?")); 1293 | } // End PCD_DumpVersionToSerial() 1294 | 1295 | /** 1296 | * Dumps debug info about the selected PICC to Serial. 1297 | * On success the PICC is halted after dumping the data. 1298 | * For MIFARE Classic the factory default key of 0xFFFFFFFFFFFF is tried. 1299 | */ 1300 | void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). 1301 | ) { 1302 | MIFARE_Key key; 1303 | 1304 | // Dump UID, SAK and Type 1305 | PICC_DumpDetailsToSerial(uid); 1306 | 1307 | // Dump contents 1308 | PICC_Type piccType = PICC_GetType(uid->sak); 1309 | switch (piccType) { 1310 | case PICC_TYPE_MIFARE_MINI: 1311 | case PICC_TYPE_MIFARE_1K: 1312 | case PICC_TYPE_MIFARE_4K: 1313 | // All keys are set to FFFFFFFFFFFFh at chip delivery from the factory. 1314 | for (byte i = 0; i < 6; i++) { 1315 | key.keyByte[i] = 0xFF; 1316 | } 1317 | PICC_DumpMifareClassicToSerial(uid, piccType, &key); 1318 | break; 1319 | 1320 | case PICC_TYPE_MIFARE_UL: 1321 | PICC_DumpMifareUltralightToSerial(); 1322 | break; 1323 | 1324 | case PICC_TYPE_ISO_14443_4: 1325 | case PICC_TYPE_ISO_18092: 1326 | case PICC_TYPE_MIFARE_PLUS: 1327 | case PICC_TYPE_TNP3XXX: 1328 | Serial.println(F("Dumping memory contents not implemented for that PICC type.")); 1329 | break; 1330 | 1331 | case PICC_TYPE_UNKNOWN: 1332 | case PICC_TYPE_NOT_COMPLETE: 1333 | default: 1334 | break; // No memory dump here 1335 | } 1336 | 1337 | Serial.println(); 1338 | PICC_HaltA(); // Already done if it was a MIFARE Classic PICC. 1339 | } // End PICC_DumpToSerial() 1340 | 1341 | /** 1342 | * Dumps card info (UID,SAK,Type) about the selected PICC to Serial. 1343 | */ 1344 | void MFRC522::PICC_DumpDetailsToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). 1345 | ) { 1346 | // UID 1347 | Serial.print(F("Card UID:")); 1348 | for (byte i = 0; i < uid->size; i++) { 1349 | if(uid->uidByte[i] < 0x10) 1350 | Serial.print(F(" 0")); 1351 | else 1352 | Serial.print(F(" ")); 1353 | Serial.print(uid->uidByte[i], HEX); 1354 | } 1355 | Serial.println(); 1356 | 1357 | // SAK 1358 | Serial.print(F("Card SAK: ")); 1359 | if(uid->sak < 0x10) 1360 | Serial.print(F("0")); 1361 | Serial.println(uid->sak, HEX); 1362 | 1363 | // (suggested) PICC type 1364 | PICC_Type piccType = PICC_GetType(uid->sak); 1365 | Serial.print(F("PICC type: ")); 1366 | Serial.println(PICC_GetTypeName(piccType)); 1367 | } // End PICC_DumpDetailsToSerial() 1368 | 1369 | /** 1370 | * Dumps memory contents of a MIFARE Classic PICC. 1371 | * On success the PICC is halted after dumping the data. 1372 | */ 1373 | void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). 1374 | PICC_Type piccType, ///< One of the PICC_Type enums. 1375 | MIFARE_Key *key ///< Key A used for all sectors. 1376 | ) { 1377 | byte no_of_sectors = 0; 1378 | switch (piccType) { 1379 | case PICC_TYPE_MIFARE_MINI: 1380 | // Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. 1381 | no_of_sectors = 5; 1382 | break; 1383 | 1384 | case PICC_TYPE_MIFARE_1K: 1385 | // Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. 1386 | no_of_sectors = 16; 1387 | break; 1388 | 1389 | case PICC_TYPE_MIFARE_4K: 1390 | // Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. 1391 | no_of_sectors = 40; 1392 | break; 1393 | 1394 | default: // Should not happen. Ignore. 1395 | break; 1396 | } 1397 | 1398 | // Dump sectors, highest address first. 1399 | if (no_of_sectors) { 1400 | Serial.println(F("Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits")); 1401 | for (int8_t i = no_of_sectors - 1; i >= 0; i--) { 1402 | PICC_DumpMifareClassicSectorToSerial(uid, key, i); 1403 | } 1404 | } 1405 | PICC_HaltA(); // Halt the PICC before stopping the encrypted session. 1406 | PCD_StopCrypto1(); 1407 | } // End PICC_DumpMifareClassicToSerial() 1408 | 1409 | /** 1410 | * Dumps memory contents of a sector of a MIFARE Classic PICC. 1411 | * Uses PCD_Authenticate(), MIFARE_Read() and PCD_StopCrypto1. 1412 | * Always uses PICC_CMD_MF_AUTH_KEY_A because only Key A can always read the sector trailer access bits. 1413 | */ 1414 | void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). 1415 | MIFARE_Key *key, ///< Key A for the sector. 1416 | byte sector ///< The sector to dump, 0..39. 1417 | ) { 1418 | MFRC522::StatusCode status; 1419 | byte firstBlock; // Address of lowest address to dump actually last block dumped) 1420 | byte no_of_blocks; // Number of blocks in sector 1421 | bool isSectorTrailer; // Set to true while handling the "last" (ie highest address) in the sector. 1422 | 1423 | // The access bits are stored in a peculiar fashion. 1424 | // There are four groups: 1425 | // g[3] Access bits for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) 1426 | // g[2] Access bits for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) 1427 | // g[1] Access bits for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) 1428 | // g[0] Access bits for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) 1429 | // Each group has access bits [C1 C2 C3]. In this code C1 is MSB and C3 is LSB. 1430 | // The four CX bits are stored together in a nible cx and an inverted nible cx_. 1431 | byte c1, c2, c3; // Nibbles 1432 | byte c1_, c2_, c3_; // Inverted nibbles 1433 | bool invertedError; // True if one of the inverted nibbles did not match 1434 | byte g[4]; // Access bits for each of the four groups. 1435 | byte group; // 0-3 - active group for access bits 1436 | bool firstInGroup; // True for the first block dumped in the group 1437 | 1438 | // Determine position and size of sector. 1439 | if (sector < 32) { // Sectors 0..31 has 4 blocks each 1440 | no_of_blocks = 4; 1441 | firstBlock = sector * no_of_blocks; 1442 | } 1443 | else if (sector < 40) { // Sectors 32-39 has 16 blocks each 1444 | no_of_blocks = 16; 1445 | firstBlock = 128 + (sector - 32) * no_of_blocks; 1446 | } 1447 | else { // Illegal input, no MIFARE Classic PICC has more than 40 sectors. 1448 | return; 1449 | } 1450 | 1451 | // Dump blocks, highest address first. 1452 | byte byteCount; 1453 | byte buffer[18]; 1454 | byte blockAddr; 1455 | isSectorTrailer = true; 1456 | for (int8_t blockOffset = no_of_blocks - 1; blockOffset >= 0; blockOffset--) { 1457 | blockAddr = firstBlock + blockOffset; 1458 | // Sector number - only on first line 1459 | if (isSectorTrailer) { 1460 | if(sector < 10) 1461 | Serial.print(F(" ")); // Pad with spaces 1462 | else 1463 | Serial.print(F(" ")); // Pad with spaces 1464 | Serial.print(sector); 1465 | Serial.print(F(" ")); 1466 | } 1467 | else { 1468 | Serial.print(F(" ")); 1469 | } 1470 | // Block number 1471 | if(blockAddr < 10) 1472 | Serial.print(F(" ")); // Pad with spaces 1473 | else { 1474 | if(blockAddr < 100) 1475 | Serial.print(F(" ")); // Pad with spaces 1476 | else 1477 | Serial.print(F(" ")); // Pad with spaces 1478 | } 1479 | Serial.print(blockAddr); 1480 | Serial.print(F(" ")); 1481 | // Establish encrypted communications before reading the first block 1482 | if (isSectorTrailer) { 1483 | status = PCD_Authenticate(PICC_CMD_MF_AUTH_KEY_A, firstBlock, key, uid); 1484 | if (status != STATUS_OK) { 1485 | Serial.print(F("PCD_Authenticate() failed: ")); 1486 | Serial.println(GetStatusCodeName(status)); 1487 | return; 1488 | } 1489 | } 1490 | // Read block 1491 | byteCount = sizeof(buffer); 1492 | status = MIFARE_Read(blockAddr, buffer, &byteCount); 1493 | if (status != STATUS_OK) { 1494 | Serial.print(F("MIFARE_Read() failed: ")); 1495 | Serial.println(GetStatusCodeName(status)); 1496 | continue; 1497 | } 1498 | // Dump data 1499 | for (byte index = 0; index < 16; index++) { 1500 | if(buffer[index] < 0x10) 1501 | Serial.print(F(" 0")); 1502 | else 1503 | Serial.print(F(" ")); 1504 | Serial.print(buffer[index], HEX); 1505 | if ((index % 4) == 3) { 1506 | Serial.print(F(" ")); 1507 | } 1508 | } 1509 | // Parse sector trailer data 1510 | if (isSectorTrailer) { 1511 | c1 = buffer[7] >> 4; 1512 | c2 = buffer[8] & 0xF; 1513 | c3 = buffer[8] >> 4; 1514 | c1_ = buffer[6] & 0xF; 1515 | c2_ = buffer[6] >> 4; 1516 | c3_ = buffer[7] & 0xF; 1517 | invertedError = (c1 != (~c1_ & 0xF)) || (c2 != (~c2_ & 0xF)) || (c3 != (~c3_ & 0xF)); 1518 | g[0] = ((c1 & 1) << 2) | ((c2 & 1) << 1) | ((c3 & 1) << 0); 1519 | g[1] = ((c1 & 2) << 1) | ((c2 & 2) << 0) | ((c3 & 2) >> 1); 1520 | g[2] = ((c1 & 4) << 0) | ((c2 & 4) >> 1) | ((c3 & 4) >> 2); 1521 | g[3] = ((c1 & 8) >> 1) | ((c2 & 8) >> 2) | ((c3 & 8) >> 3); 1522 | isSectorTrailer = false; 1523 | } 1524 | 1525 | // Which access group is this block in? 1526 | if (no_of_blocks == 4) { 1527 | group = blockOffset; 1528 | firstInGroup = true; 1529 | } 1530 | else { 1531 | group = blockOffset / 5; 1532 | firstInGroup = (group == 3) || (group != (blockOffset + 1) / 5); 1533 | } 1534 | 1535 | if (firstInGroup) { 1536 | // Print access bits 1537 | Serial.print(F(" [ ")); 1538 | Serial.print((g[group] >> 2) & 1, DEC); Serial.print(F(" ")); 1539 | Serial.print((g[group] >> 1) & 1, DEC); Serial.print(F(" ")); 1540 | Serial.print((g[group] >> 0) & 1, DEC); 1541 | Serial.print(F(" ] ")); 1542 | if (invertedError) { 1543 | Serial.print(F(" Inverted access bits did not match! ")); 1544 | } 1545 | } 1546 | 1547 | if (group != 3 && (g[group] == 1 || g[group] == 6)) { // Not a sector trailer, a value block 1548 | long value = (long(buffer[3])<<24) | (long(buffer[2])<<16) | (long(buffer[1])<<8) | long(buffer[0]); 1549 | Serial.print(F(" Value=0x")); Serial.print(value, HEX); 1550 | Serial.print(F(" Adr=0x")); Serial.print(buffer[12], HEX); 1551 | } 1552 | Serial.println(); 1553 | } 1554 | 1555 | return; 1556 | } // End PICC_DumpMifareClassicSectorToSerial() 1557 | 1558 | /** 1559 | * Dumps memory contents of a MIFARE Ultralight PICC. 1560 | */ 1561 | void MFRC522::PICC_DumpMifareUltralightToSerial() { 1562 | MFRC522::StatusCode status; 1563 | byte byteCount; 1564 | byte buffer[18]; 1565 | byte i; 1566 | 1567 | Serial.println(F("Page 0 1 2 3")); 1568 | // Try the mpages of the original Ultralight. Ultralight C has more pages. 1569 | for (byte page = 0; page < 16; page +=4) { // Read returns data for 4 pages at a time. 1570 | // Read pages 1571 | byteCount = sizeof(buffer); 1572 | status = MIFARE_Read(page, buffer, &byteCount); 1573 | if (status != STATUS_OK) { 1574 | Serial.print(F("MIFARE_Read() failed: ")); 1575 | Serial.println(GetStatusCodeName(status)); 1576 | break; 1577 | } 1578 | // Dump data 1579 | for (byte offset = 0; offset < 4; offset++) { 1580 | i = page + offset; 1581 | if(i < 10) 1582 | Serial.print(F(" ")); // Pad with spaces 1583 | else 1584 | Serial.print(F(" ")); // Pad with spaces 1585 | Serial.print(i); 1586 | Serial.print(F(" ")); 1587 | for (byte index = 0; index < 4; index++) { 1588 | i = 4 * offset + index; 1589 | if(buffer[i] < 0x10) 1590 | Serial.print(F(" 0")); 1591 | else 1592 | Serial.print(F(" ")); 1593 | Serial.print(buffer[i], HEX); 1594 | } 1595 | Serial.println(); 1596 | } 1597 | } 1598 | } // End PICC_DumpMifareUltralightToSerial() 1599 | 1600 | /** 1601 | * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tuples C1 is MSB (=4) and C3 is LSB (=1). 1602 | */ 1603 | void MFRC522::MIFARE_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte 6, 7 and 8 in the sector trailer. Bytes [0..2] will be set. 1604 | byte g0, ///< Access bits [C1 C2 C3] for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) 1605 | byte g1, ///< Access bits C1 C2 C3] for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) 1606 | byte g2, ///< Access bits C1 C2 C3] for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) 1607 | byte g3 ///< Access bits C1 C2 C3] for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) 1608 | ) { 1609 | byte c1 = ((g3 & 4) << 1) | ((g2 & 4) << 0) | ((g1 & 4) >> 1) | ((g0 & 4) >> 2); 1610 | byte c2 = ((g3 & 2) << 2) | ((g2 & 2) << 1) | ((g1 & 2) << 0) | ((g0 & 2) >> 1); 1611 | byte c3 = ((g3 & 1) << 3) | ((g2 & 1) << 2) | ((g1 & 1) << 1) | ((g0 & 1) << 0); 1612 | 1613 | accessBitBuffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF); 1614 | accessBitBuffer[1] = c1 << 4 | (~c3 & 0xF); 1615 | accessBitBuffer[2] = c3 << 4 | c2; 1616 | } // End MIFARE_SetAccessBits() 1617 | 1618 | 1619 | /** 1620 | * Performs the "magic sequence" needed to get Chinese UID changeable 1621 | * Mifare cards to allow writing to sector 0, where the card UID is stored. 1622 | * 1623 | * Note that you do not need to have selected the card through REQA or WUPA, 1624 | * this sequence works immediately when the card is in the reader vicinity. 1625 | * This means you can use this method even on "bricked" cards that your reader does 1626 | * not recognise anymore (see MFRC522::MIFARE_UnbrickUidSector). 1627 | * 1628 | * Of course with non-bricked devices, you're free to select them before calling this function. 1629 | */ 1630 | bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { 1631 | // Magic sequence: 1632 | // > 50 00 57 CD (HALT + CRC) 1633 | // > 40 (7 bits only) 1634 | // < A (4 bits only) 1635 | // > 43 1636 | // < A (4 bits only) 1637 | // Then you can write to sector 0 without authenticating 1638 | 1639 | PICC_HaltA(); // 50 00 57 CD 1640 | 1641 | byte cmd = 0x40; 1642 | byte validBits = 7; /* Our command is only 7 bits. After receiving card response, 1643 | this will contain amount of valid response bits. */ 1644 | byte response[32]; // Card's response is written here 1645 | byte received; 1646 | MFRC522::StatusCode status = PCD_TransceiveData(&cmd, (byte)1, response, &received, &validBits, (byte)0, false); // 40 1647 | if(status != STATUS_OK) { 1648 | if(logErrors) { 1649 | Serial.println(F("Card did not respond to 0x40 after HALT command. Are you sure it is a UID changeable one?")); 1650 | Serial.print(F("Error name: ")); 1651 | Serial.println(GetStatusCodeName(status)); 1652 | } 1653 | return false; 1654 | } 1655 | if (received != 1 || response[0] != 0x0A) { 1656 | if (logErrors) { 1657 | Serial.print(F("Got bad response on backdoor 0x40 command: ")); 1658 | Serial.print(response[0], HEX); 1659 | Serial.print(F(" (")); 1660 | Serial.print(validBits); 1661 | Serial.print(F(" valid bits)\r\n")); 1662 | } 1663 | return false; 1664 | } 1665 | 1666 | cmd = 0x43; 1667 | validBits = 8; 1668 | status = PCD_TransceiveData(&cmd, (byte)1, response, &received, &validBits, (byte)0, false); // 43 1669 | if(status != STATUS_OK) { 1670 | if(logErrors) { 1671 | Serial.println(F("Error in communication at command 0x43, after successfully executing 0x40")); 1672 | Serial.print(F("Error name: ")); 1673 | Serial.println(GetStatusCodeName(status)); 1674 | } 1675 | return false; 1676 | } 1677 | if (received != 1 || response[0] != 0x0A) { 1678 | if (logErrors) { 1679 | Serial.print(F("Got bad response on backdoor 0x43 command: ")); 1680 | Serial.print(response[0], HEX); 1681 | Serial.print(F(" (")); 1682 | Serial.print(validBits); 1683 | Serial.print(F(" valid bits)\r\n")); 1684 | } 1685 | return false; 1686 | } 1687 | 1688 | // You can now write to sector 0 without authenticating! 1689 | return true; 1690 | } // End MIFARE_OpenUidBackdoor() 1691 | 1692 | /** 1693 | * Reads entire block 0, including all manufacturer data, and overwrites 1694 | * that block with the new UID, a freshly calculated BCC, and the original 1695 | * manufacturer data. 1696 | * 1697 | * It assumes a default KEY A of 0xFFFFFFFFFFFF. 1698 | * Make sure to have selected the card before this function is called. 1699 | */ 1700 | bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { 1701 | 1702 | // UID + BCC byte can not be larger than 16 together 1703 | if (!newUid || !uidSize || uidSize > 15) { 1704 | if (logErrors) { 1705 | Serial.println(F("New UID buffer empty, size 0, or size > 15 given")); 1706 | } 1707 | return false; 1708 | } 1709 | 1710 | // Authenticate for reading 1711 | MIFARE_Key key = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 1712 | MFRC522::StatusCode status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); 1713 | if (status != STATUS_OK) { 1714 | 1715 | if (status == STATUS_TIMEOUT) { 1716 | // We get a read timeout if no card is selected yet, so let's select one 1717 | 1718 | // Wake the card up again if sleeping 1719 | // byte atqa_answer[2]; 1720 | // byte atqa_size = 2; 1721 | // PICC_WakeupA(atqa_answer, &atqa_size); 1722 | 1723 | if (!PICC_IsNewCardPresent() || !PICC_ReadCardSerial()) { 1724 | Serial.println(F("No card was previously selected, and none are available. Failed to set UID.")); 1725 | return false; 1726 | } 1727 | 1728 | status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); 1729 | if (status != STATUS_OK) { 1730 | // We tried, time to give up 1731 | if (logErrors) { 1732 | Serial.println(F("Failed to authenticate to card for reading, could not set UID: ")); 1733 | Serial.println(GetStatusCodeName(status)); 1734 | } 1735 | return false; 1736 | } 1737 | } 1738 | else { 1739 | if (logErrors) { 1740 | Serial.print(F("PCD_Authenticate() failed: ")); 1741 | Serial.println(GetStatusCodeName(status)); 1742 | } 1743 | return false; 1744 | } 1745 | } 1746 | 1747 | // Read block 0 1748 | byte block0_buffer[18]; 1749 | byte byteCount = sizeof(block0_buffer); 1750 | status = MIFARE_Read((byte)0, block0_buffer, &byteCount); 1751 | if (status != STATUS_OK) { 1752 | if (logErrors) { 1753 | Serial.print(F("MIFARE_Read() failed: ")); 1754 | Serial.println(GetStatusCodeName(status)); 1755 | Serial.println(F("Are you sure your KEY A for sector 0 is 0xFFFFFFFFFFFF?")); 1756 | } 1757 | return false; 1758 | } 1759 | 1760 | // Write new UID to the data we just read, and calculate BCC byte 1761 | byte bcc = 0; 1762 | for (int i = 0; i < uidSize; i++) { 1763 | block0_buffer[i] = newUid[i]; 1764 | bcc ^= newUid[i]; 1765 | } 1766 | 1767 | // Write BCC byte to buffer 1768 | block0_buffer[uidSize] = bcc; 1769 | 1770 | // Stop encrypted traffic so we can send raw bytes 1771 | PCD_StopCrypto1(); 1772 | 1773 | // Activate UID backdoor 1774 | if (!MIFARE_OpenUidBackdoor(logErrors)) { 1775 | if (logErrors) { 1776 | Serial.println(F("Activating the UID backdoor failed.")); 1777 | } 1778 | return false; 1779 | } 1780 | 1781 | // Write modified block 0 back to card 1782 | status = MIFARE_Write((byte)0, block0_buffer, (byte)16); 1783 | if (status != STATUS_OK) { 1784 | if (logErrors) { 1785 | Serial.print(F("MIFARE_Write() failed: ")); 1786 | Serial.println(GetStatusCodeName(status)); 1787 | } 1788 | return false; 1789 | } 1790 | 1791 | // Wake the card up again 1792 | byte atqa_answer[2]; 1793 | byte atqa_size = 2; 1794 | PICC_WakeupA(atqa_answer, &atqa_size); 1795 | 1796 | return true; 1797 | } 1798 | 1799 | /** 1800 | * Resets entire sector 0 to zeroes, so the card can be read again by readers. 1801 | */ 1802 | bool MFRC522::MIFARE_UnbrickUidSector(bool logErrors) { 1803 | MIFARE_OpenUidBackdoor(logErrors); 1804 | 1805 | byte block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 1806 | 1807 | // Write modified block 0 back to card 1808 | MFRC522::StatusCode status = MIFARE_Write((byte)0, block0_buffer, (byte)16); 1809 | if (status != STATUS_OK) { 1810 | if (logErrors) { 1811 | Serial.print(F("MIFARE_Write() failed: ")); 1812 | Serial.println(GetStatusCodeName(status)); 1813 | } 1814 | return false; 1815 | } 1816 | return true; 1817 | } 1818 | 1819 | ///////////////////////////////////////////////////////////////////////////////////// 1820 | // Convenience functions - does not add extra functionality 1821 | ///////////////////////////////////////////////////////////////////////////////////// 1822 | 1823 | /** 1824 | * Returns true if a PICC responds to PICC_CMD_REQA. 1825 | * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored. 1826 | * 1827 | * @return bool 1828 | */ 1829 | bool MFRC522::PICC_IsNewCardPresent() { 1830 | byte bufferATQA[2]; 1831 | byte bufferSize = sizeof(bufferATQA); 1832 | MFRC522::StatusCode result = PICC_RequestA(bufferATQA, &bufferSize); 1833 | return (result == STATUS_OK || result == STATUS_COLLISION); 1834 | } // End PICC_IsNewCardPresent() 1835 | 1836 | /** 1837 | * Simple wrapper around PICC_Select. 1838 | * Returns true if a UID could be read. 1839 | * Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first. 1840 | * The read UID is available in the class variable uid. 1841 | * 1842 | * @return bool 1843 | */ 1844 | bool MFRC522::PICC_ReadCardSerial() { 1845 | MFRC522::StatusCode result = PICC_Select(&uid); 1846 | return (result == STATUS_OK); 1847 | } // End 1848 | --------------------------------------------------------------------------------