New NFC modulation type NMT_BARCODE

This commit is contained in:
Philippe Teuwen 2017-05-17 13:38:20 +02:00
parent 9f1a68530a
commit dcdbff0705
16 changed files with 224 additions and 156 deletions

View file

@ -43,11 +43,12 @@ Improvements:
- nfc-mfultralight: add automatic modes and --check-magic - nfc-mfultralight: add automatic modes and --check-magic
- nfc-mfultralight: add support for magic gen2 cards - nfc-mfultralight: add support for magic gen2 cards
- nfc-mfultralight: add option to specify UID - nfc-mfultralight: add option to specify UID
- nfc-barcode: new command to read NFC Barcodes (Tag-Talks-First) - nfc-barcode: new command to read and decode NFC Barcodes (Tag-Talks-First)
Changes: Changes:
- nfc_get_supported_baud_rate() takes now a "mode" parameter - nfc_get_supported_baud_rate() takes now a "mode" parameter
- New nfc_get_supported_baud_rate_target_mode() - New nfc_get_supported_baud_rate_target_mode()
- New NFC modulation type NMT_BARCODE to support Thinfilm NFC Barcode protocol
Special thanks to: Special thanks to:
- Jim Anastassiou, Frédéric Bourgeois, Dario Carluccio, Emmanuel Dreyfus, - Jim Anastassiou, Frédéric Bourgeois, Dario Carluccio, Emmanuel Dreyfus,

View file

