From cd6946e75155f788156c89163518dd9a58cc72b3 Mon Sep 17 00:00:00 2001 From: Romuald Conty Date: Fri, 6 May 2011 14:14:06 +0000 Subject: [PATCH] Add ISO/IEC 14443 B' aka Type B' modulation partial support --- examples/nfc-list.c | 14 +++++++ examples/nfc-utils.c | 28 +++++++++++++ examples/nfc-utils.h | 1 + include/nfc/nfc-types.h | 22 ++++++++++ libnfc/chips/pn53x.c | 93 +++++++++++++++++++++++++++++++++++++++++ libnfc/chips/pn53x.h | 2 + libnfc/nfc.c | 13 +++++- 7 files changed, 172 insertions(+), 1 deletion(-) diff --git a/examples/nfc-list.c b/examples/nfc-list.c index 129d43e..2a367b0 100644 --- a/examples/nfc-list.c +++ b/examples/nfc-list.c @@ -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.nbr = NBR_106; // List Jewel targets diff --git a/examples/nfc-utils.c b/examples/nfc-utils.c index 9a0f0fb..5b5a0ad 100644 --- a/examples/nfc-utils.c +++ b/examples/nfc-utils.c @@ -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 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)); print_nfc_iso14443b_info (nt.nti.nbi, verbose); 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: printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr)); print_nfc_dep_info (nt.nti.ndi, verbose); diff --git a/examples/nfc-utils.h b/examples/nfc-utils.h index 018193c..14fbe4c 100644 --- a/examples/nfc-utils.h +++ b/examples/nfc-utils.h @@ -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_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_jewel_info (const nfc_jewel_info_t nji, bool verbose); void print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose); diff --git a/include/nfc/nfc-types.h b/include/nfc/nfc-types.h index ca8d7e9..a05a433 100644 --- a/include/nfc/nfc-types.h +++ b/include/nfc/nfc-types.h @@ -147,6 +147,10 @@ typedef enum { NDO_EASY_FRAMING = 0x41, /** Force the chip to switch in ISO14443-A */ 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; /** @@ -223,6 +227,22 @@ typedef struct { uint8_t ui8CardIdentifier; } 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 * @brief NFC Jewel tag information @@ -240,6 +260,7 @@ typedef union { nfc_iso14443a_info_t nai; nfc_felica_info_t nfi; nfc_iso14443b_info_t nbi; + nfc_iso14443bi_info_t nii; nfc_jewel_info_t nji; nfc_dep_info_t ndi; } nfc_target_info_t; @@ -263,6 +284,7 @@ typedef enum { typedef enum { NMT_ISO14443A, NMT_ISO14443B, + NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B' NMT_FELICA, NMT_JEWEL, NMT_DEP, diff --git a/libnfc/chips/pn53x.c b/libnfc/chips/pn53x.c index f22a630..59439ae 100644 --- a/libnfc/chips/pn53x.c +++ b/libnfc/chips/pn53x.c @@ -368,6 +368,27 @@ pn53x_decode_target_data (const byte_t * pbtRawData, size_t szRawData, pn53x_typ } 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: // We skip the first byte: its the target number (Tg) pbtRawData++; @@ -588,6 +609,40 @@ pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool b return true; 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 @@ -628,11 +683,44 @@ pn53x_initiator_select_passive_target (nfc_device_t * pnd, byte_t abtTargetsData[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; 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); if (PM_UNDEFINED == pm) { pnd->iLastError = DENOTSUP; return false; } + if (!pn53x_InListPassiveTarget (pnd, pm, 1, pbtInitData, szInitData, abtTargetsData, &szTargetsData)) return false; @@ -1048,6 +1136,7 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_ } break; case NMT_ISO14443B: + case NMT_ISO14443BI: case NMT_JEWEL: pnd->iLastError = DENOTSUP; return false; @@ -1147,6 +1236,7 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_ pbtFeliCaParams = abtFeliCaParams; break; case NMT_ISO14443B: + case NMT_ISO14443BI: case NMT_JEWEL: pnd->iLastError = DENOTSUP; return false; @@ -1925,6 +2015,8 @@ pn53x_nm_to_pm(const nfc_modulation_t nm) break; } break; + + case NMT_ISO14443BI: case NMT_DEP: // Nothing to do... break; @@ -2024,6 +2116,7 @@ pn53x_nm_to_ptt(const nfc_modulation_t nm) } break; + case NMT_ISO14443BI: case NMT_DEP: // Nothing to do... break; diff --git a/libnfc/chips/pn53x.h b/libnfc/chips/pn53x.h index d05ee04..ad5cf4a 100644 --- a/libnfc/chips/pn53x.h +++ b/libnfc/chips/pn53x.h @@ -32,6 +32,7 @@ // Registers and symbols masks used to covers parts within a register # define REG_CIU_TX_MODE 0x6302 # define SYMBOL_TX_CRC_ENABLE 0x80 +# define SYMBOL_TX_SPEED 0x70 // TX_FRAMING bits explanation: // 00 : ISO/IEC 14443A/MIFARE and Passive Communication mode 106 kbit/s // 01 : Active Communication mode @@ -46,6 +47,7 @@ # define REG_CIU_RX_MODE 0x6303 # define SYMBOL_RX_CRC_ENABLE 0x80 +# define SYMBOL_RX_SPEED 0x70 # define SYMBOL_RX_NO_ERROR 0x08 # define SYMBOL_RX_MULTIPLE 0x04 // RX_FRAMING follow same scheme than TX_FRAMING diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 700e993..e78d26c 100644 --- a/libnfc/nfc.c +++ b/libnfc/nfc.c @@ -83,6 +83,7 @@ const struct nfc_driver_t *nfc_drivers[] = { * - Invalid frames are not accepted (NDO_ACCEPT_INVALID_FRAMES = false) * - Multiple frames are not accepted (NDO_ACCEPT_MULTIPLE_FRAMES = false) * - 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) * - 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 if (!nfc_configure (pnd, NDO_FORCE_ISO14443_A, true)) return false; + // Force speed at 106kbps + if (!nfc_configure (pnd, NDO_FORCE_SPEED_106, true)) + return false; // Disallow invalid frame if (!nfc_configure (pnd, NDO_ACCEPT_INVALID_FRAMES, false)) return false; @@ -376,6 +380,12 @@ nfc_initiator_list_passive_targets (nfc_device_t * pnd, szInitDataLen = 1; } break; + case NMT_ISO14443BI: { + // APGEN + pbtInitData = (byte_t *) "\x01\x0b\x3f\x80"; + szInitDataLen = 4; + } + break; case NMT_FELICA: { // polling payload must be present (see ISO/IEC 18092 11.2.2.5) pbtInitData = (byte_t *) "\x00\xff\xff\x01\x00"; @@ -396,7 +406,8 @@ nfc_initiator_list_passive_targets (nfc_device_t * pnd, } szTargetFound++; // 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; } }