uint8_t PN532::readGPIO(void) { pn532_packetbuffer[0] = PN532_COMMAND_READGPIO; // Send the READGPIO command (0x0C) if (HAL(writeCommand)(pn532_packetbuffer, 1)) return 0x0; HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)); /* READGPIO response without prefix and suffix should be in the following format: byte Description ------------- ------------------------------------------ b0 P3 GPIO Pins b1 P7 GPIO Pins (not used ... taken by I2C) b2 Interface Mode Pins (not used ... bus select pins) */ DMSG("P3 GPIO: "); DMSG_HEX(pn532_packetbuffer[7]); DMSG("P7 GPIO: "); DMSG_HEX(pn532_packetbuffer[8]); DMSG("I0I1 GPIO: "); DMSG_HEX(pn532_packetbuffer[9]); DMSG("\n"); return pn532_packetbuffer[0]; }
// TODO this should return a Driver MifareClassic, MifareUltralight, Type 4, Unknown // Guess Tag Type by looking at the ATQA and SAK values // Need to follow spec for Card Identification. Maybe AN1303, AN1305 and ??? unsigned int NfcAdapter::guessTagType() { // 4 uint8_t id - Mifare Classic // - ATQA 0x4 && SAK 0x8 // 7 uint8_t id // - ATQA 0x44 && SAK 0x8 - Mifare Classic // - ATQA 0x44 && SAK 0x0 - Mifare Ultralight NFC Forum Type 2 // - ATQA 0x344 && SAK 0x20 - NFC Forum Type 4 DMSG("Guess type"); DMSG("ATQA: 0x"); DMSG_HEX(ATQA); DMSG("SAK: 0x"); DMSG_HEX(SAK); /*if (uidLength == 4) { return TAG_TYPE_MIFARE_CLASSIC; } else { return TAG_TYPE_2; }*/ if(ATQA==0x4&&SAK==0x8){ return TAG_TYPE_MIFARE_CLASSIC; } if(ATQA==0x44&&SAK==0x0){ return TAG_TYPE_2; } return TAG_TYPE_UNKNOWN; }
boolean PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength) { pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later) pn532_packetbuffer[2] = cardbaudrate; if (HAL(writeCommand)(pn532_packetbuffer, 3)) { DMSG("No card(s) read"); return 0x0; // no cards read } // Wait for a card to enter the field uint8_t status = PN532_I2C_BUSY; // read data packet HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)); // check some basic stuff /* ISO14443A card response should be in the following format: byte Description ------------- ------------------------------------------ b0..6 Frame header and preamble b7 Tags Found b8 Tag Number (only one used in this example) b9..10 SENS_RES b11 SEL_RES b12 NFCID Length b13..NFCIDLen NFCID */ DMSG("Found "); DMSG(pn532_packetbuffer[0]); DMSG(" tags\n"); if (pn532_packetbuffer[0] != 1) return 0; uint16_t sens_res = pn532_packetbuffer[2]; sens_res <<= 8; sens_res |= pn532_packetbuffer[3]; DMSG("ATQA: 0x"); DMSG_HEX(sens_res); DMSG("SAK: 0x"); DMSG_HEX(pn532_packetbuffer[4]); /* Card appears to be Mifare Classic */ *uidLength = pn532_packetbuffer[5]; DMSG("UID:"); for (uint8_t i=0; i < pn532_packetbuffer[5]; i++) { uid[i] = pn532_packetbuffer[6+i]; DMSG(uid[i]); } DMSG('\n'); return 1; }
bool KeyDuino::readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout) { pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later) pn532_packetbuffer[2] = cardbaudrate; if (HAL(writeCommand)(pn532_packetbuffer, 3)) { DMSG_STR("\nFailed writing"); return 0x0; // command failed } // read data packet if (HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) { DMSG_STR("\nFailed reading response"); return 0x0; } // check some basic stuff /* ISO14443A card response should be in the following format: byte Description ------------- ------------------------------------------ b0 Tags Found b1 Tag Number (only one used in this example) b2..3 SENS_RES b4 SEL_RES b5 NFCID Length b6..NFCIDLen NFCID */ if (pn532_packetbuffer[0] != 1) return 0; inListedTag = pn532_packetbuffer[1]; uint16_t sens_res = pn532_packetbuffer[2]; sens_res <<= 8; sens_res |= pn532_packetbuffer[3]; DMSG("\nATQA: 0x"); DMSG_HEX(sens_res); DMSG("\nSAK: 0x"); DMSG_HEX(pn532_packetbuffer[4]); DMSG("\n"); /* Card appears to be Mifare Classic */ *uidLength = pn532_packetbuffer[5]; this->_uidLen = pn532_packetbuffer[5]; for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) { uid[i] = pn532_packetbuffer[6 + i]; this->_uid[i] = pn532_packetbuffer[6 + i]; } return 1; }
int8_t PN532_I2C::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) { command = header[0]; _wire->beginTransmission(PN532_I2C_ADDRESS); write(PN532_PREAMBLE); write(PN532_STARTCODE1); write(PN532_STARTCODE2); uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA write(length); write(~length + 1); // checksum of length write(PN532_HOSTTOPN532); uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA DMSG("write: "); for (uint8_t i = 0; i < hlen; i++) { if (write(header[i])) { sum += header[i]; DMSG_HEX(header[i]); } else { DMSG("\nToo many data to send, I2C doesn't support such a big packet\n"); // I2C max packet: 32 bytes return PN532_INVALID_FRAME; } } for (uint8_t i = 0; i < blen; i++) { if (write(body[i])) { sum += body[i]; DMSG_HEX(body[i]); } else { DMSG("\nToo many data to send, I2C doesn't support such a big packet\n"); // I2C max packet: 32 bytes return PN532_INVALID_FRAME; } } uint8_t checksum = ~sum + 1; // checksum of TFI + DATA write(checksum); write(PN532_POSTAMBLE); _wire->endTransmission(); DMSG('\n'); return readAckFrame(); }
/** @brief receive data . @param buf --> return value buffer. len --> length expect to receive. timeout --> time of reveiving @retval number of received bytes, 0 means no data received. */ int8_t PN532_HSU::receive(uint8_t *buf, int len, uint16_t timeout) { int read_bytes = 0; int ret; unsigned long start_millis; while (read_bytes < len) { start_millis = millis(); do { ret = _serial->read(); if (ret >= 0) { break; } delay(1); } while((timeout == 0) || ((millis()- start_millis ) < timeout)); if (ret < 0) { if(read_bytes){ return read_bytes; }else{ return PN532_TIMEOUT; } } buf[read_bytes] = (uint8_t)ret; DMSG_HEX(ret); read_bytes++; } return read_bytes; }
int8_t PN532_HSU::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) { /** dump serial buffer */ if(_serial->available()){ DMSG("Dump serial buffer: "); } while(_serial->available()){ uint8_t ret = _serial->read(); DMSG_HEX(ret); } command = header[0]; _serial->write(PN532_PREAMBLE); _serial->write(PN532_STARTCODE1); _serial->write(PN532_STARTCODE2); uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA _serial->write(length); _serial->write(~length + 1); // checksum of length _serial->write(PN532_HOSTTOPN532); uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA DMSG("\r\nWrite: "); _serial->write(header, hlen); for (uint8_t i = 0; i < hlen; i++) { sum += header[i]; DMSG_HEX(header[i]); } _serial->write(body, blen); for (uint8_t i = 0; i < blen; i++) { sum += body[i]; DMSG_HEX(body[i]); } uint8_t checksum = ~sum + 1; // checksum of TFI + DATA _serial->write(checksum); _serial->write(PN532_POSTAMBLE); return readAckFrame(); }
uint8_t PN532::readGPIO(void) { pn532_packetbuffer[0] = PN532_COMMAND_READGPIO; // Send the READGPIO command (0x0C) if (HAL(writeCommand)(pn532_packetbuffer, 1)) return 0x0; HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)); /* READGPIO response without prefix and suffix should be in the following format: byte Description ------------- ------------------------------------------ b0 P3 GPIO Pins b1 P7 GPIO Pins (not used ... taken by I2C) b2 Interface Mode Pins (not used ... bus select pins) */ DMSG("P3 GPIO: "); DMSG_HEX(pn532_packetbuffer[7]); DMSG("P7 GPIO: "); DMSG_HEX(pn532_packetbuffer[8]); DMSG("I0I1 GPIO: "); DMSG_HEX(pn532_packetbuffer[9]); #ifdef DEBUG // Note: You can use the IO GPIO value to detect the serial bus being used switch(pn532_packetbuffer[3]) { case 0x00: // Using UART Serial.println("Using UART (IO = 0x00)"); break; case 0x01: // Using I2C Serial.println("Using I2C (IO = 0x01)"); break; case 0x02: // Using I2C Serial.println("Using I2C (IO = 0x02)"); break; } #endif return pn532_packetbuffer[0]; }
void PN532_SPI::writeFrame(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) { digitalWrite(_ss, LOW); delay(2); // wake up PN532 write(DATA_WRITE); write(PN532_PREAMBLE); write(PN532_STARTCODE1); write(PN532_STARTCODE2); uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA write(length); write(~length + 1); // checksum of length write(PN532_HOSTTOPN532); uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA DMSG("write: "); for (uint8_t i = 0; i < hlen; i++) { write(header[i]); sum += header[i]; DMSG_HEX(header[i]); } for (uint8_t i = 0; i < blen; i++) { write(body[i]); sum += body[i]; DMSG_HEX(body[i]); } uint8_t checksum = ~sum + 1; // checksum of TFI + DATA write(checksum); write(PN532_POSTAMBLE); digitalWrite(_ss, HIGH); DMSG_STR(); }
void PN532_HSU::wakeup() { _serial->write(0x55); _serial->write(0x55); _serial->write(0); _serial->write(0); _serial->write(0); /** dump serial buffer */ if(_serial->available()){ DMSG("Dump serial buffer: "); } while(_serial->available()){ uint8_t ret = _serial->read(); DMSG_HEX(ret); } }
bool PN532::writeGPIO(uint8_t pinstate) { // Make sure pinstate does not try to toggle P32 or P34 pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34); // Fill command buffer pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO; pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; // P3 Pins pn532_packetbuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by I2C) DMSG("Writing P3 GPIO: "); DMSG_HEX(pn532_packetbuffer[1]); DMSG("\n"); // Send the WRITEGPIO command (0x0E) if (HAL(writeCommand)(pn532_packetbuffer, 3)) return 0; return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer))); }
bool EmulateTag::emulate(const uint16_t tgInitAsTargetTimeout){ uint8_t command[] = { PN532_COMMAND_TGINITASTARGET, 5, // MODE: PICC only, Passive only 0x04, 0x00, // SENS_RES 0x00, 0x00, 0x00, // NFCID1 0x20, // SEL_RES 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // FeliCaParams 0,0, 0,0,0,0,0,0,0,0,0,0, // NFCID3t 0, // length of general bytes 0 // length of historical bytes }; if(uidPtr != 0){ // if uid is set copy 3 bytes to nfcid1 memcpy(command + 4, uidPtr, 3); } if(1 != pn532.tgInitAsTarget(command,sizeof(command), tgInitAsTargetTimeout)){ DMSG("tgInitAsTarget failed or timed out!"); pn532.inRelease(); pn532.powerDown(0xF0); return false; } uint8_t compatibility_container[] = { 0, 0x0F, 0x20, 0, 0x54, 0, 0xFF, 0x04, // T 0x06, // L 0xE1, 0x04, // File identifier ((NDEF_MAX_LENGTH & 0xFF00) >> 8), (NDEF_MAX_LENGTH & 0xFF), // maximum NDEF file size 0x00, // read access 0x0 = granted 0x00 // write access 0x0 = granted | 0xFF = deny }; if(tagWriteable == false){ compatibility_container[14] = 0xFF; } tagWrittenByInitiator = false; uint8_t rwbuf[128]; uint8_t sendlen; int16_t status; tag_file currentFile = NONE; uint16_t cc_size = sizeof(compatibility_container); bool runLoop = true; while(runLoop){ status = pn532.tgGetData(rwbuf, sizeof(rwbuf)); if(status < 0){ DMSG("tgGetData failed!\n"); pn532.inRelease(); pn532.powerDown(0xF0); return true; } uint8_t p1 = rwbuf[C_APDU_P1]; uint8_t p2 = rwbuf[C_APDU_P2]; uint8_t lc = rwbuf[C_APDU_LC]; uint16_t p1p2_length = ((int16_t) p1 << 8) + p2; switch(rwbuf[C_APDU_INS]){ case ISO7816_SELECT_FILE: switch(p1){ case C_APDU_P1_SELECT_BY_ID: if(p2 != 0x0c){ DMSG("C_APDU_P2 != 0x0c\n"); setResponse(COMMAND_COMPLETE, rwbuf, &sendlen); } else if(lc == 2 && rwbuf[C_APDU_DATA] == 0xE1 && (rwbuf[C_APDU_DATA+1] == 0x03 || rwbuf[C_APDU_DATA+1] == 0x04)){ setResponse(COMMAND_COMPLETE, rwbuf, &sendlen); if(rwbuf[C_APDU_DATA+1] == 0x03){ currentFile = CC; } else if(rwbuf[C_APDU_DATA+1] == 0x04){ currentFile = NDEF; } } else { setResponse(TAG_NOT_FOUND, rwbuf, &sendlen); } break; case C_APDU_P1_SELECT_BY_NAME: const uint8_t ndef_tag_application_name_v2[] = {0, 0x7, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 }; if(0 == memcmp(ndef_tag_application_name_v2, rwbuf + C_APDU_P2, sizeof(ndef_tag_application_name_v2))){ setResponse(COMMAND_COMPLETE, rwbuf, &sendlen); } else{ DMSG("function not supported\n"); setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen); } break; } break; case ISO7816_READ_BINARY: switch(currentFile){ case NONE: setResponse(TAG_NOT_FOUND, rwbuf, &sendlen); break; case CC: if( p1p2_length > NDEF_MAX_LENGTH){ setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen); }else { memcpy(rwbuf,compatibility_container + p1p2_length, lc); setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc); } break; case NDEF: if( p1p2_length > NDEF_MAX_LENGTH){ setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen); }else { memcpy(rwbuf, ndef_file + p1p2_length, lc); setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc); } break; } break; case ISO7816_UPDATE_BINARY: if(!tagWriteable){ setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen); } else{ if( p1p2_length > NDEF_MAX_LENGTH){ setResponse(MEMORY_FAILURE, rwbuf, &sendlen); } else{ memcpy(ndef_file + p1p2_length, rwbuf + C_APDU_DATA, lc); setResponse(COMMAND_COMPLETE, rwbuf, &sendlen); tagWrittenByInitiator = true; } } break; default: DMSG("Command not supported!"); DMSG_HEX(rwbuf[C_APDU_INS]); DMSG("\n"); setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen); } status = pn532.tgSetData(rwbuf, sendlen); if(status < 0){ DMSG("tgSetData failed\n!"); pn532.inRelease(); pn532.powerDown(0xF0); return true; } } pn532.inRelease(); pn532.powerDown(0xF0); return true; }
int16_t PN532_I2C::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout) { uint16_t time = 0; do { if (_wire->requestFrom(PN532_I2C_ADDRESS, len + 2)) { if (read() & 1) { // check first byte --- status break; // PN532 is ready } } delay(1); time++; if ((0 != timeout) && (time > timeout)) { return -1; } } while (1); if (0x00 != read() || // PREAMBLE 0x00 != read() || // STARTCODE1 0xFF != read() // STARTCODE2 ) { return PN532_INVALID_FRAME; } uint8_t length = read(); if (0 != (uint8_t)(length + read())) { // checksum of length return PN532_INVALID_FRAME; } uint8_t cmd = command + 1; // response command if (PN532_PN532TOHOST != read() || (cmd) != read()) { return PN532_INVALID_FRAME; } length -= 2; if (length > len) { return PN532_NO_SPACE; // not enough space } DMSG("read: "); DMSG_HEX(cmd); uint8_t sum = PN532_PN532TOHOST + cmd; for (uint8_t i = 0; i < length; i++) { buf[i] = read(); sum += buf[i]; DMSG_HEX(buf[i]); } DMSG('\n'); uint8_t checksum = read(); if (0 != (uint8_t)(sum + checksum)) { DMSG("checksum is not ok\n"); return PN532_INVALID_FRAME; } read(); // POSTAMBLE return length; }
int16_t PN532_SPI::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout) { uint16_t time = 0; while (!isReady()) { delay(1); time++; if (timeout > 0 && time > timeout) { return PN532_TIMEOUT; } } digitalWrite(_ss, LOW); delay(1); int16_t result; do { write(DATA_READ); if (0x00 != read() || // PREAMBLE 0x00 != read() || // STARTCODE1 0xFF != read() // STARTCODE2 ) { result = PN532_INVALID_FRAME; break; } uint8_t length = read(); if (0 != (uint8_t)(length + read())) { // checksum of length result = PN532_INVALID_FRAME; break; } uint8_t cmd = command + 1; // response command if (PN532_PN532TOHOST != read() || (cmd) != read()) { result = PN532_INVALID_FRAME; break; } DMSG("read: "); DMSG_HEX(cmd); length -= 2; if (length > len) { for (uint8_t i = 0; i < length; i++) { DMSG_HEX(read()); // dump message } DMSG_STR("\nNot enough space"); read(); read(); result = PN532_NO_SPACE; // not enough space break; } uint8_t sum = PN532_PN532TOHOST + cmd; for (uint8_t i = 0; i < length; i++) { buf[i] = read(); sum += buf[i]; DMSG_HEX(buf[i]); } DMSG_STR(); uint8_t checksum = read(); if (0 != (uint8_t)(sum + checksum)) { DMSG_STR("checksum is not ok"); result = PN532_INVALID_FRAME; break; } read(); // POSTAMBLE result = length; } while (0); digitalWrite(_ss, HIGH); return result; }
bool KeyDuino::readPassiveTargetID_B(uint8_t *uid, uint8_t *uidLength, uint16_t timeout) { pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later) pn532_packetbuffer[2] = PN532_ISO14443B; pn532_packetbuffer[3] = 0x00; //AFI if (HAL(writeCommand)(pn532_packetbuffer, 4)) { DMSG_STR("\nFailed writing"); return 0x0; // command failed } // read data packet if (HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) { DMSG_STR("\nFailed reading response"); return 0x0; } /* ISO14443B card response should be in the following format: byte Description ------------------ ------------------------------------------ b0 Tags Found b1 Tag Number (only one used in this example) b2..13 ATQB b14 ATTRIB_RES Length b15..ATTRIB_RESLen ATTRIB_RES */ if (pn532_packetbuffer[0] != 1) return 0; inListedTag = pn532_packetbuffer[1]; /* ISO14443B ATQ_B format: byte Description ----- ------------------------------------------ b0 0x50 b1..4 PUPI b5..8 Application Data b9 Bit Rate Capacity b10 Max Frame Size/-4 Info b11 FWI/Coding Options */ uint8_t atqb[12]; DMSG("\nATQ_B: "); if (pn532_packetbuffer[2] == 0x50) { //Looking for the 0x50 to check if ATQ_B is well shaped for (uint8_t i = 0; i < 12; i++) { atqb[i] = pn532_packetbuffer[i+2]; DMSG_HEX(atqb[i]); } DMSG("\n"); } else //Sometimes there are remnant bytes, in that case just let it go ... return 0; DMSG_STR("\nATTRIB_RES: "); for (uint8_t i = 0; i < pn532_packetbuffer[14]; i++) { DMSG_HEX(pn532_packetbuffer[15 + i]); } DMSG("\n"); *uidLength = 4; this->_uidLen = 4; for (uint8_t i = 0; i < 4; i++) { uid[i] = atqb[1 + i]; this->_uid[i] = atqb[1 + i]; } return 1; }