@ -1,6 +1,5 @@
SET(EXAMPLES-SOURCES SET(EXAMPLES-SOURCES
nfc-anticol nfc-anticol
nfc-barcode
nfc-dep-initiator nfc-dep-initiator
nfc-dep-target nfc-dep-target
nfc-emulate-forum-tag2 nfc-emulate-forum-tag2

View file

@ -2,7 +2,6 @@ SUBDIRS = pn53x-tamashell-scripts
bin_PROGRAMS = \ bin_PROGRAMS = \
nfc-anticol \ nfc-anticol \
nfc-barcode \
nfc-dep-initiator \ nfc-dep-initiator \
nfc-dep-target \ nfc-dep-target \
nfc-emulate-forum-tag2 \ nfc-emulate-forum-tag2 \
@ -36,10 +35,6 @@ nfc_anticol_SOURCES = nfc-anticol.c
nfc_anticol_LDADD = $(top_builddir)/libnfc/libnfc.la \ nfc_anticol_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la $(top_builddir)/utils/libnfcutils.la
nfc_barcode_SOURCES = nfc-barcode.c
nfc_barcode_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la
nfc_relay_SOURCES = nfc-relay.c nfc_relay_SOURCES = nfc-relay.c
nfc_relay_LDADD = $(top_builddir)/libnfc/libnfc.la \ nfc_relay_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la $(top_builddir)/utils/libnfcutils.la
@ -92,7 +87,6 @@ quick_start_example2_LDADD = $(top_builddir)/libnfc/libnfc.la \
dist_man_MANS = \ dist_man_MANS = \
nfc-anticol.1 \ nfc-anticol.1 \
nfc-barcode.1 \
nfc-dep-initiator.1 \ nfc-dep-initiator.1 \
nfc-dep-target.1 \ nfc-dep-target.1 \
nfc-emulate-tag.1 \ nfc-emulate-tag.1 \

View file

@ -261,6 +261,15 @@ typedef struct {
uint8_t btId[4]; uint8_t btId[4];
} nfc_jewel_info; } nfc_jewel_info;
/**
* @struct nfc_barcode_info
* @brief Thinfilm NFC Barcode information
*/
typedef struct {
size_t szDataLen;
uint8_t abtData[32];
} nfc_barcode_info;
/** /**
* @union nfc_target_info * @union nfc_target_info
* @brief Union between all kind of tags information structures. * @brief Union between all kind of tags information structures.
@ -273,6 +282,7 @@ typedef union {
nfc_iso14443b2sr_info nsi; nfc_iso14443b2sr_info nsi;
nfc_iso14443b2ct_info nci; nfc_iso14443b2ct_info nci;
nfc_jewel_info nji; nfc_jewel_info nji;
nfc_barcode_info nti; // "t" for Thinfilm, "b" already used
nfc_dep_info ndi; nfc_dep_info ndi;
} nfc_target_info; } nfc_target_info;
@ -295,6 +305,7 @@ typedef enum {
typedef enum { typedef enum {
NMT_ISO14443A = 1, NMT_ISO14443A = 1,
NMT_JEWEL, NMT_JEWEL,
NMT_BARCODE, // Thinfilm NFC Barcode
NMT_ISO14443B, NMT_ISO14443B,
NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B' NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B'
NMT_ISO14443B2SR, // ISO14443-2B ST SRx NMT_ISO14443B2SR, // ISO14443-2B ST SRx

View file

@ -57,6 +57,7 @@ const nfc_baud_rate pn533_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424,
const nfc_baud_rate pn53x_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 }; const nfc_baud_rate pn53x_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 };
const nfc_baud_rate pn53x_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 }; const nfc_baud_rate pn53x_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 };
const nfc_baud_rate pn53x_jewel_supported_baud_rates[] = { NBR_106, 0 }; const nfc_baud_rate pn53x_jewel_supported_baud_rates[] = { NBR_106, 0 };
const nfc_baud_rate pn53x_barcode_supported_baud_rates[] = { NBR_106, 0 };
const nfc_baud_rate pn532_iso14443b_supported_baud_rates[] = { NBR_106, 0 }; const nfc_baud_rate pn532_iso14443b_supported_baud_rates[] = { NBR_106, 0 };
const nfc_baud_rate pn533_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; const nfc_baud_rate pn533_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
const nfc_modulation_type pn53x_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_DEP, 0}; const nfc_modulation_type pn53x_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_DEP, 0};
@ -107,6 +108,8 @@ pn53x_init(struct nfc_device *pnd)
if (CHIP_DATA(pnd)->type != PN531) { if (CHIP_DATA(pnd)->type != PN531) {
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_JEWEL; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_JEWEL;
nbSupportedModulation++; nbSupportedModulation++;
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_BARCODE;
nbSupportedModulation++;
} }
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_DEP; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_DEP;
nbSupportedModulation++; nbSupportedModulation++;
@ -610,6 +613,10 @@ pn53x_decode_target_data(const uint8_t *pbtRawData, size_t szRawData, pn53x_type
pbtRawData += 2; pbtRawData += 2;
memcpy(pnti->nji.btId, pbtRawData, 4); memcpy(pnti->nji.btId, pbtRawData, 4);
break; break;
case NMT_BARCODE:
pnti->nti.szDataLen = szRawData;
memcpy(pnti->nti.abtData, pbtRawData, szRawData);
break;
// Should not happend... // Should not happend...
case NMT_DEP: case NMT_DEP:
return NFC_ECHIP; return NFC_ECHIP;
@ -1147,6 +1154,87 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
} while (pnd->bInfiniteSelect); } while (pnd->bInfiniteSelect);
if (! found) if (! found)
return 0; return 0;
} else if (nm.nmt == NMT_BARCODE) {
if (CHIP_DATA(pnd)->type == RCS360) {
// TODO add support for RC-S360, at the moment it refuses to send raw frames without a first select
pnd->last_error = NFC_ENOTIMPL;
return pnd->last_error;
}
// No native support in InListPassiveTarget so we do discovery by hand
// We turn RF field off first for a better detection rate but this doesn't work well with ASK LoGO
if ((! CHIP_DATA(pnd)->progressive_field) && (res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) {
return res;
}
if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false)) < 0) {
return res;
}
if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false)) < 0) {
return res;
}
bool found = false;
do {
uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
if ((res = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 0) {
if ((res == NFC_ERFTRANS) || (res == NFC_ECHIP)) { // Broken reception
continue;
} else {
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);
nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true);
return res;
}
}
// Shuffle bits to produce NFC Barcode bitstream
uint8_t uRemainder;
size_t szPos;
size_t szBytes = res / 8;
size_t off = 0;
uint8_t i;
memset(abtTargetsData, 0x00, sizeof(abtTargetsData));
// Reinject S bit
abtTargetsData[off / 8] |= 1 << (7 - (off % 8));
off++;
for (szPos = 0; szPos < szBytes; szPos++) {
for (i = 0; i < 8; i++) {
abtTargetsData[off / 8] |= ((abtRx[szPos] >> i) & 1) << (7 - (off % 8));
off++;
}
abtTargetsData[off / 8] |= abtRxPar[szPos] << (7 - (off % 8));
off++;
}
uRemainder = res % 8;
for (i = 0; i < uRemainder; i++) {
abtTargetsData[off / 8] |= ((abtRx[szPos] >> i) & 1) << (7 - (off % 8));
off++;
}
if (off % 128 != 0) {
// NFC Barcode seems incomplete
continue;
}
szTargetsData = (size_t)off / 8;
// validate CRC
uint8_t pbtCrc[2];
iso14443a_crc(abtTargetsData, szTargetsData - 2, pbtCrc);
if ((pbtCrc[1] != abtTargetsData[szTargetsData - 2]) || (pbtCrc[0] != abtTargetsData[szTargetsData - 1])) {
continue;
}
nttmp.nm = nm;
if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) {
return res;
}
found = true;
break;
} while (pnd->bInfiniteSelect);
if (! found) {
return 0;
}
} else { } else {
const pn53x_modulation pm = pn53x_nm_to_pm(nm); const pn53x_modulation pm = pn53x_nm_to_pm(nm);
if ((PM_UNDEFINED == pm) || (NBR_UNDEFINED == nm.nbr)) { if ((PM_UNDEFINED == pm) || (NBR_UNDEFINED == nm.nbr)) {
@ -1846,6 +1934,40 @@ static int pn53x_ISO14443A_Jewel_is_present(struct nfc_device *pnd)
return ret; return ret;
} }
static int pn53x_ISO14443A_Barcode_is_present(struct nfc_device *pnd)
{
int ret;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping Barcode");
// We turn RF field off first for a better detection rate but this doesn't work well with ASK LoGO
if ((! CHIP_DATA(pnd)->progressive_field) && (ret = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) {
return ret;
}
if ((ret = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false)) < 0)
return ret;
if ((ret = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false)) < 0)
return ret;
int failures = 0;
while (failures < 3) {
if ((! CHIP_DATA(pnd)->progressive_field) && (ret = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) {
return ret;
}
uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
if ((ret = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 1) {
failures++;
} else {
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);
nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true);
return NFC_SUCCESS;
}
}
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);
nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true);
return NFC_ETGRELEASED;
}
static int pn53x_ISO14443A_MFUL_is_present(struct nfc_device *pnd) static int pn53x_ISO14443A_MFUL_is_present(struct nfc_device *pnd)
{ {
int ret; int ret;
@ -2081,6 +2203,9 @@ pn53x_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt)
case NMT_JEWEL: case NMT_JEWEL:
ret = pn53x_ISO14443A_Jewel_is_present(pnd); ret = pn53x_ISO14443A_Jewel_is_present(pnd);
break; break;
case NMT_BARCODE:
ret = pn53x_ISO14443A_Barcode_is_present(pnd);
break;
case NMT_ISO14443B: case NMT_ISO14443B:
ret = pn53x_ISO14443B_4_is_present(pnd); ret = pn53x_ISO14443B_4_is_present(pnd);
break; break;
@ -2144,6 +2269,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE:
pnd->last_error = NFC_EDEVNOTSUPP; pnd->last_error = NFC_EDEVNOTSUPP;
return pnd->last_error; return pnd->last_error;
} }
@ -2245,6 +2371,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE:
pnd->last_error = NFC_EDEVNOTSUPP; pnd->last_error = NFC_EDEVNOTSUPP;
return pnd->last_error; return pnd->last_error;
} }
@ -2393,6 +2520,7 @@ pn53x_target_receive_bytes(struct nfc_device *pnd, uint8_t *pbtRx, const size_t
} }
// NO BREAK // NO BREAK
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE:
case NMT_ISO14443B: case NMT_ISO14443B:
case NMT_ISO14443BI: case NMT_ISO14443BI:
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
@ -2498,6 +2626,7 @@ pn53x_target_send_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size
} }
// NO BREAK // NO BREAK
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE:
case NMT_ISO14443B: case NMT_ISO14443B:
case NMT_ISO14443BI: case NMT_ISO14443BI:
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
@ -2714,6 +2843,7 @@ pn53x_InListPassiveTarget(struct nfc_device *pnd,
} }
break; break;
case PM_JEWEL_106: case PM_JEWEL_106:
case PM_BARCODE_106:
if (CHIP_DATA(pnd)->type == PN531) { if (CHIP_DATA(pnd)->type == PN531) {
// These modulations are not supported by pn531 // These modulations are not supported by pn531
pnd->last_error = NFC_EDEVNOTSUPP; pnd->last_error = NFC_EDEVNOTSUPP;
@ -3141,6 +3271,9 @@ pn53x_nm_to_pm(const nfc_modulation nm)
case NMT_JEWEL: case NMT_JEWEL:
return PM_JEWEL_106; return PM_JEWEL_106;
case NMT_BARCODE:
return PM_BARCODE_106;
case NMT_FELICA: case NMT_FELICA:
switch (nm.nbr) { switch (nm.nbr) {
case NBR_212: case NBR_212:
@ -3253,6 +3386,7 @@ pn53x_nm_to_ptt(const nfc_modulation nm)
case NMT_ISO14443BI: case NMT_ISO14443BI:
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
case NMT_BARCODE:
case NMT_DEP: case NMT_DEP:
// Nothing to do... // Nothing to do...
break; break;
@ -3307,6 +3441,9 @@ pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_mo
case NMT_JEWEL: case NMT_JEWEL:
*supported_br = (nfc_baud_rate *)pn53x_jewel_supported_baud_rates; *supported_br = (nfc_baud_rate *)pn53x_jewel_supported_baud_rates;
break; break;
case NMT_BARCODE:
*supported_br = (nfc_baud_rate *)pn53x_barcode_supported_baud_rates;
break;
case NMT_DEP: case NMT_DEP:
*supported_br = (nfc_baud_rate *)pn53x_dep_supported_baud_rates; *supported_br = (nfc_baud_rate *)pn53x_dep_supported_baud_rates;
break; break;
@ -3560,6 +3697,9 @@ pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io)
CHIP_DATA(pnd)->supported_modulation_as_target = NULL; CHIP_DATA(pnd)->supported_modulation_as_target = NULL;
// Set default progressive field flag
CHIP_DATA(pnd)->progressive_field = false;
return pnd->chip_data; return pnd->chip_data;
} }

View file

@ -210,6 +210,7 @@ struct pn53x_data {
/** Supported modulation type */ /** Supported modulation type */
nfc_modulation_type *supported_modulation_as_initiator; nfc_modulation_type *supported_modulation_as_initiator;
nfc_modulation_type *supported_modulation_as_target; nfc_modulation_type *supported_modulation_as_target;
bool progressive_field;
}; };
#define CHIP_DATA(pnd) ((struct pn53x_data*)(pnd->chip_data)) #define CHIP_DATA(pnd) ((struct pn53x_data*)(pnd->chip_data))
@ -231,6 +232,8 @@ typedef enum {
PM_ISO14443B_106 = 0x03, PM_ISO14443B_106 = 0x03,
/** Jewel Topaz (Innovision Research & Development) (Not supported by PN531) */ /** Jewel Topaz (Innovision Research & Development) (Not supported by PN531) */
PM_JEWEL_106 = 0x04, PM_JEWEL_106 = 0x04,
/** Thinfilm NFC Barcode (Not supported by PN531) */
PM_BARCODE_106 = 0x05,
/** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */ /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */
PM_ISO14443B_212 = 0x06, PM_ISO14443B_212 = 0x06,
/** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */ /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */

View file

@ -474,6 +474,7 @@ pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring)
// empirical tuning // empirical tuning
case ASK_LOGO: case ASK_LOGO:
CHIP_DATA(pnd)->timer_correction = 50; CHIP_DATA(pnd)->timer_correction = 50;
CHIP_DATA(pnd)->progressive_field = true;
break; break;
case SCM_SCL3711: case SCM_SCL3711:
case SCM_SCL3712: case SCM_SCL3712:

