rfr

Committer:
muhammadimran
Date:
Fri Mar 18 09:41:55 2016 +0000
Revision:
0:d4f561785b16
rr

Who changed what in which revision?

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