lora

Committer:
sarwadenj
Date:
Thu Feb 20 07:51:11 2020 +0000
Revision:
60:e8f234134c86
project

Who changed what in which revision?

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