Add ISO/IEC 14443 B' aka Type B' modulation partial support

This commit is contained in:
Romuald Conty 2011-05-06 14:14:06 +00:00
parent 77e522aade
commit cd6946e751
7 changed files with 172 additions and 1 deletions

View file

@ -185,6 +185,20 @@ main (int argc, const char *argv[])
} }
} }
nm.nmt = NMT_ISO14443BI;
nm.nbr = NBR_106;
// List ISO14443B' targets
if (nfc_initiator_list_passive_targets (pnd, nm, ant, MAX_TARGET_COUNT, &szTargetFound)) {
size_t n;
if (verbose || (szTargetFound > 0)) {
printf ("%d ISO14443B' passive target(s) found%s\n", (int) szTargetFound, (szTargetFound == 0) ? ".\n" : ":");
}
for (n = 0; n < szTargetFound; n++) {
print_nfc_iso14443bi_info (ant[n].nti.nii, verbose);
printf ("\n");
}
}
nm.nmt = NMT_JEWEL; nm.nmt = NMT_JEWEL;
nm.nbr = NBR_106; nm.nbr = NBR_106;
// List Jewel targets // List Jewel targets

View file

@ -607,6 +607,30 @@ print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose)
} }
} }
void
print_nfc_iso14443bi_info (const nfc_iso14443bi_info_t nii, bool verbose)
{
printf (" DIV: ");
print_hex (nii.abtDIV, 4);
if (verbose) {
int version = (nii.btVerLog & 0x1e)>>1;
printf (" Software Version: ");
if (version == 15) {
printf ("Undefined\n");
} else {
printf ("%i\n", version);
}
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x80)){
printf (" Wait Enable: yes");
}
}
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x40)) {
printf (" ATS: ");
print_hex (nii.abtAtr, nii.szAtrLen);
}
}
void void
print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose) print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose)
{ {
@ -712,6 +736,10 @@ print_nfc_target (const nfc_target_t nt, bool verbose)
printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr)); printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443b_info (nt.nti.nbi, verbose); print_nfc_iso14443b_info (nt.nti.nbi, verbose);
break; break;
case NMT_ISO14443BI:
printf ("ISO/IEC 14443-4B' (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443bi_info (nt.nti.nii, verbose);
break;
case NMT_DEP: case NMT_DEP:
printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr)); printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_dep_info (nt.nti.ndi, verbose); print_nfc_dep_info (nt.nti.ndi, verbose);

View file

@ -88,6 +88,7 @@ void print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t
void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose); void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose);
void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose); void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose);
void print_nfc_iso14443bi_info (const nfc_iso14443bi_info_t nii, bool verbose);
void print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose); void print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose);
void print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose); void print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose);
void print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose); void print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose);

View file

