RC522 Module and MFRC522 Library How to know PICC still present

Hello,

I am trying to find out if a PICC (RFID tag) still present on MFRC522 RFID reader.

/**
 * 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.
 * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
 * 
 * @return STATUS_OK on success, STATUS_??? otherwise.
 */
byte MFRC522::PICC_WakeupA(	byte *bufferATQA,	///< The buffer to store the ATQA (Answer to request) in
							byte *bufferSize	///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK.
							) {
	return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize);
} // End PICC_WakeupA()

I can't understand how WakeupA command works.

Library is here : GitHub - miguelbalboa/rfid: Arduino RFID Library for MFRC522
Full code is here : https://github.com/omersiar/RFID522-Door-Unlock/blob/master/RFIDDoorUnlock205.ino

I am getting UID like this;

int getID() {
  if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue
    return 0;
  }
  if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue
    return 0;
  }
  for (int i = 0; i < mfrc522.uid.size; i++) {  // for size of uid.size write uid.uidByte to readCard
    readCard[i] = mfrc522.uid.uidByte[i];
  }
  mfrc522.PICC_HaltA(); // Stop reading
  return 1;
}

and program looks EEPROM if readCard is known or not. If its a known card i want to run a program that does
1 wake up PICC which was previously Halted
2 if PICC still on reader do nothing (return 0)
3 else get back main loop (return 1)
```
*void RelayOn() {
  do {
    still = stillPresent();
    delay(1000);
  }
  while (!still); // Do nothing until PICC removed
}

int stillPresent() {
1  ????
2 ????
3 ????
}*
```
I tried checking UID again and again, but this seemed stupid because of EEPROM wears out
Thank you for your suggestions.

I tried checking UID again and again, but this seemed stupid because of EEPROM wears out

Writing to EEPROM wears it out. Reading from it does not. Of course, neither is necessary. Write only when there is new data (that is the value to write is different from what is there now). Read once and remember what you read.

I can't understand how WakeupA command works.

Does it matter that you understand it? Presumably, you are interested in having the function do something. So, just call it.

Not understanding the arguments it needs is a different story. The argument type is known - pointer to byte - which means that you need to define a byte array where the function will store some data. That data may, or more likely, may not, be of interest. The size of the array is up to you, but the comment suggests that 2 bytes is the minimum, which suggests that the function writes "OK" or "KO" there, depending on its ability to perform the requested function. Try a 10 byte array, first. See what the function actually writes into the array. Then, adjust the size of the array if needed.

Thank you for your reply. I understood, why i need byte array for buffer. I was confused by the how HaltA command works (i just call without checking Status if its succeed or failed)

I still cannot wake up PICC with this code,

#include <SPI.h>      // RC522 Module uses SPI protocol
#include <MFRC522.h>   // Library for Mifare RC522 D

#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);	// Create MFRC522 instance.


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);	 // Initialize serial communications with PC
  SPI.begin();           // MFRC522 Hardware uses SPI protocol
  mfrc522.PCD_Init();    // Initialize MFRC522 Hardware

}

void loop() {
  byte bufferATQA[10];
  byte bufferSize[10];
  // put your main code here, to run repeatedly: 
  // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    Serial.println("There is no PICC");
    return;
  }


  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    Serial.println("Cannot get UID");
    return;
  }
  Serial.println("Just got UID");
  mfrc522.PICC_HaltA();
  Serial.println("PICC Halted");
  delay(100);
  Serial.println("Im trying to Wake Up Halted PICC");
  mfrc522.PICC_WakeupA(bufferATQA, bufferSize); //wake up PICC which was previously Halted
    delay(100);
  mfrc522.PICC_RequestA(bufferATQA, bufferSize);
    delay(100);
  Serial.println("PICC Should Wake Up");
  delay(100);
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    Serial.println("Tried get UID but no luck");
  }
  delay(1000);
}
byte MFRC522::PICC_HaltA() {
	byte result;
	byte buffer[4]; 

	// Build command buffer
	buffer[0] = PICC_CMD_HLTA;
	buffer[1] = 0;
	// Calculate CRC_A
	result = PCD_CalculateCRC(buffer, 2, &buffer[2]);
	if (result != STATUS_OK) {
		return result;
	}

	// Send the command.
	// The standard says:
	//		If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the
	//		HLTA command, this response shall be interpreted as 'not acknowledge'.
	// We interpret that this way: Only STATUS_TIMEOUT is an success.
	result = PCD_TransceiveData(buffer, sizeof(buffer), NULL, 0);
	if (result == STATUS_TIMEOUT) {
		return STATUS_OK;
	}
	if (result == STATUS_OK) { // That is ironically NOT ok in this case ;-)
		return STATUS_ERROR;
	}
	return result;
} // End PICC_HaltA()
/**
 * 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.
 * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
 * 
 * @return STATUS_OK on success, STATUS_??? otherwise.
 */
byte MFRC522::PICC_WakeupA(	byte *bufferATQA,	///< The buffer to store the ATQA (Answer to request) in
							byte *bufferSize	///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK.
							) {
	return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize);
} // End PICC_WakeupA()

/**
 * Transmits REQA or WUPA commands.
 * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.
 * 
 * @return STATUS_OK on success, STATUS_??? otherwise.
 */ 
byte MFRC522::PICC_REQA_or_WUPA(	byte command, 		///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA
									byte *bufferATQA,	///< The buffer to store the ATQA (Answer to request) in
									byte *bufferSize	///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK.
							   ) {
	byte validBits;
	byte status;
	
	if (bufferATQA == NULL || *bufferSize < 2) {	// The ATQA response is 2 bytes long.
		return STATUS_NO_ROOM;
	}
	PCD_ClearRegisterBitMask(CollReg, 0x80);			// ValuesAfterColl=1 => Bits received after collision are cleared.
	validBits = 7;										// For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0]
	status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits);
	if (status != STATUS_OK) {
		return status;
	}
	if (*bufferSize != 2 || validBits != 0) {		// ATQA must be exactly 16 bits.
		return STATUS_ERROR;
	}
	return STATUS_OK;
} // End PICC_REQA_or_WUPA()

have you got the right answer to this yet, im mnew to arduino and im trying to find the same code, can you help me out please, or tell me if you coul do it, if you coul doit i can so please et back on this message, appreciate it

I had the same problem, and this code worked:

mfrc522.MIFARE_UnbrickUidSector(false); // Not sure if this is needed, but it works so I will leave it
byte bufferATQA[2];
byte bufferSize = sizeof(bufferATQA);

mfrc522.PICC_WakeupA(bufferATQA, &bufferSize);

I use this instead of PICC_IsNewCard() and it solved my problem.

Maybe someone is stumbling over this thread. so:
I had the same problem and solved it as follows:

-> PICC_IsNewCardPresent ()
-> PICC_ReadCardSerial ()
-> Save UID and note that there is an nfc tag.
-> PICC_HaltA ()

As long as the nfc tag is present, e.g. make every second:
-> PICC_WakeupA ()
-> PICC_HaltA ()

If PICC_WakeupA () fails, then note that there is no nfc tag left and continue with the top part (PICC_IsNewCardPresent ......).

So you can put the nfc tag to sleep and only checks if it can wake up (tag is present).