Bluetooth-controlled Robot with RFID switching mode

Dependencies:   Motor mbed-rtos mbed

Committer:
GuillaumeMrzo
Date:
Sun Mar 13 03:51:00 2016 +0000
Revision:
0:64f17142aa89
Bluetooth-controlled Robot with RFID switching mode

Who changed what in which revision?

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