View file

@ -201,6 +201,7 @@ prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, siz
break; break;
case NMT_ISO14443A: case NMT_ISO14443A:
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE:
case NMT_DEP: case NMT_DEP:
*ppbtInitiatorData = NULL; *ppbtInitiatorData = NULL;
*pszInitiatorData = 0; *pszInitiatorData = 0;

View file

@ -602,9 +602,10 @@ nfc_initiator_list_passive_targets(nfc_device *pnd,
break; break;
} }
nfc_initiator_deselect_target(pnd); nfc_initiator_deselect_target(pnd);
// deselect has no effect on FeliCa and Jewel cards so we'll stop after one... // deselect has no effect on FeliCa, Jewel and Thinfilm cards so we'll stop after one...
// ISO/IEC 14443 B' cards are polled at 100% probability so it's not possible to detect correctly two cards at the same time // 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) || (nm.nmt == NMT_ISO14443B2SR) || (nm.nmt == NMT_ISO14443B2CT)) { if ((nm.nmt == NMT_FELICA) || (nm.nmt == NMT_JEWEL) || (nm.nmt == NMT_BARCODE) ||
(nm.nmt == NMT_ISO14443BI) || (nm.nmt == NMT_ISO14443B2SR) || (nm.nmt == NMT_ISO14443B2CT)) {
break; break;
} }
} }
@ -1356,6 +1357,8 @@ str_nfc_modulation_type(const nfc_modulation_type nmt)
return "FeliCa"; return "FeliCa";
case NMT_JEWEL: case NMT_JEWEL:
return "Innovision Jewel"; return "Innovision Jewel";
case NMT_BARCODE:
return "Thinfilm NFC Barcode";
case NMT_DEP: case NMT_DEP:
return "D.E.P."; return "D.E.P.";
} }

