/*- * Free/Libre Near Field Communication (NFC) library * * Libnfc historical contributors: * Copyright (C) 2009 Roel Verdult * Copyright (C) 2009-2013 Romuald Conty * Copyright (C) 2010-2012 Romain Tartière * Copyright (C) 2010-2013 Philippe Teuwen * Copyright (C) 2012-2013 Ludovic Rousseau * See AUTHORS file for a more comprehensive list of contributors. * Additional contributors of this file: * Copyright (C) 2020 Adam Laurie * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ /** * @file pn53x.c * @brief PN531, PN532 and PN533 common functions */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include "nfc/nfc.h" #include "nfc-internal.h" #include "pn53x.h" #include "pn53x-internal.h" #include "mirror-subr.h" #define LOG_CATEGORY "libnfc.chip.pn53x" #define LOG_GROUP NFC_LOG_GROUP_CHIP const uint8_t pn53x_ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 }; const uint8_t pn53x_nack_frame[] = { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00 }; static const uint8_t pn53x_error_frame[] = { 0x00, 0x00, 0xff, 0x01, 0xff, 0x7f, 0x81, 0x00 }; const nfc_baud_rate pn532_iso14443a_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 }; const nfc_baud_rate pn533_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; const nfc_baud_rate pn53x_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 }; const nfc_baud_rate pn53x_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 }; const nfc_baud_rate pn53x_jewel_supported_baud_rates[] = { NBR_106, 0 }; const nfc_baud_rate pn53x_barcode_supported_baud_rates[] = { NBR_106, 0 }; const nfc_baud_rate pn532_iso14443b_supported_baud_rates[] = { NBR_106, 0 }; const nfc_baud_rate pn533_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; const nfc_modulation_type pn53x_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_DEP, 0}; /* prototypes */ int pn53x_reset_settings(struct nfc_device *pnd); int pn53x_writeback_register(struct nfc_device *pnd); nfc_modulation pn53x_ptt_to_nm(const pn53x_target_type ptt); pn53x_modulation pn53x_nm_to_pm(const nfc_modulation nm); pn53x_target_type pn53x_nm_to_ptt(const nfc_modulation nm); void *pn53x_current_target_new(const struct nfc_device *pnd, const nfc_target *pnt); void pn53x_current_target_free(const struct nfc_device *pnd); bool pn53x_current_target_is(const struct nfc_device *pnd, const nfc_target *pnt); /* implementations */ int pn53x_init(struct nfc_device *pnd) { int res = 0; // GetFirmwareVersion command is used to set PN53x chips type (PN531, PN532 or PN533) if ((res = pn53x_decode_firmware_version(pnd)) < 0) { return res; } if (!CHIP_DATA(pnd)->supported_modulation_as_initiator) { CHIP_DATA(pnd)->supported_modulation_as_initiator = malloc(sizeof(nfc_modulation_type) * (NMT_END_ENUM + 1)); if (! CHIP_DATA(pnd)->supported_modulation_as_initiator) return NFC_ESOFT; int nbSupportedModulation = 0; if ((pnd->btSupportByte & SUPPORT_ISO14443A)) { CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443A; nbSupportedModulation++; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_FELICA; nbSupportedModulation++; } if (pnd->btSupportByte & SUPPORT_ISO14443B) { CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B; nbSupportedModulation++; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443BI; nbSupportedModulation++; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B2SR; nbSupportedModulation++; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B2CT; nbSupportedModulation++; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443BICLASS; nbSupportedModulation++; } if (CHIP_DATA(pnd)->type != PN531) { CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_JEWEL; nbSupportedModulation++; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_BARCODE; nbSupportedModulation++; } CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_DEP; nbSupportedModulation++; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = 0; } if (!CHIP_DATA(pnd)->supported_modulation_as_target) { CHIP_DATA(pnd)->supported_modulation_as_target = (nfc_modulation_type *) pn53x_supported_modulation_as_target; } // CRC handling should be enabled by default as declared in nfc_device_new // which is the case by default for pn53x, so nothing to do here // Parity handling should be enabled by default as declared in nfc_device_new // which is the case by default for pn53x, so nothing to do here // We can't read these parameters, so we set a default config by using the SetParameters wrapper // Note: pn53x_SetParameters() will save the sent value in pnd->ui8Parameters cache if ((res = pn53x_SetParameters(pnd, PARAM_AUTO_ATR_RES | PARAM_AUTO_RATS)) < 0) { return res; } if ((res = pn53x_reset_settings(pnd)) < 0) { return res; } return NFC_SUCCESS; } int pn53x_reset_settings(struct nfc_device *pnd) { int res = 0; // Reset the ending transmission bits register, it is unknown what the last tranmission used there CHIP_DATA(pnd)->ui8TxBits = 0; if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_BitFraming, SYMBOL_TX_LAST_BITS, 0x00)) < 0) { return res; } // Make sure we reset the CRC and parity to chip handling. if ((res = pn53x_set_property_bool(pnd, NP_HANDLE_CRC, true)) < 0) return res; if ((res = pn53x_set_property_bool(pnd, NP_HANDLE_PARITY, true)) < 0) return res; // Activate "easy framing" feature by default if ((res = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) return res; // Deactivate the CRYPTO1 cipher, it may could cause problems when still active if ((res = pn53x_set_property_bool(pnd, NP_ACTIVATE_CRYPTO1, false)) < 0) return res; return NFC_SUCCESS; } int pn53x_transceive(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRxLen, int timeout) { bool mi = false; int res = 0; if (CHIP_DATA(pnd)->wb_trigged) { if ((res = pn53x_writeback_register(pnd)) < 0) { return res; } } PNCMD_TRACE(pbtTx[0]); if (timeout > 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Timeout value: %d", timeout); } else if (timeout == 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "No timeout"); } else if (timeout == -1) { timeout = CHIP_DATA(pnd)->timeout_command; } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid timeout value: %d", timeout); } uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); // Check if receiving buffers are available, if not, replace them if (szRxLen == 0 || !pbtRx) { pbtRx = abtRx; } else { szRx = szRxLen; } // Call the send/receice callback functions of the current driver if ((res = CHIP_DATA(pnd)->io->send(pnd, pbtTx, szTx, timeout)) < 0) { return res; } // Command is sent, we store the command CHIP_DATA(pnd)->last_command = pbtTx[0]; // Handle power mode for PN532 if ((CHIP_DATA(pnd)->type == PN532) && (TgInitAsTarget == pbtTx[0])) { // PN532 automatically goes into PowerDown mode when TgInitAsTarget command will be sent CHIP_DATA(pnd)->power_mode = POWERDOWN; } if ((res = CHIP_DATA(pnd)->io->receive(pnd, pbtRx, szRx, timeout)) < 0) { return res; } if ((CHIP_DATA(pnd)->type == PN532) && (TgInitAsTarget == pbtTx[0])) { // PN532 automatically wakeup on external RF field CHIP_DATA(pnd)->power_mode = NORMAL; // When TgInitAsTarget reply that means an external RF have waken up the chip } switch (pbtTx[0]) { case PowerDown: case InDataExchange: case InCommunicateThru: case InJumpForPSL: case InPSL: case InATR: case InSelect: case InJumpForDEP: case TgGetData: case TgGetInitiatorCommand: case TgSetData: case TgResponseToInitiator: case TgSetGeneralBytes: case TgSetMetaData: if (pbtRx[0] & 0x80) { abort(); } // NAD detected // if (pbtRx[0] & 0x40) { abort(); } // MI detected mi = pbtRx[0] & 0x40; CHIP_DATA(pnd)->last_status_byte = pbtRx[0] & 0x3f; break; case Diagnose: if (pbtTx[1] == 0x06) { // Diagnose: Card presence detection CHIP_DATA(pnd)->last_status_byte = pbtRx[0] & 0x3f; } else { CHIP_DATA(pnd)->last_status_byte = 0; }; break; case InDeselect: case InRelease: if (CHIP_DATA(pnd)->type == RCS360) { // Error code is in pbtRx[1] but we ignore error code anyway // because other PN53x chips always return 0 on those commands CHIP_DATA(pnd)->last_status_byte = 0; break; } CHIP_DATA(pnd)->last_status_byte = pbtRx[0] & 0x3f; break; case ReadRegister: case WriteRegister: if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by the status byte CHIP_DATA(pnd)->last_status_byte = pbtRx[0] & 0x3f; } else { CHIP_DATA(pnd)->last_status_byte = 0; } break; default: CHIP_DATA(pnd)->last_status_byte = 0; } while (mi) { int res2; uint8_t abtRx2[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; // Send empty command to card if ((res2 = CHIP_DATA(pnd)->io->send(pnd, pbtTx, 2, timeout)) < 0) { return res2; } if ((res2 = CHIP_DATA(pnd)->io->receive(pnd, abtRx2, sizeof(abtRx2), timeout)) < 0) { return res2; } mi = abtRx2[0] & 0x40; if ((size_t)(res + res2 - 1) > szRx) { CHIP_DATA(pnd)->last_status_byte = ESMALLBUF; break; } memcpy(pbtRx + res, abtRx2 + 1, res2 - 1); // Copy last status byte pbtRx[0] = abtRx2[0]; res += res2 - 1; } szRx = (size_t) res; switch (CHIP_DATA(pnd)->last_status_byte) { case 0: res = (int)szRx; break; case ETIMEOUT: case ECRC: case EPARITY: case EBITCOUNT: case EFRAMING: case EBITCOLL: case ERFPROTO: case ERFTIMEOUT: case EDEPUNKCMD: case EDEPINVSTATE: case ENAD: case ENFCID3: case EINVRXFRAM: case EBCC: case ECID: res = NFC_ERFTRANS; break; case ESMALLBUF: case EOVCURRENT: case EBUFOVF: case EOVHEAT: case EINBUFOVF: res = NFC_ECHIP; break; case EINVPARAM: case EOPNOTALL: case ECMD: case ENSECNOTSUPP: res = NFC_EINVARG; break; case ETGREL: case ECDISCARDED: res = NFC_ETGRELEASED; pn53x_current_target_free(pnd); break; case EMFAUTH: // When a MIFARE Classic AUTH fails, the tag is automatically in HALT state res = NFC_EMFCAUTHFAIL; break; default: res = NFC_ECHIP; break; }; if (res < 0) { pnd->last_error = res; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Chip error: \"%s\" (%02x), returned error: \"%s\" (%d))", pn53x_strerror(pnd), CHIP_DATA(pnd)->last_status_byte, nfc_strerror(pnd), res); } else { pnd->last_error = 0; } return res; } int pn53x_set_parameters(struct nfc_device *pnd, const uint8_t ui8Parameter, const bool bEnable) { uint8_t ui8Value = (bEnable) ? (CHIP_DATA(pnd)->ui8Parameters | ui8Parameter) : (CHIP_DATA(pnd)->ui8Parameters & ~(ui8Parameter)); if (ui8Value != CHIP_DATA(pnd)->ui8Parameters) { return pn53x_SetParameters(pnd, ui8Value); } return NFC_SUCCESS; } int pn53x_set_tx_bits(struct nfc_device *pnd, const uint8_t ui8Bits) { // Test if we need to update the transmission bits register setting if (CHIP_DATA(pnd)->ui8TxBits != ui8Bits) { int res = 0; // Set the amount of transmission bits in the PN53X chip register if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_BitFraming, SYMBOL_TX_LAST_BITS, ui8Bits)) < 0) return res; // Store the new setting CHIP_DATA(pnd)->ui8TxBits = ui8Bits; } return NFC_SUCCESS; } int pn53x_wrap_frame(const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtFrame) { uint8_t btData; uint32_t uiBitPos; uint32_t uiDataPos = 0; size_t szBitsLeft = szTxBits; size_t szFrameBits = 0; // Make sure we should frame at least something if (szBitsLeft == 0) return NFC_ECHIP; // Handle a short response (1byte) as a special case if (szBitsLeft < 9) { *pbtFrame = *pbtTx; szFrameBits = szTxBits; return szFrameBits; } // We start by calculating the frame length in bits szFrameBits = szTxBits + (szTxBits / 8); // Parse the data bytes and add the parity bits // This is really a sensitive process, mirror the frame bytes and append parity bits // buffer = mirror(frame-byte) + parity + mirror(frame-byte) + parity + ... // split "buffer" up in segments of 8 bits again and mirror them // air-bytes = mirror(buffer-byte) + mirror(buffer-byte) + mirror(buffer-byte) + .. while (true) { // Reset the temporary frame byte; uint8_t btFrame = 0; for (uiBitPos = 0; uiBitPos < 8; uiBitPos++) { // Copy as much data that fits in the frame byte btData = mirror(pbtTx[uiDataPos]); btFrame |= (btData >> uiBitPos); // Save this frame byte *pbtFrame = mirror(btFrame); // Set the remaining bits of the date in the new frame byte and append the parity bit btFrame = (btData << (8 - uiBitPos)); btFrame |= ((pbtTxPar[uiDataPos] & 0x01) << (7 - uiBitPos)); // Backup the frame bits we have so far pbtFrame++; *pbtFrame = mirror(btFrame); // Increase the data (without parity bit) position uiDataPos++; // Test if we are done if (szBitsLeft < 9) return szFrameBits; szBitsLeft -= 8; } // Every 8 data bytes we lose one frame byte to the parities pbtFrame++; } } int pn53x_unwrap_frame(const uint8_t *pbtFrame, const size_t szFrameBits, uint8_t *pbtRx, uint8_t *pbtRxPar) { uint8_t btFrame; uint8_t btData; uint8_t uiBitPos; uint32_t uiDataPos = 0; uint8_t *pbtFramePos = (uint8_t *) pbtFrame; size_t szBitsLeft = szFrameBits; size_t szRxBits = 0; // Make sure we should frame at least something if (szBitsLeft == 0) return NFC_ECHIP; // Handle a short response (1byte) as a special case if (szBitsLeft < 9) { *pbtRx = *pbtFrame; szRxBits = szFrameBits; return szRxBits; } // Calculate the data length in bits szRxBits = szFrameBits - (szFrameBits / 9); // Parse the frame bytes, remove the parity bits and store them in the parity array // This process is the reverse of WrapFrame(), look there for more info while (true) { for (uiBitPos = 0; uiBitPos < 8; uiBitPos++) { btFrame = mirror(pbtFramePos[uiDataPos]); btData = (btFrame << uiBitPos); btFrame = mirror(pbtFramePos[uiDataPos + 1]); btData |= (btFrame >> (8 - uiBitPos)); pbtRx[uiDataPos] = mirror(btData); if (pbtRxPar != NULL) pbtRxPar[uiDataPos] = ((btFrame >> (7 - uiBitPos)) & 0x01); // Increase the data (without parity bit) position uiDataPos++; // Test if we are done if (szBitsLeft < 9) return szRxBits; szBitsLeft -= 9; } // Every 8 data bytes we lose one frame byte to the parities pbtFramePos++; } } int pn53x_decode_target_data(const uint8_t *pbtRawData, size_t szRawData, pn53x_type type, nfc_modulation_type nmt, nfc_target_info *pnti) { uint8_t szAttribRes; const uint8_t *pbtUid; switch (nmt) { case NMT_ISO14443A: // We skip the first byte: its the target number (Tg) pbtRawData++; // Somehow they switched the lower and upper ATQA bytes around for the PN531 chipset if (type == PN531) { pnti->nai.abtAtqa[1] = *(pbtRawData++); pnti->nai.abtAtqa[0] = *(pbtRawData++); } else { pnti->nai.abtAtqa[0] = *(pbtRawData++); pnti->nai.abtAtqa[1] = *(pbtRawData++); } pnti->nai.btSak = *(pbtRawData++); // Copy the NFCID1 pnti->nai.szUidLen = *(pbtRawData++); pbtUid = pbtRawData; pbtRawData += pnti->nai.szUidLen; // Did we received an optional ATS (Smardcard ATR) if (szRawData > (pnti->nai.szUidLen + 5)) { pnti->nai.szAtsLen = ((*(pbtRawData++)) - 1); // In pbtRawData, ATS Length byte is counted in ATS Frame. memcpy(pnti->nai.abtAts, pbtRawData, pnti->nai.szAtsLen); } else { pnti->nai.szAtsLen = 0; } // For PN531, strip CT (Cascade Tag) to retrieve and store the _real_ UID // (e.g. 0x8801020304050607 is in fact 0x01020304050607) if ((pnti->nai.szUidLen == 8) && (pbtUid[0] == 0x88)) { pnti->nai.szUidLen = 7; memcpy(pnti->nai.abtUid, pbtUid + 1, 7); // } else if ((pnti->nai.szUidLen == 12) && (pbtUid[0] == 0x88) && (pbtUid[4] == 0x88)) { } else if (pnti->nai.szUidLen > 10) { pnti->nai.szUidLen = 10; memcpy(pnti->nai.abtUid, pbtUid + 1, 3); memcpy(pnti->nai.abtUid + 3, pbtUid + 5, 3); memcpy(pnti->nai.abtUid + 6, pbtUid + 8, 4); } else { // For PN532, PN533 memcpy(pnti->nai.abtUid, pbtUid, pnti->nai.szUidLen); } break; case NMT_ISO14443B: // We skip the first byte: its the target number (Tg) pbtRawData++; // Now we are in ATQB, we skip the first ATQB byte always equal to 0x50 pbtRawData++; // Store the PUPI (Pseudo-Unique PICC Identifier) memcpy(pnti->nbi.abtPupi, pbtRawData, 4); pbtRawData += 4; // Store the Application Data memcpy(pnti->nbi.abtApplicationData, pbtRawData, 4); pbtRawData += 4; // Store the Protocol Info memcpy(pnti->nbi.abtProtocolInfo, pbtRawData, 3); pbtRawData += 3; // We leave the ATQB field, we now enter in Card IDentifier szAttribRes = *(pbtRawData++); if (szAttribRes) { pnti->nbi.ui8CardIdentifier = *(pbtRawData++); } break; case NMT_ISO14443BI: // Skip V & T Addresses pbtRawData++; if (*pbtRawData != 0x07) { // 0x07 = REPGEN return NFC_ECHIP; } pbtRawData++; // Store the UID memcpy(pnti->nii.abtDIV, pbtRawData, 4); pbtRawData += 4; pnti->nii.btVerLog = *(pbtRawData++); if (pnti->nii.btVerLog & 0x80) { // Type = long? pnti->nii.btConfig = *(pbtRawData++); if (pnti->nii.btConfig & 0x40) { memcpy(pnti->nii.abtAtr, pbtRawData, szRawData - 8); pnti->nii.szAtrLen = szRawData - 8; } } break; case NMT_ISO14443B2SR: // Store the UID memcpy(pnti->nsi.abtUID, pbtRawData, 8); break; case NMT_ISO14443BICLASS: // Store the UID for (uint8_t i = 0 ; i < 8 ; ++i) pnti->nhi.abtUID[7 - i] = pbtRawData[i]; break; case NMT_ISO14443B2CT: // Store UID LSB memcpy(pnti->nci.abtUID, pbtRawData, 2); pbtRawData += 2; // Store Prod Code & Fab Code pnti->nci.btProdCode = *(pbtRawData++); pnti->nci.btFabCode = *(pbtRawData++); // Store UID MSB memcpy(pnti->nci.abtUID + 2, pbtRawData, 2); break; case NMT_FELICA: // We skip the first byte: its the target number (Tg) pbtRawData++; // Store the mandatory info pnti->nfi.szLen = *(pbtRawData++); pnti->nfi.btResCode = *(pbtRawData++); // Copy the NFCID2t memcpy(pnti->nfi.abtId, pbtRawData, 8); pbtRawData += 8; // Copy the felica padding memcpy(pnti->nfi.abtPad, pbtRawData, 8); pbtRawData += 8; // Test if the System code (SYST_CODE) is available if (pnti->nfi.szLen > 18) { memcpy(pnti->nfi.abtSysCode, pbtRawData, 2); } break; case NMT_JEWEL: // We skip the first byte: its the target number (Tg) pbtRawData++; // Store the mandatory info memcpy(pnti->nji.btSensRes, pbtRawData, 2); pbtRawData += 2; memcpy(pnti->nji.btId, pbtRawData, 4); break; case NMT_BARCODE: pnti->nti.szDataLen = szRawData; memcpy(pnti->nti.abtData, pbtRawData, szRawData); break; // Should not happend... case NMT_DEP: return NFC_ECHIP; } return NFC_SUCCESS; } static int pn53x_ReadRegister(struct nfc_device *pnd, uint16_t ui16RegisterAddress, uint8_t *ui8Value) { uint8_t abtCmd[] = { ReadRegister, ui16RegisterAddress >> 8, ui16RegisterAddress & 0xff }; uint8_t abtRegValue[2]; size_t szRegValue = sizeof(abtRegValue); int res = 0; PNREG_TRACE(ui16RegisterAddress); if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRegValue, szRegValue, -1)) < 0) { return res; } if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte *ui8Value = abtRegValue[1]; } else { *ui8Value = abtRegValue[0]; } return NFC_SUCCESS; } int pn53x_read_register(struct nfc_device *pnd, uint16_t ui16RegisterAddress, uint8_t *ui8Value) { return pn53x_ReadRegister(pnd, ui16RegisterAddress, ui8Value); } static int pn53x_WriteRegister(struct nfc_device *pnd, const uint16_t ui16RegisterAddress, const uint8_t ui8Value) { uint8_t abtCmd[] = { WriteRegister, ui16RegisterAddress >> 8, ui16RegisterAddress & 0xff, ui8Value }; PNREG_TRACE(ui16RegisterAddress); return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_write_register(struct nfc_device *pnd, const uint16_t ui16RegisterAddress, const uint8_t ui8SymbolMask, const uint8_t ui8Value) { if ((ui16RegisterAddress < PN53X_CACHE_REGISTER_MIN_ADDRESS) || (ui16RegisterAddress > PN53X_CACHE_REGISTER_MAX_ADDRESS)) { // Direct write if (ui8SymbolMask != 0xff) { int res = 0; uint8_t ui8CurrentValue; if ((res = pn53x_read_register(pnd, ui16RegisterAddress, &ui8CurrentValue)) < 0) return res; uint8_t ui8NewValue = ((ui8Value & ui8SymbolMask) | (ui8CurrentValue & (~ui8SymbolMask))); if (ui8NewValue != ui8CurrentValue) { return pn53x_WriteRegister(pnd, ui16RegisterAddress, ui8NewValue); } } else { return pn53x_WriteRegister(pnd, ui16RegisterAddress, ui8Value); } } else { // Write-back cache area const int internal_address = ui16RegisterAddress - PN53X_CACHE_REGISTER_MIN_ADDRESS; CHIP_DATA(pnd)->wb_data[internal_address] = (CHIP_DATA(pnd)->wb_data[internal_address] & CHIP_DATA(pnd)->wb_mask[internal_address] & (~ui8SymbolMask)) | (ui8Value & ui8SymbolMask); CHIP_DATA(pnd)->wb_mask[internal_address] = CHIP_DATA(pnd)->wb_mask[internal_address] | ui8SymbolMask; CHIP_DATA(pnd)->wb_trigged = true; } return NFC_SUCCESS; } int pn53x_writeback_register(struct nfc_device *pnd) { int res = 0; // TODO Check at each step (ReadRegister, WriteRegister) if we didn't exceed max supported frame length BUFFER_INIT(abtReadRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtReadRegisterCmd, ReadRegister); // First step, it looks for registers to be read before applying the requested mask CHIP_DATA(pnd)->wb_trigged = false; for (size_t n = 0; n < PN53X_CACHE_REGISTER_SIZE; n++) { if ((CHIP_DATA(pnd)->wb_mask[n]) && (CHIP_DATA(pnd)->wb_mask[n] != 0xff)) { // This register needs to be read: mask is present but does not cover full data width (ie. mask != 0xff) const uint16_t pn53x_register_address = PN53X_CACHE_REGISTER_MIN_ADDRESS + n; BUFFER_APPEND(abtReadRegisterCmd, pn53x_register_address >> 8); BUFFER_APPEND(abtReadRegisterCmd, pn53x_register_address & 0xff); } } if (BUFFER_SIZE(abtReadRegisterCmd) > 1) { // It needs to read some registers uint8_t abtRes[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRes = sizeof(abtRes); // It transceives the previously constructed ReadRegister command if ((res = pn53x_transceive(pnd, abtReadRegisterCmd, BUFFER_SIZE(abtReadRegisterCmd), abtRes, szRes, -1)) < 0) { return res; } size_t i = 0; if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte i = 1; } for (size_t n = 0; n < PN53X_CACHE_REGISTER_SIZE; n++) { if ((CHIP_DATA(pnd)->wb_mask[n]) && (CHIP_DATA(pnd)->wb_mask[n] != 0xff)) { CHIP_DATA(pnd)->wb_data[n] = ((CHIP_DATA(pnd)->wb_data[n] & CHIP_DATA(pnd)->wb_mask[n]) | (abtRes[i] & (~CHIP_DATA(pnd)->wb_mask[n]))); if (CHIP_DATA(pnd)->wb_data[n] != abtRes[i]) { // Requested value is different from read one CHIP_DATA(pnd)->wb_mask[n] = 0xff; // We can now apply whole data bits } else { CHIP_DATA(pnd)->wb_mask[n] = 0x00; // We already have the right value } i++; } } } // Now, the writeback-cache only has masks with 0xff, we can start to WriteRegister BUFFER_INIT(abtWriteRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtWriteRegisterCmd, WriteRegister); for (size_t n = 0; n < PN53X_CACHE_REGISTER_SIZE; n++) { if (CHIP_DATA(pnd)->wb_mask[n] == 0xff) { const uint16_t pn53x_register_address = PN53X_CACHE_REGISTER_MIN_ADDRESS + n; PNREG_TRACE(pn53x_register_address); BUFFER_APPEND(abtWriteRegisterCmd, pn53x_register_address >> 8); BUFFER_APPEND(abtWriteRegisterCmd, pn53x_register_address & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, CHIP_DATA(pnd)->wb_data[n]); // This register is handled, we reset the mask to prevent CHIP_DATA(pnd)->wb_mask[n] = 0x00; } } if (BUFFER_SIZE(abtWriteRegisterCmd) > 1) { // We need to write some registers if ((res = pn53x_transceive(pnd, abtWriteRegisterCmd, BUFFER_SIZE(abtWriteRegisterCmd), NULL, 0, -1)) < 0) { return res; } } return NFC_SUCCESS; } int pn53x_decode_firmware_version(struct nfc_device *pnd) { const uint8_t abtCmd[] = { GetFirmwareVersion }; uint8_t abtFw[4]; size_t szFwLen = sizeof(abtFw); int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtFw, szFwLen, -1)) < 0) { return res; } szFwLen = (size_t) res; // Determine which version of chip it is: PN531 will return only 2 bytes, while others return 4 bytes and have the first to tell the version IC if (szFwLen == 2) { CHIP_DATA(pnd)->type = PN531; } else if (szFwLen == 4) { if (abtFw[0] == 0x32) { // PN532 version IC CHIP_DATA(pnd)->type = PN532; } else if (abtFw[0] == 0x33) { // PN533 version IC if (abtFw[1] == 0x01) { // Sony ROM code CHIP_DATA(pnd)->type = RCS360; } else { CHIP_DATA(pnd)->type = PN533; } } else { // Unknown version IC return NFC_ENOTIMPL; } } else { // Unknown chip return NFC_ENOTIMPL; } // Convert firmware info in text, PN531 gives 2 bytes info, but PN532 and PN533 gives 4 switch (CHIP_DATA(pnd)->type) { case PN531: snprintf(CHIP_DATA(pnd)->firmware_text, sizeof(CHIP_DATA(pnd)->firmware_text), "PN531 v%d.%d", abtFw[0], abtFw[1]); pnd->btSupportByte = SUPPORT_ISO14443A | SUPPORT_ISO18092; break; case PN532: snprintf(CHIP_DATA(pnd)->firmware_text, sizeof(CHIP_DATA(pnd)->firmware_text), "PN532 v%d.%d", abtFw[1], abtFw[2]); pnd->btSupportByte = abtFw[3]; break; case PN533: case RCS360: snprintf(CHIP_DATA(pnd)->firmware_text, sizeof(CHIP_DATA(pnd)->firmware_text), "PN533 v%d.%d", abtFw[1], abtFw[2]); pnd->btSupportByte = abtFw[3]; break; case PN53X: // Could not happend break; } return NFC_SUCCESS; } static uint8_t pn53x_int_to_timeout(const int ms) { uint8_t res = 0; if (ms) { res = 0x10; for (int i = 3280; i > 1; i /= 2) { if (ms > i) break; res--; } } return res; } int pn53x_set_property_int(struct nfc_device *pnd, const nfc_property property, const int value) { switch (property) { case NP_TIMEOUT_COMMAND: CHIP_DATA(pnd)->timeout_command = value; break; case NP_TIMEOUT_ATR: CHIP_DATA(pnd)->timeout_atr = value; return pn53x_RFConfiguration__Various_timings(pnd, pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_atr), pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_communication)); case NP_TIMEOUT_COM: CHIP_DATA(pnd)->timeout_communication = value; return pn53x_RFConfiguration__Various_timings(pnd, pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_atr), pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_communication)); // Following properties are invalid (not integer) case NP_HANDLE_CRC: case NP_HANDLE_PARITY: case NP_ACTIVATE_FIELD: case NP_ACTIVATE_CRYPTO1: case NP_INFINITE_SELECT: case NP_ACCEPT_INVALID_FRAMES: case NP_ACCEPT_MULTIPLE_FRAMES: case NP_AUTO_ISO14443_4: case NP_EASY_FRAMING: case NP_FORCE_ISO14443_A: case NP_FORCE_ISO14443_B: case NP_FORCE_SPEED_106: return NFC_EINVARG; } return NFC_SUCCESS; } int pn53x_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable) { uint8_t btValue; int res = 0; switch (property) { case NP_HANDLE_CRC: // Enable or disable automatic receiving/sending of CRC bytes if (bEnable == pnd->bCrc) { // Nothing to do return NFC_SUCCESS; } // TX and RX are both represented by the symbol 0x80 btValue = (bEnable) ? 0x80 : 0x00; if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxMode, SYMBOL_TX_CRC_ENABLE, btValue)) < 0) return res; if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_CRC_ENABLE, btValue)) < 0) return res; pnd->bCrc = bEnable; return NFC_SUCCESS; case NP_HANDLE_PARITY: // Handle parity bit by PN53X chip or parse it as data bit if (bEnable == pnd->bPar) // Nothing to do return NFC_SUCCESS; btValue = (bEnable) ? 0x00 : SYMBOL_PARITY_DISABLE; if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_ManualRCV, SYMBOL_PARITY_DISABLE, btValue)) < 0) return res; pnd->bPar = bEnable; return NFC_SUCCESS; case NP_EASY_FRAMING: pnd->bEasyFraming = bEnable; return NFC_SUCCESS; case NP_ACTIVATE_FIELD: return pn53x_RFConfiguration__RF_field(pnd, bEnable); case NP_ACTIVATE_CRYPTO1: btValue = (bEnable) ? SYMBOL_MF_CRYPTO1_ON : 0x00; return pn53x_write_register(pnd, PN53X_REG_CIU_Status2, SYMBOL_MF_CRYPTO1_ON, btValue); case NP_INFINITE_SELECT: // TODO Made some research around this point: // timings could be tweak better than this, and maybe we can tweak timings // to "gain" a sort-of hardware polling (ie. like PN532 does) pnd->bInfiniteSelect = bEnable; return pn53x_RFConfiguration__MaxRetries(pnd, (bEnable) ? 0xff : 0x00, // MxRtyATR, default: active = 0xff, passive = 0x02 (bEnable) ? 0xff : 0x01, // MxRtyPSL, default: 0x01 (bEnable) ? 0xff : 0x02 // MxRtyPassiveActivation, default: 0xff (0x00 leads to problems with PN531) ); case NP_ACCEPT_INVALID_FRAMES: btValue = (bEnable) ? SYMBOL_RX_NO_ERROR : 0x00; return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_NO_ERROR, btValue); case NP_ACCEPT_MULTIPLE_FRAMES: btValue = (bEnable) ? SYMBOL_RX_MULTIPLE : 0x00; return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_MULTIPLE, btValue); case NP_AUTO_ISO14443_4: if (bEnable == pnd->bAutoIso14443_4) // Nothing to do return NFC_SUCCESS; pnd->bAutoIso14443_4 = bEnable; return pn53x_set_parameters(pnd, PARAM_AUTO_RATS, bEnable); case NP_FORCE_ISO14443_A: if (!bEnable) { // Nothing to do return NFC_SUCCESS; } // Force pn53x to be in ISO14443-A mode if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxMode, SYMBOL_TX_FRAMING, 0x00)) < 0) { return res; } if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_FRAMING, 0x00)) < 0) { return res; } // Set the PN53X to force 100% ASK Modified miller decoding (default for 14443A cards) return pn53x_write_register(pnd, PN53X_REG_CIU_TxAuto, SYMBOL_FORCE_100_ASK, 0x40); case NP_FORCE_ISO14443_B: if (!bEnable) { // Nothing to do return NFC_SUCCESS; } // Force pn53x to be in ISO14443-B mode if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxMode, SYMBOL_TX_FRAMING, 0x03)) < 0) { return res; } return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_FRAMING, 0x03); case NP_FORCE_SPEED_106: if (!bEnable) { // Nothing to do return NFC_SUCCESS; } // Force pn53x to be at 106 kbps if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxMode, SYMBOL_TX_SPEED, 0x00)) < 0) { return res; } return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_SPEED, 0x00); // Following properties are invalid (not boolean) case NP_TIMEOUT_COMMAND: case NP_TIMEOUT_ATR: case NP_TIMEOUT_COM: return NFC_EINVARG; } return NFC_EINVARG; } int pn53x_idle(struct nfc_device *pnd) { int res = 0; switch (CHIP_DATA(pnd)->operating_mode) { case TARGET: // InRelease used in target mode stops the target emulation and no more // tag are seen from external initiator if ((res = pn53x_InRelease(pnd, 0)) < 0) { return res; } if ((CHIP_DATA(pnd)->type == PN532) && (pnd->driver->powerdown)) { // Use PowerDown to go in "Low VBat" power mode if ((res = pnd->driver->powerdown(pnd)) < 0) { return res; } } break; case INITIATOR: // Use InRelease to go in "Standby mode" if ((res = pn53x_InRelease(pnd, 0)) < 0) { return res; } // Disable RF field to avoid heating if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) { return res; } if ((CHIP_DATA(pnd)->type == PN532) && (pnd->driver->powerdown)) { // Use PowerDown to go in "Low VBat" power mode if ((res = pnd->driver->powerdown(pnd)) < 0) { return res; } } break; case IDLE: // Nothing to do. break; }; // Clear the current nfc_target pn53x_current_target_free(pnd); CHIP_DATA(pnd)->operating_mode = IDLE; return NFC_SUCCESS; } int pn53x_check_communication(struct nfc_device *pnd) { const uint8_t abtCmd[] = { Diagnose, 0x00, 'l', 'i', 'b', 'n', 'f', 'c' }; const uint8_t abtExpectedRx[] = { 0x00, 'l', 'i', 'b', 'n', 'f', 'c' }; uint8_t abtRx[sizeof(abtExpectedRx)]; size_t szRx = sizeof(abtRx); int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRx, szRx, 500)) < 0) return res; szRx = (size_t) res; if ((sizeof(abtExpectedRx) == szRx) && (0 == memcmp(abtRx, abtExpectedRx, sizeof(abtExpectedRx)))) return NFC_SUCCESS; return NFC_EIO; } int pn53x_initiator_init(struct nfc_device *pnd) { pn53x_reset_settings(pnd); int res; if (CHIP_DATA(pnd)->sam_mode != PSM_NORMAL) { if ((res = pn532_SAMConfiguration(pnd, PSM_NORMAL, -1)) < 0) { return res; } } // Configure the PN53X to be an Initiator or Reader/Writer if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_Control, SYMBOL_INITIATOR, 0x10)) < 0) return res; CHIP_DATA(pnd)->operating_mode = INITIATOR; return NFC_SUCCESS; } // iclass requires special modulation settings void pn53x_initiator_init_iclass_modulation(struct nfc_device *pnd) { // send a bunch of low level commands reverse engineered from a working iClass reader // original device was using a PN512 // // // TxModeReg - Defines the data rate and framing during transmission. //// set bit 4 for target mode? - RxWaitRF Set to logic 1, the counter for RxWait starts only if an external RF field is detected in Target mode for NFCIP-1 or in Card Communication mode //pn512_write_register(0x12, "\x03", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_TxMode, 0x03); // // // RxModeReg - Defines the data rate and framing during reception. //pn512_write_register(0x13, "\x03", 1, false); // addy changed to set bit 3 - RxNoErr (put data in fifo before flagging read end) //pn512_write_register(0x13, "\x0B", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_RxMode, 0x0B); // ManualRCVReg - Allows manual fine tuning of the internal receiver. //pn512_write_register(0x1d, "\x10", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_ManualRCV, 0x10); // RFCfgReg - Configures the receiver gain and RF level detector sensitivity. //pn512_write_register(0x26, "\x70", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_RFCfg, 0x70); // GsNOffReg - Selects the conductance for the N-driver of the antenna driver pins TX1 and TX2 when the driver is switched off. //pn512_write_register(0x23, "\x88", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_GsNOFF, 0x88); // GsNOnReg - Selects the conductance for the N-driver of the antenna driver pins TX1 and TX2 when the driver is switched on. //pn512_write_register(0x27, "\xf8", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_GsNOn, 0xf8); // CWGsPReg - Defines the conductance of the P-driver during times of no modulation. //pn512_write_register(0x28, "\x3f", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_CWGsP, 0x3f); // ModGsPReg - Defines the driver P-output conductance during modulation. //pn512_write_register(0x29, "\x10", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_ModGsP, 0x10); // TReloadReg (MSB) - Describes the MSB of the 16-bit long timer reload value. //pn512_write_register(0x2c, "\x69", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_TReloadVal_hi, 0x69); // TReloadReg (LSB) - Describes the LSB of the 16-bit long timer reload value. //pn512_write_register(0x2d, "\xf0", 1, false); pn53x_WriteRegister(pnd, PN53X_REG_CIU_TReloadVal_lo, 0xf0); } int pn532_initiator_init_secure_element(struct nfc_device *pnd) { return pn532_SAMConfiguration(pnd, PSM_WIRED_CARD, -1); } static int pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt, int timeout) { uint8_t abtTargetsData[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szTargetsData = sizeof(abtTargetsData); int res = 0; nfc_target nttmp; memset(&nttmp, 0x00, sizeof(nfc_target)); if (nm.nmt == NMT_ISO14443BI || nm.nmt == NMT_ISO14443B2SR || nm.nmt == NMT_ISO14443B2CT || nm.nmt == NMT_ISO14443BICLASS) { if (CHIP_DATA(pnd)->type == RCS360) { // TODO add support for RC-S360, at the moment it refuses to send raw frames without a first select pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } // No native support in InListPassiveTarget so we do discovery by hand if ((res = nfc_device_set_property_bool(pnd, NP_FORCE_ISO14443_B, true)) < 0) { return res; } if ((res = nfc_device_set_property_bool(pnd, NP_FORCE_SPEED_106, true)) < 0) { return res; } if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true)) < 0) { return res; } if ((res = nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false)) < 0) { return res; } bool found = false; do { if (nm.nmt == NMT_ISO14443B2SR) { // Some work to do before getting the UID... uint8_t abtInitiate[] = "\x06\x00"; size_t szInitiateLen = 2; uint8_t abtSelect[] = { 0x0e, 0x00 }; uint8_t abtRx[1]; uint8_t *pbtInitData = (uint8_t *) "\x0b"; size_t szInitData = 1; // Getting random Chip_ID if ((res = pn53x_initiator_transceive_bytes(pnd, abtInitiate, szInitiateLen, abtRx, sizeof(abtRx), timeout)) < 0) { if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout continue; } else return res; } abtSelect[1] = abtRx[0]; if ((res = pn53x_initiator_transceive_bytes(pnd, abtSelect, sizeof(abtSelect), abtRx, sizeof(abtRx), timeout)) < 0) { return res; } szTargetsData = (size_t)res; if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) { if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout continue; } else return res; } szTargetsData = (size_t)res; } else if (nm.nmt == NMT_ISO14443B2CT) { // Some work to do before getting the UID... const uint8_t abtReqt[] = { 0x10 }; uint8_t *pbtInitData = (uint8_t *) "\x9F\xFF\xFF"; size_t szInitData = 3; // Getting product code / fab code & store it in output buffer after the serial nr we'll obtain later if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), abtTargetsData + 2, sizeof(abtTargetsData) - 2, timeout)) < 0) { if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout continue; } else return res; } szTargetsData = (size_t)res; if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) { if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout continue; } else return res; } szTargetsData = (size_t)res; if (szTargetsData != 2) return 0; // Target is not ISO14443B2CT uint8_t abtRead[] = { 0xC4 }; // Reading UID_MSB (Read address 4) if ((res = pn53x_initiator_transceive_bytes(pnd, abtRead, sizeof(abtRead), abtTargetsData + 4, sizeof(abtTargetsData) - 4, timeout)) < 0) { return res; } szTargetsData = 6; // u16 UID_LSB, u8 prod code, u8 fab code, u16 UID_MSB } else if (nm.nmt == NMT_ISO14443BICLASS) { pn53x_initiator_init_iclass_modulation(pnd); // // Some work to do before getting the UID... // send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL uint8_t abtAnticol[11]; if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "got expected timeout on iClass activate all"); //if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout // continue; //} else // return res; } // do select - returned anticol contains 'handle' for tag if present abtReqt[0] = 0x0c; // iClass SELECT abtAnticol[0] = 0x81; // iClass ANTICOL if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), &abtAnticol[1], sizeof(abtAnticol) - 1, timeout)) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass anticol"); return res; } // write back anticol handle to get UID if ((res = pn53x_initiator_transceive_bytes(pnd, abtAnticol, 9, abtTargetsData, 10, timeout)) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass get UID"); return res; } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "iClass raw UID: %02x %02x %02x %02x %02x %02x %02x %02x", abtTargetsData[0], abtTargetsData[1], abtTargetsData[2], abtTargetsData[3], abtTargetsData[4], abtTargetsData[5], abtTargetsData[6], abtTargetsData[7]); szTargetsData = 8; nttmp.nm = nm; if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { return res; } } else { if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) { if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout continue; } else return res; } szTargetsData = (size_t)res; } nttmp.nm = nm; if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { return res; } if (nm.nmt == NMT_ISO14443BI) { // Select tag uint8_t abtAttrib[6]; memcpy(abtAttrib, abtTargetsData, sizeof(abtAttrib)); abtAttrib[1] = 0x0f; // ATTRIB if ((res = pn53x_initiator_transceive_bytes(pnd, abtAttrib, sizeof(abtAttrib), NULL, 0, timeout)) < 0) { return res; } szTargetsData = (size_t)res; } found = true; break; } while (pnd->bInfiniteSelect); if (! found) return 0; } else if (nm.nmt == NMT_BARCODE) { if (CHIP_DATA(pnd)->type == RCS360) { // TODO add support for RC-S360, at the moment it refuses to send raw frames without a first select pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } // No native support in InListPassiveTarget so we do discovery by hand // We turn RF field off first for a better detection rate but this doesn't work well with ASK LoGO if ((! CHIP_DATA(pnd)->progressive_field) && (res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) { return res; } if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false)) < 0) { return res; } if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false)) < 0) { return res; } bool found = false; do { uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; if ((res = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 0) { if ((res == NFC_ERFTRANS) || (res == NFC_ECHIP)) { // Broken reception continue; } else { nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); return res; } } // Shuffle bits to produce NFC Barcode bitstream uint8_t uRemainder; size_t szPos; size_t szBytes = res / 8; size_t off = 0; uint8_t i; memset(abtTargetsData, 0x00, sizeof(abtTargetsData)); // Reinject S bit abtTargetsData[off / 8] |= 1 << (7 - (off % 8)); off++; for (szPos = 0; szPos < szBytes; szPos++) { for (i = 0; i < 8; i++) { abtTargetsData[off / 8] |= ((abtRx[szPos] >> i) & 1) << (7 - (off % 8)); off++; } abtTargetsData[off / 8] |= abtRxPar[szPos] << (7 - (off % 8)); off++; } uRemainder = res % 8; for (i = 0; i < uRemainder; i++) { abtTargetsData[off / 8] |= ((abtRx[szPos] >> i) & 1) << (7 - (off % 8)); off++; } if (off % 128 != 0) { // NFC Barcode seems incomplete continue; } szTargetsData = (size_t)off / 8; // validate CRC uint8_t pbtCrc[2]; iso14443a_crc(abtTargetsData, szTargetsData - 2, pbtCrc); if ((pbtCrc[1] != abtTargetsData[szTargetsData - 2]) || (pbtCrc[0] != abtTargetsData[szTargetsData - 1])) { continue; } nttmp.nm = nm; if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { return res; } found = true; break; } while (pnd->bInfiniteSelect); if (! found) { return 0; } } else { const pn53x_modulation pm = pn53x_nm_to_pm(nm); if ((PM_UNDEFINED == pm) || (NBR_UNDEFINED == nm.nbr)) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } if ((res = pn53x_InListPassiveTarget(pnd, pm, 1, pbtInitData, szInitData, abtTargetsData, &szTargetsData, timeout)) <= 0) return res; if (szTargetsData <= 1) // For Coverity to know szTargetsData is always > 1 if res > 0 return 0; nttmp.nm = nm; if ((res = pn53x_decode_target_data(abtTargetsData + 1, szTargetsData - 1, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { return res; } if ((nm.nmt == NMT_ISO14443A) && (nm.nbr != NBR_106)) { uint8_t pncmd_inpsl[4] = { InPSL, 0x01 }; pncmd_inpsl[2] = nm.nbr - 1; pncmd_inpsl[3] = nm.nbr - 1; if ((res = pn53x_transceive(pnd, pncmd_inpsl, sizeof(pncmd_inpsl), NULL, 0, 0)) < 0) { return res; } } } if (pn53x_current_target_new(pnd, &nttmp) == NULL) { pnd->last_error = NFC_ESOFT; return pnd->last_error; } // Is a tag info struct available if (pnt) { memcpy(pnt, &nttmp, sizeof(nfc_target)); } return abtTargetsData[0]; } int pn53x_initiator_select_passive_target(struct nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt) { return pn53x_initiator_select_passive_target_ext(pnd, nm, pbtInitData, szInitData, pnt, 300); } int pn53x_initiator_poll_target(struct nfc_device *pnd, const nfc_modulation *pnmModulations, const size_t szModulations, const uint8_t uiPollNr, const uint8_t uiPeriod, nfc_target *pnt) { int res = 0; if (CHIP_DATA(pnd)->type == PN532) { size_t szTargetTypes = 0; pn53x_target_type apttTargetTypes[32]; memset(apttTargetTypes, PTT_UNDEFINED, 32 * sizeof(pn53x_target_type)); for (size_t n = 0; n < szModulations; n++) { const pn53x_target_type ptt = pn53x_nm_to_ptt(pnmModulations[n]); if (PTT_UNDEFINED == ptt) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } apttTargetTypes[szTargetTypes] = ptt; if ((pnd->bAutoIso14443_4) && (ptt == PTT_MIFARE)) { // Hack to have ATS apttTargetTypes[szTargetTypes] = PTT_ISO14443_4A_106; szTargetTypes++; apttTargetTypes[szTargetTypes] = PTT_MIFARE; } szTargetTypes++; } nfc_target ntTargets[2]; memset(ntTargets, 0x00, sizeof(nfc_target) * 2); if ((res = pn53x_InAutoPoll(pnd, apttTargetTypes, szTargetTypes, uiPollNr, uiPeriod, ntTargets, 0)) < 0) return res; switch (res) { case 0: return pnd->last_error = NFC_SUCCESS; break; case 1: *pnt = ntTargets[0]; if (pn53x_current_target_new(pnd, pnt) == NULL) { return pnd->last_error = NFC_ESOFT; } return res; case 2: *pnt = ntTargets[1]; // We keep the selected one if (pn53x_current_target_new(pnd, pnt) == NULL) { return pnd->last_error = NFC_ESOFT; } return res; default: return NFC_ECHIP; } } else { bool bInfiniteSelect = pnd->bInfiniteSelect; int result = 0; if ((res = pn53x_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) return res; // FIXME It does not support DEP targets do { for (size_t p = 0; p < uiPollNr; p++) { for (size_t n = 0; n < szModulations; n++) { uint8_t *pbtInitiatorData; size_t szInitiatorData; prepare_initiator_data(pnmModulations[n], &pbtInitiatorData, &szInitiatorData); const int timeout_ms = uiPeriod * 150; if ((res = pn53x_initiator_select_passive_target_ext(pnd, pnmModulations[n], pbtInitiatorData, szInitiatorData, pnt, timeout_ms)) < 0) { if (pnd->last_error != NFC_ETIMEOUT) { result = pnd->last_error; goto end; } } else { result = res; goto end; } } } } while (uiPollNr == 0xff); // uiPollNr==0xff means infinite polling // We reach this point when each listing give no result, we simply have to return 0 end: if (! bInfiniteSelect) { if ((res = pn53x_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) return res; } return result; } return NFC_ECHIP; } int pn53x_initiator_select_dep_target(struct nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout) { const uint8_t abtPassiveInitiatorData[] = { 0x00, 0xff, 0xff, 0x00, 0x0f }; // Only for 212/424 kpbs: First 4 bytes shall be set like this according to NFCIP-1, last byte is TSN (Time Slot Number) const uint8_t *pbtPassiveInitiatorData = NULL; switch (nbr) { case NBR_212: case NBR_424: // Only use this predefined bytes array when we are at 212/424kbps pbtPassiveInitiatorData = abtPassiveInitiatorData; break; case NBR_106: // Nothing to do break; case NBR_847: case NBR_UNDEFINED: return NFC_EINVARG; } pn53x_current_target_free(pnd); int res; if (pndiInitiator) { res = pn53x_InJumpForDEP(pnd, ndm, nbr, pbtPassiveInitiatorData, pndiInitiator->abtNFCID3, pndiInitiator->abtGB, pndiInitiator->szGB, pnt, timeout); } else { res = pn53x_InJumpForDEP(pnd, ndm, nbr, pbtPassiveInitiatorData, NULL, NULL, 0, pnt, timeout); } if (res > 0) { if (pn53x_current_target_new(pnd, pnt) == NULL) { return NFC_ESOFT; } } return res; } int pn53x_initiator_transceive_bits(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, uint8_t *pbtRxPar) { int res = 0; size_t szFrameBits = 0; size_t szFrameBytes = 0; size_t szRxBits = 0; uint8_t ui8rcc; uint8_t ui8Bits = 0; uint8_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN] = { InCommunicateThru }; // Check if we should prepare the parity bits ourself if ((!pnd->bPar) && (szTxBits > 0)) { // Convert data with parity to a frame if ((res = pn53x_wrap_frame(pbtTx, szTxBits, pbtTxPar, abtCmd + 1)) < 0) return res; szFrameBits = res; } else { szFrameBits = szTxBits; } // Retrieve the leading bits ui8Bits = szFrameBits % 8; // Get the amount of frame bytes + optional (1 byte if there are leading bits) szFrameBytes = (szFrameBits / 8) + ((ui8Bits == 0) ? 0 : 1); // When the parity is handled before us, we just copy the data if (pnd->bPar) memcpy(abtCmd + 1, pbtTx, szFrameBytes); // Set the amount of transmission bits in the PN53X chip register if ((res = pn53x_set_tx_bits(pnd, ui8Bits)) < 0) return res; // Send the frame to the PN53X chip and get the answer // We have to give the amount of bytes + (the command byte 0x42) uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); if ((res = pn53x_transceive(pnd, abtCmd, szFrameBytes + 1, abtRx, szRx, -1)) < 0) return res; szRx = (size_t) res; // Get the last bit-count that is stored in the received byte if ((res = pn53x_read_register(pnd, PN53X_REG_CIU_Control, &ui8rcc)) < 0) return res; ui8Bits = ui8rcc & SYMBOL_RX_LAST_BITS; // Recover the real frame length in bits szFrameBits = ((szRx - 1 - ((ui8Bits == 0) ? 0 : 1)) * 8) + ui8Bits; if (pbtRx != NULL) { // Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive() // Check if we should recover the parity bits ourself if (!pnd->bPar) { // Unwrap the response frame if ((res = pn53x_unwrap_frame(abtRx + 1, szFrameBits, pbtRx, pbtRxPar)) < 0) return res; szRxBits = res; } else { // Save the received bits szRxBits = szFrameBits; // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRx - 1); } } // Everything went successful return szRxBits; } int pn53x_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout) { size_t szExtraTxLen; uint8_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; int res = 0; // We can not just send bytes without parity if while the PN53X expects we handled them if (!pnd->bPar) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } // Copy the data into the command frame if (pnd->bEasyFraming) { abtCmd[0] = InDataExchange; abtCmd[1] = 1; /* target number */ memcpy(abtCmd + 2, pbtTx, szTx); szExtraTxLen = 2; } else { abtCmd[0] = InCommunicateThru; memcpy(abtCmd + 1, pbtTx, szTx); szExtraTxLen = 1; } // To transfer command frames bytes we can not have any leading bits, reset this to zero if ((res = pn53x_set_tx_bits(pnd, 0)) < 0) { pnd->last_error = res; return pnd->last_error; } // Send the frame to the PN53X chip and get the answer // We have to give the amount of bytes + (the two command bytes 0xD4, 0x42) uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; if ((res = pn53x_transceive(pnd, abtCmd, szTx + szExtraTxLen, abtRx, sizeof(abtRx), timeout)) < 0) { pnd->last_error = res; return pnd->last_error; } const size_t szRxLen = (size_t)res - 1; if (pbtRx != NULL) { if (szRxLen > szRx) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Buffer size is too short: %" PRIuPTR " available(s), %" PRIuPTR " needed", szRx, szRxLen); return NFC_EOVFLOW; } // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRxLen); } // Everything went successful, we return received bytes count return szRxLen; } static void __pn53x_init_timer(struct nfc_device *pnd, const uint32_t max_cycles) { // The prescaler will dictate what will be the precision and // the largest delay to measure before saturation. Some examples: // prescaler = 0 => precision: ~73ns timer saturates at ~5ms // prescaler = 1 => precision: ~221ns timer saturates at ~15ms // prescaler = 2 => precision: ~369ns timer saturates at ~25ms // prescaler = 10 => precision: ~1.5us timer saturates at ~100ms if (max_cycles > 0xFFFF) { CHIP_DATA(pnd)->timer_prescaler = ((max_cycles / 0xFFFF) - 1) / 2; } else { CHIP_DATA(pnd)->timer_prescaler = 0; } uint16_t reloadval = 0xFFFF; // Initialize timer pn53x_write_register(pnd, PN53X_REG_CIU_TMode, 0xFF, SYMBOL_TAUTO | ((CHIP_DATA(pnd)->timer_prescaler >> 8) & SYMBOL_TPRESCALERHI)); pn53x_write_register(pnd, PN53X_REG_CIU_TPrescaler, 0xFF, (CHIP_DATA(pnd)->timer_prescaler & SYMBOL_TPRESCALERLO)); pn53x_write_register(pnd, PN53X_REG_CIU_TReloadVal_hi, 0xFF, (reloadval >> 8) & 0xFF); pn53x_write_register(pnd, PN53X_REG_CIU_TReloadVal_lo, 0xFF, reloadval & 0xFF); } static uint32_t __pn53x_get_timer(struct nfc_device *pnd, const uint8_t last_cmd_byte) { uint8_t counter_hi, counter_lo; uint16_t counter; uint32_t u32cycles; size_t off = 0; if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte off = 1; } // Read timer BUFFER_INIT(abtReadRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtReadRegisterCmd, ReadRegister); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_TCounterVal_hi >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_TCounterVal_hi & 0xff); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_TCounterVal_lo >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_TCounterVal_lo & 0xff); uint8_t abtRes[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRes = sizeof(abtRes); // Let's send the previously constructed ReadRegister command if (pn53x_transceive(pnd, abtReadRegisterCmd, BUFFER_SIZE(abtReadRegisterCmd), abtRes, szRes, -1) < 0) { return false; } counter_hi = abtRes[off]; counter_lo = abtRes[off + 1]; counter = counter_hi; counter = (counter << 8) + counter_lo; if (counter == 0) { // counter saturated u32cycles = 0xFFFFFFFF; } else { uint8_t parity; uint16_t u16cycles; u16cycles = 0xFFFF - counter; u32cycles = u16cycles; u32cycles *= (CHIP_DATA(pnd)->timer_prescaler * 2 + 1); u32cycles++; // Correction depending on PN53x Rx detection handling: // timer stops after 5 (or 2 for PN531) bits are received if (CHIP_DATA(pnd)->type == PN531) { u32cycles -= (2 * 128); } else { u32cycles -= (5 * 128); } // Correction depending on last parity bit sent parity = (last_cmd_byte >> 7) ^ ((last_cmd_byte >> 6) & 1) ^ ((last_cmd_byte >> 5) & 1) ^ ((last_cmd_byte >> 4) & 1) ^ ((last_cmd_byte >> 3) & 1) ^ ((last_cmd_byte >> 2) & 1) ^ ((last_cmd_byte >> 1) & 1) ^ (last_cmd_byte & 1); parity = parity ? 0 : 1; // When sent ...YY (cmd ends with logical 1, so when last parity bit is 1): if (parity) { // it finishes 64us sooner than a ...ZY signal u32cycles += 64; } // Correction depending on device design u32cycles += CHIP_DATA(pnd)->timer_correction; } return u32cycles; } int pn53x_initiator_transceive_bits_timed(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, uint8_t *pbtRxPar, uint32_t *cycles) { // TODO Do something with these bytes... (void) pbtTxPar; (void) pbtRxPar; uint16_t i; uint8_t sz = 0; int res = 0; size_t szRxBits = 0; // Sorry, no arbitrary parity bits support for now if (!pnd->bPar) { pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } // Sorry, no easy framing support if (pnd->bEasyFraming) { pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } // TODO CRC support but it probably doesn't make sense for (szTxBits % 8 != 0) ... if (pnd->bCrc) { pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } __pn53x_init_timer(pnd, *cycles); // Once timer is started, we cannot use Tama commands anymore. // E.g. on SCL3711 timer settings are reset by 0x42 InCommunicateThru command to: // 631a=82 631b=a5 631c=02 631d=00 // Prepare FIFO BUFFER_INIT(abtWriteRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtWriteRegisterCmd, WriteRegister); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_Command >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_Command & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_COMMAND & SYMBOL_COMMAND_TRANSCEIVE); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOLevel >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOLevel & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_FLUSH_BUFFER); for (i = 0; i < ((szTxBits / 8) + 1); i++) { BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOData >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOData & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, pbtTx[i]); } // Send data BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_BitFraming >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_BitFraming & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_START_SEND | ((szTxBits % 8) & SYMBOL_TX_LAST_BITS)); // Let's send the previously constructed WriteRegister command if ((res = pn53x_transceive(pnd, abtWriteRegisterCmd, BUFFER_SIZE(abtWriteRegisterCmd), NULL, 0, -1)) < 0) { return res; } // Recv data // we've to watch for coming data until we decide to timeout. // our PN53x timer saturates after 4.8ms so this function shouldn't be used for // responses coming very late anyway. // Ideally we should implement a real timer here too but looping a few times is good enough. for (i = 0; i < (3 * (CHIP_DATA(pnd)->timer_prescaler * 2 + 1)); i++) { pn53x_read_register(pnd, PN53X_REG_CIU_FIFOLevel, &sz); if (sz > 0) break; } size_t off = 0; if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte off = 1; } while (1) { BUFFER_INIT(abtReadRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtReadRegisterCmd, ReadRegister); for (i = 0; i < sz; i++) { BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOData >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOData & 0xff); } BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOLevel >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOLevel & 0xff); uint8_t abtRes[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRes = sizeof(abtRes); // Let's send the previously constructed ReadRegister command if ((res = pn53x_transceive(pnd, abtReadRegisterCmd, BUFFER_SIZE(abtReadRegisterCmd), abtRes, szRes, -1)) < 0) { return res; } for (i = 0; i < sz; i++) { pbtRx[i + szRxBits] = abtRes[i + off]; } szRxBits += (size_t)(sz & SYMBOL_FIFO_LEVEL); sz = abtRes[sz + off]; if (sz == 0) break; } szRxBits *= 8; // in bits, not bytes // Recv corrected timer value *cycles = __pn53x_get_timer(pnd, pbtTx[szTxBits / 8]); return szRxBits; } int pn53x_initiator_transceive_bytes_timed(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, uint32_t *cycles) { uint16_t i; uint8_t sz = 0; int res = 0; // We can not just send bytes without parity while the PN53X expects we handled them if (!pnd->bPar) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } // Sorry, no easy framing support // TODO to be changed once we'll provide easy framing support from libnfc itself... if (pnd->bEasyFraming) { pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } uint8_t txmode = 0; if (pnd->bCrc) { // check if we're in TypeA or TypeB mode to compute right CRC later if ((res = pn53x_read_register(pnd, PN53X_REG_CIU_TxMode, &txmode)) < 0) { return res; } } __pn53x_init_timer(pnd, *cycles); // Once timer is started, we cannot use Tama commands anymore. // E.g. on SCL3711 timer settings are reset by 0x42 InCommunicateThru command to: // 631a=82 631b=a5 631c=02 631d=00 // Prepare FIFO BUFFER_INIT(abtWriteRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtWriteRegisterCmd, WriteRegister); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_Command >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_Command & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_COMMAND & SYMBOL_COMMAND_TRANSCEIVE); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOLevel >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOLevel & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_FLUSH_BUFFER); for (i = 0; i < szTx; i++) { BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOData >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOData & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, pbtTx[i]); } // Send data BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_BitFraming >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_BitFraming & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_START_SEND); // Let's send the previously constructed WriteRegister command if ((res = pn53x_transceive(pnd, abtWriteRegisterCmd, BUFFER_SIZE(abtWriteRegisterCmd), NULL, 0, -1)) < 0) { return res; } // Recv data size_t szRxLen = 0; // we've to watch for coming data until we decide to timeout. // our PN53x timer saturates after 4.8ms so this function shouldn't be used for // responses coming very late anyway. // Ideally we should implement a real timer here too but looping a few times is good enough. for (i = 0; i < (3 * (CHIP_DATA(pnd)->timer_prescaler * 2 + 1)); i++) { pn53x_read_register(pnd, PN53X_REG_CIU_FIFOLevel, &sz); if (sz > 0) break; } size_t off = 0; if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte off = 1; } while (1) { BUFFER_INIT(abtReadRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtReadRegisterCmd, ReadRegister); for (i = 0; i < sz; i++) { BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOData >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOData & 0xff); } BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOLevel >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOLevel & 0xff); uint8_t abtRes[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRes = sizeof(abtRes); // Let's send the previously constructed ReadRegister command if ((res = pn53x_transceive(pnd, abtReadRegisterCmd, BUFFER_SIZE(abtReadRegisterCmd), abtRes, szRes, -1)) < 0) { return res; } if (pbtRx != NULL) { if ((szRxLen + sz) > szRx) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Buffer size is too short: %" PRIuPTR " available(s), %" PRIuPTR " needed", szRx, szRxLen + sz); return NFC_EOVFLOW; } // Copy the received bytes for (i = 0; i < sz; i++) { pbtRx[i + szRxLen] = abtRes[i + off]; } } szRxLen += (size_t)(sz & SYMBOL_FIFO_LEVEL); sz = abtRes[sz + off]; if (sz == 0) break; } // Recv corrected timer value if (pnd->bCrc) { // We've to compute CRC ourselves to know last byte actually sent uint8_t *pbtTxRaw; pbtTxRaw = (uint8_t *) calloc(szTx + 2, 1); if (!pbtTxRaw) return NFC_ESOFT; memcpy(pbtTxRaw, pbtTx, szTx); if ((txmode & SYMBOL_TX_FRAMING) == 0x00) iso14443a_crc_append(pbtTxRaw, szTx); else if ((txmode & SYMBOL_TX_FRAMING) == 0x03) iso14443b_crc_append(pbtTxRaw, szTx); else log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unsupported framing type %02X, cannot adjust CRC cycles", txmode & SYMBOL_TX_FRAMING); *cycles = __pn53x_get_timer(pnd, pbtTxRaw[szTx + 1]); free(pbtTxRaw); } else { *cycles = __pn53x_get_timer(pnd, pbtTx[szTx - 1]); } return szRxLen; } int pn53x_initiator_deselect_target(struct nfc_device *pnd) { pn53x_current_target_free(pnd); return pn53x_InDeselect(pnd, 0); // 0 mean deselect all selected targets } static int pn53x_Diagnose06(struct nfc_device *pnd) { // Send Card Presence command const uint8_t abtCmd[] = { Diagnose, 0x06 }; uint8_t abtRx[1]; int ret = 0; int failures = 0; // Card Presence command can take more time than default one: when a card is // removed from the field, the PN53x took few hundred ms more to reply // correctly. Longest delay observed was with a JCOP31 on a PN532. // 1000 ms should be enough to detect all tested cases while (failures < 2) { if ((ret = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRx, sizeof(abtRx), 1000)) != 1) { // When it fails with a timeout (0x01) chip error, it means the target is not reacheable anymore if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { return NFC_ETGRELEASED; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { return NFC_SUCCESS; } } return ret; } static int pn53x_ISO14443A_4_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping -4A"); if (CHIP_DATA(pnd)->type == PN533) { ret = pn53x_Diagnose06(pnd); if ((ret == NFC_ETIMEOUT) || (ret == NFC_ETGRELEASED)) { // This happens e.g. when a JCOP31 is removed from PN533 // InRelease takes an abnormal time to reply so let's take care of it now with large timeout: const uint8_t abtCmd[] = { InRelease, 0x00 }; pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 2000); ret = NFC_ETGRELEASED; } } else if (CHIP_DATA(pnd)->type == PN532) { // Diagnose06 failed completely with a JCOP31 on a PN532 so let's do it manually if ((ret = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, false)) < 0) return ret; uint8_t abtCmd[1] = {0xb2}; // CID=0 int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } int ret2; if ((ret2 = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) ret = ret2; } else { ret = NFC_EDEVNOTSUPP; } return ret; } static int pn53x_ISO14443A_Jewel_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping Jewel"); uint8_t abtCmd[1] = {0x78}; int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout return NFC_ETGRELEASED; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { return NFC_SUCCESS; } } return ret; } static int pn53x_ISO14443A_Barcode_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping Barcode"); // We turn RF field off first for a better detection rate but this doesn't work well with ASK LoGO if ((! CHIP_DATA(pnd)->progressive_field) && (ret = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) { return ret; } if ((ret = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false)) < 0) return ret; if ((ret = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false)) < 0) return ret; int failures = 0; while (failures < 3) { if ((! CHIP_DATA(pnd)->progressive_field) && (ret = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) { return ret; } uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; if (nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar) < 1) { failures++; } else { nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); return NFC_SUCCESS; } } nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); return NFC_ETGRELEASED; } static int pn53x_ISO14443A_MFUL_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping MFUL"); // Limitation: test on MFULC non-authenticated with read of first sector forbidden will fail if (CHIP_DATA(pnd)->type == PN533) { ret = pn53x_Diagnose06(pnd); } else { uint8_t abtCmd[2] = {0x30, 0x00}; int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout return NFC_ETGRELEASED; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { return NFC_SUCCESS; } } } return ret; } static int pn53x_ISO14443A_MFC_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping MFC"); if ((CHIP_DATA(pnd)->type == PN533) && (CHIP_DATA(pnd)->current_target->nti.nai.btSak != 0x09)) { // MFC Mini (atqa0004/sak09) fails on PN533, so we exclude it ret = pn53x_Diagnose06(pnd); } else { // Limitation: re-select will lose authentication of already authenticated sector bool bInfiniteSelect = pnd->bInfiniteSelect; uint8_t pbtInitiatorData[12]; size_t szInitiatorData = 0; iso14443_cascade_uid(CHIP_DATA(pnd)->current_target->nti.nai.abtUid, CHIP_DATA(pnd)->current_target->nti.nai.szUidLen, pbtInitiatorData, &szInitiatorData); if ((ret = pn53x_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) return ret; if ((ret = pn53x_initiator_select_passive_target_ext(pnd, CHIP_DATA(pnd)->current_target->nm, pbtInitiatorData, szInitiatorData, NULL, 300)) == 1) { ret = NFC_SUCCESS; } else if ((ret == 0) || (ret == NFC_ETIMEOUT)) { ret = NFC_ETGRELEASED; } if (bInfiniteSelect) { int ret2; if ((ret2 = pn53x_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) return ret2; } } return ret; } static int pn53x_DEP_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping DEP"); if ((CHIP_DATA(pnd)->type == PN531) || (CHIP_DATA(pnd)->type == PN532) || (CHIP_DATA(pnd)->type == PN533)) ret = pn53x_Diagnose06(pnd); else ret = NFC_EDEVNOTSUPP; return ret; } static int pn53x_Felica_is_present(struct nfc_device *pnd) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping Felica"); // if (CHIP_DATA(pnd)->type == PN533) { ret = pn53x_Diagnose06(pnd); } else... // Because ping fails now & then, better not to use Diagnose at all // Limitation: does not work on Felica Lite cards (neither Diagnose nor our method) uint8_t abtCmd[10] = {0x0A, 0x04}; memcpy(abtCmd + 2, CHIP_DATA(pnd)->current_target->nti.nfi.abtId, 8); int failures = 0; // Sometimes ping fails so we want to give the card some more chances... while (failures < 3) { if (nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300) == 11) { return NFC_SUCCESS; } else { failures++; } } return NFC_ETGRELEASED; } static int pn53x_ISO14443B_4_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping -4B"); if (CHIP_DATA(pnd)->type == PN533) { // Not supported on PN532 even if the doc is same as for PN533 ret = pn53x_Diagnose06(pnd); } else { // Sending R(NACK) in raw: if ((ret = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, false)) < 0) return ret; // uint8_t abtCmd[1] = {0xb2}; // if on PN533, CID=0 uint8_t abtCmd[2] = {0xba, 0x01}; // if on PN532, CID=1 int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } int ret2; if ((ret2 = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) ret = ret2; } return ret; } static int pn53x_ISO14443B_I_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B'"); // Sending ATTRIB in raw: if ((ret = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, false)) < 0) return ret; uint8_t abtCmd[6] = {0x01, 0x0f}; memcpy(abtCmd + 2, CHIP_DATA(pnd)->current_target->nti.nii.abtDIV, 4); int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } int ret2; if ((ret2 = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) ret = ret2; return ret; } static int pn53x_ISO14443B_SR_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B2 ST SRx"); // Sending Get_UID in raw: (EASY_FRAMING is already supposed to be false) uint8_t abtCmd[1] = {0x0b}; int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } return ret; } static int pn53x_ISO14443B_ICLASS_is_present(struct nfc_device *pnd) { int timeout = 300; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B iClass"); pn53x_initiator_init_iclass_modulation(pnd); // // Some work to do before getting the UID... // send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL uint8_t abtAnticol[11]; if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "got expected timeout on iClass activate all"); } // do select - returned anticol contains 'handle' for tag if present abtReqt[0] = 0x0c; // iClass SELECT abtAnticol[0] = 0x81; // iClass ANTICOL if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), &abtAnticol[1], sizeof(abtAnticol) - 1, timeout) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass anticol"); return NFC_ETGRELEASED;; } return NFC_SUCCESS; } static int pn53x_ISO14443B_CT_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B2 ASK CTx"); // Sending SELECT in raw: (EASY_FRAMING is already supposed to be false) uint8_t abtCmd[3] = {0x9f}; memcpy(abtCmd + 1, CHIP_DATA(pnd)->current_target->nti.nci.abtUID, 2); int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } return ret; } int pn53x_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt) { // Check if there is a saved target if (CHIP_DATA(pnd)->current_target == NULL) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): no saved target"); return pnd->last_error = NFC_EINVARG; } // Check if the argument target nt is equals to current saved target if ((pnt != NULL) && (!pn53x_current_target_is(pnd, pnt))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): another target"); return pnd->last_error = NFC_ETGRELEASED; } // Ping target int ret = NFC_EDEVNOTSUPP; switch (CHIP_DATA(pnd)->current_target->nm.nmt) { case NMT_ISO14443A: if (CHIP_DATA(pnd)->current_target->nti.nai.btSak & 0x20) { ret = pn53x_ISO14443A_4_is_present(pnd); } else if ((CHIP_DATA(pnd)->current_target->nti.nai.abtAtqa[0] == 0x00) && (CHIP_DATA(pnd)->current_target->nti.nai.abtAtqa[1] == 0x44) && (CHIP_DATA(pnd)->current_target->nti.nai.btSak == 0x00)) { ret = pn53x_ISO14443A_MFUL_is_present(pnd); } else if (CHIP_DATA(pnd)->current_target->nti.nai.btSak & 0x08) { ret = pn53x_ISO14443A_MFC_is_present(pnd); } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): card type A not supported"); ret = NFC_EDEVNOTSUPP; } break; case NMT_DEP: ret = pn53x_DEP_is_present(pnd); break; case NMT_FELICA: ret = pn53x_Felica_is_present(pnd); break; case NMT_JEWEL: ret = pn53x_ISO14443A_Jewel_is_present(pnd); break; case NMT_BARCODE: ret = pn53x_ISO14443A_Barcode_is_present(pnd); break; case NMT_ISO14443B: ret = pn53x_ISO14443B_4_is_present(pnd); break; case NMT_ISO14443BI: ret = pn53x_ISO14443B_I_is_present(pnd); break; case NMT_ISO14443B2SR: ret = pn53x_ISO14443B_SR_is_present(pnd); break; case NMT_ISO14443B2CT: ret = pn53x_ISO14443B_CT_is_present(pnd); break; case NMT_ISO14443BICLASS: ret = pn53x_ISO14443B_ICLASS_is_present(pnd); break; } if (ret == NFC_ETGRELEASED) pn53x_current_target_free(pnd); return pnd->last_error = ret; } #define SAK_ISO14443_4_COMPLIANT 0x20 #define SAK_ISO18092_COMPLIANT 0x40 int pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRxLen, int timeout) { pn53x_reset_settings(pnd); CHIP_DATA(pnd)->operating_mode = TARGET; pn53x_target_mode ptm = PTM_NORMAL; int res = 0; switch (pnt->nm.nmt) { case NMT_ISO14443A: ptm = PTM_PASSIVE_ONLY; if ((pnt->nti.nai.abtUid[0] != 0x08) || (pnt->nti.nai.szUidLen != 4)) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } pn53x_set_parameters(pnd, PARAM_AUTO_ATR_RES, false); if (CHIP_DATA(pnd)->type == PN532) { // We have a PN532 if ((pnt->nti.nai.btSak & SAK_ISO14443_4_COMPLIANT) && (pnd->bAutoIso14443_4)) { // We have a ISO14443-4 tag to emulate and NP_AUTO_14443_4A option is enabled ptm |= PTM_ISO14443_4_PICC_ONLY; // We add ISO14443-4 restriction pn53x_set_parameters(pnd, PARAM_14443_4_PICC, true); } else { pn53x_set_parameters(pnd, PARAM_14443_4_PICC, false); } } break; case NMT_FELICA: ptm = PTM_PASSIVE_ONLY; break; case NMT_DEP: pn53x_set_parameters(pnd, PARAM_AUTO_ATR_RES, true); ptm = PTM_DEP_ONLY; if (pnt->nti.ndi.ndm == NDM_PASSIVE) { ptm |= PTM_PASSIVE_ONLY; // We add passive mode restriction } break; case NMT_ISO14443B: case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_ISO14443BICLASS: case NMT_JEWEL: case NMT_BARCODE: pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } // Let the PN53X be activated by the RF level detector from power down mode if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxAuto, SYMBOL_INITIAL_RF_ON, 0x04)) < 0) return res; uint8_t abtMifareParams[6]; uint8_t *pbtMifareParams = NULL; uint8_t *pbtTkt = NULL; size_t szTkt = 0; uint8_t abtFeliCaParams[18]; uint8_t *pbtFeliCaParams = NULL; const uint8_t *pbtNFCID3t = NULL; const uint8_t *pbtGBt = NULL; size_t szGBt = 0; switch (pnt->nm.nmt) { case NMT_ISO14443A: { // Set ATQA (SENS_RES) abtMifareParams[0] = pnt->nti.nai.abtAtqa[1]; abtMifareParams[1] = pnt->nti.nai.abtAtqa[0]; // Set UID // Note: in this mode we can only emulate a single size (4 bytes) UID where the first is hard-wired by PN53x as 0x08 abtMifareParams[2] = pnt->nti.nai.abtUid[1]; abtMifareParams[3] = pnt->nti.nai.abtUid[2]; abtMifareParams[4] = pnt->nti.nai.abtUid[3]; // Set SAK (SEL_RES) abtMifareParams[5] = pnt->nti.nai.btSak; pbtMifareParams = abtMifareParams; // Historical Bytes pbtTkt = iso14443a_locate_historical_bytes(pnt->nti.nai.abtAts, pnt->nti.nai.szAtsLen, &szTkt); } break; case NMT_FELICA: // Set NFCID2t memcpy(abtFeliCaParams, pnt->nti.nfi.abtId, 8); // Set PAD memcpy(abtFeliCaParams + 8, pnt->nti.nfi.abtPad, 8); // Set SystemCode memcpy(abtFeliCaParams + 16, pnt->nti.nfi.abtSysCode, 2); pbtFeliCaParams = abtFeliCaParams; break; case NMT_DEP: // Set NFCID3 pbtNFCID3t = pnt->nti.ndi.abtNFCID3; // Set General Bytes, if relevant szGBt = pnt->nti.ndi.szGB; if (szGBt) pbtGBt = pnt->nti.ndi.abtGB; // Set ISO/IEC 14443 part // Set ATQA (SENS_RES) abtMifareParams[0] = 0x08; abtMifareParams[1] = 0x00; // Set UID // Note: in this mode we can only emulate a single size (4 bytes) UID where the first is hard-wired by PN53x as 0x08 abtMifareParams[2] = 0x12; abtMifareParams[3] = 0x34; abtMifareParams[4] = 0x56; // Set SAK (SEL_RES) abtMifareParams[5] = SAK_ISO18092_COMPLIANT; // Allow ISO/IEC 18092 in DEP mode pbtMifareParams = abtMifareParams; // Set FeliCa part // Set NFCID2t abtFeliCaParams[0] = 0x01; abtFeliCaParams[1] = 0xfe; abtFeliCaParams[2] = 0x12; abtFeliCaParams[3] = 0x34; abtFeliCaParams[4] = 0x56; abtFeliCaParams[5] = 0x78; abtFeliCaParams[6] = 0x90; abtFeliCaParams[7] = 0x12; // Set PAD abtFeliCaParams[8] = 0xc0; abtFeliCaParams[9] = 0xc1; abtFeliCaParams[10] = 0xc2; abtFeliCaParams[11] = 0xc3; abtFeliCaParams[12] = 0xc4; abtFeliCaParams[13] = 0xc5; abtFeliCaParams[14] = 0xc6; abtFeliCaParams[15] = 0xc7; // Set System Code abtFeliCaParams[16] = 0x0f; abtFeliCaParams[17] = 0xab; pbtFeliCaParams = abtFeliCaParams; break; case NMT_ISO14443B: case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_ISO14443BICLASS: case NMT_JEWEL: case NMT_BARCODE: pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } bool targetActivated = false; size_t szRx; while (!targetActivated) { uint8_t btActivatedMode; if ((res = pn53x_TgInitAsTarget(pnd, ptm, pbtMifareParams, pbtTkt, szTkt, pbtFeliCaParams, pbtNFCID3t, pbtGBt, szGBt, pbtRx, szRxLen, &btActivatedMode, timeout)) < 0) { if (res == NFC_ETIMEOUT) { pn53x_idle(pnd); } return res; } szRx = (size_t) res; nfc_modulation nm = { .nmt = NMT_DEP, // Silent compilation warnings .nbr = NBR_UNDEFINED }; nfc_dep_mode ndm = NDM_UNDEFINED; // Decode activated "mode" switch (btActivatedMode & 0x70) { // Baud rate case 0x00: // 106kbps nm.nbr = NBR_106; break; case 0x10: // 212kbps nm.nbr = NBR_212; break; case 0x20: // 424kbps nm.nbr = NBR_424; break; }; if (btActivatedMode & 0x04) { // D.E.P. nm.nmt = NMT_DEP; if ((btActivatedMode & 0x03) == 0x01) { // Active mode ndm = NDM_ACTIVE; } else { // Passive mode ndm = NDM_PASSIVE; } } else { // Not D.E.P. if ((btActivatedMode & 0x03) == 0x00) { // MIFARE nm.nmt = NMT_ISO14443A; } else if ((btActivatedMode & 0x03) == 0x02) { // FeliCa nm.nmt = NMT_FELICA; } } if (pnt->nm.nmt == nm.nmt) { // Actual activation have the right modulation type if ((pnt->nm.nbr == NBR_UNDEFINED) || (pnt->nm.nbr == nm.nbr)) { // Have the right baud rate (or undefined) if ((pnt->nm.nmt != NMT_DEP) || (pnt->nti.ndi.ndm == NDM_UNDEFINED) || (pnt->nti.ndi.ndm == ndm)) { // Have the right DEP mode (or is not a DEP) targetActivated = true; } } } if (targetActivated) { pnt->nm.nbr = nm.nbr; // Update baud rate if (pnt->nm.nmt == NMT_DEP) { pnt->nti.ndi.ndm = ndm; // Update DEP mode } if (pn53x_current_target_new(pnd, pnt) == NULL) { pnd->last_error = NFC_ESOFT; return pnd->last_error; } if (ptm & PTM_ISO14443_4_PICC_ONLY) { // When PN532 is in PICC target mode, it automatically reply to RATS so // we don't need to forward this command szRx = 0; } } } return szRx; } int pn53x_target_receive_bits(struct nfc_device *pnd, uint8_t *pbtRx, const size_t szRxLen, uint8_t *pbtRxPar) { size_t szRxBits = 0; uint8_t abtCmd[] = { TgGetInitiatorCommand }; uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); int res = 0; // Try to gather a received frame from the reader if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRx, szRx, -1)) < 0) return res; szRx = (size_t) res; // Get the last bit-count that is stored in the received byte uint8_t ui8rcc; if ((res = pn53x_read_register(pnd, PN53X_REG_CIU_Control, &ui8rcc)) < 0) return res; uint8_t ui8Bits = ui8rcc & SYMBOL_RX_LAST_BITS; // Recover the real frame length in bits size_t szFrameBits = ((szRx - 1 - ((ui8Bits == 0) ? 0 : 1)) * 8) + ui8Bits; // Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive() // Check if we should recover the parity bits ourself if (!pnd->bPar) { // Unwrap the response frame if ((res = pn53x_unwrap_frame(abtRx + 1, szFrameBits, pbtRx, pbtRxPar)) < 0) return res; szRxBits = res; } else { // Save the received bits szRxBits = szFrameBits; if ((szRx - 1) > szRxLen) return NFC_EOVFLOW; // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRx - 1); } // Everyting seems ok, return received bits count return szRxBits; } int pn53x_target_receive_bytes(struct nfc_device *pnd, uint8_t *pbtRx, const size_t szRxLen, int timeout) { uint8_t abtCmd[1]; // XXX I think this is not a clean way to provide some kind of "EasyFraming" // but at the moment I have no more better than this if (pnd->bEasyFraming) { switch (CHIP_DATA(pnd)->current_target->nm.nmt) { case NMT_DEP: abtCmd[0] = TgGetData; break; case NMT_ISO14443A: if (CHIP_DATA(pnd)->current_target->nti.nai.btSak & SAK_ISO14443_4_COMPLIANT) { // We are dealing with a ISO/IEC 14443-4 compliant target if ((CHIP_DATA(pnd)->type == PN532) && (pnd->bAutoIso14443_4)) { // We are using ISO/IEC 14443-4 PICC emulation capability from the PN532 abtCmd[0] = TgGetData; break; } else { // TODO Support EasyFraming for other cases by software pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } } abtCmd[0] = TgGetInitiatorCommand; break; case NMT_JEWEL: case NMT_BARCODE: case NMT_ISO14443B: case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_ISO14443BICLASS: case NMT_FELICA: abtCmd[0] = TgGetInitiatorCommand; break; } } else { abtCmd[0] = TgGetInitiatorCommand; } // Try to gather a received frame from the reader uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRx, szRx, timeout)) < 0) return pnd->last_error; szRx = (size_t) res; // Save the received bytes count szRx -= 1; if (szRx > szRxLen) return NFC_EOVFLOW; // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRx); // Everyting seems ok, return received bytes count return szRx; } int pn53x_target_send_bits(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar) { size_t szFrameBits = 0; size_t szFrameBytes = 0; uint8_t ui8Bits = 0; uint8_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN] = { TgResponseToInitiator }; int res = 0; // Check if we should prepare the parity bits ourself if (!pnd->bPar) { // Convert data with parity to a frame if ((res = pn53x_wrap_frame(pbtTx, szTxBits, pbtTxPar, abtCmd + 1)) < 0) return res; szFrameBits = res; } else { szFrameBits = szTxBits; } // Retrieve the leading bits ui8Bits = szFrameBits % 8; // Get the amount of frame bytes + optional (1 byte if there are leading bits) szFrameBytes = (szFrameBits / 8) + ((ui8Bits == 0) ? 0 : 1); // When the parity is handled before us, we just copy the data if (pnd->bPar) memcpy(abtCmd + 1, pbtTx, szFrameBytes); // Set the amount of transmission bits in the PN53X chip register if ((res = pn53x_set_tx_bits(pnd, ui8Bits)) < 0) return res; // Try to send the bits to the reader if ((res = pn53x_transceive(pnd, abtCmd, szFrameBytes + 1, NULL, 0, -1)) < 0) return res; // Everyting seems ok, return return sent bits count return szTxBits; } int pn53x_target_send_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout) { uint8_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; int res = 0; // We can not just send bytes without parity if while the PN53X expects we handled them if (!pnd->bPar) return NFC_ECHIP; // XXX I think this is not a clean way to provide some kind of "EasyFraming" // but at the moment I have no more better than this if (pnd->bEasyFraming) { switch (CHIP_DATA(pnd)->current_target->nm.nmt) { case NMT_DEP: abtCmd[0] = TgSetData; break; case NMT_ISO14443A: if (CHIP_DATA(pnd)->current_target->nti.nai.btSak & SAK_ISO14443_4_COMPLIANT) { // We are dealing with a ISO/IEC 14443-4 compliant target if ((CHIP_DATA(pnd)->type == PN532) && (pnd->bAutoIso14443_4)) { // We are using ISO/IEC 14443-4 PICC emulation capability from the PN532 abtCmd[0] = TgSetData; break; } else { // TODO Support EasyFraming for other cases by software pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } } abtCmd[0] = TgResponseToInitiator; break; case NMT_JEWEL: case NMT_BARCODE: case NMT_ISO14443B: case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_ISO14443BICLASS: case NMT_FELICA: abtCmd[0] = TgResponseToInitiator; break; } } else { abtCmd[0] = TgResponseToInitiator; } // Copy the data into the command frame memcpy(abtCmd + 1, pbtTx, szTx); // Try to send the bits to the reader if ((res = pn53x_transceive(pnd, abtCmd, szTx + 1, NULL, 0, timeout)) < 0) return res; // Everyting seems ok, return sent byte count return szTx; } static struct sErrorMessage { int iErrorCode; const char *pcErrorMsg; } sErrorMessages[] = { /* Chip-level errors (internal errors, RF errors, etc.) */ { 0x00, "Success" }, { ETIMEOUT, "Timeout" }, // Time Out, the target has not answered { ECRC, "CRC Error" }, // A CRC error has been detected by the CIU { EPARITY, "Parity Error" }, // A Parity error has been detected by the CIU { EBITCOUNT, "Erroneous Bit Count" }, // During an anti-collision/select operation (ISO/IEC14443-3 Type A and ISO/IEC18092 106 kbps passive mode), an erroneous Bit Count has been detected { EFRAMING, "Framing Error" }, // Framing error during MIFARE operation { EBITCOLL, "Bit-collision" }, // An abnormal bit-collision has been detected during bit wise anti-collision at 106 kbps { ESMALLBUF, "Communication Buffer Too Small" }, // Communication buffer size insufficient { EBUFOVF, "Buffer Overflow" }, // RF Buffer overflow has been detected by the CIU (bit BufferOvfl of the register CIU_Error) { ERFPROTO, "RF Protocol Error" }, // RF Protocol error (see PN53x manual) { EOVHEAT, "Chip Overheating" }, // Temperature error: the internal temperature sensor has detected overheating, and therefore has automatically switched off the antenna drivers { EINBUFOVF, "Internal Buffer overflow."}, // Internal buffer overflow { EINVPARAM, "Invalid Parameter"}, // Invalid parameter (range, format, …) { EOPNOTALL, "Operation Not Allowed" }, // Operation not allowed in this configuration (host controller interface) { ECMD, "Command Not Acceptable" }, // Command is not acceptable due to the current context { EOVCURRENT, "Over Current" }, /* DEP errors */ { ERFTIMEOUT, "RF Timeout" }, // In active communication mode, the RF field has not been switched on in time by the counterpart (as defined in NFCIP-1 standard) { EDEPUNKCMD, "Unknown DEP Command" }, { EDEPINVSTATE, "Invalid DEP State" }, // DEP Protocol: Invalid device state, the system is in a state which does not allow the operation { ENAD, "NAD Missing in DEP Frame" }, /* MIFARE */ { EMFAUTH, "Mifare Authentication Error" }, /* Misc */ { EINVRXFRAM, "Invalid Received Frame" }, // DEP Protocol, Mifare or ISO/IEC14443-4: The data format does not match to the specification. { ENSECNOTSUPP, "NFC Secure not supported" }, // Target or Initiator does not support NFC Secure { EBCC, "Wrong UID Check Byte (BCC)" }, // ISO/IEC14443-3: UID Check byte is wrong { ETGREL, "Target Released" }, // Target have been released by initiator { ECID, "Card ID Mismatch" }, // ISO14443 type B: Card ID mismatch, meaning that the expected card has been exchanged with another one. { ECDISCARDED, "Card Discarded" }, // ISO/IEC14443 type B: the card previously activated has disappeared. { ENFCID3, "NFCID3 Mismatch" }, }; const char * pn53x_strerror(const struct nfc_device *pnd) { const char *pcRes = "Unknown error"; size_t i; for (i = 0; i < (sizeof(sErrorMessages) / sizeof(struct sErrorMessage)); i++) { if (sErrorMessages[i].iErrorCode == CHIP_DATA(pnd)->last_status_byte) { pcRes = sErrorMessages[i].pcErrorMsg; break; } } return pcRes; } int pn53x_RFConfiguration__RF_field(struct nfc_device *pnd, bool bEnable) { uint8_t abtCmd[] = { RFConfiguration, RFCI_FIELD, (bEnable) ? 0x01 : 0x00 }; return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_RFConfiguration__Various_timings(struct nfc_device *pnd, const uint8_t fATR_RES_Timeout, const uint8_t fRetryTimeout) { uint8_t abtCmd[] = { RFConfiguration, RFCI_TIMING, 0x00, // RFU fATR_RES_Timeout, // ATR_RES timeout (default: 0x0B 102.4 ms) fRetryTimeout // TimeOut during non-DEP communications (default: 0x0A 51.2 ms) }; return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_RFConfiguration__MaxRtyCOM(struct nfc_device *pnd, const uint8_t MaxRtyCOM) { uint8_t abtCmd[] = { RFConfiguration, RFCI_RETRY_DATA, MaxRtyCOM // MaxRtyCOM, default: 0x00 (no retry, only one try), inifite: 0xff }; return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_RFConfiguration__MaxRetries(struct nfc_device *pnd, const uint8_t MxRtyATR, const uint8_t MxRtyPSL, const uint8_t MxRtyPassiveActivation) { // Retry format: 0x00 means only 1 try, 0xff means infinite uint8_t abtCmd[] = { RFConfiguration, RFCI_RETRY_SELECT, MxRtyATR, // MxRtyATR, default: active = 0xff, passive = 0x02 MxRtyPSL, // MxRtyPSL, default: 0x01 MxRtyPassiveActivation // MxRtyPassiveActivation, default: 0xff (0x00 leads to problems with PN531) }; return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_SetParameters(struct nfc_device *pnd, const uint8_t ui8Value) { uint8_t abtCmd[] = { SetParameters, ui8Value }; int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)) < 0) { return res; } // We save last parameters in register cache CHIP_DATA(pnd)->ui8Parameters = ui8Value; return NFC_SUCCESS; } int pn532_SAMConfiguration(struct nfc_device *pnd, const pn532_sam_mode sam_mode, int timeout) { uint8_t abtCmd[] = { SAMConfiguration, sam_mode, 0x00, 0x00 }; size_t szCmd = sizeof(abtCmd); if (CHIP_DATA(pnd)->type != PN532) { // This function is not supported by pn531 neither pn533 pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } switch (sam_mode) { case PSM_NORMAL: // Normal mode case PSM_WIRED_CARD: // Wired card mode szCmd = 2; break; case PSM_VIRTUAL_CARD: // Virtual card mode case PSM_DUAL_CARD: // Dual card mode // TODO Implement timeout handling szCmd = 3; break; default: pnd->last_error = NFC_EINVARG; return pnd->last_error; } CHIP_DATA(pnd)->sam_mode = sam_mode; return (pn53x_transceive(pnd, abtCmd, szCmd, NULL, 0, timeout)); } int pn53x_PowerDown(struct nfc_device *pnd) { uint8_t abtCmd[] = { PowerDown, 0xf0 }; int res; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)) < 0) return res; CHIP_DATA(pnd)->power_mode = LOWVBAT; return res; } /** * @brief C wrapper to InListPassiveTarget command * @return Returns selected targets count on success, otherwise returns libnfc's error code (negative value) * * @param pnd struct nfc_device struct pointer that represent currently used device * @param pmInitModulation Desired modulation * @param pbtInitiatorData Optional initiator data used for Felica, ISO14443B, Topaz Polling or for ISO14443A selecting a specific UID * @param szInitiatorData Length of initiator data \a pbtInitiatorData * @param pbtTargetsData pointer on a pre-allocated byte array to receive TargetData[n] as described in pn53x user manual * @param pszTargetsData size_t pointer where size of \a pbtTargetsData will be written * * @note Selected targets count can be found in \a pbtTargetsData[0] if available (i.e. \a pszTargetsData content is more than 0) * @note To decode theses TargetData[n], there is @fn pn53x_decode_target_data */ int pn53x_InListPassiveTarget(struct nfc_device *pnd, const pn53x_modulation pmInitModulation, const uint8_t szMaxTargets, const uint8_t *pbtInitiatorData, const size_t szInitiatorData, uint8_t *pbtTargetsData, size_t *pszTargetsData, int timeout) { uint8_t abtCmd[15] = { InListPassiveTarget }; abtCmd[1] = szMaxTargets; // MaxTg switch (pmInitModulation) { case PM_ISO14443A_106: case PM_FELICA_212: case PM_FELICA_424: // all gone fine. break; case PM_ISO14443B_106: if (!(pnd->btSupportByte & SUPPORT_ISO14443B)) { // Eg. Some PN532 doesn't support type B! pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } break; case PM_JEWEL_106: case PM_BARCODE_106: if (CHIP_DATA(pnd)->type == PN531) { // These modulations are not supported by pn531 pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } break; case PM_ISO14443B_212: case PM_ISO14443B_424: case PM_ISO14443B_847: if ((CHIP_DATA(pnd)->type != PN533) || (!(pnd->btSupportByte & SUPPORT_ISO14443B))) { // These modulations are not supported by pn531 neither pn532 pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } break; case PM_UNDEFINED: pnd->last_error = NFC_EINVARG; return pnd->last_error; } abtCmd[2] = pmInitModulation; // BrTy, the type of init modulation used for polling a passive tag // Set the optional initiator data (used for Felica, ISO14443B, Topaz Polling or for ISO14443A selecting a specific UID). if (pbtInitiatorData) memcpy(abtCmd + 3, pbtInitiatorData, szInitiatorData); int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, 3 + szInitiatorData, pbtTargetsData, *pszTargetsData, timeout)) < 0) { return res; } *pszTargetsData = (size_t) res; return pbtTargetsData[0]; } int pn53x_InDeselect(struct nfc_device *pnd, const uint8_t ui8Target) { if (CHIP_DATA(pnd)->type == RCS360) { // We should do act here *only* if a target was previously selected uint8_t abtStatus[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szStatus = sizeof(abtStatus); uint8_t abtCmdGetStatus[] = { GetGeneralStatus }; int res = 0; if ((res = pn53x_transceive(pnd, abtCmdGetStatus, sizeof(abtCmdGetStatus), abtStatus, szStatus, -1)) < 0) { return res; } szStatus = (size_t) res; if ((szStatus < 3) || (abtStatus[2] == 0)) { return NFC_SUCCESS; } // No much choice what to deselect actually... uint8_t abtCmdRcs360[] = { InDeselect, 0x01, 0x01 }; return (pn53x_transceive(pnd, abtCmdRcs360, sizeof(abtCmdRcs360), NULL, 0, -1)); } uint8_t abtCmd[] = { InDeselect, ui8Target }; return (pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)); } int pn53x_InRelease(struct nfc_device *pnd, const uint8_t ui8Target) { int res = 0; if (CHIP_DATA(pnd)->type == RCS360) { // We should do act here *only* if a target was previously selected uint8_t abtStatus[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szStatus = sizeof(abtStatus); uint8_t abtCmdGetStatus[] = { GetGeneralStatus }; if ((res = pn53x_transceive(pnd, abtCmdGetStatus, sizeof(abtCmdGetStatus), abtStatus, szStatus, -1)) < 0) { return res; } szStatus = (size_t) res; if ((szStatus < 3) || (abtStatus[2] == 0)) { return NFC_SUCCESS; } // No much choice what to release actually... uint8_t abtCmdRcs360[] = { InRelease, 0x01, 0x01 }; res = pn53x_transceive(pnd, abtCmdRcs360, sizeof(abtCmdRcs360), NULL, 0, -1); return (res >= 0) ? NFC_SUCCESS : res; } uint8_t abtCmd[] = { InRelease, ui8Target }; res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); return (res >= 0) ? NFC_SUCCESS : res; } int pn53x_InAutoPoll(struct nfc_device *pnd, const pn53x_target_type *ppttTargetTypes, const size_t szTargetTypes, const uint8_t btPollNr, const uint8_t btPeriod, nfc_target *pntTargets, const int timeout) { size_t szTargetFound = 0; if (CHIP_DATA(pnd)->type != PN532) { // This function is not supported by pn531 neither pn533 pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } // InAutoPoll frame looks like this { 0xd4, 0x60, 0x0f, 0x01, 0x00 } => { direction, command, pollnr, period, types... } size_t szTxInAutoPoll = 3 + szTargetTypes; uint8_t abtCmd[3 + 15] = { InAutoPoll, btPollNr, btPeriod }; for (size_t n = 0; n < szTargetTypes; n++) { abtCmd[3 + n] = ppttTargetTypes[n]; } uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); int res = pn53x_transceive(pnd, abtCmd, szTxInAutoPoll, abtRx, szRx, timeout); szRx = (size_t) res; if (res < 0) { return res; } else if (szRx > 0) { szTargetFound = abtRx[0]; if (szTargetFound > 0) { uint8_t ln; uint8_t *pbt = abtRx + 1; /* 1st target */ // Target type pn53x_target_type ptt = *(pbt++); pntTargets[0].nm = pn53x_ptt_to_nm(ptt); // AutoPollTargetData length ln = *(pbt++); if ((res = pn53x_decode_target_data(pbt, ln, CHIP_DATA(pnd)->type, pntTargets[0].nm.nmt, &(pntTargets[0].nti))) < 0) { return res; } pbt += ln; if (abtRx[0] > 1) { /* 2nd target */ // Target type ptt = *(pbt++); pntTargets[1].nm = pn53x_ptt_to_nm(ptt); // AutoPollTargetData length ln = *(pbt++); pn53x_decode_target_data(pbt, ln, CHIP_DATA(pnd)->type, pntTargets[1].nm.nmt, &(pntTargets[1].nti)); } } } return szTargetFound; } /** * @brief Wrapper for InJumpForDEP command * @param pmInitModulation desired initial modulation * @param pbtPassiveInitiatorData NFCID1 (4 bytes) at 106kbps (optionnal, see NFCIP-1: 11.2.1.26) or Polling Request Frame's payload (5 bytes) at 212/424kbps (mandatory, see NFCIP-1: 11.2.2.5) * @param szPassiveInitiatorData size of pbtPassiveInitiatorData content * @param pbtNFCID3i NFCID3 of the initiator * @param pbtGBi General Bytes of the initiator * @param szGBi count of General Bytes * @param[out] pnt \a nfc_target which will be filled by this function */ int pn53x_InJumpForDEP(struct nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const uint8_t *pbtPassiveInitiatorData, const uint8_t *pbtNFCID3i, const uint8_t *pbtGBi, const size_t szGBi, nfc_target *pnt, const int timeout) { // Max frame size = 1 (Command) + 1 (ActPass) + 1 (Baud rate) + 1 (Next) + 5 (PassiveInitiatorData) + 10 (NFCID3) + 48 (General bytes) = 67 bytes uint8_t abtCmd[67] = { InJumpForDEP, (ndm == NDM_ACTIVE) ? 0x01 : 0x00 }; size_t offset = 4; // 1 byte for command, 1 byte for DEP mode (Active/Passive), 1 byte for baud rate, 1 byte for following parameters flag switch (nbr) { case NBR_106: abtCmd[2] = 0x00; // baud rate is 106 kbps if (pbtPassiveInitiatorData && (ndm == NDM_PASSIVE)) { /* can't have passive initiator data when using active mode */ abtCmd[3] |= 0x01; memcpy(abtCmd + offset, pbtPassiveInitiatorData, 4); offset += 4; } break; case NBR_212: abtCmd[2] = 0x01; // baud rate is 212 kbps if (pbtPassiveInitiatorData && (ndm == NDM_PASSIVE)) { abtCmd[3] |= 0x01; memcpy(abtCmd + offset, pbtPassiveInitiatorData, 5); offset += 5; } break; case NBR_424: abtCmd[2] = 0x02; // baud rate is 424 kbps if (pbtPassiveInitiatorData && (ndm == NDM_PASSIVE)) { abtCmd[3] |= 0x01; memcpy(abtCmd + offset, pbtPassiveInitiatorData, 5); offset += 5; } break; case NBR_847: case NBR_UNDEFINED: pnd->last_error = NFC_EINVARG; return pnd->last_error; } if (pbtNFCID3i) { abtCmd[3] |= 0x02; memcpy(abtCmd + offset, pbtNFCID3i, 10); offset += 10; } if (szGBi && pbtGBi) { abtCmd[3] |= 0x04; memcpy(abtCmd + offset, pbtGBi, szGBi); offset += szGBi; } uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); int res = 0; // Try to find a target, call the transceive callback function of the current device if ((res = pn53x_transceive(pnd, abtCmd, offset, abtRx, szRx, timeout)) < 0) return res; szRx = (size_t) res; // Make sure one target has been found, the PN53X returns 0x00 if none was available if (abtRx[1] >= 1) { // Is a target struct available if (pnt) { pnt->nm.nmt = NMT_DEP; pnt->nm.nbr = nbr; pnt->nti.ndi.ndm = ndm; memcpy(pnt->nti.ndi.abtNFCID3, abtRx + 2, 10); pnt->nti.ndi.btDID = abtRx[12]; pnt->nti.ndi.btBS = abtRx[13]; pnt->nti.ndi.btBR = abtRx[14]; pnt->nti.ndi.btTO = abtRx[15]; pnt->nti.ndi.btPP = abtRx[16]; if (szRx > 17) { pnt->nti.ndi.szGB = szRx - 17; memcpy(pnt->nti.ndi.abtGB, abtRx + 17, pnt->nti.ndi.szGB); } else { pnt->nti.ndi.szGB = 0; } } } return abtRx[1]; } int pn53x_TgInitAsTarget(struct nfc_device *pnd, pn53x_target_mode ptm, const uint8_t *pbtMifareParams, const uint8_t *pbtTkt, size_t szTkt, const uint8_t *pbtFeliCaParams, const uint8_t *pbtNFCID3t, const uint8_t *pbtGBt, const size_t szGBt, uint8_t *pbtRx, const size_t szRxLen, uint8_t *pbtModeByte, int timeout) { uint8_t abtCmd[39 + 47 + 48] = { TgInitAsTarget }; // Worst case: 39-byte base, 47 bytes max. for General Bytes, 48 bytes max. for Historical Bytes size_t szOptionalBytes = 0; int res = 0; // Clear the target init struct, reset to all zeros memset(abtCmd + 1, 0x00, sizeof(abtCmd) - 1); // Store the target mode in the initialization params abtCmd[1] = ptm; // MIFARE part if (pbtMifareParams) { memcpy(abtCmd + 2, pbtMifareParams, 6); } // FeliCa part if (pbtFeliCaParams) { memcpy(abtCmd + 8, pbtFeliCaParams, 18); } // DEP part if (pbtNFCID3t) { memcpy(abtCmd + 26, pbtNFCID3t, 10); } // General Bytes (ISO/IEC 18092) if ((CHIP_DATA(pnd)->type == PN531) || (CHIP_DATA(pnd)->type == RCS360)) { if (szGBt) { memcpy(abtCmd + 36, pbtGBt, szGBt); szOptionalBytes = szGBt; } } else { abtCmd[36] = (uint8_t)(szGBt); if (szGBt) { memcpy(abtCmd + 37, pbtGBt, szGBt); } szOptionalBytes = szGBt + 1; } // Historical bytes (ISO/IEC 14443-4) if ((CHIP_DATA(pnd)->type != PN531) && (CHIP_DATA(pnd)->type != RCS360)) { // PN531 does not handle Historical Bytes abtCmd[36 + szOptionalBytes] = (uint8_t)(szTkt); if (szTkt) { memcpy(abtCmd + 37 + szOptionalBytes, pbtTkt, szTkt); } szOptionalBytes += szTkt + 1; } // Request the initialization as a target uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); if ((res = pn53x_transceive(pnd, abtCmd, 36 + szOptionalBytes, abtRx, szRx, timeout)) < 0) return res; szRx = (size_t) res; // Note: the first byte is skip: // its the "mode" byte which contains baudrate, DEP and Framing type (Mifare, active or FeliCa) datas. if (pbtModeByte) { *pbtModeByte = abtRx[0]; } // Save the received byte count szRx -= 1; if ((szRx - 1) > szRxLen) return NFC_EOVFLOW; // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRx); return szRx; } int pn53x_check_ack_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen) { if (szRxFrameLen >= sizeof(pn53x_ack_frame)) { if (0 == memcmp(pbtRxFrame, pn53x_ack_frame, sizeof(pn53x_ack_frame))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PN53x ACKed"); return NFC_SUCCESS; } } pnd->last_error = NFC_EIO; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unexpected PN53x reply!"); return pnd->last_error; } int pn53x_check_error_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen) { if (szRxFrameLen >= sizeof(pn53x_error_frame)) { if (0 == memcmp(pbtRxFrame, pn53x_error_frame, sizeof(pn53x_error_frame))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PN53x sent an error frame"); pnd->last_error = NFC_EIO; return pnd->last_error; } } return NFC_SUCCESS; } /** * @brief Build a PN53x frame * * @param pbtData payload (bytes array) of the frame, will become PD0, ..., PDn in PN53x frame * @note The first byte of pbtData is the Command Code (CC) */ int pn53x_build_frame(uint8_t *pbtFrame, size_t *pszFrame, const uint8_t *pbtData, const size_t szData) { if (szData <= PN53x_NORMAL_FRAME__DATA_MAX_LEN) { // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1) pbtFrame[3] = szData + 1; // LCS - Packet length checksum pbtFrame[4] = 256 - (szData + 1); // TFI pbtFrame[5] = 0xD4; // DATA - Copy the PN53X command into the packet buffer memcpy(pbtFrame + 6, pbtData, szData); // DCS - Calculate data payload checksum uint8_t btDCS = (256 - 0xD4); for (size_t szPos = 0; szPos < szData; szPos++) { btDCS -= pbtData[szPos]; } pbtFrame[6 + szData] = btDCS; // 0x00 - End of stream marker pbtFrame[szData + 7] = 0x00; (*pszFrame) = szData + PN53x_NORMAL_FRAME__OVERHEAD; } else if (szData <= PN53x_EXTENDED_FRAME__DATA_MAX_LEN) { // Extended frame marker pbtFrame[3] = 0xff; pbtFrame[4] = 0xff; // LENm pbtFrame[5] = (szData + 1) >> 8; // LENl pbtFrame[6] = (szData + 1) & 0xff; // LCS pbtFrame[7] = 256 - ((pbtFrame[5] + pbtFrame[6]) & 0xff); // TFI pbtFrame[8] = 0xD4; // DATA - Copy the PN53X command into the packet buffer memcpy(pbtFrame + 9, pbtData, szData); // DCS - Calculate data payload checksum uint8_t btDCS = (256 - 0xD4); for (size_t szPos = 0; szPos < szData; szPos++) { btDCS -= pbtData[szPos]; } pbtFrame[9 + szData] = btDCS; // 0x00 - End of stream marker pbtFrame[szData + 10] = 0x00; (*pszFrame) = szData + PN53x_EXTENDED_FRAME__OVERHEAD; } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "We can't send more than %d bytes in a raw (requested: %" PRIdPTR ")", PN53x_EXTENDED_FRAME__DATA_MAX_LEN, szData); return NFC_ECHIP; } return NFC_SUCCESS; } pn53x_modulation pn53x_nm_to_pm(const nfc_modulation nm) { switch (nm.nmt) { case NMT_ISO14443A: return PM_ISO14443A_106; case NMT_ISO14443B: case NMT_ISO14443BICLASS: switch (nm.nbr) { case NBR_106: return PM_ISO14443B_106; case NBR_212: return PM_ISO14443B_212; case NBR_424: return PM_ISO14443B_424; case NBR_847: return PM_ISO14443B_847; case NBR_UNDEFINED: // Nothing to do... break; } break; case NMT_JEWEL: return PM_JEWEL_106; case NMT_BARCODE: return PM_BARCODE_106; case NMT_FELICA: switch (nm.nbr) { case NBR_212: return PM_FELICA_212; case NBR_424: return PM_FELICA_424; case NBR_106: case NBR_847: case NBR_UNDEFINED: // Nothing to do... break; } break; case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_DEP: // Nothing to do... break; } return PM_UNDEFINED; } nfc_modulation pn53x_ptt_to_nm(const pn53x_target_type ptt) { switch (ptt) { case PTT_GENERIC_PASSIVE_106: case PTT_GENERIC_PASSIVE_212: case PTT_GENERIC_PASSIVE_424: case PTT_UNDEFINED: // XXX This should not happend, how handle it cleanly ? break; case PTT_MIFARE: case PTT_ISO14443_4A_106: return (const nfc_modulation) { .nmt = NMT_ISO14443A, .nbr = NBR_106 }; case PTT_ISO14443_4B_106: case PTT_ISO14443_4B_TCL_106: return (const nfc_modulation) { .nmt = NMT_ISO14443B, .nbr = NBR_106 }; case PTT_JEWEL_106: return (const nfc_modulation) { .nmt = NMT_JEWEL, .nbr = NBR_106 }; case PTT_FELICA_212: return (const nfc_modulation) { .nmt = NMT_FELICA, .nbr = NBR_212 }; case PTT_FELICA_424: return (const nfc_modulation) { .nmt = NMT_FELICA, .nbr = NBR_424 }; case PTT_DEP_PASSIVE_106: case PTT_DEP_ACTIVE_106: return (const nfc_modulation) { .nmt = NMT_DEP, .nbr = NBR_106 }; case PTT_DEP_PASSIVE_212: case PTT_DEP_ACTIVE_212: return (const nfc_modulation) { .nmt = NMT_DEP, .nbr = NBR_212 }; case PTT_DEP_PASSIVE_424: case PTT_DEP_ACTIVE_424: return (const nfc_modulation) { .nmt = NMT_DEP, .nbr = NBR_424 }; } // We should never be here, this line silent compilation warning return (const nfc_modulation) { .nmt = NMT_ISO14443A, .nbr = NBR_106 }; } pn53x_target_type pn53x_nm_to_ptt(const nfc_modulation nm) { switch (nm.nmt) { case NMT_ISO14443A: return PTT_MIFARE; // return PTT_ISO14443_4A_106; case NMT_ISO14443B: case NMT_ISO14443BICLASS: switch (nm.nbr) { case NBR_106: return PTT_ISO14443_4B_106; case NBR_UNDEFINED: case NBR_212: case NBR_424: case NBR_847: // Nothing to do... break; } break; case NMT_JEWEL: return PTT_JEWEL_106; case NMT_FELICA: switch (nm.nbr) { case NBR_212: return PTT_FELICA_212; case NBR_424: return PTT_FELICA_424; case NBR_UNDEFINED: case NBR_106: case NBR_847: // Nothing to do... break; } break; case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_BARCODE: case NMT_DEP: // Nothing to do... break; } return PTT_UNDEFINED; } int pn53x_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) { switch (mode) { case N_TARGET: *supported_mt = CHIP_DATA(pnd)->supported_modulation_as_target; break; case N_INITIATOR: *supported_mt = CHIP_DATA(pnd)->supported_modulation_as_initiator; break; default: return NFC_EINVARG; } return NFC_SUCCESS; } int pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) { switch (nmt) { case NMT_FELICA: *supported_br = (nfc_baud_rate *)pn53x_felica_supported_baud_rates; break; case NMT_ISO14443A: { if ((CHIP_DATA(pnd)->type != PN533) || (mode == N_TARGET)) { *supported_br = (nfc_baud_rate *)pn532_iso14443a_supported_baud_rates; } else { *supported_br = (nfc_baud_rate *)pn533_iso14443a_supported_baud_rates; } } break; case NMT_ISO14443B: { if ((CHIP_DATA(pnd)->type != PN533)) { *supported_br = (nfc_baud_rate *)pn532_iso14443b_supported_baud_rates; } else { *supported_br = (nfc_baud_rate *)pn533_iso14443b_supported_baud_rates; } } break; case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_ISO14443BICLASS: *supported_br = (nfc_baud_rate *)pn532_iso14443b_supported_baud_rates; break; case NMT_JEWEL: *supported_br = (nfc_baud_rate *)pn53x_jewel_supported_baud_rates; break; case NMT_BARCODE: *supported_br = (nfc_baud_rate *)pn53x_barcode_supported_baud_rates; break; case NMT_DEP: *supported_br = (nfc_baud_rate *)pn53x_dep_supported_baud_rates; break; default: return NFC_EINVARG; } return NFC_SUCCESS; } int pn53x_get_information_about(nfc_device *pnd, char **pbuf) { size_t buflen = 2048; *pbuf = malloc(buflen); if (! *pbuf) { return NFC_ESOFT; } char *buf = *pbuf; int res; if ((res = snprintf(buf, buflen, "chip: %s\n", CHIP_DATA(pnd)->firmware_text)) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; if ((res = snprintf(buf, buflen, "initator mode modulations: ")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; const nfc_modulation_type *nmt; if ((res = nfc_device_get_supported_modulation(pnd, N_INITIATOR, &nmt)) < 0) { free(*pbuf); return res; } for (int i = 0; nmt[i]; i++) { if ((res = snprintf(buf, buflen, "%s%s (", (i == 0) ? "" : ", ", str_nfc_modulation_type(nmt[i]))) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; const nfc_baud_rate *nbr; if ((res = nfc_device_get_supported_baud_rate(pnd, nmt[i], &nbr)) < 0) { free(*pbuf); return res; } for (int j = 0; nbr[j]; j++) { if ((res = snprintf(buf, buflen, "%s%s", (j == 0) ? "" : ", ", str_nfc_baud_rate(nbr[j]))) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; } if ((res = snprintf(buf, buflen, ")")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; } if ((res = snprintf(buf, buflen, "\n")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; if ((res = snprintf(buf, buflen, "target mode modulations: ")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; if ((res = nfc_device_get_supported_modulation(pnd, N_TARGET, &nmt)) < 0) { free(*pbuf); return res; } for (int i = 0; nmt[i]; i++) { if ((res = snprintf(buf, buflen, "%s%s (", (i == 0) ? "" : ", ", str_nfc_modulation_type(nmt[i]))) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; const nfc_baud_rate *nbr; if ((res = nfc_device_get_supported_baud_rate_target_mode(pnd, nmt[i], &nbr)) < 0) { free(*pbuf); return res; } for (int j = 0; nbr[j]; j++) { if ((res = snprintf(buf, buflen, "%s%s", (j == 0) ? "" : ", ", str_nfc_baud_rate(nbr[j]))) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; } if ((res = snprintf(buf, buflen, ")")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; } if ((res = snprintf(buf, buflen, "\n")) < 0) { free(*pbuf); return NFC_ESOFT; } //buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } //buflen -= res; return NFC_SUCCESS; } void * pn53x_current_target_new(const struct nfc_device *pnd, const nfc_target *pnt) { if (pnt == NULL) { return NULL; } // Keep the current nfc_target for further commands if (CHIP_DATA(pnd)->current_target) { free(CHIP_DATA(pnd)->current_target); } CHIP_DATA(pnd)->current_target = malloc(sizeof(nfc_target)); if (!CHIP_DATA(pnd)->current_target) { return NULL; } memcpy(CHIP_DATA(pnd)->current_target, pnt, sizeof(nfc_target)); return CHIP_DATA(pnd)->current_target; } void pn53x_current_target_free(const struct nfc_device *pnd) { if (CHIP_DATA(pnd)->current_target) { free(CHIP_DATA(pnd)->current_target); CHIP_DATA(pnd)->current_target = NULL; } } bool pn53x_current_target_is(const struct nfc_device *pnd, const nfc_target *pnt) { if ((CHIP_DATA(pnd)->current_target == NULL) || (pnt == NULL)) { return false; } // XXX It will not work if it is not binary-equal to current target if (0 != memcmp(pnt, CHIP_DATA(pnd)->current_target, sizeof(nfc_target))) { return false; } return true; } void * pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io) { pnd->chip_data = malloc(sizeof(struct pn53x_data)); if (!pnd->chip_data) { return NULL; } // Keep I/O functions CHIP_DATA(pnd)->io = io; // Set type to generic (means unknown) CHIP_DATA(pnd)->type = PN53X; // Set power mode to normal, if your device starts in LowVBat (ie. PN532 // UART) the driver layer have to correctly set it. CHIP_DATA(pnd)->power_mode = NORMAL; // PN53x starts in initiator mode CHIP_DATA(pnd)->operating_mode = INITIATOR; // Clear last status byte CHIP_DATA(pnd)->last_status_byte = 0x00; // Set current target to NULL CHIP_DATA(pnd)->current_target = NULL; // Set current sam_mode to normal mode CHIP_DATA(pnd)->sam_mode = PSM_NORMAL; // WriteBack cache is clean CHIP_DATA(pnd)->wb_trigged = false; memset(CHIP_DATA(pnd)->wb_mask, 0x00, PN53X_CACHE_REGISTER_SIZE); // Set default command timeout (350 ms) CHIP_DATA(pnd)->timeout_command = 350; // Set default ATR timeout (103 ms) CHIP_DATA(pnd)->timeout_atr = 103; // Set default communication timeout (52 ms) CHIP_DATA(pnd)->timeout_communication = 52; CHIP_DATA(pnd)->supported_modulation_as_initiator = NULL; CHIP_DATA(pnd)->supported_modulation_as_target = NULL; // Set default progressive field flag CHIP_DATA(pnd)->progressive_field = false; return pnd->chip_data; } void pn53x_data_free(struct nfc_device *pnd) { // Free current target pn53x_current_target_free(pnd); // Free supported modulation(s) if (CHIP_DATA(pnd)->supported_modulation_as_initiator) { free(CHIP_DATA(pnd)->supported_modulation_as_initiator); } free(pnd->chip_data); }