Improve API for target emulation, nfc_target_mode_t does not exist anymore (this mode is computed from nfc_target_t)

This commit is contained in:
Romuald Conty 2010-10-15 14:32:10 +00:00
parent 1e52e1dc9f
commit 1f62e9e2f2
12 changed files with 163 additions and 108 deletions

View file

@ -89,7 +89,7 @@ main (int argc, const char *argv[])
print_nfc_target (nt);
printf ("Waiting for initiator request...\n");
if(!nfc_target_init (pnd, NTM_DEP_ONLY, &nt, abtRx, &szRx)) {
if(!nfc_target_init (pnd, &nt, abtRx, &szRx)) {
nfc_perror(pnd, "nfc_target_init");
return EXIT_FAILURE;
}

View file

@ -121,7 +121,7 @@ main (int argc, char *argv[])
.nti.nai.szAtsLen = 0,
};
if (!nfc_target_init (pnd, NTM_ISO14443_4_PICC_ONLY, &nt, abtRx, &szRx)) {
if (!nfc_target_init (pnd, &nt, abtRx, &szRx)) {
nfc_perror (pnd, "nfc_target_init");
ERR("Could not come out of auto-emulation, no command was received");
return EXIT_FAILURE;

View file

@ -118,7 +118,7 @@ nfc_target_emulate_tag(nfc_device_t* pnd, nfc_target_t * pnt)
byte_t abtTx[MAX_FRAME_LEN];
bool loop = true;
if (!nfc_target_init (pnd, NTM_PASSIVE_ONLY, pnt, abtRx, &szRx)) {
if (!nfc_target_init (pnd, pnt, abtRx, &szRx)) {
nfc_perror (pnd, "nfc_target_init");
return false;
}

View file

@ -140,7 +140,7 @@ main (int argc, char *argv[])
.nti.nai.szUidLen = 4,
.nti.nai.szAtsLen = 0,
};
if (!nfc_target_init (pnd, NTM_PASSIVE_ONLY, &nt, abtRecv, &szRecvBits)) {
if (!nfc_target_init (pnd, &nt, abtRecv, &szRecvBits)) {
ERR ("Could not come out of auto-emulation, no command was received");
exit(EXIT_FAILURE);
}

View file

@ -356,7 +356,7 @@ main (int argc, char *argv[])
printf ("Connected to the NFC emulator device: %s\n", pndTarget->acName);
if (!nfc_target_init (pndTarget, NTM_ISO14443_4_PICC_ONLY, &ntEmulatedTarget, abtCapdu, &szCapduLen)) {
if (!nfc_target_init (pndTarget, &ntEmulatedTarget, abtCapdu, &szCapduLen)) {
ERR ("%s", "Initialization of NFC emulator failed");
if (!target_only_mode) {
nfc_disconnect (pndInitiator);

View file

@ -136,7 +136,7 @@ main (int argc, char *argv[])
.nti.nai.szAtsLen = 0,
};
if (!nfc_target_init (pndTag, NTM_PASSIVE_ONLY, &nt, abtReaderRx, &szReaderRxBits)) {
if (!nfc_target_init (pndTag, &nt, abtReaderRx, &szReaderRxBits)) {
ERR ("%s", "Initialization of NFC emulator failed");
nfc_disconnect (pndTag);
return EXIT_FAILURE;

View file

@ -212,7 +212,7 @@ main (int argc, const char *argv[])
};
printf ("Now both, NFC device (configured as target) and SAM are readables from an external NFC initiator.\n");
printf ("Please note that NFC device (configured as target) stay in target mode until it receive RATS, ATR_REQ or proprietary command.\n");
if (!nfc_target_init (pnd, NTM_NORMAL, &nt, abtRx, &szRx)) {
if (!nfc_target_init (pnd, &nt, abtRx, &szRx)) {
nfc_perror(pnd, "nfc_target_init");
return EXIT_FAILURE;
}

View file

@ -70,6 +70,8 @@ typedef struct {
bool bPar;
/** Should the PN53x chip handle frames encapsulation and chaining */
bool bEasyFraming;
/** Should the PN53x chip switch automatically in ISO14443-4 when ISO14443 */
bool bAutoIso14443_4;
/** Register cache for REG_CIU_BIT_FRAMING, SYMBOL_TX_LAST_BITS: The last TX bits setting, we need to reset this if it does not apply anymore */
uint8_t ui8TxBits;
/** Register cache for SetParameters function. */
@ -143,21 +145,51 @@ struct driver_callbacks {
* @brief NFC device option
*/
typedef enum {
/** Let the PN53X chip handle the CRC bytes. This means that the chip appends the CRC bytes to the frames that are transmitted. It will parse the last bytes from received frames as incoming CRC bytes. They will be verified against the used modulation and protocol. If an frame is expected with incorrect CRC bytes this option should be disabled. Example frames where this is useful are the ATQA and UID+BCC that are transmitted without CRC bytes during the anti-collision phase of the ISO14443-A protocol. */
/** Let the PN53X chip handle the CRC bytes. This means that the chip appends
* the CRC bytes to the frames that are transmitted. It will parse the last
* bytes from received frames as incoming CRC bytes. They will be verified
* against the used modulation and protocol. If an frame is expected with
* incorrect CRC bytes this option should be disabled. Example frames where
* this is useful are the ATQA and UID+BCC that are transmitted without CRC
* bytes during the anti-collision phase of the ISO14443-A protocol. */
NDO_HANDLE_CRC = 0x00,
/** Parity bits in the network layer of ISO14443-A are by default generated and validated in the PN53X chip. This is a very convenient feature. On certain times though it is useful to get full control of the transmitted data. The proprietary MIFARE Classic protocol uses for example custom (encrypted) parity bits. For interoperability it is required to be completely compatible, including the arbitrary parity bits. When this option is disabled, the functions to communicating bits should be used. */
/** Parity bits in the network layer of ISO14443-A are by default generated and
* validated in the PN53X chip. This is a very convenient feature. On certain
* times though it is useful to get full control of the transmitted data. The
* proprietary MIFARE Classic protocol uses for example custom (encrypted)
* parity bits. For interoperability it is required to be completely
* compatible, including the arbitrary parity bits. When this option is
* disabled, the functions to communicating bits should be used. */
NDO_HANDLE_PARITY = 0x01,
/** This option can be used to enable or disable the electronic field of the NFC device. */
/** This option can be used to enable or disable the electronic field of the
* NFC device. */
NDO_ACTIVATE_FIELD = 0x10,
/** The internal CRYPTO1 co-processor can be used to transmit messages encrypted. This option is automatically activated after a successful MIFARE Classic authentication. */
/** The internal CRYPTO1 co-processor can be used to transmit messages
* encrypted. This option is automatically activated after a successful MIFARE
* Classic authentication. */
NDO_ACTIVATE_CRYPTO1 = 0x11,
/** The default configuration defines that the PN53X chip will try indefinitely to invite a tag in the field to respond. This could be desired when it is certain a tag will enter the field. On the other hand, when this is uncertain, it will block the application. This option could best be compared to the (NON)BLOCKING option used by (socket)network programming. */
/** The default configuration defines that the PN53X chip will try indefinitely
* to invite a tag in the field to respond. This could be desired when it is
* certain a tag will enter the field. On the other hand, when this is
* uncertain, it will block the application. This option could best be compared
* to the (NON)BLOCKING option used by (socket)network programming. */
NDO_INFINITE_SELECT = 0x20,
/** If this option is enabled, frames that carry less than 4 bits are allowed. According to the standards these frames should normally be handles as invalid frames. */
/** If this option is enabled, frames that carry less than 4 bits are allowed.
* According to the standards these frames should normally be handles as
* invalid frames. */
NDO_ACCEPT_INVALID_FRAMES = 0x30,
/** If the NFC device should only listen to frames, it could be useful to let it gather multiple frames in a sequence. They will be stored in the internal FIFO of the PN53X chip. This could be retrieved by using the receive data functions. Note that if the chip runs out of bytes (FIFO = 64 bytes long), it will overwrite the first received frames, so quick retrieving of the received data is desirable. */
/** If the NFC device should only listen to frames, it could be useful to let
* it gather multiple frames in a sequence. They will be stored in the internal
* FIFO of the PN53X chip. This could be retrieved by using the receive data
* functions. Note that if the chip runs out of bytes (FIFO = 64 bytes long),
* it will overwrite the first received frames, so quick retrieving of the
* received data is desirable. */
NDO_ACCEPT_MULTIPLE_FRAMES = 0x31,
/** This option can be used to enable or disable the auto-switching mode to ISO14443-4 is device is compliant */
/** This option can be used to enable or disable the auto-switching mode to
* ISO14443-4 is device is compliant.
* In initiator mode, it means that NFC chip will send RATS automatically.
* In target mode, with a NFC chip compiliant (ie. PN532), the chip will
* emulate a 14443-4 PICC using hardware capability */
NDO_AUTO_ISO14443_4 = 0x40,
/** Use automatic frames encapsulation and chaining. */
NDO_EASY_FRAMING = 0x41,
@ -165,6 +197,16 @@ typedef enum {
NDO_FORCE_ISO14443_A = 0x42,
} nfc_device_option_t;
/**
* @enum nfc_dep_mode_t
* @brief NFC D.E.P. (Data Exchange Protocol) active/passive mode
*/
typedef enum {
NDM_UNDEFINED = 0,
NDM_PASSIVE,
NDM_ACTIVE,
} nfc_dep_mode_t;
/**
* @struct nfc_dep_info_t
* @brief NFC target information in D.E.P. (Data Exchange Protocol) see ISO/IEC 18092 (NFCIP-1)
@ -185,17 +227,10 @@ typedef struct {
/** General Bytes */
byte_t abtGB[48];
size_t szGB;
/** DEP mode */
nfc_dep_mode_t ndm;
} nfc_dep_info_t;
/**
* @enum nfc_dep_mode_t
* @brief NFC D.E.P. (Data Exchange Protocol) active/passive mode
*/
typedef enum {
NDM_PASSIVE,
NDM_ACTIVE,
} nfc_dep_mode_t;
/**
* @struct nfc_iso14443a_info_t
* @brief NFC ISO14443A tag (MIFARE) information
@ -257,21 +292,6 @@ typedef union {
nfc_dep_info_t ndi;
} nfc_target_info_t;
/**
* @enum nfc_target_mode_t
* @brief NFC target type enumeration
*/
typedef enum {
/** Configure the PN53x to accept all initiator mode */
NTM_NORMAL = 0x00,
/** Configure the PN53x to accept to be initialized only in passive mode */
NTM_PASSIVE_ONLY = 0x01,
/** Configure the PN53x to accept to be initialized only as DEP target */
NTM_DEP_ONLY = 0x02,
/** Configure the PN532 to accept to be initialized only as ISO/IEC14443-4 PICC */
NTM_ISO14443_4_PICC_ONLY = 0x04
} nfc_target_mode_t;
/**
* @enum nfc_baud_rate_t
* @brief NFC baud rate enumeration

View file

@ -89,7 +89,7 @@ extern "C" {
byte_t * pbtRxPar);
/* NFC target: act as tag (i.e. MIFARE Classic) or NFC target device. */
NFC_EXPORT bool nfc_target_init (nfc_device_t * pnd, const nfc_target_mode_t ntm, nfc_target_t * pnt, byte_t * pbtRx, size_t * pszRx);
NFC_EXPORT bool nfc_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_t * pszRx);
NFC_EXPORT bool nfc_target_send_bytes (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx);
NFC_EXPORT bool nfc_target_receive_bytes (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRx);
NFC_EXPORT bool nfc_target_send_bits (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxBits,

View file

@ -828,6 +828,10 @@ pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool b
break;
case NDO_INFINITE_SELECT:
// TODO Made some research around this point:
// timings could be tweak better than this, and maybe we can tweak timings
// to "gain" a sort-of hardware polling (ie. like PN532 does)
// Retry format: 0x00 means only 1 try, 0xff means infinite
abtCmd[2] = RFCI_RETRY_SELECT;
abtCmd[3] = (bEnable) ? 0xff : 0x00; // MxRtyATR, default: active = 0xff, passive = 0x02
@ -851,6 +855,8 @@ pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool b
break;
case NDO_AUTO_ISO14443_4:
// TODO Cache activated/disactivated options
pnd->bAutoIso14443_4 = bEnable;
return pn53x_set_parameter(pnd, PARAM_AUTO_RATS, bEnable);
break;
@ -1107,43 +1113,43 @@ pn53x_initiator_transceive_bytes (nfc_device_t * pnd, const byte_t * pbtTx, cons
return true;
}
#define SAK_ISO14443_4_COMPLIANT 0x20
bool
pn53x_target_init (nfc_device_t * pnd, const nfc_target_mode_t ntm, nfc_target_t * pnt, byte_t * pbtRx, size_t * pszRx)
pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_t * pszRx)
{
// Save the current configuration settings
bool bCrc = pnd->bCrc;
bool bPar = pnd->bPar;
// Configure the target corresponding to the requested mode
// XXX I (Romuald) don't think that a good thing to select NDO_EASY_FRAMING here, that's a user choice...
switch(ntm)
{
case NTM_NORMAL:
case NTM_PASSIVE_ONLY:
pn53x_target_mode_t ptm = PTM_NORMAL;
switch (pnt->nm.nmt) {
case NMT_ISO14443A:
ptm = PTM_PASSIVE_ONLY;
pn53x_set_parameter(pnd, PARAM_AUTO_ATR_RES, false);
pn53x_configure(pnd, NDO_EASY_FRAMING, false);
break;
case NTM_DEP_ONLY:
// XXX Should we check that nt is a DEP ?
pn53x_set_parameter(pnd, PARAM_AUTO_ATR_RES, true);
pn53x_configure(pnd, NDO_EASY_FRAMING, true);
break;
case NTM_ISO14443_4_PICC_ONLY:
// XXX Should we check that nt is a ISO14443A ?
if(pnd->nc != NC_PN532) {
// This mode is not supported by pn531 neither pn533
pnd->iLastError = DENOTSUP;
return false;
if (pnd->nc == NC_PN532) { // We have a PN532
if ((pnt->nti.nai.btSak & SAK_ISO14443_4_COMPLIANT) && (pnd->bAutoIso14443_4)) { // We have a ISO14443-4 tag to emulate and NDO_AUTO_14443_4A option is enabled
ptm |= PTM_ISO14443_4_PICC_ONLY; // We add ISO14443-4 restriction
pn53x_set_parameter(pnd, PARAM_14443_4_PICC, true);
} else {
pn53x_set_parameter(pnd, PARAM_14443_4_PICC, false);
}
}
pn53x_set_parameter(pnd, PARAM_14443_4_PICC, true);
pn53x_configure(pnd, NDO_EASY_FRAMING, true);
break;
default:
// Unknown mode
case NMT_FELICA:
ptm = PTM_PASSIVE_ONLY;
break;
case NMT_DEP:
pn53x_set_parameter(pnd, PARAM_AUTO_ATR_RES, true);
ptm = PTM_DEP_ONLY;
if (pnt->nti.ndi.ndm = NDM_PASSIVE) {
ptm |= PTM_PASSIVE_ONLY; // We add passive mode restriction
}
break;
case NMT_ISO14443B:
case NMT_JEWEL:
pnd->iLastError = DENOTSUP;
return false;
break;
}
// Make sure the CRC & parity are handled by the device, this is needed for target_init to work properly
@ -1212,46 +1218,60 @@ pn53x_target_init (nfc_device_t * pnd, const nfc_target_mode_t ntm, nfc_target_t
break;
}
byte_t btActivatedMode;
target_activation:
if(!pn53x_TgInitAsTarget(pnd, ntm, pbtMifareParams, pbtTkt, szTkt, pbtFeliCaParams, pbtNFCID3t, pbtGBt, szGBt, pbtRx, pszRx, &btActivatedMode)) {
return false;
}
bool targetActivated = false;
while (!targetActivated) {
nfc_modulation_t nm;
nfc_dep_mode_t ndm = NDM_UNDEFINED;
byte_t btActivatedMode;
nfc_modulation_t nm;
// Decode activated "mode"
switch(btActivatedMode & 0x70) { // Baud rate
case 0x00: // 106kbps
nm.nbr = NBR_106;
break;
case 0x10: // 212kbps
nm.nbr = NBR_212;
break;
case 0x20: // 424kbps
nm.nbr = NBR_424;
break;
};
if (btActivatedMode & 0x04) { // D.E.P.
nm.nmt = NMT_DEP;
if ((btActivatedMode & 0x03) == 0x01) { // Active mode
// XXX What to do ?
} else { // Passive mode
if(!pn53x_TgInitAsTarget(pnd, ptm, pbtMifareParams, pbtTkt, szTkt, pbtFeliCaParams, pbtNFCID3t, pbtGBt, szGBt, pbtRx, pszRx, &btActivatedMode)) {
return false;
}
} else { // Not D.E.P.
if ((btActivatedMode & 0x03) == 0x00) { // MIFARE
nm.nmt = NMT_ISO14443A;
} else if ((btActivatedMode & 0x03) == 0x02) { // FeliCa
nm.nmt = NMT_FELICA;
// Decode activated "mode"
switch(btActivatedMode & 0x70) { // Baud rate
case 0x00: // 106kbps
nm.nbr = NBR_106;
break;
case 0x10: // 212kbps
nm.nbr = NBR_212;
break;
case 0x20: // 424kbps
nm.nbr = NBR_424;
break;
};
if (btActivatedMode & 0x04) { // D.E.P.
nm.nmt = NMT_DEP;
if ((btActivatedMode & 0x03) == 0x01) { // Active mode
ndm = NDM_ACTIVE;
} else { // Passive mode
ndm = NDM_PASSIVE;
}
} else { // Not D.E.P.
if ((btActivatedMode & 0x03) == 0x00) { // MIFARE
nm.nmt = NMT_ISO14443A;
} else if ((btActivatedMode & 0x03) == 0x02) { // FeliCa
nm.nmt = NMT_FELICA;
}
}
if(pnt->nm.nmt == nm.nmt) { // Actual activation have the right modulation type
if ((pnt->nm.nbr == NBR_UNDEFINED) || (pnt->nm.nbr == nm.nbr)) { // Have the right baud rate (or undefined)
if ((pnt->nm.nmt != NMT_DEP) || (pnt->nti.ndi.ndm == NDM_UNDEFINED) || (pnt->nti.ndi.ndm == ndm)) { // Have the right DEP mode (or is not a DEP)
targetActivated = true;
}
}
}
if (targetActivated) {
pnt->nm.nbr = nm.nbr; // Update baud rate
if (pnt->nm.nmt == NMT_DEP) {
pnt->nti.ndi.ndm = ndm; // Update DEP mode
}
}
}
// XXX When using DEP, shouldn't we update target modulation ?
if(nm.nmt != pnt->nm.nmt) {
goto target_activation;
}
pnt->nm.nbr = nm.nbr;
// Restore the CRC & parity setting to the original value (if needed)
if (!bCrc)
pn53x_configure ((nfc_device_t *) pnd, NDO_HANDLE_CRC, false);
@ -1262,7 +1282,7 @@ target_activation:
}
bool
pn53x_TgInitAsTarget (nfc_device_t * pnd, nfc_target_mode_t ntm,
pn53x_TgInitAsTarget (nfc_device_t * pnd, pn53x_target_mode_t ptm,
const byte_t * pbtMifareParams,
const byte_t * pbtTkt, size_t szTkt,
const byte_t * pbtFeliCaParams,
@ -1280,7 +1300,7 @@ pn53x_TgInitAsTarget (nfc_device_t * pnd, nfc_target_mode_t ntm,
memset (abtCmd + sizeof (pncmd_target_init), 0x00, sizeof (abtCmd) - sizeof (pncmd_target_init));
// Store the target mode in the initialization params
abtCmd[2] = ntm;
abtCmd[2] = ptm;
// MIFARE part
if (pbtMifareParams) {

View file

@ -153,6 +153,21 @@ typedef enum {
PTT_DEP_ACTIVE_424 = 0x82,
} pn53x_target_type_t;
/**
* @enum pn53x_target_mode_t
* @brief PN53x target mode enumeration
*/
typedef enum {
/** Configure the PN53x to accept all initiator mode */
PTM_NORMAL = 0x00,
/** Configure the PN53x to accept to be initialized only in passive mode */
PTM_PASSIVE_ONLY = 0x01,
/** Configure the PN53x to accept to be initialized only as DEP target */
PTM_DEP_ONLY = 0x02,
/** Configure the PN532 to accept to be initialized only as ISO/IEC14443-4 PICC */
PTM_ISO14443_4_PICC_ONLY = 0x04
} pn53x_target_mode_t;
bool pn53x_init(nfc_device_t * pnd);
bool pn53x_transceive_check_ack_frame_callback (nfc_device_t * pnd, const byte_t * pbtRxFrame,
const size_t szRxFrameLen);
@ -193,7 +208,7 @@ bool pn53x_initiator_transceive_bits (nfc_device_t * pnd, const byte_t * pbtT
bool pn53x_initiator_transceive_bytes (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx,
byte_t * pbtRx, size_t * pszRx);
// NFC device as Target functions
bool pn53x_target_init (nfc_device_t * pnd, const nfc_target_mode_t ntm, nfc_target_t * pnt, byte_t * pbtRx, size_t * pszRx);
bool pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_t * pszRx);
bool pn53x_target_receive_bits (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRxBits, byte_t * pbtRxPar);
bool pn53x_target_receive_bytes (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRx);
bool pn53x_target_send_bits (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxBits,
@ -221,7 +236,7 @@ bool pn53x_InJumpForDEP (nfc_device_t * pnd,
const byte_t * pbtNFCID3i,
const byte_t * pbtGB, const size_t szGB,
nfc_target_t * pnt);
bool pn53x_TgInitAsTarget (nfc_device_t * pnd, nfc_target_mode_t ntm,
bool pn53x_TgInitAsTarget (nfc_device_t * pnd, pn53x_target_mode_t ptm,
const byte_t * pbtMifareParams,
const byte_t * pbtTkt, size_t szTkt,
const byte_t * pbtFeliCaParams,

View file

@ -555,11 +555,11 @@ nfc_initiator_transceive_bits (nfc_device_t * pnd, const byte_t * pbtTx, const s
* receive functions can be used.
*/
bool
nfc_target_init (nfc_device_t * pnd, const nfc_target_mode_t ntm, nfc_target_t * pnt, byte_t * pbtRx, size_t * pszRx)
nfc_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_t * pszRx)
{
pnd->iLastError = 0;
return pn53x_target_init (pnd, ntm, pnt, pbtRx, pszRx);
return pn53x_target_init (pnd, pnt, pbtRx, pszRx);
}
/**