View file

@ -498,6 +498,22 @@ snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool
snprint_hex(dst + off, size - off, pnji->btId, 4); snprint_hex(dst + off, size - off, pnji->btId, 4);
} }
void
snprint_nfc_barcode_info(char *dst, size_t size, const nfc_barcode_info *pnti, bool verbose)
{
(void) verbose;
int off = 0;
off += snprintf(dst + off, size - off, " Size (bits): %lu\n", pnti->szDataLen * 8);
off += snprintf(dst + off, size - off, " Content: ");
for (uint8_t i = 0; i < pnti->szDataLen; i++) {
off += snprintf(dst + off, size - off, "%02X", pnti->abtData[i]);
if ((i % 8 == 7) && (i < (pnti->szDataLen - 1))) {
off += snprintf(dst + off, size - off, "\n ");
}
}
snprintf(dst + off, size - off, "\n");
}
#define PI_ISO14443_4_SUPPORTED 0x01 #define PI_ISO14443_4_SUPPORTED 0x01
#define PI_NAD_SUPPORTED 0x01 #define PI_NAD_SUPPORTED 0x01
#define PI_CID_SUPPORTED 0x02 #define PI_CID_SUPPORTED 0x02
@ -637,6 +653,9 @@ snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose)
case NMT_JEWEL: case NMT_JEWEL:
snprint_nfc_jewel_info(dst + off, size - off, &pnt->nti.nji, verbose); snprint_nfc_jewel_info(dst + off, size - off, &pnt->nti.nji, verbose);
break; break;
case NMT_BARCODE:
snprint_nfc_barcode_info(dst + off, size - off, &pnt->nti.nti, verbose);
break;
case NMT_FELICA: case NMT_FELICA:
snprint_nfc_felica_info(dst + off, size - off, &pnt->nti.nfi, verbose); snprint_nfc_felica_info(dst + off, size - off, &pnt->nti.nfi, verbose);
break; break;

