/* * Copyright (c) 2014-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * \file pn512_poll.c * \copyright Copyright (c) ARM Ltd 2014 * \author Donatien Garnier */ #define __DEBUG__ 0 #ifndef __MODULE__ #define __MODULE__ "pn512_poll.c" #endif #include "stack/nfc_errors.h" #include "pn512.h" #include "pn512_poll.h" #include "pn512_transceive.h" #include "pn512_registers.h" #include "pn512_rf.h" #include "pn512_cmd.h" #include "pn512_internal.h" #define TIMEOUT 1000 static void pn512_target_anticollision(pn512_t *pPN512, pn512_cb_t cb); static void pn512_initiator_isoa_anticollision(pn512_t *pPN512, pn512_cb_t cb); static inline bool pn512_config_initiator(pn512_t *pPN512) { return (pPN512->config.initiators.nfc_iso_dep_a | pPN512->config.initiators.nfc_iso_dep_b | pPN512->config.initiators.nfc_nfc_dep_a | pPN512->config.initiators.nfc_nfc_dep_f_212 | pPN512->config.initiators.nfc_nfc_dep_f_424 | pPN512->config.initiators.nfc_type1 | pPN512->config.initiators.nfc_type2 | pPN512->config.initiators.nfc_type3) != 0; } static inline bool pn512_config_target(pn512_t *pPN512) { return (pPN512->config.targets.nfc_iso_dep_a | pPN512->config.targets.nfc_iso_dep_b | pPN512->config.targets.nfc_nfc_dep_a | pPN512->config.targets.nfc_nfc_dep_f_212 | pPN512->config.initiators.nfc_nfc_dep_f_424 | pPN512->config.targets.nfc_type1 | pPN512->config.targets.nfc_type2 | pPN512->config.targets.nfc_type3) != 0; } void pn512_target_anticollision_complete(pn512_t *pPN512, nfc_err_t ret) { bool iso14443a = pPN512->config.targets.nfc_type2 || pPN512->config.targets.nfc_iso_dep_a || pPN512->config.targets.nfc_nfc_dep_a; //We do not support type 1 card emulation so irrelevant bool felica = pPN512->config.targets.nfc_type3 || pPN512->config.targets.nfc_nfc_dep_f_212 || pPN512->config.targets.nfc_nfc_dep_f_424; nfc_transceiver_t *pTransceiver = &pPN512->transceiver; if (ret) { NFC_WARN("Returned %d", ret); pn512_anticollision_callback(pPN512, ret); return; } //Data available in FIFO if (pPN512->readLastByteLength != 8) { //We should receive a full byte NFC_WARN("Not enough data in FIFO"); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } //If successful, update state machine if (iso14443a && felica) { //Update current protocol accordingly uint8_t txmode = pn512_register_read(pPN512, PN512_REG_TXMODE); if ((txmode & 0x03) == 0x00) { pn512_framing_set(pPN512, nfc_framing_target_a_106); NFC_DBG("A 106"); felica = false; } else if ((txmode & 0x03) == 0x02) { if ((txmode & 0x70) == 0x20) { //424kbps NFC_DBG("F 424"); pn512_framing_set(pPN512, nfc_framing_target_f_424); } else { //212kbps NFC_DBG("F 212"); pn512_framing_set(pPN512, nfc_framing_target_f_212); } iso14443a = false; } else { //Unsupported mode, exit pn512_anticollision_callback(pPN512, NFC_ERR_UNSUPPORTED); return; } } if (iso14443a) { if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pPN512->readBufBldr)) == 0) { pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } //Halt device, so that if anticollision is restarted it's in the correct state (cleared automatically by RF reset) pn512_register_write(pPN512, PN512_REG_MIFNFC, 0x62 | 0x04); //Copy buffer to peek ac_buffer_t readBufDup; ac_buffer_dup(&readBufDup, ac_buffer_builder_buffer(&pPN512->readBufBldr)); uint8_t b0 = ac_buffer_read_nu8(&readBufDup); //Get first byte //Read FIFO to see if the target was selected as NFC-DEP, ISO-DEP or proprietary (NFC Type 2) //F0 --> NFC-DEP //E0 --> ISO-DEP //Anything else --> NFC Type 2 //First check if this could be NFC-DEP if (pPN512->config.targets.nfc_nfc_dep_a && (b0 == 0xF0)) { pTransceiver->active_tech.nfc_nfc_dep_a = true; } else if (pPN512->config.targets.nfc_iso_dep_a && (b0 == 0xE0)) { pTransceiver->active_tech.nfc_iso_dep_a = true; } else if (pPN512->config.targets.nfc_type2) { pTransceiver->active_tech.nfc_type2 = true; } else { //Unknown tech, return error pn512_anticollision_callback(pPN512, NFC_ERR_UNSUPPORTED); return; } //Give control to higher layer pn512_anticollision_callback(pPN512, NFC_OK); return; } else if (felica) { //First check if this could be NFC-DEP if ((pPN512->config.targets.nfc_nfc_dep_f_212 || pPN512->config.targets.nfc_nfc_dep_f_424)) { if (pPN512->framing == nfc_framing_target_f_424) { pTransceiver->active_tech.nfc_nfc_dep_f_424 = true; } else { pTransceiver->active_tech.nfc_nfc_dep_f_212 = true; } } else { pn512_anticollision_callback(pPN512, NFC_ERR_UNSUPPORTED); return; } } //NFC-IP 1 active mode is not supported by other devices so ignore it for now pn512_anticollision_callback(pPN512, NFC_OK); } void pn512_target_anticollision(pn512_t *pPN512, pn512_cb_t cb) { pPN512->anticollision.cb = cb; //Reset active states pPN512->transceiver.initiator_ntarget = false; pPN512->transceiver.active_tech.nfc_type1 = pPN512->transceiver.active_tech.nfc_type2 = pPN512->transceiver.active_tech.nfc_type3 = pPN512->transceiver.active_tech.nfc_iso_dep_a = pPN512->transceiver.active_tech.nfc_nfc_dep_a = pPN512->transceiver.active_tech.nfc_nfc_dep_f_212 = pPN512->transceiver.active_tech.nfc_nfc_dep_f_424 = 0; pn512_set_timeout((nfc_transceiver_t *)pPN512, -1); //Should only fail on RF drop pn512_transceive_hw(pPN512, pn512_transceive_mode_target_autocoll, pn512_target_anticollision_complete); } // ISO A #define ISO14443A_BUF_SIZE 8 #define REQA 0x26 #define SEL(n) (0x93 + (n)*2) #define NVB(bits) ( (((2*8 + (bits))>>3)<<4) | ((bits) & 0x7) ) #define HALTA1 0x50 #define HALTA2 0x00 #define CT 0x88 static void pn512_initiator_isoa_anticollision_reqa(pn512_t *pPN512); static void pn512_initiator_isoa_anticollision_atqa(pn512_t *pPN512, nfc_err_t ret); static void pn512_initiator_isoa_anticollision_cascade_1(pn512_t *pPN512); static void pn512_initiator_isoa_anticollision_cascade_2(pn512_t *pPN512, nfc_err_t ret); static void pn512_initiator_isoa_anticollision_cascade_3(pn512_t *pPN512, nfc_err_t ret); static void pn512_initiator_isoa_anticollision_cascade_4(pn512_t *pPN512, nfc_err_t ret); static void pn512_initiator_isoa_anticollision_complete(pn512_t *pPN512); void pn512_initiator_isoa_anticollision(pn512_t *pPN512, pn512_cb_t cb) { pPN512->anticollision.cb = cb; // Reset transceive mode pPN512->transceive.mode = pn512_transceive_mode_idle; pn512_initiator_isoa_anticollision_reqa(pPN512); } void pn512_initiator_isoa_anticollision_reqa(pn512_t *pPN512) { ac_buffer_builder_t *pDataOutBldr = &pPN512->readBufBldr; ac_buffer_builder_reset(pDataOutBldr); pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.uidLength = 0; ac_buffer_builder_write_nu8(pDataOutBldr, REQA); pn512_set_last_byte_length((nfc_transceiver_t *)pPN512, 7); //Only 7 bits in this first command // FIXME PN512 Anomaly: pn512_register_write(pPN512, PN512_REG_COLL, 0x00); // Set MSB to 0, to accept collisions pn512_set_crc((nfc_transceiver_t *)pPN512, false, false); pn512_set_timeout((nfc_transceiver_t *)pPN512, 4); pn512_set_write((nfc_transceiver_t *)pPN512, ac_buffer_builder_buffer(pDataOutBldr)); pn512_transceive_hw(pPN512, pn512_transceive_mode_transceive, pn512_initiator_isoa_anticollision_atqa); } void pn512_initiator_isoa_anticollision_atqa(pn512_t *pPN512, nfc_err_t ret) { // Clear collisions register // FIXME PN512 Anomaly: pn512_register_write(pPN512, PN512_REG_COLL, 0x80); // Set MSB to 1, to treat collisions as errors if (ret && (ret != NFC_ERR_COLLISION)) { // There might be collisions here NFC_WARN("Did not receive ATQA: error %d", ret); pn512_anticollision_callback(pPN512, NFC_ERR_NOPEER); return; } ac_buffer_t *pResp = pn512_get_read((nfc_transceiver_t *)pPN512); if (ac_buffer_reader_readable(pResp) != 2) { NFC_WARN("Wrong length (%u bytes)", ac_buffer_reader_readable(pResp)); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } NFC_DBG("Got ATQA:"); NFC_DBG_BLOCK(ac_buffer_dump(pResp);) // Ignore ATQA as there can be collisions ac_buffer_read_n_bytes(pResp, pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.atqa, 2); //Start cascading pPN512->anticollision.iso_a.cascade_level = 1; pPN512->anticollision.iso_a.valid_bits = 0; pPN512->anticollision.iso_a.more_targets = false; memset(pPN512->anticollision.iso_a.cln, 0, 5); pn512_initiator_isoa_anticollision_cascade_1(pPN512); } void pn512_initiator_isoa_anticollision_cascade_1(pn512_t *pPN512) { ac_buffer_builder_t *pDataOutBldr = &pPN512->readBufBldr; ac_buffer_builder_reset(pDataOutBldr); //SEL ac_buffer_builder_write_nu8(pDataOutBldr, SEL(pPN512->anticollision.iso_a.cascade_level - 1)); //SEL: Cascade level ac_buffer_builder_write_nu8(pDataOutBldr, NVB(pPN512->anticollision.iso_a.valid_bits)); //First NVB: Bytecount = 2, Bitcount = 0, then adapt if collision detected NFC_DBG("SEL - cascade level %u, %u valid bits - NVB %u", pPN512->anticollision.iso_a.cascade_level, pPN512->anticollision.iso_a.valid_bits, NVB(pPN512->anticollision.iso_a.valid_bits)); if (pPN512->anticollision.iso_a.valid_bits > 0) { // Transmit first part of uid ac_buffer_builder_write_n_bytes(pDataOutBldr, pPN512->anticollision.iso_a.cln, (pPN512->anticollision.iso_a.valid_bits >> 3) + ((pPN512->anticollision.iso_a.valid_bits & 0x7) ? 1 : 0)); pn512_set_last_byte_length((nfc_transceiver_t *)pPN512, pPN512->anticollision.iso_a.valid_bits & 0x7); pn512_set_first_byte_align((nfc_transceiver_t *)pPN512, pPN512->anticollision.iso_a.valid_bits & 0x7); } // FIXME PN512 Anomaly: pn512_register_write(pPN512, PN512_REG_COLL, 0x00); // Set MSB to 0, to accept collisions pn512_set_crc((nfc_transceiver_t *)pPN512, false, false); pn512_set_timeout((nfc_transceiver_t *)pPN512, 30); pn512_set_write((nfc_transceiver_t *)pPN512, ac_buffer_builder_buffer(pDataOutBldr)); pn512_register_write(pPN512, PN512_REG_COMIRQ, 2); NFC_DBG("IRQ status %04X", ((pn512_register_read(pPN512, PN512_REG_COMIRQ)) | ((pn512_register_read(pPN512, PN512_REG_DIVIRQ)) << 8))); pn512_transceive_hw(pPN512, pn512_transceive_mode_transceive, pn512_initiator_isoa_anticollision_cascade_2); } void pn512_initiator_isoa_anticollision_cascade_2(pn512_t *pPN512, nfc_err_t ret) { ac_buffer_t *pResp = pn512_get_read((nfc_transceiver_t *)pPN512); // Load & clear collisions register // FIXME PN512 Anomaly: pn512_register_write(pPN512, PN512_REG_COLL, 0x80); // Set MSB to 1, to treat collisions as errors if (ret && (ret != NFC_ERR_COLLISION)) { // There might be collisions here NFC_WARN("Did not receive response: error %d", ret); pn512_anticollision_callback(pPN512, ret); return; } // We should receive 5 bytes back minus all the CLn bits that we have transmitted; we ignore all bits from the first collision size_t expected_resp_bits = (5 << 3) - pPN512->anticollision.iso_a.valid_bits; // Check for collision uint8_t valid_bits = expected_resp_bits; if (ret == NFC_ERR_COLLISION) { uint8_t coll_reg = pn512_register_read(pPN512, PN512_REG_COLL); // FIXME - PN512 error //if( !(coll_reg & 0x20) ) // bit 5 is CollPosNotValidSet { valid_bits = (coll_reg & 0x1f); if (valid_bits == 0) { valid_bits = 32; } valid_bits--; NFC_DBG("Collision detected, %u valid bits", valid_bits); if (valid_bits < expected_resp_bits) { // Collision detected pPN512->anticollision.iso_a.more_targets = true; } else { valid_bits = expected_resp_bits; } } } size_t resp_sz = (valid_bits >> 3) + ((valid_bits & 0x7) ? 1 : 0); if (ac_buffer_reader_readable(pResp) < resp_sz) { (void) pn512_register_read(pPN512, PN512_REG_COLL); NFC_WARN("Wrong length (%u instead of %u - valid bits %u)", ac_buffer_reader_readable(pResp), resp_sz, valid_bits); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } // Read bytes uint8_t bufIn[5] = {0}; ac_buffer_read_n_bytes(pResp, bufIn + (pPN512->anticollision.iso_a.valid_bits >> 3), resp_sz); // Mask out valid bits that are already known bufIn[pPN512->anticollision.iso_a.valid_bits >> 3] &= 0xff << (pPN512->anticollision.iso_a.valid_bits & 0x7); // Update number of valid bits pPN512->anticollision.iso_a.valid_bits += valid_bits; // Mask out bits past valid bits in last byte bufIn[pPN512->anticollision.iso_a.valid_bits >> 3] &= 0xff >> ((8 - pPN512->anticollision.iso_a.valid_bits) & 0x7); // Now remember bits before collision for (size_t p = 0; p < 5; p++) { pPN512->anticollision.iso_a.cln[p] |= bufIn[p]; } // If we have all bits, then check BCC, go to next step if (pPN512->anticollision.iso_a.valid_bits < 5 * 8) { // Collision, add a 1 at the end of known bits to resolve collision pPN512->anticollision.iso_a.cln[pPN512->anticollision.iso_a.valid_bits >> 3] |= (1 << (pPN512->anticollision.iso_a.valid_bits & 0x7)); pPN512->anticollision.iso_a.valid_bits++; // Restart first step with more valid bits pn512_initiator_isoa_anticollision_cascade_1(pPN512); return; } //Check BCC if all bits are valid if (pPN512->anticollision.iso_a.cln[4] != (pPN512->anticollision.iso_a.cln[0] ^ pPN512->anticollision.iso_a.cln[1] ^ pPN512->anticollision.iso_a.cln[2] ^ pPN512->anticollision.iso_a.cln[3])) { NFC_WARN("Wrong BCC %02X != %02X", bufIn[4], bufIn[0] ^ bufIn[1] ^ bufIn[2] ^ bufIn[3]); pn512_anticollision_callback(pPN512, NFC_ERR_COLLISION); return; //TODO handle this properly } if (pPN512->anticollision.iso_a.cln[0] == CT) { //Not the last cascade level if (pPN512->anticollision.iso_a.cascade_level == 3) { // not allowed NFC_WARN("Cascade tag present in cascade level 3"); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } memcpy(&pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.uid[(pPN512->anticollision.iso_a.cascade_level - 1) * 3], &pPN512->anticollision.iso_a.cln[1], 3); pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.uidLength += 3; } else { //Last cascade level memcpy(&pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.uid[(pPN512->anticollision.iso_a.cascade_level - 1) * 3], &pPN512->anticollision.iso_a.cln[0], 4); pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.uidLength += 4; } ac_buffer_builder_t *pDataOutBldr = &pPN512->readBufBldr; ac_buffer_builder_reset(pDataOutBldr); //Select and get SAK ac_buffer_builder_write_nu8(pDataOutBldr, SEL(pPN512->anticollision.iso_a.cascade_level - 1)); //SEL: Cascade level ac_buffer_builder_write_nu8(pDataOutBldr, NVB(40)); //NVB: 40 valid bits = 5 bytes //Transmit last 4 transmitted UID bytes + BCC (including cascade byte if relevant) ac_buffer_builder_write_n_bytes(pDataOutBldr, pPN512->anticollision.iso_a.cln, 5); NFC_DBG("Selecting target"); //This time compute & check CRC pn512_set_crc((nfc_transceiver_t *)pPN512, true, true); pn512_set_write((nfc_transceiver_t *)pPN512, ac_buffer_builder_buffer(pDataOutBldr)); pn512_transceive_hw(pPN512, pn512_transceive_mode_transceive, pn512_initiator_isoa_anticollision_cascade_3); } static void pn512_initiator_isoa_anticollision_cascade_3(pn512_t *pPN512, nfc_err_t ret) { ac_buffer_t *pResp = pn512_get_read((nfc_transceiver_t *)pPN512); if (ret) { NFC_WARN("Did not receive response: error %d", ret); pn512_anticollision_callback(pPN512, ret); return; } if (ac_buffer_reader_readable(pResp) != 1) { NFC_WARN("Wrong length"); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.sak = ac_buffer_read_nu8(pResp); NFC_DBG("Got SAK %02X", pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.sak); //Check SAK if (pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.sak & 0x04) { //Continue anticollision pPN512->anticollision.iso_a.cascade_level++; pPN512->anticollision.iso_a.valid_bits = 0; memset(pPN512->anticollision.iso_a.cln, 0, 5); pn512_initiator_isoa_anticollision_cascade_1(pPN512); } else { //Anticollision complete NFC_DBG("Found one target- SAK = %02X", pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.sak); //Analyze SAK memset(&pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type, 0, sizeof(nfc_tech_t)); if (pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.sak & 0x40) { //NFC-IP1 compliant pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type.nfc_nfc_dep_a = true; } if ((pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.sak & 0x20) && pPN512->config.initiators.nfc_iso_dep_a) { //ISO-14443A-4 compliant pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type.nfc_iso_dep_a = true; } if (!(pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.sak & 0x60) && pPN512->config.initiators.nfc_type2) { //Potentially NFC Type 2 (or Mifare, etc) pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type.nfc_type2 = true; } // Unknown target if (!pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type.nfc_iso_dep_a && !pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type.nfc_nfc_dep_a && !pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type.nfc_type2 ) { pn512_anticollision_callback(pPN512, NFC_ERR_NOPEER); return; } // Valid target detected pPN512->transceiver.active_tech = pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type; pPN512->transceiver.remote_targets_count++; if (!pPN512->config.options.bail_at_first_target && pPN512->anticollision.iso_a.more_targets && (pPN512->transceiver.remote_targets_count < MUNFC_MAX_REMOTE_TARGETS)) { // Halt target and continue with others ac_buffer_builder_t *pDataOutBldr = &pPN512->readBufBldr; ac_buffer_builder_reset(pDataOutBldr); //HALTA ac_buffer_builder_write_nu8(pDataOutBldr, HALTA1); ac_buffer_builder_write_nu8(pDataOutBldr, HALTA2); pn512_set_crc((nfc_transceiver_t *)pPN512, true, false); pn512_set_timeout((nfc_transceiver_t *)pPN512, 30); pn512_set_write((nfc_transceiver_t *)pPN512, ac_buffer_builder_buffer(pDataOutBldr)); pn512_transceive_hw(pPN512, pn512_transceive_mode_transmit, pn512_initiator_isoa_anticollision_cascade_4); return; } // Leave it activated and finish! pn512_initiator_isoa_anticollision_complete(pPN512); } } static void pn512_initiator_isoa_anticollision_cascade_4(pn512_t *pPN512, nfc_err_t ret) { if (ret) { NFC_WARN("Could not halt device: error %d", ret); pn512_anticollision_callback(pPN512, ret); return; } // Start again pn512_initiator_isoa_anticollision_reqa(pPN512); } void pn512_initiator_isoa_anticollision_complete(pn512_t *pPN512) { pn512_anticollision_callback(pPN512, NFC_OK); } // ISO B static void pn512_initiator_isob_anticollision(pn512_t *pPN512, pn512_cb_t cb); static void pn512_initiator_isob_anticollision_reqb(pn512_t *pPN512); static void pn512_initiator_isob_anticollision_atqb(pn512_t *pPN512, nfc_err_t ret); static void pn512_initiator_isob_anticollision_next_slot(pn512_t *pPN512); static void pn512_initiator_isob_anticollision_haltb_resp(pn512_t *pPN512, nfc_err_t ret); static void pn512_initiator_isob_anticollision_complete(pn512_t *pPN512); #define REQB 0x05 #define HALTB 0x50 void pn512_initiator_isob_anticollision(pn512_t *pPN512, pn512_cb_t cb) { pPN512->anticollision.cb = cb; pPN512->anticollision.iso_b.slots_num_exponent = 0; // Start with one slot pPN512->anticollision.iso_b.slot_number = 0; pPN512->anticollision.iso_b.found_one = false; // Reset transceive mode pPN512->transceive.mode = pn512_transceive_mode_idle; pn512_initiator_isob_anticollision_reqb(pPN512); } void pn512_initiator_isob_anticollision_reqb(pn512_t *pPN512) { ac_buffer_builder_t *pDataOutBldr = &pPN512->readBufBldr; ac_buffer_builder_reset(pDataOutBldr); if (pPN512->anticollision.iso_b.slot_number == 0) { // Send REQB/WUPB pPN512->anticollision.iso_b.more_targets = false; ac_buffer_builder_write_nu8(pDataOutBldr, REQB); ac_buffer_builder_write_nu8(pDataOutBldr, 0x00); // AFI: All card types should respond uint8_t wup = 0; if ( pPN512->anticollision.iso_b.slots_num_exponent == 0 //&& (pPN512->anticollision.iso_b.slot_number == 0) ) { wup |= 0x8; // Send Wake-Up command on first iteration } ac_buffer_builder_write_nu8(pDataOutBldr, wup | (pPN512->anticollision.iso_b.slots_num_exponent & 0x7)); // Param: number of slots } else { // Just send slot marker ac_buffer_builder_write_nu8(pDataOutBldr, REQB | ((pPN512->anticollision.iso_b.slot_number & 0xf) << 4)); } pn512_set_crc((nfc_transceiver_t *)pPN512, true, true); pn512_set_timeout((nfc_transceiver_t *)pPN512, 18); pn512_set_write((nfc_transceiver_t *)pPN512, ac_buffer_builder_buffer(pDataOutBldr)); pn512_transceive_hw(pPN512, pn512_transceive_mode_transceive, pn512_initiator_isob_anticollision_atqb); } void pn512_initiator_isob_anticollision_atqb(pn512_t *pPN512, nfc_err_t ret) { // Three cases: // - 1 response --> store response, halt PICC and check next slot number // - No response --> check next slot number // - Collision --> check next slot number but we will have to increment number of slots ac_buffer_t *pResp = pn512_get_read((nfc_transceiver_t *)pPN512); if (ret && (ret != NFC_ERR_COLLISION) && (ret != NFC_ERR_WRONG_COMM) && (ret != NFC_ERR_TIMEOUT)) { NFC_WARN("Did not receive ATQB: error %u", ret); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } // Increment slot number pPN512->anticollision.iso_b.slot_number++; if ((ret == NFC_ERR_COLLISION) || (ret == NFC_ERR_WRONG_COMM)) { pPN512->anticollision.iso_b.more_targets = true; } else if (!ret) { pPN512->anticollision.iso_b.found_one = true; // Decode ATQB if (ac_buffer_reader_readable(pResp) != 12) { NFC_WARN("Wrong length (%u bytes)", ac_buffer_reader_readable(pResp)); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } NFC_DBG("Got ATQB:"); NFC_DBG_BLOCK(ac_buffer_dump(pResp);) // Check first byte uint8_t atqb0 = ac_buffer_read_nu8(pResp); if (atqb0 != 0x50) { NFC_WARN("Wrong first byte for ATQB: %02X", atqb0); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } memset(&pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type, 0, sizeof(nfc_tech_t)); pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type.nfc_iso_dep_b = true; // Save PUPI, application data & protocol info ac_buffer_read_n_bytes(pResp, pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcB.pupi, 4); ac_buffer_read_n_bytes(pResp, pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcB.application_data, 4); ac_buffer_read_n_bytes(pResp, pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcB.protocol_info, 3); // Valid target detected pPN512->transceiver.active_tech = pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type; pPN512->transceiver.remote_targets_count++; if (!pPN512->config.options.bail_at_first_target && (pPN512->anticollision.iso_b.more_targets || (pPN512->anticollision.iso_b.slot_number < (1 << pPN512->anticollision.iso_b.slots_num_exponent))) && (pPN512->transceiver.remote_targets_count < MUNFC_MAX_REMOTE_TARGETS)) { // Halt target and continue with others ac_buffer_builder_t *pDataOutBldr = &pPN512->readBufBldr; ac_buffer_builder_reset(pDataOutBldr); // Halt PICC and move on to the next slot //HALTB ac_buffer_builder_write_nu8(pDataOutBldr, HALTB); ac_buffer_builder_write_n_bytes(pDataOutBldr, pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count - 1].nfcB.pupi, 4); pn512_set_crc((nfc_transceiver_t *)pPN512, true, true); pn512_set_timeout((nfc_transceiver_t *)pPN512, 30); pn512_set_write((nfc_transceiver_t *)pPN512, ac_buffer_builder_buffer(pDataOutBldr)); pn512_transceive_hw(pPN512, pn512_transceive_mode_transceive, pn512_initiator_isob_anticollision_haltb_resp); return; } else { pn512_initiator_isob_anticollision_complete(pPN512); return; } } // Move on to the next slot pn512_initiator_isob_anticollision_next_slot(pPN512); } void pn512_initiator_isob_anticollision_next_slot(pn512_t *pPN512) { if (pPN512->anticollision.iso_b.slot_number >= (1 << pPN512->anticollision.iso_b.slots_num_exponent)) { if (!pPN512->anticollision.iso_b.more_targets) { // No further collisions to resolve pn512_initiator_isob_anticollision_complete(pPN512); return; } if (pPN512->anticollision.iso_b.slots_num_exponent >= 4) { // Cannot handle more than 16 slots pn512_initiator_isob_anticollision_complete(pPN512); return; } pPN512->anticollision.iso_b.slots_num_exponent++; pPN512->anticollision.iso_b.slot_number = 0; } pn512_initiator_isob_anticollision_reqb(pPN512); } void pn512_initiator_isob_anticollision_haltb_resp(pn512_t *pPN512, nfc_err_t ret) { // Check for response if (ret) { NFC_WARN("Did not receive HALTB response: error %u", ret); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } ac_buffer_t *pResp = pn512_get_read((nfc_transceiver_t *)pPN512); if (ac_buffer_reader_readable(pResp) != 1) { NFC_WARN("Wrong length (%u bytes)", ac_buffer_reader_readable(pResp)); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } NFC_DBG("Got HALTB response:"); NFC_DBG_BLOCK(ac_buffer_dump(pResp);) // Check byte uint8_t haltbr = ac_buffer_read_nu8(pResp); if (haltbr != 0x00) { NFC_WARN("Wrong byte for HALTB response: %02X", haltbr); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } // PICC halted, move to next slot pn512_initiator_isob_anticollision_next_slot(pPN512); } void pn512_initiator_isob_anticollision_complete(pn512_t *pPN512) { if (pPN512->anticollision.iso_b.found_one) { pn512_anticollision_callback(pPN512, NFC_OK); } else { pn512_anticollision_callback(pPN512, NFC_ERR_NOPEER); } } // Felica static void pn512_initiator_felica_anticollision(pn512_t *pPN512, pn512_cb_t cb); static void pn512_initiator_felica_anticollision_reqc(pn512_t *pPN512); static void pn512_initiator_felica_anticollision_atqc(pn512_t *pPN512, nfc_err_t ret); static void pn512_initiator_felica_anticollision_complete(pn512_t *pPN512); #define REQC 0x00 void pn512_initiator_felica_anticollision(pn512_t *pPN512, pn512_cb_t cb) { pPN512->anticollision.cb = cb; // Reset transceive mode pPN512->transceive.mode = pn512_transceive_mode_idle; pn512_initiator_felica_anticollision_reqc(pPN512); } void pn512_initiator_felica_anticollision_reqc(pn512_t *pPN512) { ac_buffer_builder_t *pDataOutBldr = &pPN512->readBufBldr; ac_buffer_builder_reset(pDataOutBldr); ac_buffer_builder_write_nu8(pDataOutBldr, 6); //Length ac_buffer_builder_write_nu8(pDataOutBldr, REQC); ac_buffer_builder_write_nu16(pDataOutBldr, 0xFFFF); //Any system code ac_buffer_builder_write_nu8(pDataOutBldr, 0x00); // Padding ac_buffer_builder_write_nu8(pDataOutBldr, 0x07); // 8 time slots, more would overflow the rx buffer if many cards responded pn512_set_crc((nfc_transceiver_t *)pPN512, true, true); pn512_set_timeout((nfc_transceiver_t *)pPN512, 13); //8 timeslots at 212kbps pn512_set_write((nfc_transceiver_t *)pPN512, ac_buffer_builder_buffer(pDataOutBldr)); pn512_framing_rx_multiple_enable(pPN512); // Set RxMultiple bit pn512_transceive_hw(pPN512, pn512_transceive_mode_transceive, pn512_initiator_felica_anticollision_atqc); } void pn512_initiator_felica_anticollision_atqc(pn512_t *pPN512, nfc_err_t ret) { ac_buffer_t *pResp = pn512_get_read((nfc_transceiver_t *)pPN512); if (ret || (ac_buffer_reader_readable(pResp) == 0)) { NFC_WARN("Did not receive ATQC: error %d", ret); pn512_anticollision_callback(pPN512, NFC_ERR_NOPEER); return; } // We might have multiple responses NFC_DBG("Got ATQC:"); NFC_DBG_BLOCK(ac_buffer_dump(pResp);) while (ac_buffer_reader_readable(pResp) > 0) { if (ac_buffer_reader_readable(pResp) != 18 + 1) { // ATQC is 18 bytes, 1 byte for errors added by PN512 NFC_WARN("Wrong length (%d bytes)", ac_buffer_reader_readable(pResp)); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } // First byte is length, check that it's correct uint8_t frame_length = ac_buffer_read_nu8(pResp); uint8_t atqc0 = ac_buffer_read_nu8(pResp); if ((frame_length != 18) || (atqc0 != 0x01)) { NFC_WARN("Wrong ATQC frame"); pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL); return; } // Read NFCID2 ac_buffer_read_n_bytes(pResp, pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcF.nfcid2, 8); // Discard padding bytes ac_buffer_read_n_skip(pResp, 8); // Read error register uint8_t err_reg = ac_buffer_read_nu8(pResp); if (err_reg & 0x1f) { // Error within this time slot, skip continue; } //Populate tech accordingly memset(&pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type, 0, sizeof(nfc_tech_t)); if ( (pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcF.nfcid2[0] == 0x01) && (pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcF.nfcid2[1] == 0xFE) ) { // NFC-DEP supported pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type.nfc_nfc_dep_f_212 = 1; } else { // Type 3 supported pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type.nfc_type3 = 1; } pPN512->transceiver.active_tech = pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].type; pPN512->transceiver.remote_targets_count++; // Only continue if we can have more targets if (!pPN512->config.options.bail_at_first_target && (pPN512->transceiver.remote_targets_count < MUNFC_MAX_REMOTE_TARGETS)) { continue; } break; } pn512_initiator_felica_anticollision_complete(pPN512); } void pn512_initiator_felica_anticollision_complete(pn512_t *pPN512) { pn512_anticollision_callback(pPN512, NFC_OK); } void pn512_poll_setup(pn512_t *pPN512) { bool target = pPN512->config.targets.nfc_type2 || pPN512->config.targets.nfc_type3 || pPN512->config.targets.nfc_iso_dep_a || pPN512->config.targets.nfc_nfc_dep_a || pPN512->config.targets.nfc_nfc_dep_f_212 || pPN512->config.targets.nfc_nfc_dep_f_424; // No need for initiator-specific configuration at this stage, but keep this just in case // bool initiator = pPN512->config.initiators.nfc_type1 // || pPN512->config.initiators.nfc_type2 // || pPN512->config.initiators.nfc_type3 // || pPN512->config.initiators.nfc_iso_dep_a // || pPN512->config.initiators.nfc_nfc_dep_a // || pPN512->config.initiators.nfc_nfc_dep_f_212 // || pPN512->config.initiators.nfc_nfc_dep_f_424; if (target) { NFC_DBG("Configure anticoll/polling response"); //Setup ATQA, SAK and Felica polling response pn512_fifo_clear(pPN512); ac_buffer_builder_t *pDataCfgBldr = &pPN512->readBufBldr; ac_buffer_builder_reset(pDataCfgBldr); //Write ATQA ac_buffer_builder_write_nu8(pDataCfgBldr, 0x04); ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); //Write NFCID1 (0s as it will be randomly generated) - first byte will be set to 0x08 by HW according to NFC-IP1 for (int i = 0; i < 3; i++) { ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); } //Write SAK uint8_t sak = 0x00; //Default SAK (UID complete) if (pPN512->config.targets.nfc_iso_dep_a) { sak |= 0x20; //This target is ISO-14443A-4 compliant } if (pPN512->config.targets.nfc_nfc_dep_a) { sak |= 0x40; //This target is NFC-IP1 compliant } ac_buffer_builder_write_nu8(pDataCfgBldr, sak); //Write NFCID2 (xx 0xfe according to NFC-IP1 and 0s as 6 bytes will be randomly generated) if (pPN512->config.targets.nfc_nfc_dep_f_212 || pPN512->config.targets.nfc_nfc_dep_f_424) { //Byte 1 is 0x01 if supporting NFC-IP1 ac_buffer_builder_write_nu8(pDataCfgBldr, 0x01); } else if (pPN512->config.targets.nfc_type3) { //NFC-IP will have priority over type 3 tag emulation //Byte 1 is 0x02 if supporting Type 3 tag platform ac_buffer_builder_write_nu8(pDataCfgBldr, 0x02); } else { ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); } ac_buffer_builder_write_nu8(pDataCfgBldr, 0xFE); for (int i = 0; i < 6; i++) { ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); } //2 PAD0 bytes (Felica spec) - this would code the manufacturer + IC code (0xFFFF for NFC-IP1 tags) ac_buffer_builder_write_nu8(pDataCfgBldr, 0xFF); ac_buffer_builder_write_nu8(pDataCfgBldr, 0xFF); //3 PAD1 bytes ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); if (!(pPN512->config.targets.nfc_nfc_dep_f_212 || pPN512->config.targets.nfc_nfc_dep_f_424) && pPN512->config.targets.nfc_type3) { ac_buffer_builder_write_nu8(pDataCfgBldr, 0x01); //MRTI Check ac_buffer_builder_write_nu8(pDataCfgBldr, 0x01); //MRTI Update } else { ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); } //1 PAD2 byte ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); //2 system code bytes if (!(pPN512->config.targets.nfc_nfc_dep_f_212 || pPN512->config.targets.nfc_nfc_dep_f_424) && pPN512->config.targets.nfc_type3) { ac_buffer_builder_write_nu8(pDataCfgBldr, 0x12); ac_buffer_builder_write_nu8(pDataCfgBldr, 0xFC); } else { ac_buffer_builder_write_nu8(pDataCfgBldr, 0xFF); //Wildcard system code ac_buffer_builder_write_nu8(pDataCfgBldr, 0xFF); } //Write NFCID3 ac_buffer_builder_write_nu8(pDataCfgBldr, 0x00); pn512_fifo_write(pPN512, ac_buffer_builder_buffer(pDataCfgBldr)); pn512_cmd_exec(pPN512, PN512_CMD_CONFIG); pn512_cmd_wait_idle(pPN512, -1); NFC_DBG("Overwrite NFCIDs with random numbers"); //Overwrite NFCIDs with random numbers pn512_cmd_exec(pPN512, PN512_CMD_RNDIDG); pn512_cmd_wait_idle(pPN512, -1); } } static void pn512_poll_iteration(pn512_t *pPN512, nfc_err_t ret); static void pn512_poll_delay_complete(uint32_t events, void *pUserData) { pn512_t *pPN512 = (pn512_t *) pUserData; if (events & EVENT_ABORTED) { pn512_poll_callback(pPN512, NFC_ERR_ABORTED); return; } pn512_poll_iteration(pPN512, NFC_OK); } static void pn512_poll_delay(pn512_t *pPN512, uint32_t timeout) { task_init(&pPN512->transceiver.task, EVENT_TIMEOUT, timeout, pn512_poll_delay_complete, pPN512); nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task); } void pn512_poll_iteration(pn512_t *pPN512, nfc_err_t ret) { do { if (pPN512->poll.state == pn512_polling_state_start_listening) { NFC_DBG("pn512_polling_state_start_listening"); // Start with listening if (!pn512_config_target(pPN512)) { // Otherwise switch to next step pPN512->poll.state = pn512_polling_state_start_polling; continue; } pPN512->poll.state = pn512_polling_state_listen_wait_for_remote_field; // Shortcut if target is halted (means RF field is still here) if (pn512_register_read(pPN512, PN512_REG_MIFNFC) & 0x04) { continue; } // Fix for PN512 bug that sometimes detects its own RF field // if(pPN512->rf_on) { //Switch RF field off pn512_rf_field_switch_off(pPN512); NFC_DBG("RF field switched off"); } NFC_DBG("Target anticollision"); bool iso14443a = pPN512->config.targets.nfc_type2 || pPN512->config.targets.nfc_iso_dep_a || pPN512->config.targets.nfc_nfc_dep_a; bool felica = pPN512->config.targets.nfc_type3 || pPN512->config.targets.nfc_nfc_dep_f_212 || pPN512->config.targets.nfc_nfc_dep_f_424; NFC_DBG("Switch in target mode and set framing: ISO A: %s; Felica: %s", iso14443a ? "Yes" : "No", felica ? "Yes" : "No"); //Switch in target mode if (iso14443a && felica) { pn512_framing_set(pPN512, nfc_framing_target_mode_detector); } else if (iso14443a) { pn512_framing_set(pPN512, nfc_framing_target_a_106); } else if (felica) { pn512_framing_set(pPN512, nfc_framing_target_f_212); } pn512_rf_field_wait_for_external(pPN512, pPN512->config.options.listen_for, pn512_poll_iteration); return; } if (pPN512->poll.state == pn512_polling_state_listen_wait_for_remote_field) { NFC_DBG("pn512_polling_state_listen_wait_for_remote_field"); if (!pn512_config_target(pPN512)) { // Otherwise switch to next step pPN512->poll.state = pn512_polling_state_start_listening; continue; } if (ret == NFC_ERR_TIMEOUT) { // Continue polling pPN512->poll.state = pn512_polling_state_start_polling; continue; } if (ret) { pn512_poll_callback(pPN512, ret); return; } pPN512->poll.state = pn512_polling_state_listen_anticollision; pn512_target_anticollision(pPN512, pn512_poll_iteration); return; } if (pPN512->poll.state == pn512_polling_state_listen_anticollision) { NFC_DBG("pn512_polling_state_listen_anticollision"); if (ret == NFC_ERR_FIELD) { // This means that a remote field was dropped - give it another chance pPN512->poll.state = pn512_polling_state_listen_wait_for_remote_field; pn512_rf_field_switch_off(pPN512); pn512_rf_field_wait_for_external(pPN512, pPN512->config.options.listen_for, pn512_poll_iteration); return; } if (ret) { pn512_poll_callback(pPN512, ret); return; } // Be safe, not sure what the framing is pPN512->framing = nfc_framing_unknown; pn512_poll_callback(pPN512, NFC_OK); return; } if (pPN512->poll.state == pn512_polling_state_start_polling) { NFC_DBG("pn512_polling_state_start_polling"); if (!pn512_config_initiator(pPN512)) { // Otherwise switch to next step pPN512->poll.state = pn512_polling_state_start_listening; continue; } // Try to activate RF field pPN512->poll.state = pn512_polling_state_rf_collision_avoidance; pn512_rf_field_nfcip1_rf_collision_avoidance(pPN512, pn512_poll_iteration); return; } if (pPN512->poll.state == pn512_polling_state_rf_collision_avoidance) { NFC_DBG("pn512_polling_state_rf_collision_avoidance"); if (ret) { pn512_poll_callback(pPN512, ret); return; } NFC_DBG("Own RF field is %s", pPN512->rf_on ? "on" : "off"); if (!pPN512->rf_on) { // Go back to listening, target framing is still valid so no need to reset it pPN512->poll.state = pn512_polling_state_listen_wait_for_remote_field; continue; } pPN512->poll.state = pn512_polling_state_polling_nfc_a_start; } if (pPN512->poll.state == pn512_polling_state_polling_nfc_a_start) { NFC_DBG("pn512_polling_state_polling_nfc_a_start"); //Check if ISO A is needed bool nfc_a = pPN512->config.initiators.nfc_type2 || pPN512->config.initiators.nfc_iso_dep_a || pPN512->config.initiators.nfc_nfc_dep_a; //We do not support type 1 card emulation so irrelevant if (!nfc_a) { // Continue with NFC B pPN512->poll.state = pn512_polling_state_polling_nfc_b_start; continue; } pPN512->transceiver.initiator_ntarget = true; pn512_framing_set(pPN512, nfc_framing_initiator_a_106); pPN512->poll.state = pn512_polling_state_polling_nfc_a_gt; pn512_poll_delay(pPN512, 10 + 5); // Guard time for ISO A is 5 ms return; } if (pPN512->poll.state == pn512_polling_state_polling_nfc_a_gt) { NFC_DBG("pn512_polling_state_polling_nfc_a_gt"); // Start anticollision pPN512->poll.state = pn512_polling_state_polling_nfc_a_anticollision; pn512_initiator_isoa_anticollision(pPN512, pn512_poll_iteration); return; } if (pPN512->poll.state == pn512_polling_state_polling_nfc_a_anticollision) { NFC_DBG("pn512_polling_state_polling_nfc_a_anticollision"); if (ret == NFC_ERR_NOPEER) { NFC_DBG("Not found"); // Continue with NFC B pPN512->poll.state = pn512_polling_state_polling_nfc_b_start; continue; } if ((ret == NFC_OK) && (pPN512->config.options.bail_at_first_tech || (pPN512->transceiver.remote_targets_count == MUNFC_MAX_REMOTE_TARGETS))) { // At least one target found, exit polling loop pn512_poll_callback(pPN512, NFC_OK); return; } if (ret == NFC_ERR_ABORTED) { pn512_poll_callback(pPN512, ret); return; } // Continue with NFC B pPN512->poll.state = pn512_polling_state_polling_nfc_b_start; continue; } if (pPN512->poll.state == pn512_polling_state_polling_nfc_b_start) { NFC_DBG("pn512_polling_state_polling_nfc_b_start"); //Check if ISO B is needed bool nfc_b = pPN512->config.initiators.nfc_iso_dep_b; if (!nfc_b) { // Continue with NFC F pPN512->poll.state = pn512_polling_state_polling_nfc_f_start; continue; } pPN512->transceiver.initiator_ntarget = true; pn512_framing_set(pPN512, nfc_framing_initiator_b_106); pPN512->poll.state = pn512_polling_state_polling_nfc_b_gt; pn512_poll_delay(pPN512, 10 + 5); // Guard time for ISO B is 5 ms return; } if (pPN512->poll.state == pn512_polling_state_polling_nfc_b_gt) { NFC_DBG("pn512_polling_state_polling_nfc_b_gt"); // Start anticollision pPN512->poll.state = pn512_polling_state_polling_nfc_b_anticollision; pn512_initiator_isob_anticollision(pPN512, pn512_poll_iteration); return; } if (pPN512->poll.state == pn512_polling_state_polling_nfc_b_anticollision) { NFC_DBG("pn512_polling_state_polling_nfc_b_anticollision"); if (ret == NFC_ERR_NOPEER) { NFC_DBG("Not found"); // Continue with NFC F pPN512->poll.state = pn512_polling_state_polling_nfc_f_start; continue; } if ((ret == NFC_OK) && (pPN512->config.options.bail_at_first_tech || (pPN512->transceiver.remote_targets_count == MUNFC_MAX_REMOTE_TARGETS))) { // At least one target found, exit polling loop pn512_poll_callback(pPN512, NFC_OK); return; } if (ret == NFC_ERR_ABORTED) { pn512_poll_callback(pPN512, ret); return; } // Continue with NFC F pPN512->poll.state = pn512_polling_state_polling_nfc_f_start; continue; } if (pPN512->poll.state == pn512_polling_state_polling_nfc_f_start) { NFC_DBG("pn512_polling_state_polling_nfc_f_start"); //Check if Felica is needed bool nfc_f = pPN512->config.initiators.nfc_type3 || pPN512->config.initiators.nfc_nfc_dep_f_212; if (!nfc_f) { // Wrap up pPN512->poll.state = pn512_polling_state_finish_polling; continue; } pPN512->transceiver.initiator_ntarget = true; pn512_framing_set(pPN512, nfc_framing_initiator_f_212); pPN512->poll.state = pn512_polling_state_polling_nfc_f_gt; pn512_poll_delay(pPN512, 20); // Guard time for Felica is 20 ms return; } if (pPN512->poll.state == pn512_polling_state_polling_nfc_f_gt) { NFC_DBG("pn512_polling_state_polling_nfc_f_gt"); // Start anticollision pPN512->poll.state = pn512_polling_state_polling_nfc_f_anticollision; pn512_initiator_felica_anticollision(pPN512, pn512_poll_iteration); return; } if (pPN512->poll.state == pn512_polling_state_polling_nfc_f_anticollision) { NFC_DBG("pn512_polling_state_polling_nfc_f_anticollision"); if (ret == NFC_ERR_NOPEER) { NFC_DBG("Not found"); // Resolve polling pPN512->poll.state = pn512_polling_state_finish_polling; continue; } if ((ret == NFC_OK) && (pPN512->config.options.bail_at_first_tech || (pPN512->transceiver.remote_targets_count == MUNFC_MAX_REMOTE_TARGETS))) { // At least one target found, exit polling loop pn512_poll_callback(pPN512, NFC_OK); return; } if (ret == NFC_ERR_ABORTED) { pn512_poll_callback(pPN512, ret); return; } // Resolve polling pPN512->poll.state = pn512_polling_state_finish_polling; continue; } if (pPN512->poll.state == pn512_polling_state_finish_polling) { if (pPN512->transceiver.remote_targets_count > 0) { pn512_poll_callback(pPN512, NFC_OK); } else { pn512_poll_callback(pPN512, NFC_ERR_NOPEER); } return; } } while (true); } // Main polling loop function void pn512_poll_hw(pn512_t *pPN512, pn512_cb_t cb) { nfc_transceiver_t *pTransceiver = (nfc_transceiver_t *)pPN512; pPN512->poll.cb = cb; //Reset active state pTransceiver->initiator_ntarget = false; memset(&pTransceiver->active_tech, 0, sizeof(nfc_tech_t)); //Reset discovered targets pTransceiver->remote_targets_count = 0; //Initialize state machine pPN512->poll.state = pn512_polling_state_start_listening; if (!pn512_config_target(pPN512) && !pn512_config_initiator(pPN512)) { pn512_poll_callback(pPN512, NFC_ERR_PARAMS); return; } //First iteration pn512_poll_iteration(pPN512, NFC_OK); }