mbed-os/features/nfc/stack/transceiver/pn512/pn512_poll.c

1266 lines
51 KiB
C

/*
* 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);
}