I already wrote a blog post about how to read two Mifare cards simultaneously. This approach is similar, but in the NFC Payment cards, we have to deal with the APDU communication protocol differently in the PN532 board.

Communicating with two NFC financial cards has the same process of InListing them. The main idea of InListing cards is to detect the UID of each one. So we can select them when we need them without halting none of them.

As usual, I am using the Adafruit PN532 library and the Adafruit PN532 Board to modify the examples and run the code. In this case, I will add some new methods in the Adafruit_PN532.cpp file library starting with inListPassiveTarget2 method.

…
bool Adafruit_PN532::inListPassiveTarget2(uint8_t * numTags) {
   pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
   pn532_packetbuffer[1] = 2;
   pn532_packetbuffer[2] = 0;
   …

So I copied the inListPassiveTarget and created a new one: inListPassiveTarget2. The main difference in this second method is that I added one parameter to grab the number of detected cards. Also I modified the pn532_packetbuffer[1] = 2 to inList the limit; two cards if they are in the field range.

To save the number of detected cards, I added the declaration inside of the next if:

...
if (pn532_packetbuffer[5]==PN532_PN532TOHOST && pn532_packetbuffer[6]==PN532_RESPONSE_INLISTPASSIVETARGET) {
if (pn532_packetbuffer[7] != 1) {
...
*numTags = pn532_packetbuffer[7];
return true;
}

...

The next part is to modify InDataExchange. In this method, I added only one parameter to decide which card to read using tagActive instead of _inListedTag:

…
bool Adafruit_PN532::inDataExchange2(uint8_t * send, uint8_t sendLength, uint8_t * response, uint8_t * responseLength, uint8_t tagActive) {

  if (sendLength > PN532_PACKBUFFSIZ-2) {
    #ifdef PN532DEBUG
      PN532DEBUGPRINT.println(F("APDU length too long for packet buffer"));
    #endif
    return false;
  }
  uint8_t i;

  pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
  pn532_packetbuffer[1] = tagActive;
  for (i=0; i<sendLength; ++i) {
    pn532_packetbuffer[i+2] = send[i];
  }
  …

Now we have to design a new program to implements these new changes. Specially, it has to be capable to handle both cards. For this section, I modified the iso14443a_uid example to read data from the cards. As PoC, I just started the communication processes from two different cards: Visa and MasterCard using this code:

void loop(void) {
   bool success, success2;
   uint8_t numCards = 0;
   uint8_t apdubuffer[255] = {}, apdulen;
   uint8_t ppsecmd[] = {0x00, 0xA4, 0x04, 0x00, 0x0e, 0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00};
   success = nfc.inListPassiveTarget2(&numCards);
   if (numCards > 1){
     Serial.println("");
     Serial.println("Found TWO cards!");    
     success2 = nfc.inDataExchange2(ppsecmd, sizeof(ppsecmd), &apdubuffer[0], &apdulen, 1);
     Serial.print("First PPSE: ");
     for (uint8_t i=0; i < apdulen; i++) {
         Serial.print(apdubuffer[i], HEX); 
     }
     success2 = nfc.inDataExchange2(ppsecmd, sizeof(ppsecmd), &apdubuffer[0], &apdulen, 2);
     Serial.println("");
     Serial.print("Second PPSE: ");
     for (uint8_t i=0; i < apdulen; i++) {
         Serial.print(apdubuffer[i], HEX); 
     }
     …
   }
   delay(1000);
 }

Mainly, when I inListed, I sent a variable as parameter to detect the number of the cards. If numCards is more than 1, it will run the inDataExchange2 for each card using the first PPSE(ppsecmd[]) command to extract the type of the card depending in the card number parameter.

As note, this is NOT a completed communication process to extract all the cards’ data.