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

1410 lines
47 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 "inc/nfc.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(buffer_reader_readable(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
buffer_t readBufDup;
buffer_dup(&readBufDup, buffer_builder_buffer(&pPN512->readBufBldr));
uint8_t b0 = 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)
{
buffer_builder_t* pDataOutBldr = &pPN512->readBufBldr;
buffer_builder_reset(pDataOutBldr);
pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcA.uidLength = 0;
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, 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;
}
buffer_t* pResp = pn512_get_read((nfc_transceiver_t*)pPN512);
if (buffer_reader_readable(pResp) != 2)
{
NFC_WARN("Wrong length (%u bytes)", buffer_reader_readable(pResp));
pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL);
return;
}
NFC_DBG("Got ATQA:");
DBG_BLOCK( buffer_dump(pResp); )
// Ignore ATQA as there can be collisions
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)
{
buffer_builder_t* pDataOutBldr = &pPN512->readBufBldr;
buffer_builder_reset(pDataOutBldr);
//SEL
buffer_builder_write_nu8(pDataOutBldr, SEL(pPN512->anticollision.iso_a.cascade_level - 1)); //SEL: Cascade level
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
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, 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)
{
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( 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)", buffer_reader_readable(pResp), resp_sz, valid_bits);
pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL);
return;
}
// Read bytes
uint8_t bufIn[5] = {0};
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;
}
buffer_builder_t* pDataOutBldr = &pPN512->readBufBldr;
buffer_builder_reset(pDataOutBldr);
//Select and get SAK
buffer_builder_write_nu8(pDataOutBldr, SEL(pPN512->anticollision.iso_a.cascade_level - 1) ); //SEL: Cascade level
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)
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, 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)
{
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( 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 = 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
buffer_builder_t* pDataOutBldr = &pPN512->readBufBldr;
buffer_builder_reset(pDataOutBldr);
//HALTA
buffer_builder_write_nu8(pDataOutBldr, HALTA1);
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, 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)
{
buffer_builder_t* pDataOutBldr = &pPN512->readBufBldr;
buffer_builder_reset(pDataOutBldr);
if (pPN512->anticollision.iso_b.slot_number == 0)
{
// Send REQB/WUPB
pPN512->anticollision.iso_b.more_targets = false;
buffer_builder_write_nu8(pDataOutBldr, REQB);
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
}
buffer_builder_write_nu8(pDataOutBldr, wup | (pPN512->anticollision.iso_b.slots_num_exponent & 0x7)); // Param: number of slots
}
else
{
// Just send slot marker
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, 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
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 (buffer_reader_readable(pResp) != 12)
{
NFC_WARN("Wrong length (%u bytes)", buffer_reader_readable(pResp));
pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL);
return;
}
NFC_DBG("Got ATQB:");
DBG_BLOCK( buffer_dump(pResp); )
// Check first byte
uint8_t atqb0 = 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
buffer_read_n_bytes(pResp, pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcB.pupi, 4);
buffer_read_n_bytes(pResp, pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcB.application_data, 4);
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
buffer_builder_t* pDataOutBldr = &pPN512->readBufBldr;
buffer_builder_reset(pDataOutBldr);
// Halt PICC and move on to the next slot
//HALTB
buffer_builder_write_nu8(pDataOutBldr, HALTB);
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, 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;
}
buffer_t* pResp = pn512_get_read((nfc_transceiver_t*)pPN512);
if (buffer_reader_readable(pResp) != 1)
{
NFC_WARN("Wrong length (%u bytes)", buffer_reader_readable(pResp));
pn512_anticollision_callback(pPN512, NFC_ERR_PROTOCOL);
return;
}
NFC_DBG("Got HALTB response:");
DBG_BLOCK( buffer_dump(pResp); )
// Check byte
uint8_t haltbr = 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)
{
buffer_builder_t* pDataOutBldr = &pPN512->readBufBldr;
buffer_builder_reset(pDataOutBldr);
buffer_builder_write_nu8(pDataOutBldr, 6); //Length
buffer_builder_write_nu8(pDataOutBldr, REQC);
buffer_builder_write_nu16(pDataOutBldr, 0xFFFF); //Any system code
buffer_builder_write_nu8(pDataOutBldr, 0x00); // Padding
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, 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)
{
buffer_t* pResp = pn512_get_read((nfc_transceiver_t*)pPN512);
if (ret || (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:");
DBG_BLOCK( buffer_dump(pResp); )
while (buffer_reader_readable(pResp) > 0)
{
if (buffer_reader_readable(pResp) != 18 + 1) // ATQC is 18 bytes, 1 byte for errors added by PN512
{
NFC_WARN("Wrong length (%d bytes)", 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 = buffer_read_nu8(pResp);
uint8_t atqc0 = 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
buffer_read_n_bytes(pResp, pPN512->transceiver.remote_targets[pPN512->transceiver.remote_targets_count].nfcF.nfcid2, 8);
// Discard padding bytes
buffer_read_n_skip(pResp, 8);
// Read error register
uint8_t err_reg = 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);
buffer_builder_t* pDataCfgBldr = &pPN512->readBufBldr;
buffer_builder_reset(pDataCfgBldr);
//Write ATQA
buffer_builder_write_nu8(pDataCfgBldr, 0x04);
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++)
{
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
}
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
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
buffer_builder_write_nu8(pDataCfgBldr, 0x02);
}
else
{
buffer_builder_write_nu8(pDataCfgBldr, 0x00);
}
buffer_builder_write_nu8(pDataCfgBldr, 0xFE);
for (int i = 0; i < 6; i++)
{
buffer_builder_write_nu8(pDataCfgBldr, 0x00);
}
//2 PAD0 bytes (Felica spec) - this would code the manufacturer + IC code (0xFFFF for NFC-IP1 tags)
buffer_builder_write_nu8(pDataCfgBldr, 0xFF);
buffer_builder_write_nu8(pDataCfgBldr, 0xFF);
//3 PAD1 bytes
buffer_builder_write_nu8(pDataCfgBldr, 0x00);
buffer_builder_write_nu8(pDataCfgBldr, 0x00);
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)
{
buffer_builder_write_nu8(pDataCfgBldr, 0x01); //MRTI Check
buffer_builder_write_nu8(pDataCfgBldr, 0x01); //MRTI Update
}
else
{
buffer_builder_write_nu8(pDataCfgBldr, 0x00);
buffer_builder_write_nu8(pDataCfgBldr, 0x00);
}
//1 PAD2 byte
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)
{
buffer_builder_write_nu8(pDataCfgBldr, 0x12);
buffer_builder_write_nu8(pDataCfgBldr, 0xFC);
}
else
{
buffer_builder_write_nu8(pDataCfgBldr, 0xFF); //Wildcard system code
buffer_builder_write_nu8(pDataCfgBldr, 0xFF);
}
//Write NFCID3
buffer_builder_write_nu8(pDataCfgBldr, 0x00);
pn512_fifo_write(pPN512, 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);
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;
// 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);
}