This is a cost effective alert system that uses radio frequency identification. RC522 module and 13.56MHz RFID tags are used. Differentiates between registered and unregistered users based on UID of the tag, then displays alerts in serial terminal. The code presently has two registered users; can be easily expanded to have more registered users.

Dependencies:   MFRC522 mbed

Committer:
nivmukka
Date:
Sun Mar 27 03:35:10 2016 +0000
Revision:
1:d950cea9271b
Parent:
0:1026a98e87f4
Differentiates between registered and unregistered users based on UID of the tag, then displays alerts in serial terminal.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
nivmukka 0:1026a98e87f4 1 /*
nivmukka 0:1026a98e87f4 2 * MFRC522.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT.
nivmukka 0:1026a98e87f4 3 * _Please_ see the comments in MFRC522.h - they give useful hints and background.
nivmukka 0:1026a98e87f4 4 * Released into the public domain.
nivmukka 0:1026a98e87f4 5 */
nivmukka 0:1026a98e87f4 6
nivmukka 0:1026a98e87f4 7 #include "MFRC522.h"
nivmukka 0:1026a98e87f4 8
nivmukka 0:1026a98e87f4 9 static const char* const _TypeNamePICC[] =
nivmukka 0:1026a98e87f4 10 {
nivmukka 0:1026a98e87f4 11 "Unknown type",
nivmukka 0:1026a98e87f4 12 "PICC compliant with ISO/IEC 14443-4",
nivmukka 0:1026a98e87f4 13 "PICC compliant with ISO/IEC 18092 (NFC)",
nivmukka 0:1026a98e87f4 14 "MIFARE Mini, 320 bytes",
nivmukka 0:1026a98e87f4 15 "MIFARE 1KB",
nivmukka 0:1026a98e87f4 16 "MIFARE 4KB",
nivmukka 0:1026a98e87f4 17 "MIFARE Ultralight or Ultralight C",
nivmukka 0:1026a98e87f4 18 "MIFARE Plus",
nivmukka 0:1026a98e87f4 19 "MIFARE TNP3XXX",
nivmukka 0:1026a98e87f4 20
nivmukka 0:1026a98e87f4 21 /* not complete UID */
nivmukka 0:1026a98e87f4 22 "SAK indicates UID is not complete"
nivmukka 0:1026a98e87f4 23 };
nivmukka 0:1026a98e87f4 24
nivmukka 0:1026a98e87f4 25 static const char* const _ErrorMessage[] =
nivmukka 0:1026a98e87f4 26 {
nivmukka 0:1026a98e87f4 27 "Unknown error",
nivmukka 0:1026a98e87f4 28 "Success",
nivmukka 0:1026a98e87f4 29 "Error in communication",
nivmukka 0:1026a98e87f4 30 "Collision detected",
nivmukka 0:1026a98e87f4 31 "Timeout in communication",
nivmukka 0:1026a98e87f4 32 "A buffer is not big enough",
nivmukka 0:1026a98e87f4 33 "Internal error in the code, should not happen",
nivmukka 0:1026a98e87f4 34 "Invalid argument",
nivmukka 0:1026a98e87f4 35 "The CRC_A does not match",
nivmukka 0:1026a98e87f4 36 "A MIFARE PICC responded with NAK"
nivmukka 0:1026a98e87f4 37 };
nivmukka 0:1026a98e87f4 38
nivmukka 0:1026a98e87f4 39 #define MFRC522_MaxPICCs (sizeof(_TypeNamePICC)/sizeof(_TypeNamePICC[0]))
nivmukka 0:1026a98e87f4 40 #define MFRC522_MaxError (sizeof(_ErrorMessage)/sizeof(_ErrorMessage[0]))
nivmukka 0:1026a98e87f4 41
nivmukka 0:1026a98e87f4 42 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 43 // Functions for setting up the driver
nivmukka 0:1026a98e87f4 44 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 45
nivmukka 0:1026a98e87f4 46 /**
nivmukka 0:1026a98e87f4 47 * Constructor.
nivmukka 0:1026a98e87f4 48 * Prepares the output pins.
nivmukka 0:1026a98e87f4 49 */
nivmukka 0:1026a98e87f4 50 MFRC522::MFRC522(PinName mosi,
nivmukka 0:1026a98e87f4 51 PinName miso,
nivmukka 0:1026a98e87f4 52 PinName sclk,
nivmukka 0:1026a98e87f4 53 PinName cs,
nivmukka 0:1026a98e87f4 54 PinName reset) : m_SPI(mosi, miso, sclk), m_CS(cs), m_RESET(reset)
nivmukka 0:1026a98e87f4 55 {
nivmukka 0:1026a98e87f4 56 /* Configure SPI bus */
nivmukka 0:1026a98e87f4 57 m_SPI.format(8, 0);
nivmukka 0:1026a98e87f4 58 m_SPI.frequency(8000000);
nivmukka 0:1026a98e87f4 59
nivmukka 0:1026a98e87f4 60 /* Release SPI-CS pin */
nivmukka 0:1026a98e87f4 61 m_CS = 1;
nivmukka 0:1026a98e87f4 62
nivmukka 0:1026a98e87f4 63 /* Release RESET pin */
nivmukka 0:1026a98e87f4 64 m_RESET = 1;
nivmukka 0:1026a98e87f4 65 } // End constructor
nivmukka 0:1026a98e87f4 66
nivmukka 0:1026a98e87f4 67
nivmukka 0:1026a98e87f4 68 /**
nivmukka 0:1026a98e87f4 69 * Destructor.
nivmukka 0:1026a98e87f4 70 */
nivmukka 0:1026a98e87f4 71 MFRC522::~MFRC522()
nivmukka 0:1026a98e87f4 72 {
nivmukka 0:1026a98e87f4 73
nivmukka 0:1026a98e87f4 74 }
nivmukka 0:1026a98e87f4 75
nivmukka 0:1026a98e87f4 76
nivmukka 0:1026a98e87f4 77 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 78 // Basic interface functions for communicating with the MFRC522
nivmukka 0:1026a98e87f4 79 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 80
nivmukka 0:1026a98e87f4 81 /**
nivmukka 0:1026a98e87f4 82 * Writes a byte to the specified register in the MFRC522 chip.
nivmukka 0:1026a98e87f4 83 * The interface is described in the datasheet section 8.1.2.
nivmukka 0:1026a98e87f4 84 */
nivmukka 0:1026a98e87f4 85 void MFRC522::PCD_WriteRegister(uint8_t reg, uint8_t value)
nivmukka 0:1026a98e87f4 86 {
nivmukka 0:1026a98e87f4 87 m_CS = 0; /* Select SPI Chip MFRC522 */
nivmukka 0:1026a98e87f4 88
nivmukka 0:1026a98e87f4 89 // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3.
nivmukka 0:1026a98e87f4 90 (void) m_SPI.write(reg & 0x7E);
nivmukka 0:1026a98e87f4 91 (void) m_SPI.write(value);
nivmukka 0:1026a98e87f4 92
nivmukka 0:1026a98e87f4 93 m_CS = 1; /* Release SPI Chip MFRC522 */
nivmukka 0:1026a98e87f4 94 } // End PCD_WriteRegister()
nivmukka 0:1026a98e87f4 95
nivmukka 0:1026a98e87f4 96 /**
nivmukka 0:1026a98e87f4 97 * Writes a number of bytes to the specified register in the MFRC522 chip.
nivmukka 0:1026a98e87f4 98 * The interface is described in the datasheet section 8.1.2.
nivmukka 0:1026a98e87f4 99 */
nivmukka 0:1026a98e87f4 100 void MFRC522::PCD_WriteRegister(uint8_t reg, uint8_t count, uint8_t *values)
nivmukka 0:1026a98e87f4 101 {
nivmukka 0:1026a98e87f4 102 m_CS = 0; /* Select SPI Chip MFRC522 */
nivmukka 0:1026a98e87f4 103
nivmukka 0:1026a98e87f4 104 // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3.
nivmukka 0:1026a98e87f4 105 (void) m_SPI.write(reg & 0x7E);
nivmukka 0:1026a98e87f4 106 for (uint8_t index = 0; index < count; index++)
nivmukka 0:1026a98e87f4 107 {
nivmukka 0:1026a98e87f4 108 (void) m_SPI.write(values[index]);
nivmukka 0:1026a98e87f4 109 }
nivmukka 0:1026a98e87f4 110
nivmukka 0:1026a98e87f4 111 m_CS = 1; /* Release SPI Chip MFRC522 */
nivmukka 0:1026a98e87f4 112 } // End PCD_WriteRegister()
nivmukka 0:1026a98e87f4 113
nivmukka 0:1026a98e87f4 114 /**
nivmukka 0:1026a98e87f4 115 * Reads a byte from the specified register in the MFRC522 chip.
nivmukka 0:1026a98e87f4 116 * The interface is described in the datasheet section 8.1.2.
nivmukka 0:1026a98e87f4 117 */
nivmukka 0:1026a98e87f4 118 uint8_t MFRC522::PCD_ReadRegister(uint8_t reg)
nivmukka 0:1026a98e87f4 119 {
nivmukka 0:1026a98e87f4 120 uint8_t value;
nivmukka 0:1026a98e87f4 121 m_CS = 0; /* Select SPI Chip MFRC522 */
nivmukka 0:1026a98e87f4 122
nivmukka 0:1026a98e87f4 123 // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3.
nivmukka 0:1026a98e87f4 124 (void) m_SPI.write(0x80 | reg);
nivmukka 0:1026a98e87f4 125
nivmukka 0:1026a98e87f4 126 // Read the value back. Send 0 to stop reading.
nivmukka 0:1026a98e87f4 127 value = m_SPI.write(0);
nivmukka 0:1026a98e87f4 128
nivmukka 0:1026a98e87f4 129 m_CS = 1; /* Release SPI Chip MFRC522 */
nivmukka 0:1026a98e87f4 130
nivmukka 0:1026a98e87f4 131 return value;
nivmukka 0:1026a98e87f4 132 } // End PCD_ReadRegister()
nivmukka 0:1026a98e87f4 133
nivmukka 0:1026a98e87f4 134 /**
nivmukka 0:1026a98e87f4 135 * Reads a number of bytes from the specified register in the MFRC522 chip.
nivmukka 0:1026a98e87f4 136 * The interface is described in the datasheet section 8.1.2.
nivmukka 0:1026a98e87f4 137 */
nivmukka 0:1026a98e87f4 138 void MFRC522::PCD_ReadRegister(uint8_t reg, uint8_t count, uint8_t *values, uint8_t rxAlign)
nivmukka 0:1026a98e87f4 139 {
nivmukka 0:1026a98e87f4 140 if (count == 0) { return; }
nivmukka 0:1026a98e87f4 141
nivmukka 0:1026a98e87f4 142 uint8_t address = 0x80 | reg; // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3.
nivmukka 0:1026a98e87f4 143 uint8_t index = 0; // Index in values array.
nivmukka 0:1026a98e87f4 144
nivmukka 0:1026a98e87f4 145 m_CS = 0; /* Select SPI Chip MFRC522 */
nivmukka 0:1026a98e87f4 146 count--; // One read is performed outside of the loop
nivmukka 0:1026a98e87f4 147 (void) m_SPI.write(address); // Tell MFRC522 which address we want to read
nivmukka 0:1026a98e87f4 148
nivmukka 0:1026a98e87f4 149 while (index < count)
nivmukka 0:1026a98e87f4 150 {
nivmukka 0:1026a98e87f4 151 if ((index == 0) && rxAlign) // Only update bit positions rxAlign..7 in values[0]
nivmukka 0:1026a98e87f4 152 {
nivmukka 0:1026a98e87f4 153 // Create bit mask for bit positions rxAlign..7
nivmukka 0:1026a98e87f4 154 uint8_t mask = 0;
nivmukka 0:1026a98e87f4 155 for (uint8_t i = rxAlign; i <= 7; i++)
nivmukka 0:1026a98e87f4 156 {
nivmukka 0:1026a98e87f4 157 mask |= (1 << i);
nivmukka 0:1026a98e87f4 158 }
nivmukka 0:1026a98e87f4 159
nivmukka 0:1026a98e87f4 160 // Read value and tell that we want to read the same address again.
nivmukka 0:1026a98e87f4 161 uint8_t value = m_SPI.write(address);
nivmukka 0:1026a98e87f4 162
nivmukka 0:1026a98e87f4 163 // Apply mask to both current value of values[0] and the new data in value.
nivmukka 0:1026a98e87f4 164 values[0] = (values[index] & ~mask) | (value & mask);
nivmukka 0:1026a98e87f4 165 }
nivmukka 0:1026a98e87f4 166 else
nivmukka 0:1026a98e87f4 167 {
nivmukka 0:1026a98e87f4 168 // Read value and tell that we want to read the same address again.
nivmukka 0:1026a98e87f4 169 values[index] = m_SPI.write(address);
nivmukka 0:1026a98e87f4 170 }
nivmukka 0:1026a98e87f4 171
nivmukka 0:1026a98e87f4 172 index++;
nivmukka 0:1026a98e87f4 173 }
nivmukka 0:1026a98e87f4 174
nivmukka 0:1026a98e87f4 175 values[index] = m_SPI.write(0); // Read the final byte. Send 0 to stop reading.
nivmukka 0:1026a98e87f4 176
nivmukka 0:1026a98e87f4 177 m_CS = 1; /* Release SPI Chip MFRC522 */
nivmukka 0:1026a98e87f4 178 } // End PCD_ReadRegister()
nivmukka 0:1026a98e87f4 179
nivmukka 0:1026a98e87f4 180 /**
nivmukka 0:1026a98e87f4 181 * Sets the bits given in mask in register reg.
nivmukka 0:1026a98e87f4 182 */
nivmukka 0:1026a98e87f4 183 void MFRC522::PCD_SetRegisterBits(uint8_t reg, uint8_t mask)
nivmukka 0:1026a98e87f4 184 {
nivmukka 0:1026a98e87f4 185 uint8_t tmp = PCD_ReadRegister(reg);
nivmukka 0:1026a98e87f4 186 PCD_WriteRegister(reg, tmp | mask); // set bit mask
nivmukka 0:1026a98e87f4 187 } // End PCD_SetRegisterBitMask()
nivmukka 0:1026a98e87f4 188
nivmukka 0:1026a98e87f4 189 /**
nivmukka 0:1026a98e87f4 190 * Clears the bits given in mask from register reg.
nivmukka 0:1026a98e87f4 191 */
nivmukka 0:1026a98e87f4 192 void MFRC522::PCD_ClrRegisterBits(uint8_t reg, uint8_t mask)
nivmukka 0:1026a98e87f4 193 {
nivmukka 0:1026a98e87f4 194 uint8_t tmp = PCD_ReadRegister(reg);
nivmukka 0:1026a98e87f4 195 PCD_WriteRegister(reg, tmp & (~mask)); // clear bit mask
nivmukka 0:1026a98e87f4 196 } // End PCD_ClearRegisterBitMask()
nivmukka 0:1026a98e87f4 197
nivmukka 0:1026a98e87f4 198
nivmukka 0:1026a98e87f4 199 /**
nivmukka 0:1026a98e87f4 200 * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A.
nivmukka 0:1026a98e87f4 201 */
nivmukka 0:1026a98e87f4 202 uint8_t MFRC522::PCD_CalculateCRC(uint8_t *data, uint8_t length, uint8_t *result)
nivmukka 0:1026a98e87f4 203 {
nivmukka 0:1026a98e87f4 204 PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command.
nivmukka 0:1026a98e87f4 205 PCD_WriteRegister(DivIrqReg, 0x04); // Clear the CRCIRq interrupt request bit
nivmukka 0:1026a98e87f4 206 PCD_SetRegisterBits(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization
nivmukka 0:1026a98e87f4 207 PCD_WriteRegister(FIFODataReg, length, data); // Write data to the FIFO
nivmukka 0:1026a98e87f4 208 PCD_WriteRegister(CommandReg, PCD_CalcCRC); // Start the calculation
nivmukka 0:1026a98e87f4 209
nivmukka 0:1026a98e87f4 210 // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73us.
nivmukka 0:1026a98e87f4 211 uint16_t i = 5000;
nivmukka 0:1026a98e87f4 212 uint8_t n;
nivmukka 0:1026a98e87f4 213 while (1)
nivmukka 0:1026a98e87f4 214 {
nivmukka 0:1026a98e87f4 215 n = PCD_ReadRegister(DivIrqReg); // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved
nivmukka 0:1026a98e87f4 216 if (n & 0x04)
nivmukka 0:1026a98e87f4 217 {
nivmukka 0:1026a98e87f4 218 // CRCIRq bit set - calculation done
nivmukka 0:1026a98e87f4 219 break;
nivmukka 0:1026a98e87f4 220 }
nivmukka 0:1026a98e87f4 221
nivmukka 0:1026a98e87f4 222 if (--i == 0)
nivmukka 0:1026a98e87f4 223 {
nivmukka 0:1026a98e87f4 224 // The emergency break. We will eventually terminate on this one after 89ms.
nivmukka 0:1026a98e87f4 225 // Communication with the MFRC522 might be down.
nivmukka 0:1026a98e87f4 226 return STATUS_TIMEOUT;
nivmukka 0:1026a98e87f4 227 }
nivmukka 0:1026a98e87f4 228 }
nivmukka 0:1026a98e87f4 229
nivmukka 0:1026a98e87f4 230 // Stop calculating CRC for new content in the FIFO.
nivmukka 0:1026a98e87f4 231 PCD_WriteRegister(CommandReg, PCD_Idle);
nivmukka 0:1026a98e87f4 232
nivmukka 0:1026a98e87f4 233 // Transfer the result from the registers to the result buffer
nivmukka 0:1026a98e87f4 234 result[0] = PCD_ReadRegister(CRCResultRegL);
nivmukka 0:1026a98e87f4 235 result[1] = PCD_ReadRegister(CRCResultRegH);
nivmukka 0:1026a98e87f4 236 return STATUS_OK;
nivmukka 0:1026a98e87f4 237 } // End PCD_CalculateCRC()
nivmukka 0:1026a98e87f4 238
nivmukka 0:1026a98e87f4 239
nivmukka 0:1026a98e87f4 240 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 241 // Functions for manipulating the MFRC522
nivmukka 0:1026a98e87f4 242 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 243
nivmukka 0:1026a98e87f4 244 /**
nivmukka 0:1026a98e87f4 245 * Initializes the MFRC522 chip.
nivmukka 0:1026a98e87f4 246 */
nivmukka 0:1026a98e87f4 247 void MFRC522::PCD_Init()
nivmukka 0:1026a98e87f4 248 {
nivmukka 0:1026a98e87f4 249 /* Reset MFRC522 */
nivmukka 0:1026a98e87f4 250 m_RESET = 0;
nivmukka 0:1026a98e87f4 251 wait_ms(10);
nivmukka 0:1026a98e87f4 252 m_RESET = 1;
nivmukka 0:1026a98e87f4 253
nivmukka 0:1026a98e87f4 254 // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74us. Let us be generous: 50ms.
nivmukka 0:1026a98e87f4 255 wait_ms(50);
nivmukka 0:1026a98e87f4 256
nivmukka 0:1026a98e87f4 257 // When communicating with a PICC we need a timeout if something goes wrong.
nivmukka 0:1026a98e87f4 258 // f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo].
nivmukka 0:1026a98e87f4 259 // TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg.
nivmukka 0:1026a98e87f4 260 PCD_WriteRegister(TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds
nivmukka 0:1026a98e87f4 261 PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25us.
nivmukka 0:1026a98e87f4 262 PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout.
nivmukka 0:1026a98e87f4 263 PCD_WriteRegister(TReloadRegL, 0xE8);
nivmukka 0:1026a98e87f4 264
nivmukka 0:1026a98e87f4 265 PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting
nivmukka 0:1026a98e87f4 266 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)
nivmukka 0:1026a98e87f4 267
nivmukka 0:1026a98e87f4 268 PCD_WriteRegister(RFCfgReg, (0x07<<4)); // Set Rx Gain to max
nivmukka 0:1026a98e87f4 269
nivmukka 0:1026a98e87f4 270 PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset)
nivmukka 0:1026a98e87f4 271 } // End PCD_Init()
nivmukka 0:1026a98e87f4 272
nivmukka 0:1026a98e87f4 273 /**
nivmukka 0:1026a98e87f4 274 * Performs a soft reset on the MFRC522 chip and waits for it to be ready again.
nivmukka 0:1026a98e87f4 275 */
nivmukka 0:1026a98e87f4 276 void MFRC522::PCD_Reset()
nivmukka 0:1026a98e87f4 277 {
nivmukka 0:1026a98e87f4 278 PCD_WriteRegister(CommandReg, PCD_SoftReset); // Issue the SoftReset command.
nivmukka 0:1026a98e87f4 279 // The datasheet does not mention how long the SoftRest command takes to complete.
nivmukka 0:1026a98e87f4 280 // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg)
nivmukka 0:1026a98e87f4 281 // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74us. Let us be generous: 50ms.
nivmukka 0:1026a98e87f4 282 wait_ms(50);
nivmukka 0:1026a98e87f4 283
nivmukka 0:1026a98e87f4 284 // Wait for the PowerDown bit in CommandReg to be cleared
nivmukka 0:1026a98e87f4 285 while (PCD_ReadRegister(CommandReg) & (1<<4))
nivmukka 0:1026a98e87f4 286 {
nivmukka 0:1026a98e87f4 287 // PCD still restarting - unlikely after waiting 50ms, but better safe than sorry.
nivmukka 0:1026a98e87f4 288 }
nivmukka 0:1026a98e87f4 289 } // End PCD_Reset()
nivmukka 0:1026a98e87f4 290
nivmukka 0:1026a98e87f4 291 /**
nivmukka 0:1026a98e87f4 292 * Turns the antenna on by enabling pins TX1 and TX2.
nivmukka 0:1026a98e87f4 293 * After a reset these pins disabled.
nivmukka 0:1026a98e87f4 294 */
nivmukka 0:1026a98e87f4 295 void MFRC522::PCD_AntennaOn()
nivmukka 0:1026a98e87f4 296 {
nivmukka 0:1026a98e87f4 297 uint8_t value = PCD_ReadRegister(TxControlReg);
nivmukka 0:1026a98e87f4 298 if ((value & 0x03) != 0x03)
nivmukka 0:1026a98e87f4 299 {
nivmukka 0:1026a98e87f4 300 PCD_WriteRegister(TxControlReg, value | 0x03);
nivmukka 0:1026a98e87f4 301 }
nivmukka 0:1026a98e87f4 302 } // End PCD_AntennaOn()
nivmukka 0:1026a98e87f4 303
nivmukka 0:1026a98e87f4 304 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 305 // Functions for communicating with PICCs
nivmukka 0:1026a98e87f4 306 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 307
nivmukka 0:1026a98e87f4 308 /**
nivmukka 0:1026a98e87f4 309 * Executes the Transceive command.
nivmukka 0:1026a98e87f4 310 * CRC validation can only be done if backData and backLen are specified.
nivmukka 0:1026a98e87f4 311 */
nivmukka 0:1026a98e87f4 312 uint8_t MFRC522::PCD_TransceiveData(uint8_t *sendData,
nivmukka 0:1026a98e87f4 313 uint8_t sendLen,
nivmukka 0:1026a98e87f4 314 uint8_t *backData,
nivmukka 0:1026a98e87f4 315 uint8_t *backLen,
nivmukka 0:1026a98e87f4 316 uint8_t *validBits,
nivmukka 0:1026a98e87f4 317 uint8_t rxAlign,
nivmukka 0:1026a98e87f4 318 bool checkCRC)
nivmukka 0:1026a98e87f4 319 {
nivmukka 0:1026a98e87f4 320 uint8_t waitIRq = 0x30; // RxIRq and IdleIRq
nivmukka 0:1026a98e87f4 321 return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign, checkCRC);
nivmukka 0:1026a98e87f4 322 } // End PCD_TransceiveData()
nivmukka 0:1026a98e87f4 323
nivmukka 0:1026a98e87f4 324 /**
nivmukka 0:1026a98e87f4 325 * Transfers data to the MFRC522 FIFO, executes a commend, waits for completion and transfers data back from the FIFO.
nivmukka 0:1026a98e87f4 326 * CRC validation can only be done if backData and backLen are specified.
nivmukka 0:1026a98e87f4 327 */
nivmukka 0:1026a98e87f4 328 uint8_t MFRC522::PCD_CommunicateWithPICC(uint8_t command,
nivmukka 0:1026a98e87f4 329 uint8_t waitIRq,
nivmukka 0:1026a98e87f4 330 uint8_t *sendData,
nivmukka 0:1026a98e87f4 331 uint8_t sendLen,
nivmukka 0:1026a98e87f4 332 uint8_t *backData,
nivmukka 0:1026a98e87f4 333 uint8_t *backLen,
nivmukka 0:1026a98e87f4 334 uint8_t *validBits,
nivmukka 0:1026a98e87f4 335 uint8_t rxAlign,
nivmukka 0:1026a98e87f4 336 bool checkCRC)
nivmukka 0:1026a98e87f4 337 {
nivmukka 0:1026a98e87f4 338 uint8_t n, _validBits = 0;
nivmukka 0:1026a98e87f4 339 uint32_t i;
nivmukka 0:1026a98e87f4 340
nivmukka 0:1026a98e87f4 341 // Prepare values for BitFramingReg
nivmukka 0:1026a98e87f4 342 uint8_t txLastBits = validBits ? *validBits : 0;
nivmukka 0:1026a98e87f4 343 uint8_t bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0]
nivmukka 0:1026a98e87f4 344
nivmukka 0:1026a98e87f4 345 PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command.
nivmukka 0:1026a98e87f4 346 PCD_WriteRegister(ComIrqReg, 0x7F); // Clear all seven interrupt request bits
nivmukka 0:1026a98e87f4 347 PCD_SetRegisterBits(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization
nivmukka 0:1026a98e87f4 348 PCD_WriteRegister(FIFODataReg, sendLen, sendData); // Write sendData to the FIFO
nivmukka 0:1026a98e87f4 349 PCD_WriteRegister(BitFramingReg, bitFraming); // Bit adjustments
nivmukka 0:1026a98e87f4 350 PCD_WriteRegister(CommandReg, command); // Execute the command
nivmukka 0:1026a98e87f4 351 if (command == PCD_Transceive)
nivmukka 0:1026a98e87f4 352 {
nivmukka 0:1026a98e87f4 353 PCD_SetRegisterBits(BitFramingReg, 0x80); // StartSend=1, transmission of data starts
nivmukka 0:1026a98e87f4 354 }
nivmukka 0:1026a98e87f4 355
nivmukka 0:1026a98e87f4 356 // Wait for the command to complete.
nivmukka 0:1026a98e87f4 357 // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops transmitting.
nivmukka 0:1026a98e87f4 358 // Each iteration of the do-while-loop takes 17.86us.
nivmukka 0:1026a98e87f4 359 i = 2000;
nivmukka 0:1026a98e87f4 360 while (1)
nivmukka 0:1026a98e87f4 361 {
nivmukka 0:1026a98e87f4 362 n = PCD_ReadRegister(ComIrqReg); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq
nivmukka 0:1026a98e87f4 363 if (n & waitIRq)
nivmukka 0:1026a98e87f4 364 { // One of the interrupts that signal success has been set.
nivmukka 0:1026a98e87f4 365 break;
nivmukka 0:1026a98e87f4 366 }
nivmukka 0:1026a98e87f4 367
nivmukka 0:1026a98e87f4 368 if (n & 0x01)
nivmukka 0:1026a98e87f4 369 { // Timer interrupt - nothing received in 25ms
nivmukka 0:1026a98e87f4 370 return STATUS_TIMEOUT;
nivmukka 0:1026a98e87f4 371 }
nivmukka 0:1026a98e87f4 372
nivmukka 0:1026a98e87f4 373 if (--i == 0)
nivmukka 0:1026a98e87f4 374 { // The emergency break. If all other condions fail we will eventually terminate on this one after 35.7ms. Communication with the MFRC522 might be down.
nivmukka 0:1026a98e87f4 375 return STATUS_TIMEOUT;
nivmukka 0:1026a98e87f4 376 }
nivmukka 0:1026a98e87f4 377 }
nivmukka 0:1026a98e87f4 378
nivmukka 0:1026a98e87f4 379 // Stop now if any errors except collisions were detected.
nivmukka 0:1026a98e87f4 380 uint8_t errorRegValue = PCD_ReadRegister(ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr
nivmukka 0:1026a98e87f4 381 if (errorRegValue & 0x13)
nivmukka 0:1026a98e87f4 382 { // BufferOvfl ParityErr ProtocolErr
nivmukka 0:1026a98e87f4 383 return STATUS_ERROR;
nivmukka 0:1026a98e87f4 384 }
nivmukka 0:1026a98e87f4 385
nivmukka 0:1026a98e87f4 386 // If the caller wants data back, get it from the MFRC522.
nivmukka 0:1026a98e87f4 387 if (backData && backLen)
nivmukka 0:1026a98e87f4 388 {
nivmukka 0:1026a98e87f4 389 n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO
nivmukka 0:1026a98e87f4 390 if (n > *backLen)
nivmukka 0:1026a98e87f4 391 {
nivmukka 0:1026a98e87f4 392 return STATUS_NO_ROOM;
nivmukka 0:1026a98e87f4 393 }
nivmukka 0:1026a98e87f4 394
nivmukka 0:1026a98e87f4 395 *backLen = n; // Number of bytes returned
nivmukka 0:1026a98e87f4 396 PCD_ReadRegister(FIFODataReg, n, backData, rxAlign); // Get received data from FIFO
nivmukka 0:1026a98e87f4 397 _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.
nivmukka 0:1026a98e87f4 398 if (validBits)
nivmukka 0:1026a98e87f4 399 {
nivmukka 0:1026a98e87f4 400 *validBits = _validBits;
nivmukka 0:1026a98e87f4 401 }
nivmukka 0:1026a98e87f4 402 }
nivmukka 0:1026a98e87f4 403
nivmukka 0:1026a98e87f4 404 // Tell about collisions
nivmukka 0:1026a98e87f4 405 if (errorRegValue & 0x08)
nivmukka 0:1026a98e87f4 406 { // CollErr
nivmukka 0:1026a98e87f4 407 return STATUS_COLLISION;
nivmukka 0:1026a98e87f4 408 }
nivmukka 0:1026a98e87f4 409
nivmukka 0:1026a98e87f4 410 // Perform CRC_A validation if requested.
nivmukka 0:1026a98e87f4 411 if (backData && backLen && checkCRC)
nivmukka 0:1026a98e87f4 412 {
nivmukka 0:1026a98e87f4 413 // In this case a MIFARE Classic NAK is not OK.
nivmukka 0:1026a98e87f4 414 if ((*backLen == 1) && (_validBits == 4))
nivmukka 0:1026a98e87f4 415 {
nivmukka 0:1026a98e87f4 416 return STATUS_MIFARE_NACK;
nivmukka 0:1026a98e87f4 417 }
nivmukka 0:1026a98e87f4 418
nivmukka 0:1026a98e87f4 419 // We need at least the CRC_A value and all 8 bits of the last byte must be received.
nivmukka 0:1026a98e87f4 420 if ((*backLen < 2) || (_validBits != 0))
nivmukka 0:1026a98e87f4 421 {
nivmukka 0:1026a98e87f4 422 return STATUS_CRC_WRONG;
nivmukka 0:1026a98e87f4 423 }
nivmukka 0:1026a98e87f4 424
nivmukka 0:1026a98e87f4 425 // Verify CRC_A - do our own calculation and store the control in controlBuffer.
nivmukka 0:1026a98e87f4 426 uint8_t controlBuffer[2];
nivmukka 0:1026a98e87f4 427 n = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]);
nivmukka 0:1026a98e87f4 428 if (n != STATUS_OK)
nivmukka 0:1026a98e87f4 429 {
nivmukka 0:1026a98e87f4 430 return n;
nivmukka 0:1026a98e87f4 431 }
nivmukka 0:1026a98e87f4 432
nivmukka 0:1026a98e87f4 433 if ((backData[*backLen - 2] != controlBuffer[0]) || (backData[*backLen - 1] != controlBuffer[1]))
nivmukka 0:1026a98e87f4 434 {
nivmukka 0:1026a98e87f4 435 return STATUS_CRC_WRONG;
nivmukka 0:1026a98e87f4 436 }
nivmukka 0:1026a98e87f4 437 }
nivmukka 0:1026a98e87f4 438
nivmukka 0:1026a98e87f4 439 return STATUS_OK;
nivmukka 0:1026a98e87f4 440 } // End PCD_CommunicateWithPICC()
nivmukka 0:1026a98e87f4 441
nivmukka 0:1026a98e87f4 442 /*
nivmukka 0:1026a98e87f4 443 * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
nivmukka 0:1026a98e87f4 444 * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
nivmukka 0:1026a98e87f4 445 */
nivmukka 0:1026a98e87f4 446 uint8_t MFRC522::PICC_RequestA(uint8_t *bufferATQA, uint8_t *bufferSize)
nivmukka 0:1026a98e87f4 447 {
nivmukka 0:1026a98e87f4 448 return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize);
nivmukka 0:1026a98e87f4 449 } // End PICC_RequestA()
nivmukka 0:1026a98e87f4 450
nivmukka 0:1026a98e87f4 451 /**
nivmukka 0:1026a98e87f4 452 * 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.
nivmukka 0:1026a98e87f4 453 * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
nivmukka 0:1026a98e87f4 454 */
nivmukka 0:1026a98e87f4 455 uint8_t MFRC522::PICC_WakeupA(uint8_t *bufferATQA, uint8_t *bufferSize)
nivmukka 0:1026a98e87f4 456 {
nivmukka 0:1026a98e87f4 457 return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize);
nivmukka 0:1026a98e87f4 458 } // End PICC_WakeupA()
nivmukka 0:1026a98e87f4 459
nivmukka 0:1026a98e87f4 460 /*
nivmukka 0:1026a98e87f4 461 * Transmits REQA or WUPA commands.
nivmukka 0:1026a98e87f4 462 * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
nivmukka 0:1026a98e87f4 463 */
nivmukka 0:1026a98e87f4 464 uint8_t MFRC522::PICC_REQA_or_WUPA(uint8_t command, uint8_t *bufferATQA, uint8_t *bufferSize)
nivmukka 0:1026a98e87f4 465 {
nivmukka 0:1026a98e87f4 466 uint8_t validBits;
nivmukka 0:1026a98e87f4 467 uint8_t status;
nivmukka 0:1026a98e87f4 468
nivmukka 0:1026a98e87f4 469 if (bufferATQA == NULL || *bufferSize < 2)
nivmukka 0:1026a98e87f4 470 { // The ATQA response is 2 bytes long.
nivmukka 0:1026a98e87f4 471 return STATUS_NO_ROOM;
nivmukka 0:1026a98e87f4 472 }
nivmukka 0:1026a98e87f4 473
nivmukka 0:1026a98e87f4 474 // ValuesAfterColl=1 => Bits received after collision are cleared.
nivmukka 0:1026a98e87f4 475 PCD_ClrRegisterBits(CollReg, 0x80);
nivmukka 0:1026a98e87f4 476
nivmukka 0:1026a98e87f4 477 // For REQA and WUPA we need the short frame format
nivmukka 0:1026a98e87f4 478 // - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0]
nivmukka 0:1026a98e87f4 479 validBits = 7;
nivmukka 0:1026a98e87f4 480
nivmukka 0:1026a98e87f4 481 status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits);
nivmukka 0:1026a98e87f4 482 if (status != STATUS_OK)
nivmukka 0:1026a98e87f4 483 {
nivmukka 0:1026a98e87f4 484 return status;
nivmukka 0:1026a98e87f4 485 }
nivmukka 0:1026a98e87f4 486
nivmukka 0:1026a98e87f4 487 if ((*bufferSize != 2) || (validBits != 0))
nivmukka 0:1026a98e87f4 488 { // ATQA must be exactly 16 bits.
nivmukka 0:1026a98e87f4 489 return STATUS_ERROR;
nivmukka 0:1026a98e87f4 490 }
nivmukka 0:1026a98e87f4 491
nivmukka 0:1026a98e87f4 492 return STATUS_OK;
nivmukka 0:1026a98e87f4 493 } // End PICC_REQA_or_WUPA()
nivmukka 0:1026a98e87f4 494
nivmukka 0:1026a98e87f4 495 /*
nivmukka 0:1026a98e87f4 496 * Transmits SELECT/ANTICOLLISION commands to select a single PICC.
nivmukka 0:1026a98e87f4 497 */
nivmukka 0:1026a98e87f4 498 uint8_t MFRC522::PICC_Select(Uid *uid, uint8_t validBits)
nivmukka 0:1026a98e87f4 499 {
nivmukka 0:1026a98e87f4 500 bool uidComplete;
nivmukka 0:1026a98e87f4 501 bool selectDone;
nivmukka 0:1026a98e87f4 502 bool useCascadeTag;
nivmukka 0:1026a98e87f4 503 uint8_t cascadeLevel = 1;
nivmukka 0:1026a98e87f4 504 uint8_t result;
nivmukka 0:1026a98e87f4 505 uint8_t count;
nivmukka 0:1026a98e87f4 506 uint8_t index;
nivmukka 0:1026a98e87f4 507 uint8_t uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level.
nivmukka 0:1026a98e87f4 508 uint8_t currentLevelKnownBits; // The number of known UID bits in the current Cascade Level.
nivmukka 0:1026a98e87f4 509 uint8_t buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A
nivmukka 0:1026a98e87f4 510 uint8_t bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO.
nivmukka 0:1026a98e87f4 511 uint8_t rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received.
nivmukka 0:1026a98e87f4 512 uint8_t txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte.
nivmukka 0:1026a98e87f4 513 uint8_t *responseBuffer;
nivmukka 0:1026a98e87f4 514 uint8_t responseLength;
nivmukka 0:1026a98e87f4 515
nivmukka 0:1026a98e87f4 516 // Description of buffer structure:
nivmukka 0:1026a98e87f4 517 // Byte 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3
nivmukka 0:1026a98e87f4 518 // Byte 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete bytes, Low nibble: Extra bits.
nivmukka 0:1026a98e87f4 519 // Byte 2: UID-data or CT See explanation below. CT means Cascade Tag.
nivmukka 0:1026a98e87f4 520 // Byte 3: UID-data
nivmukka 0:1026a98e87f4 521 // Byte 4: UID-data
nivmukka 0:1026a98e87f4 522 // Byte 5: UID-data
nivmukka 0:1026a98e87f4 523 // Byte 6: BCC Block Check Character - XOR of bytes 2-5
nivmukka 0:1026a98e87f4 524 // Byte 7: CRC_A
nivmukka 0:1026a98e87f4 525 // Byte 8: CRC_A
nivmukka 0:1026a98e87f4 526 // The BCC and CRC_A is only transmitted if we know all the UID bits of the current Cascade Level.
nivmukka 0:1026a98e87f4 527 //
nivmukka 0:1026a98e87f4 528 // Description of bytes 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels)
nivmukka 0:1026a98e87f4 529 // UID size Cascade level Byte2 Byte3 Byte4 Byte5
nivmukka 0:1026a98e87f4 530 // ======== ============= ===== ===== ===== =====
nivmukka 0:1026a98e87f4 531 // 4 bytes 1 uid0 uid1 uid2 uid3
nivmukka 0:1026a98e87f4 532 // 7 bytes 1 CT uid0 uid1 uid2
nivmukka 0:1026a98e87f4 533 // 2 uid3 uid4 uid5 uid6
nivmukka 0:1026a98e87f4 534 // 10 bytes 1 CT uid0 uid1 uid2
nivmukka 0:1026a98e87f4 535 // 2 CT uid3 uid4 uid5
nivmukka 0:1026a98e87f4 536 // 3 uid6 uid7 uid8 uid9
nivmukka 0:1026a98e87f4 537
nivmukka 0:1026a98e87f4 538 // Sanity checks
nivmukka 0:1026a98e87f4 539 if (validBits > 80)
nivmukka 0:1026a98e87f4 540 {
nivmukka 0:1026a98e87f4 541 return STATUS_INVALID;
nivmukka 0:1026a98e87f4 542 }
nivmukka 0:1026a98e87f4 543
nivmukka 0:1026a98e87f4 544 // Prepare MFRC522
nivmukka 0:1026a98e87f4 545 // ValuesAfterColl=1 => Bits received after collision are cleared.
nivmukka 0:1026a98e87f4 546 PCD_ClrRegisterBits(CollReg, 0x80);
nivmukka 0:1026a98e87f4 547
nivmukka 0:1026a98e87f4 548 // Repeat Cascade Level loop until we have a complete UID.
nivmukka 0:1026a98e87f4 549 uidComplete = false;
nivmukka 0:1026a98e87f4 550 while ( ! uidComplete)
nivmukka 0:1026a98e87f4 551 {
nivmukka 0:1026a98e87f4 552 // Set the Cascade Level in the SEL byte, find out if we need to use the Cascade Tag in byte 2.
nivmukka 0:1026a98e87f4 553 switch (cascadeLevel)
nivmukka 0:1026a98e87f4 554 {
nivmukka 0:1026a98e87f4 555 case 1:
nivmukka 0:1026a98e87f4 556 buffer[0] = PICC_CMD_SEL_CL1;
nivmukka 0:1026a98e87f4 557 uidIndex = 0;
nivmukka 0:1026a98e87f4 558 useCascadeTag = validBits && (uid->size > 4); // When we know that the UID has more than 4 bytes
nivmukka 0:1026a98e87f4 559 break;
nivmukka 0:1026a98e87f4 560
nivmukka 0:1026a98e87f4 561 case 2:
nivmukka 0:1026a98e87f4 562 buffer[0] = PICC_CMD_SEL_CL2;
nivmukka 0:1026a98e87f4 563 uidIndex = 3;
nivmukka 0:1026a98e87f4 564 useCascadeTag = validBits && (uid->size > 7); // When we know that the UID has more than 7 bytes
nivmukka 0:1026a98e87f4 565 break;
nivmukka 0:1026a98e87f4 566
nivmukka 0:1026a98e87f4 567 case 3:
nivmukka 0:1026a98e87f4 568 buffer[0] = PICC_CMD_SEL_CL3;
nivmukka 0:1026a98e87f4 569 uidIndex = 6;
nivmukka 0:1026a98e87f4 570 useCascadeTag = false; // Never used in CL3.
nivmukka 0:1026a98e87f4 571 break;
nivmukka 0:1026a98e87f4 572
nivmukka 0:1026a98e87f4 573 default:
nivmukka 0:1026a98e87f4 574 return STATUS_INTERNAL_ERROR;
nivmukka 0:1026a98e87f4 575 //break;
nivmukka 0:1026a98e87f4 576 }
nivmukka 0:1026a98e87f4 577
nivmukka 0:1026a98e87f4 578 // How many UID bits are known in this Cascade Level?
nivmukka 0:1026a98e87f4 579 if(validBits > (8 * uidIndex))
nivmukka 0:1026a98e87f4 580 {
nivmukka 0:1026a98e87f4 581 currentLevelKnownBits = validBits - (8 * uidIndex);
nivmukka 0:1026a98e87f4 582 }
nivmukka 0:1026a98e87f4 583 else
nivmukka 0:1026a98e87f4 584 {
nivmukka 0:1026a98e87f4 585 currentLevelKnownBits = 0;
nivmukka 0:1026a98e87f4 586 }
nivmukka 0:1026a98e87f4 587
nivmukka 0:1026a98e87f4 588 // Copy the known bits from uid->uidByte[] to buffer[]
nivmukka 0:1026a98e87f4 589 index = 2; // destination index in buffer[]
nivmukka 0:1026a98e87f4 590 if (useCascadeTag)
nivmukka 0:1026a98e87f4 591 {
nivmukka 0:1026a98e87f4 592 buffer[index++] = PICC_CMD_CT;
nivmukka 0:1026a98e87f4 593 }
nivmukka 0:1026a98e87f4 594
nivmukka 0:1026a98e87f4 595 uint8_t bytesToCopy = currentLevelKnownBits / 8 + (currentLevelKnownBits % 8 ? 1 : 0); // The number of bytes needed to represent the known bits for this level.
nivmukka 0:1026a98e87f4 596 if (bytesToCopy)
nivmukka 0:1026a98e87f4 597 {
nivmukka 0:1026a98e87f4 598 // Max 4 bytes in each Cascade Level. Only 3 left if we use the Cascade Tag
nivmukka 0:1026a98e87f4 599 uint8_t maxBytes = useCascadeTag ? 3 : 4;
nivmukka 0:1026a98e87f4 600 if (bytesToCopy > maxBytes)
nivmukka 0:1026a98e87f4 601 {
nivmukka 0:1026a98e87f4 602 bytesToCopy = maxBytes;
nivmukka 0:1026a98e87f4 603 }
nivmukka 0:1026a98e87f4 604
nivmukka 0:1026a98e87f4 605 for (count = 0; count < bytesToCopy; count++)
nivmukka 0:1026a98e87f4 606 {
nivmukka 0:1026a98e87f4 607 buffer[index++] = uid->uidByte[uidIndex + count];
nivmukka 0:1026a98e87f4 608 }
nivmukka 0:1026a98e87f4 609 }
nivmukka 0:1026a98e87f4 610
nivmukka 0:1026a98e87f4 611 // Now that the data has been copied we need to include the 8 bits in CT in currentLevelKnownBits
nivmukka 0:1026a98e87f4 612 if (useCascadeTag)
nivmukka 0:1026a98e87f4 613 {
nivmukka 0:1026a98e87f4 614 currentLevelKnownBits += 8;
nivmukka 0:1026a98e87f4 615 }
nivmukka 0:1026a98e87f4 616
nivmukka 0:1026a98e87f4 617 // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations.
nivmukka 0:1026a98e87f4 618 selectDone = false;
nivmukka 0:1026a98e87f4 619 while ( ! selectDone)
nivmukka 0:1026a98e87f4 620 {
nivmukka 0:1026a98e87f4 621 // Find out how many bits and bytes to send and receive.
nivmukka 0:1026a98e87f4 622 if (currentLevelKnownBits >= 32)
nivmukka 0:1026a98e87f4 623 { // All UID bits in this Cascade Level are known. This is a SELECT.
nivmukka 0:1026a98e87f4 624 //Serial.print("SELECT: currentLevelKnownBits="); Serial.println(currentLevelKnownBits, DEC);
nivmukka 0:1026a98e87f4 625 buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole bytes
nivmukka 0:1026a98e87f4 626
nivmukka 0:1026a98e87f4 627 // Calulate BCC - Block Check Character
nivmukka 0:1026a98e87f4 628 buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5];
nivmukka 0:1026a98e87f4 629
nivmukka 0:1026a98e87f4 630 // Calculate CRC_A
nivmukka 0:1026a98e87f4 631 result = PCD_CalculateCRC(buffer, 7, &buffer[7]);
nivmukka 0:1026a98e87f4 632 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 633 {
nivmukka 0:1026a98e87f4 634 return result;
nivmukka 0:1026a98e87f4 635 }
nivmukka 0:1026a98e87f4 636
nivmukka 0:1026a98e87f4 637 txLastBits = 0; // 0 => All 8 bits are valid.
nivmukka 0:1026a98e87f4 638 bufferUsed = 9;
nivmukka 0:1026a98e87f4 639
nivmukka 0:1026a98e87f4 640 // Store response in the last 3 bytes of buffer (BCC and CRC_A - not needed after tx)
nivmukka 0:1026a98e87f4 641 responseBuffer = &buffer[6];
nivmukka 0:1026a98e87f4 642 responseLength = 3;
nivmukka 0:1026a98e87f4 643 }
nivmukka 0:1026a98e87f4 644 else
nivmukka 0:1026a98e87f4 645 { // This is an ANTICOLLISION.
nivmukka 0:1026a98e87f4 646 //Serial.print("ANTICOLLISION: currentLevelKnownBits="); Serial.println(currentLevelKnownBits, DEC);
nivmukka 0:1026a98e87f4 647 txLastBits = currentLevelKnownBits % 8;
nivmukka 0:1026a98e87f4 648 count = currentLevelKnownBits / 8; // Number of whole bytes in the UID part.
nivmukka 0:1026a98e87f4 649 index = 2 + count; // Number of whole bytes: SEL + NVB + UIDs
nivmukka 0:1026a98e87f4 650 buffer[1] = (index << 4) + txLastBits; // NVB - Number of Valid Bits
nivmukka 0:1026a98e87f4 651 bufferUsed = index + (txLastBits ? 1 : 0);
nivmukka 0:1026a98e87f4 652
nivmukka 0:1026a98e87f4 653 // Store response in the unused part of buffer
nivmukka 0:1026a98e87f4 654 responseBuffer = &buffer[index];
nivmukka 0:1026a98e87f4 655 responseLength = sizeof(buffer) - index;
nivmukka 0:1026a98e87f4 656 }
nivmukka 0:1026a98e87f4 657
nivmukka 0:1026a98e87f4 658 // Set bit adjustments
nivmukka 0:1026a98e87f4 659 rxAlign = txLastBits; // Having a seperate variable is overkill. But it makes the next line easier to read.
nivmukka 0:1026a98e87f4 660 PCD_WriteRegister(BitFramingReg, (rxAlign << 4) + txLastBits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0]
nivmukka 0:1026a98e87f4 661
nivmukka 0:1026a98e87f4 662 // Transmit the buffer and receive the response.
nivmukka 0:1026a98e87f4 663 result = PCD_TransceiveData(buffer, bufferUsed, responseBuffer, &responseLength, &txLastBits, rxAlign);
nivmukka 0:1026a98e87f4 664 if (result == STATUS_COLLISION)
nivmukka 0:1026a98e87f4 665 { // More than one PICC in the field => collision.
nivmukka 0:1026a98e87f4 666 result = PCD_ReadRegister(CollReg); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0]
nivmukka 0:1026a98e87f4 667 if (result & 0x20)
nivmukka 0:1026a98e87f4 668 { // CollPosNotValid
nivmukka 0:1026a98e87f4 669 return STATUS_COLLISION; // Without a valid collision position we cannot continue
nivmukka 0:1026a98e87f4 670 }
nivmukka 0:1026a98e87f4 671
nivmukka 0:1026a98e87f4 672 uint8_t collisionPos = result & 0x1F; // Values 0-31, 0 means bit 32.
nivmukka 0:1026a98e87f4 673 if (collisionPos == 0)
nivmukka 0:1026a98e87f4 674 {
nivmukka 0:1026a98e87f4 675 collisionPos = 32;
nivmukka 0:1026a98e87f4 676 }
nivmukka 0:1026a98e87f4 677
nivmukka 0:1026a98e87f4 678 if (collisionPos <= currentLevelKnownBits)
nivmukka 0:1026a98e87f4 679 { // No progress - should not happen
nivmukka 0:1026a98e87f4 680 return STATUS_INTERNAL_ERROR;
nivmukka 0:1026a98e87f4 681 }
nivmukka 0:1026a98e87f4 682
nivmukka 0:1026a98e87f4 683 // Choose the PICC with the bit set.
nivmukka 0:1026a98e87f4 684 currentLevelKnownBits = collisionPos;
nivmukka 0:1026a98e87f4 685 count = (currentLevelKnownBits - 1) % 8; // The bit to modify
nivmukka 0:1026a98e87f4 686 index = 1 + (currentLevelKnownBits / 8) + (count ? 1 : 0); // First byte is index 0.
nivmukka 0:1026a98e87f4 687 buffer[index] |= (1 << count);
nivmukka 0:1026a98e87f4 688 }
nivmukka 0:1026a98e87f4 689 else if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 690 {
nivmukka 0:1026a98e87f4 691 return result;
nivmukka 0:1026a98e87f4 692 }
nivmukka 0:1026a98e87f4 693 else
nivmukka 0:1026a98e87f4 694 { // STATUS_OK
nivmukka 0:1026a98e87f4 695 if (currentLevelKnownBits >= 32)
nivmukka 0:1026a98e87f4 696 { // This was a SELECT.
nivmukka 0:1026a98e87f4 697 selectDone = true; // No more anticollision
nivmukka 0:1026a98e87f4 698 // We continue below outside the while.
nivmukka 0:1026a98e87f4 699 }
nivmukka 0:1026a98e87f4 700 else
nivmukka 0:1026a98e87f4 701 { // This was an ANTICOLLISION.
nivmukka 0:1026a98e87f4 702 // We now have all 32 bits of the UID in this Cascade Level
nivmukka 0:1026a98e87f4 703 currentLevelKnownBits = 32;
nivmukka 0:1026a98e87f4 704 // Run loop again to do the SELECT.
nivmukka 0:1026a98e87f4 705 }
nivmukka 0:1026a98e87f4 706 }
nivmukka 0:1026a98e87f4 707 } // End of while ( ! selectDone)
nivmukka 0:1026a98e87f4 708
nivmukka 0:1026a98e87f4 709 // We do not check the CBB - it was constructed by us above.
nivmukka 0:1026a98e87f4 710
nivmukka 0:1026a98e87f4 711 // Copy the found UID bytes from buffer[] to uid->uidByte[]
nivmukka 0:1026a98e87f4 712 index = (buffer[2] == PICC_CMD_CT) ? 3 : 2; // source index in buffer[]
nivmukka 0:1026a98e87f4 713 bytesToCopy = (buffer[2] == PICC_CMD_CT) ? 3 : 4;
nivmukka 0:1026a98e87f4 714 for (count = 0; count < bytesToCopy; count++)
nivmukka 0:1026a98e87f4 715 {
nivmukka 0:1026a98e87f4 716 uid->uidByte[uidIndex + count] = buffer[index++];
nivmukka 0:1026a98e87f4 717 }
nivmukka 0:1026a98e87f4 718
nivmukka 0:1026a98e87f4 719 // Check response SAK (Select Acknowledge)
nivmukka 0:1026a98e87f4 720 if (responseLength != 3 || txLastBits != 0)
nivmukka 0:1026a98e87f4 721 { // SAK must be exactly 24 bits (1 byte + CRC_A).
nivmukka 0:1026a98e87f4 722 return STATUS_ERROR;
nivmukka 0:1026a98e87f4 723 }
nivmukka 0:1026a98e87f4 724
nivmukka 0:1026a98e87f4 725 // Verify CRC_A - do our own calculation and store the control in buffer[2..3] - those bytes are not needed anymore.
nivmukka 0:1026a98e87f4 726 result = PCD_CalculateCRC(responseBuffer, 1, &buffer[2]);
nivmukka 0:1026a98e87f4 727 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 728 {
nivmukka 0:1026a98e87f4 729 return result;
nivmukka 0:1026a98e87f4 730 }
nivmukka 0:1026a98e87f4 731
nivmukka 0:1026a98e87f4 732 if ((buffer[2] != responseBuffer[1]) || (buffer[3] != responseBuffer[2]))
nivmukka 0:1026a98e87f4 733 {
nivmukka 0:1026a98e87f4 734 return STATUS_CRC_WRONG;
nivmukka 0:1026a98e87f4 735 }
nivmukka 0:1026a98e87f4 736
nivmukka 0:1026a98e87f4 737 if (responseBuffer[0] & 0x04)
nivmukka 0:1026a98e87f4 738 { // Cascade bit set - UID not complete yes
nivmukka 0:1026a98e87f4 739 cascadeLevel++;
nivmukka 0:1026a98e87f4 740 }
nivmukka 0:1026a98e87f4 741 else
nivmukka 0:1026a98e87f4 742 {
nivmukka 0:1026a98e87f4 743 uidComplete = true;
nivmukka 0:1026a98e87f4 744 uid->sak = responseBuffer[0];
nivmukka 0:1026a98e87f4 745 }
nivmukka 0:1026a98e87f4 746 } // End of while ( ! uidComplete)
nivmukka 0:1026a98e87f4 747
nivmukka 0:1026a98e87f4 748 // Set correct uid->size
nivmukka 0:1026a98e87f4 749 uid->size = 3 * cascadeLevel + 1;
nivmukka 0:1026a98e87f4 750
nivmukka 0:1026a98e87f4 751 return STATUS_OK;
nivmukka 0:1026a98e87f4 752 } // End PICC_Select()
nivmukka 0:1026a98e87f4 753
nivmukka 0:1026a98e87f4 754 /*
nivmukka 0:1026a98e87f4 755 * Instructs a PICC in state ACTIVE(*) to go to state HALT.
nivmukka 0:1026a98e87f4 756 */
nivmukka 0:1026a98e87f4 757 uint8_t MFRC522::PICC_HaltA()
nivmukka 0:1026a98e87f4 758 {
nivmukka 0:1026a98e87f4 759 uint8_t result;
nivmukka 0:1026a98e87f4 760 uint8_t buffer[4];
nivmukka 0:1026a98e87f4 761
nivmukka 0:1026a98e87f4 762 // Build command buffer
nivmukka 0:1026a98e87f4 763 buffer[0] = PICC_CMD_HLTA;
nivmukka 0:1026a98e87f4 764 buffer[1] = 0;
nivmukka 0:1026a98e87f4 765
nivmukka 0:1026a98e87f4 766 // Calculate CRC_A
nivmukka 0:1026a98e87f4 767 result = PCD_CalculateCRC(buffer, 2, &buffer[2]);
nivmukka 0:1026a98e87f4 768 if (result == STATUS_OK)
nivmukka 0:1026a98e87f4 769 {
nivmukka 0:1026a98e87f4 770 // Send the command.
nivmukka 0:1026a98e87f4 771 // The standard says:
nivmukka 0:1026a98e87f4 772 // If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the
nivmukka 0:1026a98e87f4 773 // HLTA command, this response shall be interpreted as 'not acknowledge'.
nivmukka 0:1026a98e87f4 774 // We interpret that this way: Only STATUS_TIMEOUT is an success.
nivmukka 0:1026a98e87f4 775 result = PCD_TransceiveData(buffer, sizeof(buffer), NULL, 0);
nivmukka 0:1026a98e87f4 776 if (result == STATUS_TIMEOUT)
nivmukka 0:1026a98e87f4 777 {
nivmukka 0:1026a98e87f4 778 result = STATUS_OK;
nivmukka 0:1026a98e87f4 779 }
nivmukka 0:1026a98e87f4 780 else if (result == STATUS_OK)
nivmukka 0:1026a98e87f4 781 { // That is ironically NOT ok in this case ;-)
nivmukka 0:1026a98e87f4 782 result = STATUS_ERROR;
nivmukka 0:1026a98e87f4 783 }
nivmukka 0:1026a98e87f4 784 }
nivmukka 0:1026a98e87f4 785
nivmukka 0:1026a98e87f4 786 return result;
nivmukka 0:1026a98e87f4 787 } // End PICC_HaltA()
nivmukka 0:1026a98e87f4 788
nivmukka 0:1026a98e87f4 789
nivmukka 0:1026a98e87f4 790 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 791 // Functions for communicating with MIFARE PICCs
nivmukka 0:1026a98e87f4 792 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 793
nivmukka 0:1026a98e87f4 794 /*
nivmukka 0:1026a98e87f4 795 * Executes the MFRC522 MFAuthent command.
nivmukka 0:1026a98e87f4 796 */
nivmukka 0:1026a98e87f4 797 uint8_t MFRC522::PCD_Authenticate(uint8_t command, uint8_t blockAddr, MIFARE_Key *key, Uid *uid)
nivmukka 0:1026a98e87f4 798 {
nivmukka 0:1026a98e87f4 799 uint8_t i, waitIRq = 0x10; // IdleIRq
nivmukka 0:1026a98e87f4 800
nivmukka 0:1026a98e87f4 801 // Build command buffer
nivmukka 0:1026a98e87f4 802 uint8_t sendData[12];
nivmukka 0:1026a98e87f4 803 sendData[0] = command;
nivmukka 0:1026a98e87f4 804 sendData[1] = blockAddr;
nivmukka 0:1026a98e87f4 805
nivmukka 0:1026a98e87f4 806 for (i = 0; i < MF_KEY_SIZE; i++)
nivmukka 0:1026a98e87f4 807 { // 6 key bytes
nivmukka 0:1026a98e87f4 808 sendData[2+i] = key->keyByte[i];
nivmukka 0:1026a98e87f4 809 }
nivmukka 0:1026a98e87f4 810
nivmukka 0:1026a98e87f4 811 for (i = 0; i < 4; i++)
nivmukka 0:1026a98e87f4 812 { // The first 4 bytes of the UID
nivmukka 0:1026a98e87f4 813 sendData[8+i] = uid->uidByte[i];
nivmukka 0:1026a98e87f4 814 }
nivmukka 0:1026a98e87f4 815
nivmukka 0:1026a98e87f4 816 // Start the authentication.
nivmukka 0:1026a98e87f4 817 return PCD_CommunicateWithPICC(PCD_MFAuthent, waitIRq, &sendData[0], sizeof(sendData));
nivmukka 0:1026a98e87f4 818 } // End PCD_Authenticate()
nivmukka 0:1026a98e87f4 819
nivmukka 0:1026a98e87f4 820 /*
nivmukka 0:1026a98e87f4 821 * Used to exit the PCD from its authenticated state.
nivmukka 0:1026a98e87f4 822 * Remember to call this function after communicating with an authenticated PICC - otherwise no new communications can start.
nivmukka 0:1026a98e87f4 823 */
nivmukka 0:1026a98e87f4 824 void MFRC522::PCD_StopCrypto1()
nivmukka 0:1026a98e87f4 825 {
nivmukka 0:1026a98e87f4 826 // Clear MFCrypto1On bit
nivmukka 0:1026a98e87f4 827 PCD_ClrRegisterBits(Status2Reg, 0x08); // Status2Reg[7..0] bits are: TempSensClear I2CForceHS reserved reserved MFCrypto1On ModemState[2:0]
nivmukka 0:1026a98e87f4 828 } // End PCD_StopCrypto1()
nivmukka 0:1026a98e87f4 829
nivmukka 0:1026a98e87f4 830 /*
nivmukka 0:1026a98e87f4 831 * Reads 16 bytes (+ 2 bytes CRC_A) from the active PICC.
nivmukka 0:1026a98e87f4 832 */
nivmukka 0:1026a98e87f4 833 uint8_t MFRC522::MIFARE_Read(uint8_t blockAddr, uint8_t *buffer, uint8_t *bufferSize)
nivmukka 0:1026a98e87f4 834 {
nivmukka 0:1026a98e87f4 835 uint8_t result = STATUS_NO_ROOM;
nivmukka 0:1026a98e87f4 836
nivmukka 0:1026a98e87f4 837 // Sanity check
nivmukka 0:1026a98e87f4 838 if ((buffer == NULL) || (*bufferSize < 18))
nivmukka 0:1026a98e87f4 839 {
nivmukka 0:1026a98e87f4 840 return result;
nivmukka 0:1026a98e87f4 841 }
nivmukka 0:1026a98e87f4 842
nivmukka 0:1026a98e87f4 843 // Build command buffer
nivmukka 0:1026a98e87f4 844 buffer[0] = PICC_CMD_MF_READ;
nivmukka 0:1026a98e87f4 845 buffer[1] = blockAddr;
nivmukka 0:1026a98e87f4 846
nivmukka 0:1026a98e87f4 847 // Calculate CRC_A
nivmukka 0:1026a98e87f4 848 result = PCD_CalculateCRC(buffer, 2, &buffer[2]);
nivmukka 0:1026a98e87f4 849 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 850 {
nivmukka 0:1026a98e87f4 851 return result;
nivmukka 0:1026a98e87f4 852 }
nivmukka 0:1026a98e87f4 853
nivmukka 0:1026a98e87f4 854 // Transmit the buffer and receive the response, validate CRC_A.
nivmukka 0:1026a98e87f4 855 return PCD_TransceiveData(buffer, 4, buffer, bufferSize, NULL, 0, true);
nivmukka 0:1026a98e87f4 856 } // End MIFARE_Read()
nivmukka 0:1026a98e87f4 857
nivmukka 0:1026a98e87f4 858 /*
nivmukka 0:1026a98e87f4 859 * Writes 16 bytes to the active PICC.
nivmukka 0:1026a98e87f4 860 */
nivmukka 0:1026a98e87f4 861 uint8_t MFRC522::MIFARE_Write(uint8_t blockAddr, uint8_t *buffer, uint8_t bufferSize)
nivmukka 0:1026a98e87f4 862 {
nivmukka 0:1026a98e87f4 863 uint8_t result;
nivmukka 0:1026a98e87f4 864
nivmukka 0:1026a98e87f4 865 // Sanity check
nivmukka 0:1026a98e87f4 866 if (buffer == NULL || bufferSize < 16)
nivmukka 0:1026a98e87f4 867 {
nivmukka 0:1026a98e87f4 868 return STATUS_INVALID;
nivmukka 0:1026a98e87f4 869 }
nivmukka 0:1026a98e87f4 870
nivmukka 0:1026a98e87f4 871 // Mifare Classic protocol requires two communications to perform a write.
nivmukka 0:1026a98e87f4 872 // Step 1: Tell the PICC we want to write to block blockAddr.
nivmukka 0:1026a98e87f4 873 uint8_t cmdBuffer[2];
nivmukka 0:1026a98e87f4 874 cmdBuffer[0] = PICC_CMD_MF_WRITE;
nivmukka 0:1026a98e87f4 875 cmdBuffer[1] = blockAddr;
nivmukka 0:1026a98e87f4 876 // Adds CRC_A and checks that the response is MF_ACK.
nivmukka 0:1026a98e87f4 877 result = PCD_MIFARE_Transceive(cmdBuffer, 2);
nivmukka 0:1026a98e87f4 878 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 879 {
nivmukka 0:1026a98e87f4 880 return result;
nivmukka 0:1026a98e87f4 881 }
nivmukka 0:1026a98e87f4 882
nivmukka 0:1026a98e87f4 883 // Step 2: Transfer the data
nivmukka 0:1026a98e87f4 884 // Adds CRC_A and checks that the response is MF_ACK.
nivmukka 0:1026a98e87f4 885 result = PCD_MIFARE_Transceive(buffer, bufferSize);
nivmukka 0:1026a98e87f4 886 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 887 {
nivmukka 0:1026a98e87f4 888 return result;
nivmukka 0:1026a98e87f4 889 }
nivmukka 0:1026a98e87f4 890
nivmukka 0:1026a98e87f4 891 return STATUS_OK;
nivmukka 0:1026a98e87f4 892 } // End MIFARE_Write()
nivmukka 0:1026a98e87f4 893
nivmukka 0:1026a98e87f4 894 /*
nivmukka 0:1026a98e87f4 895 * Writes a 4 byte page to the active MIFARE Ultralight PICC.
nivmukka 0:1026a98e87f4 896 */
nivmukka 0:1026a98e87f4 897 uint8_t MFRC522::MIFARE_UltralightWrite(uint8_t page, uint8_t *buffer, uint8_t bufferSize)
nivmukka 0:1026a98e87f4 898 {
nivmukka 0:1026a98e87f4 899 uint8_t result;
nivmukka 0:1026a98e87f4 900
nivmukka 0:1026a98e87f4 901 // Sanity check
nivmukka 0:1026a98e87f4 902 if (buffer == NULL || bufferSize < 4)
nivmukka 0:1026a98e87f4 903 {
nivmukka 0:1026a98e87f4 904 return STATUS_INVALID;
nivmukka 0:1026a98e87f4 905 }
nivmukka 0:1026a98e87f4 906
nivmukka 0:1026a98e87f4 907 // Build commmand buffer
nivmukka 0:1026a98e87f4 908 uint8_t cmdBuffer[6];
nivmukka 0:1026a98e87f4 909 cmdBuffer[0] = PICC_CMD_UL_WRITE;
nivmukka 0:1026a98e87f4 910 cmdBuffer[1] = page;
nivmukka 0:1026a98e87f4 911 memcpy(&cmdBuffer[2], buffer, 4);
nivmukka 0:1026a98e87f4 912
nivmukka 0:1026a98e87f4 913 // Perform the write
nivmukka 0:1026a98e87f4 914 result = PCD_MIFARE_Transceive(cmdBuffer, 6); // Adds CRC_A and checks that the response is MF_ACK.
nivmukka 0:1026a98e87f4 915 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 916 {
nivmukka 0:1026a98e87f4 917 return result;
nivmukka 0:1026a98e87f4 918 }
nivmukka 0:1026a98e87f4 919
nivmukka 0:1026a98e87f4 920 return STATUS_OK;
nivmukka 0:1026a98e87f4 921 } // End MIFARE_Ultralight_Write()
nivmukka 0:1026a98e87f4 922
nivmukka 0:1026a98e87f4 923 /*
nivmukka 0:1026a98e87f4 924 * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory.
nivmukka 0:1026a98e87f4 925 */
nivmukka 0:1026a98e87f4 926 uint8_t MFRC522::MIFARE_Decrement(uint8_t blockAddr, uint32_t delta)
nivmukka 0:1026a98e87f4 927 {
nivmukka 0:1026a98e87f4 928 return MIFARE_TwoStepHelper(PICC_CMD_MF_DECREMENT, blockAddr, delta);
nivmukka 0:1026a98e87f4 929 } // End MIFARE_Decrement()
nivmukka 0:1026a98e87f4 930
nivmukka 0:1026a98e87f4 931 /*
nivmukka 0:1026a98e87f4 932 * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory.
nivmukka 0:1026a98e87f4 933 */
nivmukka 0:1026a98e87f4 934 uint8_t MFRC522::MIFARE_Increment(uint8_t blockAddr, uint32_t delta)
nivmukka 0:1026a98e87f4 935 {
nivmukka 0:1026a98e87f4 936 return MIFARE_TwoStepHelper(PICC_CMD_MF_INCREMENT, blockAddr, delta);
nivmukka 0:1026a98e87f4 937 } // End MIFARE_Increment()
nivmukka 0:1026a98e87f4 938
nivmukka 0:1026a98e87f4 939 /**
nivmukka 0:1026a98e87f4 940 * MIFARE Restore copies the value of the addressed block into a volatile memory.
nivmukka 0:1026a98e87f4 941 */
nivmukka 0:1026a98e87f4 942 uint8_t MFRC522::MIFARE_Restore(uint8_t blockAddr)
nivmukka 0:1026a98e87f4 943 {
nivmukka 0:1026a98e87f4 944 // The datasheet describes Restore as a two step operation, but does not explain what data to transfer in step 2.
nivmukka 0:1026a98e87f4 945 // Doing only a single step does not work, so I chose to transfer 0L in step two.
nivmukka 0:1026a98e87f4 946 return MIFARE_TwoStepHelper(PICC_CMD_MF_RESTORE, blockAddr, 0L);
nivmukka 0:1026a98e87f4 947 } // End MIFARE_Restore()
nivmukka 0:1026a98e87f4 948
nivmukka 0:1026a98e87f4 949 /*
nivmukka 0:1026a98e87f4 950 * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore.
nivmukka 0:1026a98e87f4 951 */
nivmukka 0:1026a98e87f4 952 uint8_t MFRC522::MIFARE_TwoStepHelper(uint8_t command, uint8_t blockAddr, uint32_t data)
nivmukka 0:1026a98e87f4 953 {
nivmukka 0:1026a98e87f4 954 uint8_t result;
nivmukka 0:1026a98e87f4 955 uint8_t cmdBuffer[2]; // We only need room for 2 bytes.
nivmukka 0:1026a98e87f4 956
nivmukka 0:1026a98e87f4 957 // Step 1: Tell the PICC the command and block address
nivmukka 0:1026a98e87f4 958 cmdBuffer[0] = command;
nivmukka 0:1026a98e87f4 959 cmdBuffer[1] = blockAddr;
nivmukka 0:1026a98e87f4 960
nivmukka 0:1026a98e87f4 961 // Adds CRC_A and checks that the response is MF_ACK.
nivmukka 0:1026a98e87f4 962 result = PCD_MIFARE_Transceive(cmdBuffer, 2);
nivmukka 0:1026a98e87f4 963 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 964 {
nivmukka 0:1026a98e87f4 965 return result;
nivmukka 0:1026a98e87f4 966 }
nivmukka 0:1026a98e87f4 967
nivmukka 0:1026a98e87f4 968 // Step 2: Transfer the data
nivmukka 0:1026a98e87f4 969 // Adds CRC_A and accept timeout as success.
nivmukka 0:1026a98e87f4 970 result = PCD_MIFARE_Transceive((uint8_t *) &data, 4, true);
nivmukka 0:1026a98e87f4 971 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 972 {
nivmukka 0:1026a98e87f4 973 return result;
nivmukka 0:1026a98e87f4 974 }
nivmukka 0:1026a98e87f4 975
nivmukka 0:1026a98e87f4 976 return STATUS_OK;
nivmukka 0:1026a98e87f4 977 } // End MIFARE_TwoStepHelper()
nivmukka 0:1026a98e87f4 978
nivmukka 0:1026a98e87f4 979 /*
nivmukka 0:1026a98e87f4 980 * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block.
nivmukka 0:1026a98e87f4 981 */
nivmukka 0:1026a98e87f4 982 uint8_t MFRC522::MIFARE_Transfer(uint8_t blockAddr)
nivmukka 0:1026a98e87f4 983 {
nivmukka 0:1026a98e87f4 984 uint8_t cmdBuffer[2]; // We only need room for 2 bytes.
nivmukka 0:1026a98e87f4 985
nivmukka 0:1026a98e87f4 986 // Tell the PICC we want to transfer the result into block blockAddr.
nivmukka 0:1026a98e87f4 987 cmdBuffer[0] = PICC_CMD_MF_TRANSFER;
nivmukka 0:1026a98e87f4 988 cmdBuffer[1] = blockAddr;
nivmukka 0:1026a98e87f4 989
nivmukka 0:1026a98e87f4 990 // Adds CRC_A and checks that the response is MF_ACK.
nivmukka 0:1026a98e87f4 991 return PCD_MIFARE_Transceive(cmdBuffer, 2);
nivmukka 0:1026a98e87f4 992 } // End MIFARE_Transfer()
nivmukka 0:1026a98e87f4 993
nivmukka 0:1026a98e87f4 994
nivmukka 0:1026a98e87f4 995 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 996 // Support functions
nivmukka 0:1026a98e87f4 997 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 998
nivmukka 0:1026a98e87f4 999 /*
nivmukka 0:1026a98e87f4 1000 * Wrapper for MIFARE protocol communication.
nivmukka 0:1026a98e87f4 1001 * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout.
nivmukka 0:1026a98e87f4 1002 */
nivmukka 0:1026a98e87f4 1003 uint8_t MFRC522::PCD_MIFARE_Transceive(uint8_t *sendData, uint8_t sendLen, bool acceptTimeout)
nivmukka 0:1026a98e87f4 1004 {
nivmukka 0:1026a98e87f4 1005 uint8_t result;
nivmukka 0:1026a98e87f4 1006 uint8_t cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A.
nivmukka 0:1026a98e87f4 1007
nivmukka 0:1026a98e87f4 1008 // Sanity check
nivmukka 0:1026a98e87f4 1009 if (sendData == NULL || sendLen > 16)
nivmukka 0:1026a98e87f4 1010 {
nivmukka 0:1026a98e87f4 1011 return STATUS_INVALID;
nivmukka 0:1026a98e87f4 1012 }
nivmukka 0:1026a98e87f4 1013
nivmukka 0:1026a98e87f4 1014 // Copy sendData[] to cmdBuffer[] and add CRC_A
nivmukka 0:1026a98e87f4 1015 memcpy(cmdBuffer, sendData, sendLen);
nivmukka 0:1026a98e87f4 1016 result = PCD_CalculateCRC(cmdBuffer, sendLen, &cmdBuffer[sendLen]);
nivmukka 0:1026a98e87f4 1017 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 1018 {
nivmukka 0:1026a98e87f4 1019 return result;
nivmukka 0:1026a98e87f4 1020 }
nivmukka 0:1026a98e87f4 1021
nivmukka 0:1026a98e87f4 1022 sendLen += 2;
nivmukka 0:1026a98e87f4 1023
nivmukka 0:1026a98e87f4 1024 // Transceive the data, store the reply in cmdBuffer[]
nivmukka 0:1026a98e87f4 1025 uint8_t waitIRq = 0x30; // RxIRq and IdleIRq
nivmukka 0:1026a98e87f4 1026 uint8_t cmdBufferSize = sizeof(cmdBuffer);
nivmukka 0:1026a98e87f4 1027 uint8_t validBits = 0;
nivmukka 0:1026a98e87f4 1028 result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, sendLen, cmdBuffer, &cmdBufferSize, &validBits);
nivmukka 0:1026a98e87f4 1029 if (acceptTimeout && result == STATUS_TIMEOUT)
nivmukka 0:1026a98e87f4 1030 {
nivmukka 0:1026a98e87f4 1031 return STATUS_OK;
nivmukka 0:1026a98e87f4 1032 }
nivmukka 0:1026a98e87f4 1033
nivmukka 0:1026a98e87f4 1034 if (result != STATUS_OK)
nivmukka 0:1026a98e87f4 1035 {
nivmukka 0:1026a98e87f4 1036 return result;
nivmukka 0:1026a98e87f4 1037 }
nivmukka 0:1026a98e87f4 1038
nivmukka 0:1026a98e87f4 1039 // The PICC must reply with a 4 bit ACK
nivmukka 0:1026a98e87f4 1040 if (cmdBufferSize != 1 || validBits != 4)
nivmukka 0:1026a98e87f4 1041 {
nivmukka 0:1026a98e87f4 1042 return STATUS_ERROR;
nivmukka 0:1026a98e87f4 1043 }
nivmukka 0:1026a98e87f4 1044
nivmukka 0:1026a98e87f4 1045 if (cmdBuffer[0] != MF_ACK)
nivmukka 0:1026a98e87f4 1046 {
nivmukka 0:1026a98e87f4 1047 return STATUS_MIFARE_NACK;
nivmukka 0:1026a98e87f4 1048 }
nivmukka 0:1026a98e87f4 1049
nivmukka 0:1026a98e87f4 1050 return STATUS_OK;
nivmukka 0:1026a98e87f4 1051 } // End PCD_MIFARE_Transceive()
nivmukka 0:1026a98e87f4 1052
nivmukka 0:1026a98e87f4 1053
nivmukka 0:1026a98e87f4 1054 /*
nivmukka 0:1026a98e87f4 1055 * Translates the SAK (Select Acknowledge) to a PICC type.
nivmukka 0:1026a98e87f4 1056 */
nivmukka 0:1026a98e87f4 1057 uint8_t MFRC522::PICC_GetType(uint8_t sak)
nivmukka 0:1026a98e87f4 1058 {
nivmukka 0:1026a98e87f4 1059 uint8_t retType = PICC_TYPE_UNKNOWN;
nivmukka 0:1026a98e87f4 1060
nivmukka 0:1026a98e87f4 1061 if (sak & 0x04)
nivmukka 0:1026a98e87f4 1062 { // UID not complete
nivmukka 0:1026a98e87f4 1063 retType = PICC_TYPE_NOT_COMPLETE;
nivmukka 0:1026a98e87f4 1064 }
nivmukka 0:1026a98e87f4 1065 else
nivmukka 0:1026a98e87f4 1066 {
nivmukka 0:1026a98e87f4 1067 switch (sak)
nivmukka 0:1026a98e87f4 1068 {
nivmukka 0:1026a98e87f4 1069 case 0x09: retType = PICC_TYPE_MIFARE_MINI; break;
nivmukka 0:1026a98e87f4 1070 case 0x08: retType = PICC_TYPE_MIFARE_1K; break;
nivmukka 0:1026a98e87f4 1071 case 0x18: retType = PICC_TYPE_MIFARE_4K; break;
nivmukka 0:1026a98e87f4 1072 case 0x00: retType = PICC_TYPE_MIFARE_UL; break;
nivmukka 0:1026a98e87f4 1073 case 0x10:
nivmukka 0:1026a98e87f4 1074 case 0x11: retType = PICC_TYPE_MIFARE_PLUS; break;
nivmukka 0:1026a98e87f4 1075 case 0x01: retType = PICC_TYPE_TNP3XXX; break;
nivmukka 0:1026a98e87f4 1076 default:
nivmukka 0:1026a98e87f4 1077 if (sak & 0x20)
nivmukka 0:1026a98e87f4 1078 {
nivmukka 0:1026a98e87f4 1079 retType = PICC_TYPE_ISO_14443_4;
nivmukka 0:1026a98e87f4 1080 }
nivmukka 0:1026a98e87f4 1081 else if (sak & 0x40)
nivmukka 0:1026a98e87f4 1082 {
nivmukka 0:1026a98e87f4 1083 retType = PICC_TYPE_ISO_18092;
nivmukka 0:1026a98e87f4 1084 }
nivmukka 0:1026a98e87f4 1085 break;
nivmukka 0:1026a98e87f4 1086 }
nivmukka 0:1026a98e87f4 1087 }
nivmukka 0:1026a98e87f4 1088
nivmukka 0:1026a98e87f4 1089 return (retType);
nivmukka 0:1026a98e87f4 1090 } // End PICC_GetType()
nivmukka 0:1026a98e87f4 1091
nivmukka 0:1026a98e87f4 1092 /*
nivmukka 0:1026a98e87f4 1093 * Returns a string pointer to the PICC type name.
nivmukka 0:1026a98e87f4 1094 */
nivmukka 0:1026a98e87f4 1095 char* MFRC522::PICC_GetTypeName(uint8_t piccType)
nivmukka 0:1026a98e87f4 1096 {
nivmukka 0:1026a98e87f4 1097 if(piccType == PICC_TYPE_NOT_COMPLETE)
nivmukka 0:1026a98e87f4 1098 {
nivmukka 0:1026a98e87f4 1099 piccType = MFRC522_MaxPICCs - 1;
nivmukka 0:1026a98e87f4 1100 }
nivmukka 0:1026a98e87f4 1101
nivmukka 0:1026a98e87f4 1102 return((char *) _TypeNamePICC[piccType]);
nivmukka 0:1026a98e87f4 1103 } // End PICC_GetTypeName()
nivmukka 0:1026a98e87f4 1104
nivmukka 0:1026a98e87f4 1105 /*
nivmukka 0:1026a98e87f4 1106 * Returns a string pointer to a status code name.
nivmukka 0:1026a98e87f4 1107 */
nivmukka 0:1026a98e87f4 1108 char* MFRC522::GetStatusCodeName(uint8_t code)
nivmukka 0:1026a98e87f4 1109 {
nivmukka 0:1026a98e87f4 1110 return((char *) _ErrorMessage[code]);
nivmukka 0:1026a98e87f4 1111 } // End GetStatusCodeName()
nivmukka 0:1026a98e87f4 1112
nivmukka 0:1026a98e87f4 1113 /*
nivmukka 0:1026a98e87f4 1114 * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1).
nivmukka 0:1026a98e87f4 1115 */
nivmukka 0:1026a98e87f4 1116 void MFRC522::MIFARE_SetAccessBits(uint8_t *accessBitBuffer,
nivmukka 0:1026a98e87f4 1117 uint8_t g0,
nivmukka 0:1026a98e87f4 1118 uint8_t g1,
nivmukka 0:1026a98e87f4 1119 uint8_t g2,
nivmukka 0:1026a98e87f4 1120 uint8_t g3)
nivmukka 0:1026a98e87f4 1121 {
nivmukka 0:1026a98e87f4 1122 uint8_t c1 = ((g3 & 4) << 1) | ((g2 & 4) << 0) | ((g1 & 4) >> 1) | ((g0 & 4) >> 2);
nivmukka 0:1026a98e87f4 1123 uint8_t c2 = ((g3 & 2) << 2) | ((g2 & 2) << 1) | ((g1 & 2) << 0) | ((g0 & 2) >> 1);
nivmukka 0:1026a98e87f4 1124 uint8_t c3 = ((g3 & 1) << 3) | ((g2 & 1) << 2) | ((g1 & 1) << 1) | ((g0 & 1) << 0);
nivmukka 0:1026a98e87f4 1125
nivmukka 0:1026a98e87f4 1126 accessBitBuffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF);
nivmukka 0:1026a98e87f4 1127 accessBitBuffer[1] = c1 << 4 | (~c3 & 0xF);
nivmukka 0:1026a98e87f4 1128 accessBitBuffer[2] = c3 << 4 | c2;
nivmukka 0:1026a98e87f4 1129 } // End MIFARE_SetAccessBits()
nivmukka 0:1026a98e87f4 1130
nivmukka 0:1026a98e87f4 1131 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 1132 // Convenience functions - does not add extra functionality
nivmukka 0:1026a98e87f4 1133 /////////////////////////////////////////////////////////////////////////////////////
nivmukka 0:1026a98e87f4 1134
nivmukka 0:1026a98e87f4 1135 /*
nivmukka 0:1026a98e87f4 1136 * Returns true if a PICC responds to PICC_CMD_REQA.
nivmukka 0:1026a98e87f4 1137 * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored.
nivmukka 0:1026a98e87f4 1138 */
nivmukka 0:1026a98e87f4 1139 bool MFRC522::PICC_IsNewCardPresent(void)
nivmukka 0:1026a98e87f4 1140 {
nivmukka 0:1026a98e87f4 1141 uint8_t bufferATQA[2];
nivmukka 0:1026a98e87f4 1142 uint8_t bufferSize = sizeof(bufferATQA);
nivmukka 0:1026a98e87f4 1143 uint8_t result = PICC_RequestA(bufferATQA, &bufferSize);
nivmukka 0:1026a98e87f4 1144 return ((result == STATUS_OK) || (result == STATUS_COLLISION));
nivmukka 0:1026a98e87f4 1145 } // End PICC_IsNewCardPresent()
nivmukka 0:1026a98e87f4 1146
nivmukka 0:1026a98e87f4 1147 /*
nivmukka 0:1026a98e87f4 1148 * Simple wrapper around PICC_Select.
nivmukka 0:1026a98e87f4 1149 */
nivmukka 0:1026a98e87f4 1150 bool MFRC522::PICC_ReadCardSerial(void)
nivmukka 0:1026a98e87f4 1151 {
nivmukka 0:1026a98e87f4 1152 uint8_t result = PICC_Select(&uid);
nivmukka 0:1026a98e87f4 1153 return (result == STATUS_OK);
nivmukka 0:1026a98e87f4 1154 } // End PICC_ReadCardSerial()