View file

@ -40,6 +40,7 @@ void snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443
void snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose); void snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose);
void snprint_nfc_felica_info(char *dst, size_t size, const nfc_felica_info *pnfi, bool verbose); void snprint_nfc_felica_info(char *dst, size_t size, const nfc_felica_info *pnfi, bool verbose);
void snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool verbose); void snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool verbose);
void snprint_nfc_barcode_info(char *dst, size_t size, const nfc_barcode_info *pnti, bool verbose);
void snprint_nfc_dep_info(char *dst, size_t size, const nfc_dep_info *pndi, bool verbose); void snprint_nfc_dep_info(char *dst, size_t size, const nfc_dep_info *pndi, bool verbose);
void snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose); void snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose);

View file

@ -1,4 +1,5 @@
SET(UTILS-SOURCES SET(UTILS-SOURCES
nfc-barcode
nfc-emulate-forum-tag4 nfc-emulate-forum-tag4
nfc-jewel nfc-jewel
nfc-list nfc-list

View file

@ -1,4 +1,5 @@
bin_PROGRAMS = \ bin_PROGRAMS = \
nfc-barcode \
nfc-emulate-forum-tag4 \ nfc-emulate-forum-tag4 \
nfc-jewel \ nfc-jewel \
nfc-list \ nfc-list \
@ -16,6 +17,10 @@ noinst_LTLIBRARIES = libnfcutils.la
libnfcutils_la_SOURCES = nfc-utils.c libnfcutils_la_SOURCES = nfc-utils.c
libnfcutils_la_LIBADD = -lnfc libnfcutils_la_LIBADD = -lnfc
nfc_barcode_SOURCES = nfc-barcode.c
nfc_barcode_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la
nfc_emulate_forum_tag4_SOURCES = nfc-emulate-forum-tag4.c nfc-utils.h nfc_emulate_forum_tag4_SOURCES = nfc-emulate-forum-tag4.c nfc-utils.h
nfc_emulate_forum_tag4_LDADD = $(top_builddir)/libnfc/libnfc.la \ nfc_emulate_forum_tag4_LDADD = $(top_builddir)/libnfc/libnfc.la \
libnfcutils.la libnfcutils.la
@ -47,6 +52,7 @@ nfc_scan_device_LDADD = $(top_builddir)/libnfc/libnfc.la \
libnfcutils.la libnfcutils.la
dist_man_MANS = \ dist_man_MANS = \
nfc-barcode.1 \
nfc-emulate-forum-tag4.1 \ nfc-emulate-forum-tag4.1 \
nfc-jewel.1 \ nfc-jewel.1 \
nfc-list.1 \ nfc-list.1 \

View file

@ -5,7 +5,7 @@ nfc-barcode \- NFC Barcode (Tag-Talks-First) reader
.B nfc-barcode .B nfc-barcode
.SH DESCRIPTION .SH DESCRIPTION
.B nfc-barcode .B nfc-barcode
is a utility to read NFC Barcodes is a utility to read and decode NFC Barcodes
.SH OPTIONS .SH OPTIONS
.B -d .B -d
@ -14,14 +14,6 @@ Decode content, if possible.
.B -v .B -v
Verbose. Verbose.
.B -r
Keep RF field on (for slow devices such as ASK LoGO).
.B -n N
Try up to
.B N
times (default=1, max 255).
.SH BUGS .SH BUGS
Please report any bugs on the Please report any bugs on the
.B libnfc .B libnfc

View file

@ -55,9 +55,6 @@
static nfc_device *pnd; static nfc_device *pnd;
bool verbose = false; bool verbose = false;
bool decode = false;
bool rfoff = true;
uint8_t n = 1;
static void static void
print_usage(char *argv[]) print_usage(char *argv[])
@ -66,64 +63,12 @@ print_usage(char *argv[])
printf("Options:\n"); printf("Options:\n");
printf("\t-h\tHelp. Print this message.\n"); printf("\t-h\tHelp. Print this message.\n");
printf("\t-q\tVerbose mode.\n"); printf("\t-q\tVerbose mode.\n");
printf("\t-d\tDecode content.\n");
printf("\t-r\tKeep RF field on (for slow devices such as ASK LoGO).\n");
printf("\t-n\tTry up to n times (default=1, max 255).\n");
} }
static int
bits2barcode(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar, uint8_t *pbtBarcode, const size_t szBarcode)
{
uint8_t uRemainder;
size_t szPos;
size_t szBytes = szBits / 8;
size_t off = 0;
uint8_t i;
for (i = 0; i < szBarcode; i++) {
pbtBarcode[i] = 0;
}
// Reinject S bit
pbtBarcode[off / 8] |= 1 << (7 - (off % 8));
off++;
for (szPos = 0; szPos < szBytes; szPos++) {
for (i = 0; i < 8; i++) {
pbtBarcode[off / 8] |= ((pbtData[szPos] >> i) & 1) << (7 - (off % 8));
off++;
}
pbtBarcode[off / 8] |= pbtDataPar[szPos] << (7 - (off % 8));
off++;
}
uRemainder = szBits % 8;
for (i = 0; i < uRemainder; i++) {
pbtBarcode[off / 8] |= ((pbtData[szPos] >> i) & 1) << (7 - (off % 8));
off++;
}
return off;
}
static bool
validate_crc(uint8_t *pbtBarcode, const size_t szBarcode)
{
if (szBarcode % 128 != 0) {
printf("Warning, NFC Barcode seems incomplete, skipping CRC\n");
return false;
}
uint8_t pbtCrc[2];
iso14443a_crc(pbtBarcode, (szBarcode / 8) - 2, pbtCrc);
if (verbose)
printf("Computed CRC: %02X %02X\n", pbtCrc[1], pbtCrc[0]);
return (pbtCrc[1] == pbtBarcode[(szBarcode / 8) - 2]) && (pbtCrc[0] == pbtBarcode[(szBarcode / 8) - 1]);
}
static bool static bool
decode_barcode(uint8_t *pbtBarcode, const size_t szBarcode) decode_barcode(uint8_t *pbtBarcode, const size_t szBarcode)
{ {
if (szBarcode % 128 != 0) {
printf("Warning, NFC Barcode seems incomplete, skipping decoding\n");
return false;
}
if (verbose) { if (verbose) {
printf("Manufacturer ID field: %02X\n", pbtBarcode[0]); printf("Manufacturer ID field: %02X\n", pbtBarcode[0]);
switch (pbtBarcode[0]) { switch (pbtBarcode[0]) {
@ -180,7 +125,7 @@ decode_barcode(uint8_t *pbtBarcode, const size_t szBarcode)
default: default:
printf("Data Format Field: unknown (%02X)\n", pbtBarcode[1]); printf("Data Format Field: unknown (%02X)\n", pbtBarcode[1]);
printf("Data:"); printf("Data:");
for (uint8_t i = 2; i < (szBarcode / 8) - 2; i++) { for (uint8_t i = 2; i < szBarcode - 2; i++) {
printf("%02x", pbtBarcode[i]); printf("%02x", pbtBarcode[i]);
} }
printf("\n"); printf("\n");
@ -193,9 +138,6 @@ int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int arg; int arg;
uint8_t abtRx[MAX_FRAME_LEN];
uint8_t abtRxPar[MAX_FRAME_LEN];
uint8_t pbtBarcode[64];
// Get commandline options // Get commandline options
for (arg = 1; arg < argc; arg++) { for (arg = 1; arg < argc; arg++) {
@ -204,16 +146,6 @@ main(int argc, char *argv[])
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} else if (0 == strcmp(argv[arg], "-v")) { } else if (0 == strcmp(argv[arg], "-v")) {
verbose = true; verbose = true;
} else if (0 == strcmp(argv[arg], "-d")) {
decode = true;
} else if (0 == strcmp(argv[arg], "-r")) {
rfoff = false;
} else if (0 == strcmp(argv[arg], "-n")) {
arg++;
int tmpn = atoi(argv[arg]);
if ((tmpn > 0) && (tmpn < 256)) {
n = tmpn;
}
} else { } else {
ERR("%s is not supported option.", argv[arg]); ERR("%s is not supported option.", argv[arg]);
print_usage(argv); print_usage(argv);
@ -247,72 +179,19 @@ main(int argc, char *argv[])
printf("NFC reader: %s opened\n\n", nfc_device_get_name(pnd)); printf("NFC reader: %s opened\n\n", nfc_device_get_name(pnd));
if ((rfoff && (nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false) < 0)) || nfc_modulation nm;
(nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) || nm.nmt = NMT_BARCODE;
(nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false) < 0)) { nm.nbr = NBR_106;
nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_target ant[1];
nfc_close(pnd); // List NFC Barcode targets
nfc_exit(context); if ((nfc_initiator_list_passive_targets(pnd, nm, ant, 1)) == 1) {
exit(EXIT_FAILURE); if (verbose) {
} for (uint8_t i = 0; i < (&ant[0])->nti.nti.szDataLen; i++) {
printf("%02x", (&ant[0])->nti.nti.abtData[i]);
for (; n > 0; n--) {
int res;
if ((res = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 0) {
if (verbose)
nfc_perror(pnd, "nfc_initiator_transceive_bits");
if (n == 1) {
printf("No NFC Barcode found\n");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
continue;
}
if (verbose)
print_hex_par(abtRx, res, abtRxPar);
res = bits2barcode(abtRx, res, abtRxPar, pbtBarcode, sizeof(pbtBarcode));
if (res % 128 != 0) {
if (verbose) {
printf("Error, NFC Barcode seems incomplete, received %u bits\n", res);
print_hex_bits(pbtBarcode, res);
}
if (n == 1) {
printf("Error, NFC Barcode seems incomplete, received %u bits\n", res);
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
continue;
}
if (validate_crc(pbtBarcode, res)) {
if (verbose) {
printf("CRC correct\n");
}
} else {
if (n == 1) {
printf("CRC error\n");
if (verbose) {
print_hex_bits(pbtBarcode, res);
}
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
continue;
}
if (verbose || ! decode) {
for (uint8_t i = 0; i < res / 8; i++) {
printf("%02x", pbtBarcode[i]);
} }
printf("\n"); printf("\n");
} }
if (decode) { decode_barcode((&ant[0])->nti.nti.abtData, (&ant[0])->nti.nti.szDataLen);
decode_barcode(pbtBarcode, res);
}
break;
} }
nfc_close(pnd); nfc_close(pnd);
nfc_exit(context); nfc_exit(context);

View file

@ -71,8 +71,9 @@ print_usage(const char *progname)
printf("\t 16: ISO14443B'\n"); printf("\t 16: ISO14443B'\n");
printf("\t 32: ISO14443B-2 ST SRx\n"); printf("\t 32: ISO14443B-2 ST SRx\n");
printf("\t 64: ISO14443B-2 ASK CTx\n"); printf("\t 64: ISO14443B-2 ASK CTx\n");
printf("\t 128: Jewel\n"); printf("\t 128: ISO14443A-3 Jewel\n");
printf("\tSo 255 (default) polls for all types.\n"); printf("\t 256: ISO14443A-2 NFC Barcode\n");
printf("\tSo 511 (default) polls for all types.\n");
printf("\tNote that if 16, 32 or 64 then 8 is selected too.\n"); printf("\tNote that if 16, 32 or 64 then 8 is selected too.\n");
} }
@ -84,7 +85,7 @@ main(int argc, const char *argv[])
size_t i; size_t i;
bool verbose = false; bool verbose = false;
int res = 0; int res = 0;
int mask = 0xff; int mask = 0x1ff;
int arg; int arg;
nfc_context *context; nfc_context *context;
@ -108,7 +109,7 @@ main(int argc, const char *argv[])
} else if ((0 == strcmp(argv[arg], "-t")) && (arg + 1 < argc)) { } else if ((0 == strcmp(argv[arg], "-t")) && (arg + 1 < argc)) {
arg++; arg++;
mask = atoi(argv[arg]); mask = atoi(argv[arg]);
if ((mask < 1) || (mask > 255)) { if ((mask < 1) || (mask > 0x1ff)) {
ERR("%i is invalid value for type bitfield.", mask); ERR("%i is invalid value for type bitfield.", mask);
print_usage(argv[0]); print_usage(argv[0]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -277,7 +278,23 @@ main(int argc, const char *argv[])
if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) {
int n; int n;
if (verbose || (res > 0)) { if (verbose || (res > 0)) {
printf("%d Jewel passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":"); printf("%d ISO14443A-3 Jewel passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
}
for (n = 0; n < res; n++) {
print_nfc_target(&ant[n], verbose);
printf("\n");
}
}
}
if (mask & 0x100) {
nm.nmt = NMT_BARCODE;
nm.nbr = NBR_106;
// List NFC Barcode targets
if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) {
int n;
if (verbose || (res > 0)) {
printf("%d ISO14443A-2 NFC Barcode passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
} }
for (n = 0; n < res; n++) { for (n = 0; n < res; n++) {
print_nfc_target(&ant[n], verbose); print_nfc_target(&ant[n], verbose);