@ -147,6 +147,10 @@ typedef enum {
NDO_EASY_FRAMING = 0x41, NDO_EASY_FRAMING = 0x41,
/** Force the chip to switch in ISO14443-A */ /** Force the chip to switch in ISO14443-A */
NDO_FORCE_ISO14443_A = 0x42, NDO_FORCE_ISO14443_A = 0x42,
/** Force the chip to switch in ISO14443-B */
NDO_FORCE_ISO14443_B = 0x43,
/** Force the chip to run at 106 kbps */
NDO_FORCE_SPEED_106 = 0x50,
} nfc_device_option_t; } nfc_device_option_t;
/** /**
@ -223,6 +227,22 @@ typedef struct {
uint8_t ui8CardIdentifier; uint8_t ui8CardIdentifier;
} nfc_iso14443b_info_t; } nfc_iso14443b_info_t;
/**
* @struct nfc_iso14443bi_info_t
* @brief NFC ISO14443B' tag information
*/
typedef struct {
/** DIV: 4 LSBytes of tag serial number */
byte_t abtDIV[4];
/** Software version & type of REPGEN */
byte_t btVerLog;
/** Config Byte, present if long REPGEN */
byte_t btConfig;
/** ATR, if any */
size_t szAtrLen;
byte_t abtAtr[33];
} nfc_iso14443bi_info_t;
/** /**
* @struct nfc_jewel_info_t * @struct nfc_jewel_info_t
* @brief NFC Jewel tag information * @brief NFC Jewel tag information
@ -240,6 +260,7 @@ typedef union {
nfc_iso14443a_info_t nai; nfc_iso14443a_info_t nai;
nfc_felica_info_t nfi; nfc_felica_info_t nfi;
nfc_iso14443b_info_t nbi; nfc_iso14443b_info_t nbi;
nfc_iso14443bi_info_t nii;
nfc_jewel_info_t nji; nfc_jewel_info_t nji;
nfc_dep_info_t ndi; nfc_dep_info_t ndi;
} nfc_target_info_t; } nfc_target_info_t;
@ -263,6 +284,7 @@ typedef enum {
typedef enum { typedef enum {
NMT_ISO14443A, NMT_ISO14443A,
NMT_ISO14443B, NMT_ISO14443B,
NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B'
NMT_FELICA, NMT_FELICA,
NMT_JEWEL, NMT_JEWEL,
NMT_DEP, NMT_DEP,

View file

@ -368,6 +368,27 @@ pn53x_decode_target_data (const byte_t * pbtRawData, size_t szRawData, pn53x_typ
} }
break; break;
case NMT_ISO14443BI:
// Skip V & T Addresses
pbtRawData++;
if (*pbtRawData != 0x07) { // 0x07 = REPGEN
return false;
}
pbtRawData++;
// Store the UID
memcpy (pnti->nii.abtDIV, pbtRawData, 4);
pbtRawData += 4;
pnti->nii.btVerLog = *(pbtRawData++);
if (pnti->nii.btVerLog & 0x80) { // Type = long?
pnti->nii.btConfig = *(pbtRawData++);
if (pnti->nii.btConfig & 0x40) {
memcpy (pnti->nii.abtAtr, pbtRawData, szRawData - 8);
pbtRawData += szRawData - 6;
pnti->nii.szAtrLen = szRawData - 8;
}
}
break;
case NMT_FELICA: case NMT_FELICA:
// We skip the first byte: its the target number (Tg) // We skip the first byte: its the target number (Tg)
pbtRawData++; pbtRawData++;
@ -588,6 +609,40 @@ pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool b
return true; return true;
break; break;
case NDO_FORCE_ISO14443_B:
if(!bEnable) {
// Nothing to do
return true;
}
// Force pn53x to be in ISO14443-B mode
if (!pn53x_write_register (pnd, REG_CIU_TX_MODE, SYMBOL_TX_FRAMING, 0x03)) {
return false;
}
if (!pn53x_write_register (pnd, REG_CIU_RX_MODE, SYMBOL_RX_FRAMING, 0x03)) {
return false;
}
return true;
break;
case NDO_FORCE_SPEED_106:
if(!bEnable) {
// Nothing to do
return true;
}
// Force pn53x to be at 106 kbps
if (!pn53x_write_register (pnd, REG_CIU_TX_MODE, SYMBOL_TX_SPEED, 0x00)) {
return false;
}
if (!pn53x_write_register (pnd, REG_CIU_RX_MODE, SYMBOL_RX_SPEED, 0x00)) {
return false;
}
// TODO not yet sufficient to setup TypeB, some settings are missing here...
return true;
break;
} }
// When we reach this, the configuration is completed and succesful // When we reach this, the configuration is completed and succesful
@ -628,11 +683,44 @@ pn53x_initiator_select_passive_target (nfc_device_t * pnd,
byte_t abtTargetsData[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; byte_t abtTargetsData[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
size_t szTargetsData = sizeof(abtTargetsData); size_t szTargetsData = sizeof(abtTargetsData);
if (nm.nmt == NMT_ISO14443BI) {
// No native support in InListPassiveTarget so we do discovery by hand
byte_t abtAttrib[6];
size_t szAttrib = sizeof(abtAttrib);
if (!nfc_configure (pnd, NDO_FORCE_ISO14443_B, true)) {
return false;
}
if (!nfc_configure (pnd, NDO_FORCE_SPEED_106, true)) {
return false;
}
if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
return false;
}
pnd->bEasyFraming = false;
if (!pn53x_initiator_transceive_bytes (pnd, pbtInitData, szInitData, abtTargetsData, &szTargetsData)) {
return false;
}
if (pnt) {
pnt->nm = nm;
// Fill the tag info struct with the values corresponding to this init modulation
if (!pn53x_decode_target_data (abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(pnt->nti))) {
return false;
}
}
memcpy(abtAttrib, abtTargetsData, szAttrib);
abtAttrib[1] = 0x0f; // ATTRIB
if (!pn53x_initiator_transceive_bytes (pnd, abtAttrib, szAttrib, NULL, NULL)) {
return false;
}
return true;
} // else:
const pn53x_modulation_t pm = pn53x_nm_to_pm(nm); const pn53x_modulation_t pm = pn53x_nm_to_pm(nm);
if (PM_UNDEFINED == pm) { if (PM_UNDEFINED == pm) {
pnd->iLastError = DENOTSUP; pnd->iLastError = DENOTSUP;
return false; return false;
} }
if (!pn53x_InListPassiveTarget (pnd, pm, 1, pbtInitData, szInitData, abtTargetsData, &szTargetsData)) if (!pn53x_InListPassiveTarget (pnd, pm, 1, pbtInitData, szInitData, abtTargetsData, &szTargetsData))
return false; return false;
@ -1048,6 +1136,7 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_
} }
break; break;
case NMT_ISO14443B: case NMT_ISO14443B:
case NMT_ISO14443BI:
case NMT_JEWEL: case NMT_JEWEL:
pnd->iLastError = DENOTSUP; pnd->iLastError = DENOTSUP;
return false; return false;
@ -1147,6 +1236,7 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_
pbtFeliCaParams = abtFeliCaParams; pbtFeliCaParams = abtFeliCaParams;
break; break;
case NMT_ISO14443B: case NMT_ISO14443B:
case NMT_ISO14443BI:
case NMT_JEWEL: case NMT_JEWEL:
pnd->iLastError = DENOTSUP; pnd->iLastError = DENOTSUP;
return false; return false;
@ -1925,6 +2015,8 @@ pn53x_nm_to_pm(const nfc_modulation_t nm)
break; break;
} }
break; break;
case NMT_ISO14443BI:
case NMT_DEP: case NMT_DEP:
// Nothing to do... // Nothing to do...
break; break;
@ -2024,6 +2116,7 @@ pn53x_nm_to_ptt(const nfc_modulation_t nm)
} }
break; break;
case NMT_ISO14443BI:
case NMT_DEP: case NMT_DEP:
// Nothing to do... // Nothing to do...
break; break;

View file

@ -32,6 +32,7 @@
// Registers and symbols masks used to covers parts within a register // Registers and symbols masks used to covers parts within a register
# define REG_CIU_TX_MODE 0x6302 # define REG_CIU_TX_MODE 0x6302
# define SYMBOL_TX_CRC_ENABLE 0x80 # define SYMBOL_TX_CRC_ENABLE 0x80
# define SYMBOL_TX_SPEED 0x70
// TX_FRAMING bits explanation: // TX_FRAMING bits explanation:
// 00 : ISO/IEC 14443A/MIFARE and Passive Communication mode 106 kbit/s // 00 : ISO/IEC 14443A/MIFARE and Passive Communication mode 106 kbit/s
// 01 : Active Communication mode // 01 : Active Communication mode
@ -46,6 +47,7 @@
# define REG_CIU_RX_MODE 0x6303 # define REG_CIU_RX_MODE 0x6303
# define SYMBOL_RX_CRC_ENABLE 0x80 # define SYMBOL_RX_CRC_ENABLE 0x80
# define SYMBOL_RX_SPEED 0x70
# define SYMBOL_RX_NO_ERROR 0x08 # define SYMBOL_RX_NO_ERROR 0x08
# define SYMBOL_RX_MULTIPLE 0x04 # define SYMBOL_RX_MULTIPLE 0x04
// RX_FRAMING follow same scheme than TX_FRAMING // RX_FRAMING follow same scheme than TX_FRAMING

View file

@ -83,6 +83,7 @@ const struct nfc_driver_t *nfc_drivers[] = {
* - Invalid frames are not accepted (NDO_ACCEPT_INVALID_FRAMES = false) * - Invalid frames are not accepted (NDO_ACCEPT_INVALID_FRAMES = false)
* - Multiple frames are not accepted (NDO_ACCEPT_MULTIPLE_FRAMES = false) * - Multiple frames are not accepted (NDO_ACCEPT_MULTIPLE_FRAMES = false)
* - 14443-A mode is activated (NDO_FORCE_ISO14443_A = true) * - 14443-A mode is activated (NDO_FORCE_ISO14443_A = true)
* - speed is set to 106 kbps (NDO_FORCE_SPEED_106 = true)
* - Let the device try forever to find a target (NDO_INFINITE_SELECT = true) * - Let the device try forever to find a target (NDO_INFINITE_SELECT = true)
* - RF field is shortly dropped (if it was enabled) then activated again * - RF field is shortly dropped (if it was enabled) then activated again
*/ */
@ -241,6 +242,9 @@ nfc_initiator_init (nfc_device_t * pnd)
// Force 14443-A mode // Force 14443-A mode
if (!nfc_configure (pnd, NDO_FORCE_ISO14443_A, true)) if (!nfc_configure (pnd, NDO_FORCE_ISO14443_A, true))
return false; return false;
// Force speed at 106kbps
if (!nfc_configure (pnd, NDO_FORCE_SPEED_106, true))
return false;
// Disallow invalid frame // Disallow invalid frame
if (!nfc_configure (pnd, NDO_ACCEPT_INVALID_FRAMES, false)) if (!nfc_configure (pnd, NDO_ACCEPT_INVALID_FRAMES, false))
return false; return false;
@ -376,6 +380,12 @@ nfc_initiator_list_passive_targets (nfc_device_t * pnd,
szInitDataLen = 1; szInitDataLen = 1;
} }
break; break;
case NMT_ISO14443BI: {
// APGEN
pbtInitData = (byte_t *) "\x01\x0b\x3f\x80";
szInitDataLen = 4;
}
break;
case NMT_FELICA: { case NMT_FELICA: {
// polling payload must be present (see ISO/IEC 18092 11.2.2.5) // polling payload must be present (see ISO/IEC 18092 11.2.2.5)
pbtInitData = (byte_t *) "\x00\xff\xff\x01\x00"; pbtInitData = (byte_t *) "\x00\xff\xff\x01\x00";
@ -396,7 +406,8 @@ nfc_initiator_list_passive_targets (nfc_device_t * pnd,
} }
szTargetFound++; szTargetFound++;
// deselect has no effect on FeliCa and Jewel cards so we'll stop after one... // deselect has no effect on FeliCa and Jewel cards so we'll stop after one...
if ((nm.nmt == NMT_FELICA) || (nm.nmt == NMT_JEWEL)) { // ISO/IEC 14443 B' cards are polled at 100% probability so it's not possible to detect correctly two cards at the same time
if ((nm.nmt == NMT_FELICA) || (nm.nmt == NMT_JEWEL) || (nm.nmt == NMT_ISO14443BI)) {
break; break;
} }
} }