2009-10-12 16:52:26 +02:00
|
|
|
/**
|
|
|
|
* Public platform independent Near Field Communication (NFC) library
|
|
|
|
*
|
|
|
|
* Copyright (C) 2009, Roel Verdult
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU Lesser General Public License as published by the
|
|
|
|
* Free Software Foundation, either version 3 of the License, or (at your
|
|
|
|
* option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
|
|
*
|
|
|
|
*
|
2009-11-04 11:14:17 +01:00
|
|
|
* @file nfc.c
|
2009-11-18 12:52:18 +01:00
|
|
|
* @brief NFC library implementation
|
2009-10-12 16:52:26 +02:00
|
|
|
*/
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-05-27 14:18:21 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
#include <stdio.h>
|
2009-05-27 14:18:21 +02:00
|
|
|
#include <stddef.h>
|
2009-04-29 14:47:41 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
2009-12-01 15:23:00 +01:00
|
|
|
#include <nfc/nfc.h>
|
2009-11-24 14:03:48 +01:00
|
|
|
|
2009-11-20 12:27:07 +01:00
|
|
|
#include "chips.h"
|
2009-11-04 11:14:17 +01:00
|
|
|
#include "drivers.h"
|
2009-07-15 19:45:38 +02:00
|
|
|
|
2009-12-01 15:23:00 +01:00
|
|
|
#include <nfc/nfc-messages.h>
|
2009-05-27 14:18:21 +02:00
|
|
|
|
2009-11-04 11:14:17 +01:00
|
|
|
#include "../../config.h"
|
2009-11-02 15:05:03 +01:00
|
|
|
|
2009-11-24 18:49:24 +01:00
|
|
|
nfc_device_desc_t * nfc_pick_device (void);
|
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// PN53X configuration
|
2009-11-20 12:27:07 +01:00
|
|
|
extern const byte_t pncmd_get_firmware_version [ 2];
|
|
|
|
extern const byte_t pncmd_get_general_status [ 2];
|
|
|
|
extern const byte_t pncmd_get_register [ 4];
|
|
|
|
extern const byte_t pncmd_set_register [ 5];
|
|
|
|
extern const byte_t pncmd_set_parameters [ 3];
|
|
|
|
extern const byte_t pncmd_rf_configure [ 14];
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Reader
|
2009-11-20 12:27:07 +01:00
|
|
|
extern const byte_t pncmd_initiator_list_passive [264];
|
|
|
|
extern const byte_t pncmd_initiator_jump_for_dep [ 68];
|
|
|
|
extern const byte_t pncmd_initiator_select [ 3];
|
|
|
|
extern const byte_t pncmd_initiator_deselect [ 3];
|
|
|
|
extern const byte_t pncmd_initiator_release [ 3];
|
|
|
|
extern const byte_t pncmd_initiator_set_baud_rate [ 5];
|
|
|
|
extern const byte_t pncmd_initiator_exchange_data [265];
|
|
|
|
extern const byte_t pncmd_initiator_exchange_raw_data [266];
|
|
|
|
extern const byte_t pncmd_initiator_auto_poll [ 5];
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Target
|
2009-11-20 12:27:07 +01:00
|
|
|
extern const byte_t pncmd_target_get_data [ 2];
|
|
|
|
extern const byte_t pncmd_target_set_data [264];
|
|
|
|
extern const byte_t pncmd_target_init [ 39];
|
|
|
|
extern const byte_t pncmd_target_virtual_card [ 4];
|
|
|
|
extern const byte_t pncmd_target_receive [ 2];
|
|
|
|
extern const byte_t pncmd_target_send [264];
|
|
|
|
extern const byte_t pncmd_target_get_status [ 2];
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-11-24 18:49:24 +01:00
|
|
|
nfc_device_desc_t *
|
|
|
|
nfc_pick_device (void)
|
|
|
|
{
|
|
|
|
uint32_t uiDriver;
|
|
|
|
nfc_device_desc_t *nddRes;
|
|
|
|
|
|
|
|
for (uiDriver=0; uiDriver<sizeof(drivers_callbacks_list)/sizeof(drivers_callbacks_list[0]); uiDriver++)
|
|
|
|
{
|
|
|
|
if (drivers_callbacks_list[uiDriver].pick_device != NULL)
|
|
|
|
{
|
|
|
|
nddRes = drivers_callbacks_list[uiDriver].pick_device ();
|
|
|
|
if (nddRes != NULL) return nddRes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nfc_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound)
|
|
|
|
{
|
|
|
|
uint32_t uiDriver;
|
|
|
|
|
|
|
|
*pszDeviceFound = 0;
|
|
|
|
|
|
|
|
for (uiDriver=0; uiDriver<sizeof(drivers_callbacks_list)/sizeof(drivers_callbacks_list[0]); uiDriver++)
|
|
|
|
{
|
|
|
|
if (drivers_callbacks_list[uiDriver].list_devices != NULL)
|
|
|
|
{
|
2009-12-03 22:24:06 +01:00
|
|
|
DBG("List avaible device using %s driver",drivers_callbacks_list[uiDriver].acDriver);
|
2009-11-24 18:49:24 +01:00
|
|
|
size_t szN = 0;
|
|
|
|
if (drivers_callbacks_list[uiDriver].list_devices (pnddDevices + (*pszDeviceFound), szDevices - (*pszDeviceFound), &szN))
|
|
|
|
{
|
|
|
|
*pszDeviceFound += szN;
|
|
|
|
}
|
|
|
|
}
|
2009-12-01 23:28:41 +01:00
|
|
|
else
|
2009-12-03 22:24:06 +01:00
|
|
|
{
|
|
|
|
DBG("No listing function avaible for %s driver",drivers_callbacks_list[uiDriver].acDriver);
|
|
|
|
}
|
2009-11-24 18:49:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
nfc_device_t* nfc_connect(nfc_device_desc_t* pndd)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-12-03 03:08:40 +01:00
|
|
|
nfc_device_t* pnd = NULL;
|
2009-11-24 18:49:24 +01:00
|
|
|
uint32_t uiDriver;
|
2009-07-16 14:09:06 +02:00
|
|
|
byte_t abtFw[4];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szFwLen = sizeof(abtFw);
|
2009-08-28 18:54:04 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Search through the device list for an available device
|
2009-11-24 18:49:24 +01:00
|
|
|
for (uiDriver=0; uiDriver<sizeof(drivers_callbacks_list)/sizeof(drivers_callbacks_list[0]); uiDriver++)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-12-07 14:53:15 +01:00
|
|
|
if(pndd == NULL) {
|
2009-09-04 15:24:34 +02:00
|
|
|
// No device description specified: try to automatically claim a device
|
2009-12-03 22:24:06 +01:00
|
|
|
if(drivers_callbacks_list[uiDriver].pick_device != NULL) {
|
|
|
|
DBG("Autodetecting available devices using %s driver.", drivers_callbacks_list[uiDriver].acDriver);
|
2009-12-02 12:45:38 +01:00
|
|
|
pndd = drivers_callbacks_list[uiDriver].pick_device ();
|
2009-12-07 14:53:15 +01:00
|
|
|
|
|
|
|
if(pndd != NULL) {
|
|
|
|
DBG("Auto-connecting to %s using %s driver", pndd->acDevice, drivers_callbacks_list[uiDriver].acDriver);
|
|
|
|
pnd = drivers_callbacks_list[uiDriver].connect(pndd);
|
|
|
|
if(pnd == NULL) {
|
|
|
|
DBG("No device available using %s driver",drivers_callbacks_list[uiDriver].acDriver);
|
|
|
|
pndd = NULL;
|
|
|
|
}
|
|
|
|
}
|
2009-12-02 12:45:38 +01:00
|
|
|
}
|
2009-09-04 15:24:34 +02:00
|
|
|
} else {
|
2009-10-02 11:52:02 +02:00
|
|
|
// Specific device is requested: using device description pndd
|
2009-11-24 18:49:24 +01:00
|
|
|
if( 0 != strcmp(drivers_callbacks_list[uiDriver].acDriver, pndd->pcDriver ) )
|
2009-09-04 15:24:34 +02:00
|
|
|
{
|
2009-11-24 18:49:24 +01:00
|
|
|
DBG("Looking for %s, found %s... Skip it.", pndd->pcDriver, drivers_callbacks_list[uiDriver].acDriver);
|
2009-09-04 15:24:34 +02:00
|
|
|
continue;
|
|
|
|
} else {
|
2009-11-24 18:49:24 +01:00
|
|
|
DBG("Looking for %s, found %s... Use it.", pndd->pcDriver, drivers_callbacks_list[uiDriver].acDriver);
|
|
|
|
pnd = drivers_callbacks_list[uiDriver].connect(pndd);
|
2009-09-04 15:24:34 +02:00
|
|
|
}
|
|
|
|
}
|
2009-08-28 18:54:04 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Test if the connection was successful
|
2009-11-18 12:11:06 +01:00
|
|
|
if (pnd != NULL)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-11-09 12:23:33 +01:00
|
|
|
DBG("[%s] has been claimed.", pnd->acName);
|
2009-04-29 14:47:41 +02:00
|
|
|
// Great we have claimed a device
|
2009-11-24 18:49:24 +01:00
|
|
|
pnd->pdc = &(drivers_callbacks_list[uiDriver]);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Try to retrieve PN53x chip revision
|
2009-09-25 13:09:50 +02:00
|
|
|
// We can not use pn53x_transceive() because abtRx[0] gives no status info
|
2009-11-18 11:52:13 +01:00
|
|
|
if (!pnd->pdc->transceive(pnd->nds,pncmd_get_firmware_version,2,abtFw,&szFwLen))
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
|
|
|
// Failed to get firmware revision??, whatever...let's disconnect and clean up and return err
|
2009-11-09 12:23:33 +01:00
|
|
|
ERR("Failed to get firmware revision for: %s", pnd->acName);
|
|
|
|
pnd->pdc->disconnect(pnd);
|
2009-11-18 12:11:06 +01:00
|
|
|
return NULL;
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add the firmware revision to the device name, PN531 gives 2 bytes info, but PN532 gives 4
|
2009-11-18 11:52:13 +01:00
|
|
|
switch(pnd->nc)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-11-18 11:52:13 +01:00
|
|
|
case NC_PN531: sprintf(pnd->acName,"%s - PN531 v%d.%d",pnd->acName,abtFw[0],abtFw[1]); break;
|
|
|
|
case NC_PN532: sprintf(pnd->acName,"%s - PN532 v%d.%d (0x%02x)",pnd->acName,abtFw[1],abtFw[2],abtFw[3]); break;
|
|
|
|
case NC_PN533: sprintf(pnd->acName,"%s - PN533 v%d.%d (0x%02x)",pnd->acName,abtFw[1],abtFw[2],abtFw[3]); break;
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reset the ending transmission bits register, it is unknown what the last tranmission used there
|
2009-11-18 12:11:06 +01:00
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_BIT_FRAMING,SYMBOL_TX_LAST_BITS,0x00)) return NULL;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Make sure we reset the CRC and parity to chip handling.
|
2009-11-18 12:11:06 +01:00
|
|
|
if (!nfc_configure(pnd,NDO_HANDLE_CRC,true)) return NULL;
|
|
|
|
if (!nfc_configure(pnd,NDO_HANDLE_PARITY,true)) return NULL;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Deactivate the CRYPTO1 chiper, it may could cause problems when still active
|
2009-11-18 12:11:06 +01:00
|
|
|
if (!nfc_configure(pnd,NDO_ACTIVATE_CRYPTO1,false)) return NULL;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
return pnd;
|
2009-09-07 12:15:34 +02:00
|
|
|
} else {
|
2009-11-24 18:49:24 +01:00
|
|
|
DBG("No device found using driver: %s", drivers_callbacks_list[uiDriver].acDriver);
|
2009-09-07 12:15:34 +02:00
|
|
|
}
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
// To bad, no reader is ready to be claimed
|
2009-11-18 12:11:06 +01:00
|
|
|
return NULL;
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
void nfc_disconnect(nfc_device_t* pnd)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
// Release and deselect all active communications
|
2009-11-09 12:23:33 +01:00
|
|
|
nfc_initiator_deselect_tag(pnd);
|
2009-12-01 10:31:29 +01:00
|
|
|
// Disable RF field to avoid heating
|
2009-12-01 11:44:31 +01:00
|
|
|
nfc_configure(pnd,NDO_ACTIVATE_FIELD,false);
|
2009-04-29 14:47:41 +02:00
|
|
|
// Disconnect, clean up and release the device
|
2009-11-09 12:23:33 +01:00
|
|
|
pnd->pdc->disconnect(pnd);
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
|
2009-11-18 12:11:06 +01:00
|
|
|
bool nfc_configure(nfc_device_t* pnd, const nfc_device_option_t dco, const bool bEnable)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-09-07 12:15:34 +02:00
|
|
|
byte_t btValue;
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_rf_configure)];
|
|
|
|
memcpy(abtCmd,pncmd_rf_configure,sizeof(pncmd_rf_configure));
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Make sure we are dealing with a active device
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bActive) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
switch(dco)
|
|
|
|
{
|
2009-11-18 12:11:06 +01:00
|
|
|
case NDO_HANDLE_CRC:
|
2009-04-29 14:47:41 +02:00
|
|
|
// Enable or disable automatic receiving/sending of CRC bytes
|
|
|
|
// TX and RX are both represented by the symbol 0x80
|
|
|
|
btValue = (bEnable) ? 0x80 : 0x00;
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_TX_MODE,SYMBOL_TX_CRC_ENABLE,btValue)) return false;
|
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_RX_MODE,SYMBOL_RX_CRC_ENABLE,btValue)) return false;
|
|
|
|
pnd->bCrc = bEnable;
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
2009-11-18 12:11:06 +01:00
|
|
|
case NDO_HANDLE_PARITY:
|
2009-04-29 14:47:41 +02:00
|
|
|
// Handle parity bit by PN53X chip or parse it as data bit
|
|
|
|
btValue = (bEnable) ? 0x00 : SYMBOL_PARITY_DISABLE;
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_MANUAL_RCV,SYMBOL_PARITY_DISABLE,btValue)) return false;
|
|
|
|
pnd->bPar = bEnable;
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
2009-11-18 12:11:06 +01:00
|
|
|
case NDO_ACTIVATE_FIELD:
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[2] = RFCI_FIELD;
|
|
|
|
abtCmd[3] = (bEnable) ? 1 : 0;
|
|
|
|
// We can not use pn53x_transceive() because abtRx[0] gives no status info
|
2009-11-18 11:52:13 +01:00
|
|
|
if (!pnd->pdc->transceive(pnd->nds,abtCmd,4,NULL,NULL)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
2009-11-18 12:11:06 +01:00
|
|
|
case NDO_ACTIVATE_CRYPTO1:
|
2009-04-29 14:47:41 +02:00
|
|
|
btValue = (bEnable) ? SYMBOL_MF_CRYPTO1_ON : 0x00;
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_STATUS2,SYMBOL_MF_CRYPTO1_ON,btValue)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
2009-11-18 12:11:06 +01:00
|
|
|
case NDO_INFINITE_SELECT:
|
2009-04-29 14:47:41 +02:00
|
|
|
// Retry format: 0x00 means only 1 try, 0xff means infinite
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[2] = RFCI_RETRY_SELECT;
|
|
|
|
abtCmd[3] = (bEnable) ? 0xff : 0x00; // MxRtyATR, default: active = 0xff, passive = 0x02
|
|
|
|
abtCmd[4] = (bEnable) ? 0xff : 0x00; // MxRtyPSL, default: 0x01
|
|
|
|
abtCmd[5] = (bEnable) ? 0xff : 0x00; // MxRtyPassiveActivation, default: 0xff
|
|
|
|
// We can not use pn53x_transceive() because abtRx[0] gives no status info
|
2009-11-18 11:52:13 +01:00
|
|
|
if (!pnd->pdc->transceive(pnd->nds,abtCmd,6,NULL,NULL)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
2009-11-18 12:11:06 +01:00
|
|
|
case NDO_ACCEPT_INVALID_FRAMES:
|
2009-04-29 14:47:41 +02:00
|
|
|
btValue = (bEnable) ? SYMBOL_RX_NO_ERROR : 0x00;
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_RX_MODE,SYMBOL_RX_NO_ERROR,btValue)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
2009-11-18 12:11:06 +01:00
|
|
|
case NDO_ACCEPT_MULTIPLE_FRAMES:
|
2009-04-29 14:47:41 +02:00
|
|
|
btValue = (bEnable) ? SYMBOL_RX_MULTIPLE : 0x00;
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_RX_MODE,SYMBOL_RX_MULTIPLE,btValue)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// When we reach this, the configuration is completed and succesful
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_initiator_init(const nfc_device_t* pnd)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
|
|
|
// Make sure we are dealing with a active device
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bActive) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Set the PN53X to force 100% ASK Modified miller decoding (default for 14443A cards)
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_TX_AUTO,SYMBOL_FORCE_100_ASK,0x40)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Configure the PN53X to be an Initiator or Reader/Writer
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_CONTROL,SYMBOL_INITIATOR,0x10)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-18 12:52:18 +01:00
|
|
|
bool nfc_initiator_select_dep_target(const nfc_device_t* pnd, const nfc_modulation_t nmInitModulation, const byte_t* pbtPidData, const size_t szPidDataLen, const byte_t* pbtNFCID3i, const size_t szNFCID3iDataLen, const byte_t *pbtGbData, const size_t szGbDataLen, nfc_target_info_t* pnti)
|
2009-09-03 15:47:26 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szRxLen;
|
|
|
|
size_t offset;
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_initiator_jump_for_dep)];
|
|
|
|
memcpy(abtCmd,pncmd_initiator_jump_for_dep,sizeof(pncmd_initiator_jump_for_dep));
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-11-18 12:52:18 +01:00
|
|
|
if(nmInitModulation == NM_ACTIVE_DEP) {
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[2] = 0x01; /* active DEP */
|
2009-09-03 15:47:26 +02:00
|
|
|
}
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[3] = 0x00; /* baud rate = 106kbps */
|
2009-09-03 15:47:26 +02:00
|
|
|
|
2009-09-04 10:32:32 +02:00
|
|
|
offset = 5;
|
2009-11-18 12:52:18 +01:00
|
|
|
if(pbtPidData && nmInitModulation != NM_ACTIVE_DEP) { /* can't have passive initiator data when using active mode */
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[4] |= 0x01;
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(abtCmd+offset,pbtPidData,szPidDataLen);
|
|
|
|
offset+= szPidDataLen;
|
|
|
|
}
|
2009-09-03 15:47:26 +02:00
|
|
|
|
|
|
|
if(pbtNFCID3i) {
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[4] |= 0x02;
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(abtCmd+offset,pbtNFCID3i,szNFCID3iDataLen);
|
|
|
|
offset+= szNFCID3iDataLen;
|
2009-09-03 15:47:26 +02:00
|
|
|
}
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-09-03 15:47:26 +02:00
|
|
|
if(pbtGbData) {
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[4] |= 0x04;
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(abtCmd+offset,pbtGbData,szGbDataLen);
|
|
|
|
offset+= szGbDataLen;
|
2009-09-03 15:47:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Try to find a target, call the transceive callback function of the current device
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,abtCmd,5+szPidDataLen+szNFCID3iDataLen+szGbDataLen,abtRx,&szRxLen)) return false;
|
2009-09-03 15:47:26 +02:00
|
|
|
|
|
|
|
// Make sure one target has been found, the PN53X returns 0x00 if none was available
|
|
|
|
if (abtRx[1] != 1) return false;
|
|
|
|
|
|
|
|
// Is a target info struct available
|
2009-11-18 12:52:18 +01:00
|
|
|
if (pnti)
|
2009-09-03 15:47:26 +02:00
|
|
|
{
|
2009-11-18 12:52:18 +01:00
|
|
|
memcpy(pnti->ndi.NFCID3i,abtRx+2,10);
|
|
|
|
pnti->ndi.btDID = abtRx[12];
|
|
|
|
pnti->ndi.btBSt = abtRx[13];
|
|
|
|
pnti->ndi.btBRt = abtRx[14];
|
2009-09-03 15:47:26 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-18 12:52:18 +01:00
|
|
|
bool nfc_initiator_select_tag(const nfc_device_t* pnd, const nfc_modulation_t nmInitModulation, const byte_t* pbtInitData, const size_t szInitDataLen, nfc_target_info_t* pnti)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-10-19 15:08:29 +02:00
|
|
|
byte_t abtInit[MAX_FRAME_LEN];
|
|
|
|
size_t szInitLen;
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szRxLen;
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_initiator_list_passive)];
|
|
|
|
memcpy(abtCmd,pncmd_initiator_list_passive,sizeof(pncmd_initiator_list_passive));
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-09-24 16:33:42 +02:00
|
|
|
// Make sure we are dealing with a active device
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bActive) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[2] = 1; // MaxTg, we only want to select 1 tag at the time
|
2009-11-18 12:52:18 +01:00
|
|
|
abtCmd[3] = nmInitModulation; // BrTy, the type of init modulation used for polling a passive tag
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-11-18 12:52:18 +01:00
|
|
|
switch(nmInitModulation)
|
2009-10-19 15:08:29 +02:00
|
|
|
{
|
2009-11-18 12:52:18 +01:00
|
|
|
case NM_ISO14443A_106:
|
2009-10-19 15:08:29 +02:00
|
|
|
switch (szInitDataLen)
|
|
|
|
{
|
|
|
|
case 7:
|
|
|
|
abtInit[0] = 0x88;
|
|
|
|
memcpy(abtInit+1,pbtInitData,7);
|
|
|
|
szInitLen = 8;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 10:
|
|
|
|
abtInit[0] = 0x88;
|
|
|
|
memcpy(abtInit+1,pbtInitData,3);
|
|
|
|
abtInit[4] = 0x88;
|
|
|
|
memcpy(abtInit+4,pbtInitData+3,7);
|
|
|
|
szInitLen = 12;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
default:
|
|
|
|
memcpy(abtInit,pbtInitData,szInitDataLen);
|
|
|
|
szInitLen = szInitDataLen;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
memcpy(abtInit,pbtInitData,szInitDataLen);
|
|
|
|
szInitLen = szInitDataLen;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Set the optional initiator data (used for Felica, ISO14443B, Topaz Polling or for ISO14443A selecting a specific UID).
|
2009-10-19 15:08:29 +02:00
|
|
|
if (pbtInitData) memcpy(abtCmd+4,abtInit,szInitLen);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Try to find a tag, call the tranceive callback function of the current device
|
2009-10-02 11:52:02 +02:00
|
|
|
szRxLen = MAX_FRAME_LEN;
|
2009-09-25 13:09:50 +02:00
|
|
|
// We can not use pn53x_transceive() because abtRx[0] gives no status info
|
2009-11-18 11:52:13 +01:00
|
|
|
if (!pnd->pdc->transceive(pnd->nds,abtCmd,4+szInitLen,abtRx,&szRxLen)) return false;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Make sure one tag has been found, the PN53X returns 0x00 if none was available
|
|
|
|
if (abtRx[0] != 1) return false;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Is a tag info struct available
|
2009-11-18 12:52:18 +01:00
|
|
|
if (pnti)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
|
|
|
// Fill the tag info struct with the values corresponding to this init modulation
|
2009-11-18 12:52:18 +01:00
|
|
|
switch(nmInitModulation)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-11-18 12:52:18 +01:00
|
|
|
case NM_ISO14443A_106:
|
2009-04-29 14:47:41 +02:00
|
|
|
// Somehow they switched the lower and upper ATQA bytes around for the PN531 chipset
|
2009-11-18 11:52:13 +01:00
|
|
|
if (pnd->nc == NC_PN531)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-11-18 12:52:18 +01:00
|
|
|
pnti->nai.abtAtqa[0] = abtRx[3];
|
|
|
|
pnti->nai.abtAtqa[1] = abtRx[2];
|
2009-04-29 14:47:41 +02:00
|
|
|
} else {
|
2009-11-18 12:52:18 +01:00
|
|
|
memcpy(pnti->nai.abtAtqa,abtRx+2,2);
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
2009-11-18 12:52:18 +01:00
|
|
|
pnti->nai.btSak = abtRx[4];
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the NFCID1
|
2009-11-18 12:52:18 +01:00
|
|
|
pnti->nai.szUidLen = abtRx[5];
|
|
|
|
memcpy(pnti->nai.abtUid,abtRx+6,pnti->nai.szUidLen);
|
2009-04-29 14:47:41 +02:00
|
|
|
// Did we received an optional ATS (Smardcard ATR)
|
2009-11-18 12:52:18 +01:00
|
|
|
if (szRxLen > pnti->nai.szUidLen+6)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-11-18 12:52:18 +01:00
|
|
|
pnti->nai.szAtsLen = abtRx[pnti->nai.szUidLen+6];
|
|
|
|
memcpy(pnti->nai.abtAts,abtRx+pnti->nai.szUidLen+6,pnti->nai.szAtsLen);
|
2009-04-29 14:47:41 +02:00
|
|
|
} else {
|
2009-11-18 12:52:18 +01:00
|
|
|
pnti->nai.szAtsLen = 0;
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-11-18 12:52:18 +01:00
|
|
|
case NM_FELICA_212:
|
|
|
|
case NM_FELICA_424:
|
2009-04-29 14:47:41 +02:00
|
|
|
// Store the mandatory info
|
2009-11-18 12:52:18 +01:00
|
|
|
pnti->nfi.szLen = abtRx[2];
|
|
|
|
pnti->nfi.btResCode = abtRx[3];
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the NFCID2t
|
2009-11-18 12:52:18 +01:00
|
|
|
memcpy(pnti->nfi.abtId,abtRx+4,8);
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the felica padding
|
2009-11-18 12:52:18 +01:00
|
|
|
memcpy(pnti->nfi.abtPad,abtRx+12,8);
|
2009-04-29 14:47:41 +02:00
|
|
|
// Test if the System code (SYST_CODE) is available
|
2009-10-02 11:52:02 +02:00
|
|
|
if (szRxLen > 20)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-11-18 12:52:18 +01:00
|
|
|
memcpy(pnti->nfi.abtSysCode,abtRx+20,2);
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-11-18 12:52:18 +01:00
|
|
|
case NM_ISO14443B_106:
|
2009-04-29 14:47:41 +02:00
|
|
|
// Store the mandatory info
|
2009-11-18 12:52:18 +01:00
|
|
|
memcpy(pnti->nbi.abtAtqb,abtRx+2,12);
|
2009-04-29 14:47:41 +02:00
|
|
|
// Ignore the 0x1D byte, and just store the 4 byte id
|
2009-11-18 12:52:18 +01:00
|
|
|
memcpy(pnti->nbi.abtId,abtRx+15,4);
|
|
|
|
pnti->nbi.btParam1 = abtRx[19];
|
|
|
|
pnti->nbi.btParam2 = abtRx[20];
|
|
|
|
pnti->nbi.btParam3 = abtRx[21];
|
|
|
|
pnti->nbi.btParam4 = abtRx[22];
|
2009-04-29 14:47:41 +02:00
|
|
|
// Test if the Higher layer (INF) is available
|
2009-10-02 11:52:02 +02:00
|
|
|
if (szRxLen > 22)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-11-18 12:52:18 +01:00
|
|
|
pnti->nbi.szInfLen = abtRx[23];
|
|
|
|
memcpy(pnti->nbi.abtInf,abtRx+24,pnti->nbi.szInfLen);
|
2009-04-29 14:47:41 +02:00
|
|
|
} else {
|
2009-11-18 12:52:18 +01:00
|
|
|
pnti->nbi.szInfLen = 0;
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-11-18 12:52:18 +01:00
|
|
|
case NM_JEWEL_106:
|
2009-04-29 14:47:41 +02:00
|
|
|
// Store the mandatory info
|
2009-11-18 12:52:18 +01:00
|
|
|
memcpy(pnti->nji.btSensRes,abtRx+2,2);
|
|
|
|
memcpy(pnti->nji.btId,abtRx+4,4);
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Should not be possible, so whatever...
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_initiator_deselect_tag(const nfc_device_t* pnd)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-11-09 12:23:33 +01:00
|
|
|
return (pn53x_transceive(pnd,pncmd_initiator_deselect,3,NULL,NULL));
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_initiator_transceive_bits(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxBits, const byte_t* pbtTxPar, byte_t* pbtRx, size_t* pszRxBits, byte_t* pbtRxPar)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szRxLen;
|
|
|
|
size_t szFrameBits = 0;
|
|
|
|
size_t szFrameBytes = 0;
|
2009-05-27 12:13:19 +02:00
|
|
|
uint8_t ui8Bits = 0;
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_initiator_exchange_raw_data)];
|
|
|
|
memcpy(abtCmd,pncmd_initiator_exchange_raw_data,sizeof(pncmd_initiator_exchange_raw_data));
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Check if we should prepare the parity bits ourself
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bPar)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
|
|
|
// Convert data with parity to a frame
|
2009-10-02 11:52:02 +02:00
|
|
|
pn53x_wrap_frame(pbtTx,szTxBits,pbtTxPar,abtCmd+2,&szFrameBits);
|
2009-04-29 14:47:41 +02:00
|
|
|
} else {
|
2009-10-02 11:52:02 +02:00
|
|
|
szFrameBits = szTxBits;
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the leading bits
|
2009-10-02 11:52:02 +02:00
|
|
|
ui8Bits = szFrameBits%8;
|
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Get the amount of frame bytes + optional (1 byte if there are leading bits)
|
2009-10-02 11:52:02 +02:00
|
|
|
szFrameBytes = (szFrameBits/8)+((ui8Bits==0)?0:1);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// When the parity is handled before us, we just copy the data
|
2009-11-09 12:23:33 +01:00
|
|
|
if (pnd->bPar) memcpy(abtCmd+2,pbtTx,szFrameBytes);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Set the amount of transmission bits in the PN53X chip register
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_tx_bits(pnd,ui8Bits)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Send the frame to the PN53X chip and get the answer
|
|
|
|
// We have to give the amount of bytes + (the two command bytes 0xD4, 0x42)
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,abtCmd,szFrameBytes+2,abtRx,&szRxLen)) return false;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Get the last bit-count that is stored in the received byte
|
2009-11-09 12:23:33 +01:00
|
|
|
ui8Bits = pn53x_get_reg(pnd,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Recover the real frame length in bits
|
2009-10-02 11:52:02 +02:00
|
|
|
szFrameBits = ((szRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive()
|
|
|
|
// Check if we should recover the parity bits ourself
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bPar)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
|
|
|
// Unwrap the response frame
|
2009-10-02 11:52:02 +02:00
|
|
|
pn53x_unwrap_frame(abtRx+1,szFrameBits,pbtRx,pszRxBits,pbtRxPar);
|
2009-04-29 14:47:41 +02:00
|
|
|
} else {
|
|
|
|
// Save the received bits
|
2009-10-02 11:52:02 +02:00
|
|
|
*pszRxBits = szFrameBits;
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the received bytes
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(pbtRx,abtRx+1,szRxLen-1);
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Everything went successful
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_initiator_transceive_dep_bytes(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen)
|
2009-09-25 13:09:50 +02:00
|
|
|
{
|
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szRxLen;
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_initiator_exchange_data)];
|
|
|
|
memcpy(abtCmd,pncmd_initiator_exchange_data,sizeof(pncmd_initiator_exchange_data));
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-09-03 15:47:26 +02:00
|
|
|
// We can not just send bytes without parity if while the PN53X expects we handled them
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bPar) return false;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-09-03 15:47:26 +02:00
|
|
|
// Copy the data into the command frame
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[2] = 1; /* target number */
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(abtCmd+3,pbtTx,szTxLen);
|
2009-09-03 15:47:26 +02:00
|
|
|
|
|
|
|
// To transfer command frames bytes we can not have any leading bits, reset this to zero
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_tx_bits(pnd,0)) return false;
|
2009-09-03 15:47:26 +02:00
|
|
|
|
|
|
|
// Send the frame to the PN53X chip and get the answer
|
|
|
|
// We have to give the amount of bytes + (the two command bytes 0xD4, 0x42)
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,abtCmd,szTxLen+3,abtRx,&szRxLen)) return false;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-09-03 15:47:26 +02:00
|
|
|
// Save the received byte count
|
2009-10-02 11:52:02 +02:00
|
|
|
*pszRxLen = szRxLen-1;
|
|
|
|
|
2009-09-03 15:47:26 +02:00
|
|
|
// Copy the received bytes
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(pbtRx,abtRx+1,*pszRxLen);
|
2009-09-03 15:47:26 +02:00
|
|
|
|
|
|
|
// Everything went successful
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_initiator_transceive_bytes(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szRxLen;
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_initiator_exchange_raw_data)];
|
|
|
|
memcpy(abtCmd,pncmd_initiator_exchange_raw_data,sizeof(pncmd_initiator_exchange_raw_data));
|
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// We can not just send bytes without parity if while the PN53X expects we handled them
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bPar) return false;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the data into the command frame
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(abtCmd+2,pbtTx,szTxLen);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// To transfer command frames bytes we can not have any leading bits, reset this to zero
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_tx_bits(pnd,0)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Send the frame to the PN53X chip and get the answer
|
|
|
|
// We have to give the amount of bytes + (the two command bytes 0xD4, 0x42)
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,abtCmd,szTxLen+2,abtRx,&szRxLen)) return false;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Save the received byte count
|
2009-10-02 11:52:02 +02:00
|
|
|
*pszRxLen = szRxLen-1;
|
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the received bytes
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(pbtRx,abtRx+1,*pszRxLen);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Everything went successful
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_initiator_mifare_cmd(const nfc_device_t* pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param* pmp)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szRxLen;
|
|
|
|
size_t szParamLen;
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_initiator_exchange_data)];
|
|
|
|
memcpy(abtCmd,pncmd_initiator_exchange_data,sizeof(pncmd_initiator_exchange_data));
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-10-02 11:52:02 +02:00
|
|
|
// Make sure we are dealing with a active device
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bActive) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[2] = 0x01; // Use first target/card
|
|
|
|
abtCmd[3] = mc; // The MIFARE Classic command
|
|
|
|
abtCmd[4] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
switch (mc)
|
|
|
|
{
|
|
|
|
// Read and store command have no parameter
|
|
|
|
case MC_READ:
|
|
|
|
case MC_STORE:
|
2009-10-02 11:52:02 +02:00
|
|
|
szParamLen = 0;
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Authenticate command
|
|
|
|
case MC_AUTH_A:
|
|
|
|
case MC_AUTH_B:
|
2009-10-02 11:52:02 +02:00
|
|
|
szParamLen = sizeof(mifare_param_auth);
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
// Data command
|
|
|
|
case MC_WRITE:
|
2009-10-02 11:52:02 +02:00
|
|
|
szParamLen = sizeof(mifare_param_data);
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
// Value command
|
|
|
|
case MC_DECREMENT:
|
|
|
|
case MC_INCREMENT:
|
|
|
|
case MC_TRANSFER:
|
2009-10-02 11:52:02 +02:00
|
|
|
szParamLen = sizeof(mifare_param_value);
|
2009-04-29 14:47:41 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
// Please fix your code, you never should reach this statement
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
}
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// When available, copy the parameter bytes
|
2009-10-02 11:52:02 +02:00
|
|
|
if (szParamLen) memcpy(abtCmd+5,(byte_t*)pmp,szParamLen);
|
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Fire the mifare command
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,abtCmd,5+szParamLen,abtRx,&szRxLen)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// When we have executed a read command, copy the received bytes into the param
|
2009-10-02 11:52:02 +02:00
|
|
|
if (mc == MC_READ && szRxLen == 17) memcpy(pmp->mpd.abtData,abtRx+1,16);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Command succesfully executed
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_target_init(const nfc_device_t* pnd, byte_t* pbtRx, size_t* pszRxBits)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szRxLen;
|
2009-05-27 12:13:19 +02:00
|
|
|
uint8_t ui8Bits;
|
2009-04-29 14:47:41 +02:00
|
|
|
// Save the current configuration settings
|
2009-11-09 12:23:33 +01:00
|
|
|
bool bCrc = pnd->bCrc;
|
|
|
|
bool bPar = pnd->bPar;
|
2009-09-29 17:19:15 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_target_init)];
|
|
|
|
memcpy(abtCmd,pncmd_target_init,sizeof(pncmd_target_init));
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Clear the target init struct, reset to all zeros
|
2009-09-25 13:09:50 +02:00
|
|
|
memset(abtCmd+2,0x00,37);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-10-02 11:52:02 +02:00
|
|
|
// Set ATQA (SENS_RES)
|
|
|
|
abtCmd[3] = 0x04;
|
|
|
|
abtCmd[4] = 0x00;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-10-02 11:52:02 +02:00
|
|
|
// Set SAK (SEL_RES)
|
2009-09-25 13:09:50 +02:00
|
|
|
abtCmd[8] = 0x20;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-10-02 11:52:02 +02:00
|
|
|
// Set UID
|
|
|
|
abtCmd[5] = 0x00;
|
|
|
|
abtCmd[6] = 0xb0;
|
|
|
|
abtCmd[7] = 0x0b;
|
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Make sure the CRC & parity are handled by the device, this is needed for target_init to work properly
|
2009-11-18 12:11:06 +01:00
|
|
|
if (!bCrc) nfc_configure((nfc_device_t*)pnd,NDO_HANDLE_CRC,true);
|
|
|
|
if (!bPar) nfc_configure((nfc_device_t*)pnd,NDO_HANDLE_PARITY,true);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Let the PN53X be activated by the RF level detector from power down mode
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_reg(pnd,REG_CIU_TX_AUTO, SYMBOL_INITIAL_RF_ON,0x04)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Request the initialization as a target, we can not use pn53x_transceive() because
|
|
|
|
// abtRx[0] contains the emulation mode (baudrate, 14443-4?, DEP and framing type)
|
2009-10-02 11:52:02 +02:00
|
|
|
szRxLen = MAX_FRAME_LEN;
|
2009-11-18 11:52:13 +01:00
|
|
|
if (!pnd->pdc->transceive(pnd->nds,abtCmd,39,abtRx,&szRxLen)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Get the last bit-count that is stored in the received byte
|
2009-11-09 12:23:33 +01:00
|
|
|
ui8Bits = pn53x_get_reg(pnd,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// We are sure the parity is handled by the PN53X chip, so we handle it this way
|
2009-10-02 11:52:02 +02:00
|
|
|
*pszRxBits = ((szRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits;
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the received bytes
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(pbtRx,abtRx+1,szRxLen-1);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Restore the CRC & parity setting to the original value (if needed)
|
2009-11-18 12:11:06 +01:00
|
|
|
if (!bCrc) nfc_configure((nfc_device_t*)pnd,NDO_HANDLE_CRC,false);
|
|
|
|
if (!bPar) nfc_configure((nfc_device_t*)pnd,NDO_HANDLE_PARITY,false);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_target_receive_bits(const nfc_device_t* pnd, byte_t* pbtRx, size_t* pszRxBits, byte_t* pbtRxPar)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szRxLen;
|
|
|
|
size_t szFrameBits;
|
2009-05-27 12:13:19 +02:00
|
|
|
uint8_t ui8Bits;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
2009-10-02 11:52:02 +02:00
|
|
|
// Try to gather a received frame from the reader
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,pncmd_target_receive,2,abtRx,&szRxLen)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Get the last bit-count that is stored in the received byte
|
2009-11-09 12:23:33 +01:00
|
|
|
ui8Bits = pn53x_get_reg(pnd,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Recover the real frame length in bits
|
2009-10-02 11:52:02 +02:00
|
|
|
szFrameBits = ((szRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive()
|
|
|
|
// Check if we should recover the parity bits ourself
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bPar)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
|
|
|
// Unwrap the response frame
|
2009-10-02 11:52:02 +02:00
|
|
|
pn53x_unwrap_frame(abtRx+1,szFrameBits,pbtRx,pszRxBits,pbtRxPar);
|
2009-04-29 14:47:41 +02:00
|
|
|
} else {
|
|
|
|
// Save the received bits
|
2009-10-02 11:52:02 +02:00
|
|
|
*pszRxBits = szFrameBits;
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the received bytes
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(pbtRx,abtRx+1,szRxLen-1);
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
// Everyting seems ok, return true
|
2009-10-02 11:52:02 +02:00
|
|
|
return true;
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_target_receive_dep_bytes(const nfc_device_t* pnd, byte_t* pbtRx, size_t* pszRxLen)
|
2009-09-03 15:47:26 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szRxLen;
|
2009-09-25 13:09:50 +02:00
|
|
|
|
2009-10-02 11:52:02 +02:00
|
|
|
// Try to gather a received frame from the reader
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,pncmd_target_get_data,2,abtRx,&szRxLen)) return false;
|
2009-09-03 15:47:26 +02:00
|
|
|
|
|
|
|
// Save the received byte count
|
2009-10-02 11:52:02 +02:00
|
|
|
*pszRxLen = szRxLen-1;
|
|
|
|
|
2009-09-03 15:47:26 +02:00
|
|
|
// Copy the received bytes
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(pbtRx,abtRx+1,*pszRxLen);
|
2009-09-03 15:47:26 +02:00
|
|
|
|
|
|
|
// Everyting seems ok, return true
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_target_receive_bytes(const nfc_device_t* pnd, byte_t* pbtRx, size_t* pszRxLen)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtRx[MAX_FRAME_LEN];
|
2009-10-05 10:43:43 +02:00
|
|
|
size_t szRxLen;
|
2009-09-25 13:09:50 +02:00
|
|
|
|
2009-10-02 11:52:02 +02:00
|
|
|
// Try to gather a received frame from the reader
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,pncmd_target_receive,2,abtRx,&szRxLen)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Save the received byte count
|
2009-10-02 11:52:02 +02:00
|
|
|
*pszRxLen = szRxLen-1;
|
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the received bytes
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(pbtRx,abtRx+1,*pszRxLen);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Everyting seems ok, return true
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_target_send_bits(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxBits, const byte_t* pbtTxPar)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-10-02 11:52:02 +02:00
|
|
|
size_t szFrameBits = 0;
|
|
|
|
size_t szFrameBytes = 0;
|
2009-05-27 12:13:19 +02:00
|
|
|
uint8_t ui8Bits = 0;
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_target_send)];
|
|
|
|
memcpy(abtCmd,pncmd_target_send,sizeof(pncmd_target_send));
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Check if we should prepare the parity bits ourself
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bPar)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
|
|
|
// Convert data with parity to a frame
|
2009-10-02 11:52:02 +02:00
|
|
|
pn53x_wrap_frame(pbtTx,szTxBits,pbtTxPar,abtCmd+2,&szFrameBits);
|
2009-04-29 14:47:41 +02:00
|
|
|
} else {
|
2009-10-02 11:52:02 +02:00
|
|
|
szFrameBits = szTxBits;
|
2009-04-29 14:47:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the leading bits
|
2009-10-02 11:52:02 +02:00
|
|
|
ui8Bits = szFrameBits%8;
|
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Get the amount of frame bytes + optional (1 byte if there are leading bits)
|
2009-10-02 11:52:02 +02:00
|
|
|
szFrameBytes = (szFrameBits/8)+((ui8Bits==0)?0:1);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// When the parity is handled before us, we just copy the data
|
2009-11-09 12:23:33 +01:00
|
|
|
if (pnd->bPar) memcpy(abtCmd+2,pbtTx,szFrameBytes);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Set the amount of transmission bits in the PN53X chip register
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_set_tx_bits(pnd,ui8Bits)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Try to send the bits to the reader
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,abtCmd,szFrameBytes+2,NULL,NULL)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Everyting seems ok, return true
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_target_send_bytes(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen)
|
2009-04-29 14:47:41 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_target_send)];
|
|
|
|
memcpy(abtCmd,pncmd_target_send,sizeof(pncmd_target_send));
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// We can not just send bytes without parity if while the PN53X expects we handled them
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bPar) return false;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-04-29 14:47:41 +02:00
|
|
|
// Copy the data into the command frame
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(abtCmd+2,pbtTx,szTxLen);
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Try to send the bits to the reader
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,abtCmd,szTxLen+2,NULL,NULL)) return false;
|
2009-04-29 14:47:41 +02:00
|
|
|
|
|
|
|
// Everyting seems ok, return true
|
|
|
|
return true;
|
|
|
|
}
|
2009-09-03 15:47:26 +02:00
|
|
|
|
2009-11-09 12:23:33 +01:00
|
|
|
bool nfc_target_send_dep_bytes(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen)
|
2009-09-03 15:47:26 +02:00
|
|
|
{
|
2009-09-25 13:09:50 +02:00
|
|
|
byte_t abtCmd[sizeof(pncmd_target_set_data)];
|
|
|
|
memcpy(abtCmd,pncmd_target_set_data,sizeof(pncmd_target_set_data));
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-09-03 15:47:26 +02:00
|
|
|
// We can not just send bytes without parity if while the PN53X expects we handled them
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pnd->bPar) return false;
|
2009-10-02 11:52:02 +02:00
|
|
|
|
2009-09-03 15:47:26 +02:00
|
|
|
// Copy the data into the command frame
|
2009-10-02 11:52:02 +02:00
|
|
|
memcpy(abtCmd+2,pbtTx,szTxLen);
|
2009-09-03 15:47:26 +02:00
|
|
|
|
|
|
|
// Try to send the bits to the reader
|
2009-11-09 12:23:33 +01:00
|
|
|
if (!pn53x_transceive(pnd,abtCmd,szTxLen+2,NULL,NULL)) return false;
|
2009-09-03 15:47:26 +02:00
|
|
|
|
|
|
|
// Everyting seems ok, return true
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-02 15:05:03 +01:00
|
|
|
const char* nfc_version(void)
|
|
|
|
{
|
2009-11-20 14:43:18 +01:00
|
|
|
#ifdef SVN_REVISION
|
|
|
|
return PACKAGE_VERSION" (r"SVN_REVISION")";
|
|
|
|
#else
|
2009-11-02 15:05:03 +01:00
|
|
|
return PACKAGE_VERSION;
|
2009-11-20 14:43:18 +01:00
|
|
|
#endif // SVN_REVISION
|
2009-11-02 15:05:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|